接下来讲讲当咱们遇到以下的excel文档,要求采纳这种模板形式导出

若每个单元格都设置款式的形式,则会很繁琐

那么咱们能不能读取该模板,获取外面的款式,导出的时候使用到呢?

一、应用模板打印


要想应用模板的形式读取款式,首先就获取到该模板,咱们的思路是

  1. 制作模版文件(模版文件的门路)
  2. 导入(加载)模版文件,从而失去一个工作簿
  3. 读取工作表
  4. 读取行
  5. 读取单元格
  6. 读取单元格款式
  7. 设置单元格内容
  8. 其余单元格应用读取款式

接下来让咱们代码实际实现思路,从获取模板开始....

@RequestMapping(value = "/export/{month}", method = RequestMethod.GET)public void export(@PathVariable(name = "month") String month) throws Exception {    //1.结构数据    List<User> list = userService.findByReport(companyId,month+"%");        //2.加载模板流数据    Resource resource = new ClassPathResource("excel-template/hr-demo.xlsx");    FileInputStream fis = new FileInputStream(resource.getFile());        //3.依据文件流,加载指定的工作簿    XSSFWorkbook wb = new XSSFWorkbook(fis);        //4.读取工作表    Sheet sheet = wb.getSheetAt(0);        //5.抽取公共的款式    Row styleRow = sheet.getRow(2);//第三行    CellStyle [] styles = new CellStyle[styleRow.getLastCellNum()];    for(int i=0;i<styleRow.getLastCellNum();i++) {        styles[i] = styleRow.getCell(i).getCellStyle();    }}

这时咱们曾经将Excel文档里的第三行单元格款式保留到CelStyle数组里

若咱们想应用的话,只须要依据对应数组下标for循环读取即可

@RequestMapping(value = "/export/{month}", method = RequestMethod.GET)public void export(@PathVariable(name = "month") String month) throws Exception {        //6.构建cell单元格    Cell cell = null;    int titleInext = 2;    for (user report : list) {        styleRow = sheet.createRow(titleInext++);        //编号        cell = dataRow.createCell(0);        cell.setCellValue(report.getUserId());        cell.setCellStyle(styles[0]);        //姓名        cell = dataRow.createCell(1);        cell.setCellValue(report.getUsername());        cell.setCellStyle(styles[1]);        //手机        cell = dataRow.createCell(2);        cell.setCellValue(report.getMobile());        cell.setCellStyle(styles[2]);    }     //7.输入文件下载    String fileName = URLEncoder.encode(month+"人员信息.xlsx", "UTF-8");    response.setContentType("application/octet-stream");    response.setHeader("content-disposition", "attachment;filename=" + newString(fileName.getBytes("ISO8859-1")));    response.setHeader("filename", fileName);    workbook.write(response.getOutputStream());   }

再导出的话,咱们就能够领有对应的款式了

二、自定义工具类


应用模板打印时,咱们将模板里的第三行单元格款式存储到数组中

那么咱们采纳一个for循环的操作进行赋值

for (user report : list) {    styleRow = sheet.createRow(titleInext++);    for(int j=0;j<styles.length;j++){        cell = dataRow.createCell(j);//创立单元格        cell.setCellStyle(styles[0]);//赋值单元格款式    }}

然而咱们怎么晓得这个第一个单元格赋值ID、第二个单元格赋值名称呢?

咱们对于单元格的地位和属性,并且动静的应用对象属性赋值须要思考

咱们能够不能够应用注解的形式进行标注呢?

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface ExcelAttribute {    /** 对应的列名称 */    String name() default "";    /** 列序号 */    int sort();    /** 字段类型对应的格局 */    String format() default "";}

当咱们须要应用的时候则在User类应用注解形式来定位赋值的地位

class User{        @ExcelAttribute(sort = 0)    private String name;        @ExcelAttribute(sort = 1)    private String tel;    //省略其余关键性代码.....}

接下来咱们领会领会应用注解的形式获取值

//1.结构数据List<User> list = userService.findByReport(companyId,month+"%");//2.加载模板流数据Resource resource = new ClassPathResource("excel-template/hr-demo.xlsx");FileInputStream fis = new FileInputStream(resource.getFile());//3.获取User类的ClassClass clazz = User.class;//3.获取本人申明User的各种字段//包含public,protected,privateField fields[] = clazz.getDeclaredFields();//4.依据文件流,加载指定的工作簿XSSFWorkbook wb = new XSSFWorkbook(fis);    //5.读取工作表Sheet sheet = wb.getSheetAt(0);//6.抽取公共的款式Row styleRow = sheet.getRow(2);//第三行CellStyle [] styles = new CellStyle[styleRow.getLastCellNum()];for(int i=0;i<styleRow.getLastCellNum();i++) {    styles[i] = styleRow.getCell(i).getCellStyle();}//7.写入单元格表int titleInext = 2;for (user report : list) {    Row row = sheet.createRow(titleInext++);    for(int i=0;i<styles.length;i++) {        Cell cell = row.createCell(i);        cell.setCellStyle(styles[i]);        //获取本人申明User的各种字段        for (Field field : fields) {            //如果ExcelAttribute注解存在于此字段上            if(field.isAnnotationPresent(ExcelAttribute.class)){                //setAccessible = true意味着容许客户端领有超级权限                //比方Java对象序列化 或者 其余长久化机制等通常禁止的机制                field.setAccessible(true);                //返回字段上的ExcelAttribute 注解                ExcelAttribute ea = field.getAnnotation(ExcelAttribute.class);                //将字段上的排序序号进行匹配赋值                if(i == ea.sort()) {                    cell.setCellValue(field.get(t).toString());                }            }        }    }}

这样的状况咱们只须要标注对应的字段地位款式即可,更加简洁代码

三、导入工具类


同理,依据导出的思路,咱们也能够将导入的形式也变成一个工具类

一样应用一个注解的形式来标注对应的单元格与字段地位

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface ExcelAttribute {    /** 对应的列名称 */    String name() default "";    /** 列序号 */    int sort();    /** 字段类型对应的格局 */    String format() default "";}
class User{        @ExcelAttribute(sort = 0)    private String name;        @ExcelAttribute(sort = 1)    private String tel;    //省略其余关键性代码.....}

咱们的目标是将单元格里的信息与字段进行匹配返回实体类汇合

那么对于单元格里的属性解决、以及实体类的字段类型咱们要进行转换

/** * 格局转为String * @param cell * @return */public String getValue(Cell cell) {    if (cell == null) {        return "";    }    switch (cell.getCellType()) {        case STRING:            return cell.getRichStringCellValue().getString().trim();        case NUMERIC:            if (DateUtil.isCellDateFormatted(cell)) {                Date dt = DateUtil.getJavaDate(cell.getNumericCellValue());                return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(dt);            } else {                // 避免数值变成迷信计数法                String strCell = "";                Double num = cell.getNumericCellValue();                BigDecimal bd = new BigDecimal(num.toString());                if (bd != null) {                    strCell = bd.toPlainString();                }                // 去除 浮点型 主动加的 .0                if (strCell.endsWith(".0")) {                    strCell = strCell.substring(0, strCell.indexOf("."));                }                return strCell;            }        case BOOLEAN:            return String.valueOf(cell.getBooleanCellValue());        default:            return "";    }}
/** * 类型转换 将cell 单元格格局转为 字段类型 */private Object covertAttrType(Field field, Cell cell) throws Exception {    String fieldType = field.getType().getSimpleName();    if ("String".equals(fieldType)) {        return getValue(cell);    }else if ("Date".equals(fieldType)) {        return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(getValue(cell)) ;    }else if ("int".equals(fieldType) || "Integer".equals(fieldType)) {        return Integer.parseInt(getValue(cell));    }else if ("double".equals(fieldType) || "Double".equals(fieldType)) {        return Double.parseDouble(getValue(cell));    }else {        return null;    }    //其余类型待增加......}

接下来咱们依据导出的思路,编写导入的形式将对应的单元格绑定实体类

//1.组装User的汇合List<User> list = new ArrayList<User>();//2.反射实体类User entity = null;//3.导入的文件InputStream流XSSFWorkbook workbook = new XSSFWorkbook(is);Sheet sheet = workbook.getSheetAt(0);//4.获取User类的ClassClass clazz = User.class;//5.获取本人申明User的各种字段//包含public,protected,privateField fields[] = clazz.getDeclaredFields();//6.定义初始行数与单元格int beginRow = 1;//从第几行开始读取int beginCell = 1;//从第几单元格开始读取Row row = null;//7.循环读取行数try {    for (int rowNum = beginRow; rowNum <= sheet.getLastRowNum(); rowNum++) {        //获取行        row = sheet.getRow(rowNum);        //实例化对象        entity = (User)clazz.newInstance();        //循环读取每行的单元格数        for (int j = beginCell; j < row.getLastCellNum(); j++) {            //获取单元格            Cell cell = row.getCell(j);            for (Field field : fields) {                if(field.isAnnotationPresent(ExcelAttribute.class)){                    field.setAccessible(true);                    ExcelAttribute ea = field.getAnnotation(ExcelAttribute.class);                    if(j == ea.sort()) {                        //应用covertAttrType进行类型转换                        field.set(entity, covertAttrType(field, cell));                    }                }            }        }        list.add(entity);    }} catch (Exception e) {    e.printStackTrace();}

这样咱们就能够应用工具类,将导入的excel文档读取单元格信息与实体类绑定

四、工具类整顿


依据咱们的思路提供整合导入工具类、导出工具类方便使用

//导入工具类public class ExcelImportUtil<T> {     private Class clazz;    private  Field fields[];     public ExcelImportUtil(Class clazz) {        this.clazz = clazz;        fields = clazz.getDeclaredFields();    }     /**     * 基于注解读取excel     */    public List<T> readExcel(InputStream is, int rowIndex,int cellIndex) {        List<T> list = new ArrayList<T>();        T entity = null;        try {            XSSFWorkbook workbook = new XSSFWorkbook(is);            Sheet sheet = workbook.getSheetAt(0);            System.out.println(sheet.getLastRowNum());            for (int rowNum = rowIndex; rowNum <= sheet.getLastRowNum(); rowNum++) {                Row row = sheet.getRow(rowNum);                entity = (T) clazz.newInstance();                System.out.println(row.getLastCellNum());                for (int j = cellIndex; j < row.getLastCellNum(); j++) {                    Cell cell = row.getCell(j);                    for (Field field : fields) {                        if(field.isAnnotationPresent(ExcelAttribute.class)){                            field.setAccessible(true);                            ExcelAttribute ea = field.getAnnotation(ExcelAttribute.class);                            if(j == ea.sort()) {                                field.set(entity, covertAttrType(field, cell));                            }                        }                    }                }                list.add(entity);            }        } catch (Exception e) {            e.printStackTrace();        }        return list;    }     /**     * 类型转换 将cell 单元格格局转为 字段类型     */    private Object covertAttrType(Field field, Cell cell) throws Exception {        String fieldType = field.getType().getSimpleName();        if ("String".equals(fieldType)) {            return getValue(cell);        }else if ("Date".equals(fieldType)) {            return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(getValue(cell)) ;        }else if ("int".equals(fieldType) || "Integer".equals(fieldType)) {            return Integer.parseInt(getValue(cell));        }else if ("double".equals(fieldType) || "Double".equals(fieldType)) {            return Double.parseDouble(getValue(cell));        }else {            return null;        }    }      /**     * 格局转为String     * @param cell     * @return     */    public String getValue(Cell cell) {        if (cell == null) {            return "";        }        switch (cell.getCellType()) {            case STRING:                return cell.getRichStringCellValue().getString().trim();            case NUMERIC:                if (DateUtil.isCellDateFormatted(cell)) {                    Date dt = DateUtil.getJavaDate(cell.getNumericCellValue());                    return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(dt);                } else {                    // 避免数值变成迷信计数法                    String strCell = "";                    Double num = cell.getNumericCellValue();                    BigDecimal bd = new BigDecimal(num.toString());                    if (bd != null) {                        strCell = bd.toPlainString();                    }                    // 去除 浮点型 主动加的 .0                    if (strCell.endsWith(".0")) {                        strCell = strCell.substring(0, strCell.indexOf("."));                    }                    return strCell;                }            case BOOLEAN:                return String.valueOf(cell.getBooleanCellValue());            default:                return "";        }    }}
@Getter@Setter//导出工具类public class ExcelExportUtil<T> {    private int rowIndex;    private int styleIndex;    private String templatePath;    private Class clazz;    private  Field fields[];    public ExcelExportUtil(Class clazz,int rowIndex,int styleIndex) {        this.clazz = clazz;        this.rowIndex = rowIndex;        this.styleIndex = styleIndex;        fields = clazz.getDeclaredFields();    }    /**     * 基于注解导出     */    public void export(HttpServletResponse response,InputStream is, List<T> objs,String fileName) throws Exception {        XSSFWorkbook workbook = new XSSFWorkbook(is);        Sheet sheet = workbook.getSheetAt(0);        CellStyle[] styles = getTemplateStyles(sheet.getRow(styleIndex));        AtomicInteger datasAi = new AtomicInteger(rowIndex);        for (T t : objs) {            Row row = sheet.createRow(datasAi.getAndIncrement());            for(int i=0;i<styles.length;i++) {                Cell cell = row.createCell(i);                cell.setCellStyle(styles[i]);                for (Field field : fields) {                    if(field.isAnnotationPresent(ExcelAttribute.class)){                        field.setAccessible(true);                        ExcelAttribute ea = field.getAnnotation(ExcelAttribute.class);                        if(i == ea.sort()) {                            cell.setCellValue(field.get(t).toString());                        }                    }                }            }        }        fileName = URLEncoder.encode(fileName, "UTF-8");        response.setContentType("application/octet-stream");        response.setHeader("content-disposition", "attachment;filename=" + new String(fileName.getBytes("ISO8859-1")));        response.setHeader("filename", fileName);        workbook.write(response.getOutputStream());    }    public CellStyle[] getTemplateStyles(Row row) {        CellStyle [] styles = new CellStyle[row.getLastCellNum()];        for(int i=0;i<row.getLastCellNum();i++) {            styles[i] = row.getCell(i).getCellStyle();        }        return styles;    }}

参考资料


黑马程序员:基于SaaS平台的iHRM刷脸登录实战开发(报表相干视频)