Java之基于注解的Excel导出

数据库Excel导出操作代码过于冗长惨不忍睹,无法复用。


目录

第一步:自定义注解:

第二步:实体类:

第三步:解析工具类:

第四步:使用:



依赖:

 <dependency>



            <groupId>cn.afterturn</groupId>



            <artifactId>easypoi-base</artifactId>



            <version>4.1.2</version>



        </dependency>



        <dependency>



            <groupId>cn.afterturn</groupId>



            <artifactId>easypoi-web</artifactId>



            <version>4.1.2</version>



        </dependency>



        <dependency>



            <groupId>cn.afterturn</groupId>



            <artifactId>easypoi-annotation</artifactId>



            <version>4.1.2</version>



        </dependency>

注解配合工具类做了个小工具如下:

第一步:自定义注解:

import java.lang.annotation.ElementType;



import java.lang.annotation.Retention;



import java.lang.annotation.RetentionPolicy;



import java.lang.annotation.Target;



 



/**



 * 自定义导出Excel数据注解



 *



 * @author sunziwen



 * @version 1.0



 * @date 2018-12-29 15:00



 **/



@Retention(RetentionPolicy.RUNTIME)



@Target(ElementType.FIELD)



public @interface Excel {



    /**



     * 导出到Excel中的名字.



     */



    public String name();



 



    /**



     * 日期格式, 如: yyyy-MM-dd



     */



    public String dateFormat() default "";



 



    /**



     * 读取内容转表达式 (如: 0=男,1=女,2=未知)



     */



    public String readConverterExp() default "";



 



    /**



     * 导出时在excel中每个列的高度 单位为字符



     */



    public double height() default 14;



 



    /**



     * 导出时在excel中每个列的宽 单位为字符



     */



    public double width() default 20;



 



    /**



     * 文字后缀,如% 90 变成90%



     */



    public String suffix() default "";



 



    /**



     * 当值为空时,字段的默认值



     */



    public String defaultValue() default "";



 



    /**



     * 提示信息



     */



    public String prompt() default "";



 



    /**



     * 设置只能选择不能输入的列内容.



     */



    public String[] combo() default {};



 



    /**



     * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.



     */



    public boolean isExport() default true;



}

第二步:实体类:

import java.time.LocalDateTime;



 



import com.ciih.authcenter.client.util.excel.Excel;



import io.swagger.annotations.ApiModelProperty;



import lombok.Data;



import lombok.EqualsAndHashCode;



 



/**



 * (User)表实体类



 *



 * @author suzniwen



 * @since 2021-04-13 16:11:55



 */



@SuppressWarnings("serial")



@EqualsAndHashCode(callSuper = true)



@Data



public class User {



    @Excel(name = "编号")



    @ApiModelProperty(value = "主键")



    private String id;



    @Excel(name = "账号")



    @ApiModelProperty(value = "账号")



    private String loginName;



    @Excel(name = "用户名")



    @ApiModelProperty(value = "用户名")



    private String userName;



    @ApiModelProperty(value = "用户名拼音")



    private String namePinyin;



    @Excel(name = "性别", readConverterExp = "1=男,0=女")



    @ApiModelProperty(value = "性别")



    private String gender;



    @Excel(name = "证件类型",readConverterExp="1=居民身份证,2=香港居民来往内地通行证,3=澳门居民来往内地通行证,4=台湾居民来往大陆通行证,6=护照")



    @ApiModelProperty(value = "证件类型")



    private String credType;



    @Excel(name = "证件号码")



    @ApiModelProperty(value = "证件号码")



    private String credNum;



    @ApiModelProperty(value = "机构id")



    private String orgId;



    @Excel(name = "机构名称")



    @ApiModelProperty(value = "机构名称")



    private String orgName;



    @Excel(name = "电话")



    @ApiModelProperty(value = "电话")



    private String phone;



    @Excel(name = "邮箱")



    @ApiModelProperty(value = "邮箱")



    private String email;



    @Excel(name = "人员类型",readConverterExp = "student=学生,teacher=教师,parent=家长,system=系统人员,developers=开发者,manager=管理员")



    @ApiModelProperty(value = "人员类型")



    private String personType;



    @Excel(name = "应用系统角色编码")



    @ApiModelProperty(value = "应用系统角色编码")



    private String appRoleCode;



    @ApiModelProperty(value = "创建时间")



    private LocalDateTime createTime;



    @ApiModelProperty(value = "更新时间")



    private LocalDateTime updateTime;



}

第三步:解析工具类:

package com.ciih.authcenter.client.util.excel;



 



import java.io.IOException;



import java.io.InputStream;



import java.lang.reflect.Field;



import java.net.URLEncoder;



import java.text.SimpleDateFormat;



import java.util.ArrayList;



import java.util.Date;



import java.util.HashMap;



import java.util.Iterator;



import java.util.List;



import java.util.Map;



import java.util.Set;



 



import javax.servlet.http.HttpServletResponse;



 



import org.apache.commons.lang3.StringUtils;



import org.apache.poi.hssf.usermodel.DVConstraint;



import org.apache.poi.hssf.usermodel.HSSFCell;



import org.apache.poi.hssf.usermodel.HSSFCellStyle;



import org.apache.poi.hssf.usermodel.HSSFDataValidation;



import org.apache.poi.hssf.usermodel.HSSFFont;



import org.apache.poi.hssf.usermodel.HSSFRow;



import org.apache.poi.hssf.usermodel.HSSFSheet;



import org.apache.poi.hssf.usermodel.HSSFWorkbook;



import org.apache.poi.hssf.util.HSSFColor;



import org.apache.poi.ss.usermodel.Cell;



import org.apache.poi.ss.usermodel.CellType;



import org.apache.poi.ss.usermodel.FillPatternType;



import org.apache.poi.ss.usermodel.HorizontalAlignment;



import org.apache.poi.ss.usermodel.Row;



import org.apache.poi.ss.usermodel.Sheet;



import org.apache.poi.ss.usermodel.VerticalAlignment;



import org.apache.poi.ss.usermodel.Workbook;



import org.apache.poi.ss.usermodel.WorkbookFactory;



import org.apache.poi.ss.util.CellRangeAddressList;



import org.slf4j.Logger;



import org.slf4j.LoggerFactory;



 



/**



 * Excel相关操作



 *



 * @author sunziwen



 * @version 1.0



 * @date 2018-12-29 15:00



 **/



public class ExcelUtil<T> {



    private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);



 



    private Class<T> clazz;



 



    public ExcelUtil(Class<T> clazz) {



        this.clazz = clazz;



    }



 



    /**



     * 对excel表单默认第一个索引名转换成list



     *



     * @param input 输入流



     * @return 转换后集合



     */



    public List<T> importExcel(InputStream input) throws Exception {



        return importExcel(StringUtils.EMPTY, input);



    }



 



    /**



     * 对excel表单指定表格索引名转换成list



     *



     * @param sheetName 表格索引名



     * @param input     输入流



     * @return 转换后集合



     */



    public List<T> importExcel(String sheetName, InputStream input) throws Exception {



        List<T> list = new ArrayList<T>();



 



        Workbook workbook = WorkbookFactory.create(input);



        Sheet sheet = null;



        if (StringUtils.isNotEmpty(sheetName)) {



            // 如果指定sheet名,则取指定sheet中的内容.



            sheet = workbook.getSheet(sheetName);



        } else {



            // 如果传入的sheet名不存在则默认指向第1个sheet.



            sheet = workbook.getSheetAt(0);



        }



 



        if (sheet == null) {



            throw new IOException("文件sheet不存在");



        }



 



        int rows = sheet.getPhysicalNumberOfRows();



 



        if (rows > 0) {



            // 默认序号



            int serialNum = 0;



            // 有数据时才处理 得到类的所有field.



            Field[] allFields = clazz.getDeclaredFields();



            // 定义一个map用于存放列的序号和field.



            Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>();



            for (int col = 0; col < allFields.length; col++) {



                Field field = allFields[col];



                // 将有注解的field存放到map中.



                if (field.isAnnotationPresent(Excel.class)) {



                    // 设置类的私有字段属性可访问.



                    field.setAccessible(true);



                    fieldsMap.put(++serialNum, field);



                }



            }



            for (int i = 1; i < rows; i++) {



                // 从第2行开始取数据,默认第一行是表头.



                Row row = sheet.getRow(i);



                int cellNum = serialNum;



                T entity = null;



                for (int j = 0; j < cellNum; j++) {



                    Cell cell = row.getCell(j);



                    if (cell == null) {



                        continue;



                    } else {



                        // 先设置Cell的类型,然后就可以把纯数字作为String类型读进来了



                        row.getCell(j).setCellType(CellType.STRING);



                        cell = row.getCell(j);



                    }



 



                    String c = cell.getStringCellValue();



                    if (StringUtils.isEmpty(c)) {



                        continue;



                    }



 



                    // 如果不存在实例则新建.



                    entity = (entity == null ? clazz.newInstance() : entity);



                    // 从map中得到对应列的field.



                    Field field = fieldsMap.get(j + 1);



                    // 取得类型,并根据对象类型设置值.



                    Class<?> fieldType = field.getType();



                    if (String.class == fieldType) {



                        field.set(entity, String.valueOf(c));



                    } else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) {



                        field.set(entity, Integer.parseInt(c));



                    } else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) {



                        field.set(entity, Long.valueOf(c));



                    } else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) {



                        field.set(entity, Float.valueOf(c));



                    } else if ((Short.TYPE == fieldType) || (Short.class == fieldType)) {



                        field.set(entity, Short.valueOf(c));



                    } else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) {



                        field.set(entity, Double.valueOf(c));



                    } else if (Character.TYPE == fieldType) {



                        if ((c != null) && (c.length() > 0)) {



                            field.set(entity, Character.valueOf(c.charAt(0)));



                        }



                    } else if (Date.class == fieldType) {



                        if (cell.getCellTypeEnum() == CellType.NUMERIC) {



                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");



                            cell.setCellValue(sdf.format(cell.getNumericCellValue()));



                            c = sdf.format(cell.getNumericCellValue());



                        } else {



                            c = cell.getStringCellValue();



                        }



                    } else if (java.math.BigDecimal.class == fieldType) {



                        c = cell.getStringCellValue();



                    }



                }



                if (entity != null) {



                    list.add(entity);



                }



            }



        }



 



        return list;



    }



 



    /**



     * 对list数据源将其里面的数据导入到excel表单



     * 针对List<Map>类型的数据



     *



     * @param list      导出数据集合



     * @param sheetName 工作表的名称



     * @return 结果



     */



    public static void exportMapExcel(List<Map> list,String[]title, String sheetName,HttpServletResponse response) {



    	if(null == list || list.size() == 0)



    		return;



 



        HSSFWorkbook workbook = null;



        try {



            // 产生工作薄对象



            workbook = new HSSFWorkbook();



            // excel2003中每个sheet中最多有65536行



            int sheetSize = 65536;



            // 取出一共有多少个sheet.



            double sheetNo = Math.ceil(list.size() / sheetSize);



            for (int index = 0; index <= sheetNo; index++) {



                // 产生工作表对象



                HSSFSheet sheet = workbook.createSheet();



                if (sheetNo == 0) {



                    workbook.setSheetName(index, sheetName);



                } else {



                    // 设置工作表的名称.



                    workbook.setSheetName(index, sheetName + index);



                }



                HSSFRow row;



                HSSFCell cell; // 产生单元格



 



                // 产生第一行,写入标题



                row = sheet.createRow(0);



                if(null == title || title.length == 0) {



                	throw new RuntimeException("导出错误");



                }



                for(int i = 0;i<title.length;i++) {



                	cell = row.createCell(i);



                	cell.setCellType(CellType.STRING);



                	cell.setCellValue(title[i]);



                }



                int cell_idx = 0;



                int startNo = index * sheetSize;



                int endNo = Math.min(startNo + sheetSize, list.size());



                // 写入各条记录,每条记录对应excel表中的一行



                for (int i = startNo; i < endNo; i++) {



                    row = sheet.createRow(i + 1 - startNo);



                    // 得到导出对象.



                    Map map = list.get(i);



                    Set keySet = map.keySet();



                    Iterator values = keySet.iterator();



                    cell_idx = 0;



                    while(values.hasNext()) {



                    	Object value = map.get(values.next());



                    	cell = row.createCell(cell_idx);



                    	cell.setCellValue(value.toString());



                    	cell_idx++;



                    }



                }



            }



            //String filename = encodingFilename(sheetName);



            response.setHeader("content-Type", "application/vnd.ms-excel");



            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(sheetName, "UTF-8"));



//            response.setContentType("application/octet-stream");



//            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));



            response.flushBuffer();



            workbook.write(response.getOutputStream());



            //return filename;



        } catch (Exception e) {



            log.error("导出Excel异常{}", e.getMessage());



            throw new RuntimeException("导出Excel失败,请联系网站管理员!");



        } finally {



            if (workbook != null) {



                try {



                    workbook.close();



                } catch (IOException e1) {



                    e1.printStackTrace();



                }



            }



        }



    }



 



    /**



     * 对list数据源将其里面的数据导入到excel表单



     *



     * @param list      导出数据集合



     * @param sheetName 工作表的名称



     * @return 结果



     */



    public void exportExcel(List<T> list, String sheetName,HttpServletResponse response) {



        HSSFWorkbook workbook = null;



        try {



            // 得到所有定义字段



            Field[] allFields = clazz.getDeclaredFields();



            List<Field> fields = new ArrayList<Field>();



            // 得到所有field并存放到一个list中.



            for (Field field : allFields) {



                if (field.isAnnotationPresent(Excel.class)) {



                    fields.add(field);



                }



            }



 



            // 产生工作薄对象



            workbook = new HSSFWorkbook();



            // excel2003中每个sheet中最多有65536行



            int sheetSize = 65536;



            // 取出一共有多少个sheet.



            double sheetNo = Math.ceil(list.size() / sheetSize);



            for (int index = 0; index <= sheetNo; index++) {



                // 产生工作表对象



                HSSFSheet sheet = workbook.createSheet();



                if (sheetNo == 0) {



                    workbook.setSheetName(index, sheetName);



                } else {



                    // 设置工作表的名称.



                    workbook.setSheetName(index, sheetName + index);



                }



                HSSFRow row;



                HSSFCell cell; // 产生单元格



 



                // 产生一行



                row = sheet.createRow(0);



                // 写入各个字段的列头名称



                for (int i = 0; i < fields.size(); i++) {



                    Field field = fields.get(i);



                    Excel attr = field.getAnnotation(Excel.class);



                    // 创建列



                    cell = row.createCell(i);



                    // 设置列中写入内容为String类型



                    cell.setCellType(CellType.STRING);



                    HSSFCellStyle cellStyle = workbook.createCellStyle();



                    cellStyle.setAlignment(HorizontalAlignment.CENTER);



                    cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);



                    if (attr.name().indexOf("注:") >= 0) {



                        HSSFFont font = workbook.createFont();



                        font.setColor(HSSFFont.COLOR_RED);



                        cellStyle.setFont(font);



                        cellStyle.setFillForegroundColor(HSSFColor.HSSFColorPredefined.YELLOW.getIndex());



                        sheet.setColumnWidth(i, 6000);



                    } else {



                        HSSFFont font = workbook.createFont();



                        // 粗体显示



                        font.setBold(true);



                        // 选择需要用到的字体格式



                        cellStyle.setFont(font);



                        cellStyle.setFillForegroundColor(HSSFColor.HSSFColorPredefined.LIGHT_YELLOW.getIndex());



                        // 设置列宽



                        sheet.setColumnWidth(i, (int) ((attr.width() + 0.72) * 256));



                        row.setHeight((short) (attr.height() * 20));



                    }



                    cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);



                    cellStyle.setWrapText(true);



                    cell.setCellStyle(cellStyle);



 



                    // 写入列名



                    cell.setCellValue(attr.name());



 



                    // 如果设置了提示信息则鼠标放上去提示.



                    if (StringUtils.isNotEmpty(attr.prompt())) {



                        // 这里默认设了2-101列提示.



                        setHSSFPrompt(sheet, "", attr.prompt(), 1, 100, i, i);



                    }



                    // 如果设置了combo属性则本列只能选择不能输入



                    if (attr.combo().length > 0) {



                        // 这里默认设了2-101列只能选择不能输入.



                        setHSSFValidation(sheet, attr.combo(), 1, 100, i, i);



                    }



                }



 



                int startNo = index * sheetSize;



                int endNo = Math.min(startNo + sheetSize, list.size());



                // 写入各条记录,每条记录对应excel表中的一行



                HSSFCellStyle cs = workbook.createCellStyle();



                cs.setAlignment(HorizontalAlignment.CENTER);



                cs.setVerticalAlignment(VerticalAlignment.CENTER);



                for (int i = startNo; i < endNo; i++) {



                    row = sheet.createRow(i + 1 - startNo);



                    // 得到导出对象.



                    T vo = (T) list.get(i);



                    for (int j = 0; j < fields.size(); j++) {



                        // 获得field.



                        Field field = fields.get(j);



                        // 设置实体类私有属性可访问



                        field.setAccessible(true);



                        Excel attr = field.getAnnotation(Excel.class);



                        try {



                            // 设置行高



                            row.setHeight((short) (attr.height() * 20));



                            // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.



                            if (attr.isExport()) {



                                // 创建cell



                                cell = row.createCell(j);



                                cell.setCellStyle(cs);



                                if (vo == null) {



                                    // 如果数据存在就填入,不存在填入空格.



                                    cell.setCellValue("");



                                    continue;



                                }



 



                                String dateFormat = attr.dateFormat();



                                String readConverterExp = attr.readConverterExp();



                                if (StringUtils.isNotEmpty(dateFormat)) {



                                    cell.setCellValue(new SimpleDateFormat(dateFormat).format((Date) field.get(vo)));



                                } else if (StringUtils.isNotEmpty(readConverterExp)) {



                                    cell.setCellValue(convertByExp(String.valueOf(field.get(vo)), readConverterExp));



                                } else {



                                    cell.setCellType(CellType.STRING);



                                    // 如果数据存在就填入,不存在填入空格.



                                    cell.setCellValue(field.get(vo) == null ? attr.defaultValue() : field.get(vo) + attr.suffix());



                                }



                            }



                        } catch (Exception e) {



                            log.error("导出Excel失败{}", e.getMessage());



                        }



                    }



                }



            }



            //String filename = encodingFilename(sheetName);



            response.setContentType("application/octet-stream");



            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(sheetName, "UTF-8"));



            response.flushBuffer();



            workbook.write(response.getOutputStream());



        } catch (Exception e) {



            log.error("导出Excel异常{}", e.getMessage());



            throw new RuntimeException("导出Excel失败,请联系网站管理员!");



        } finally {



            if (workbook != null) {



                try {



                    workbook.close();



                } catch (IOException e1) {



                    e1.printStackTrace();



                }



            }



        }



    }



 



    /**



     * 设置单元格上提示



     *



     * @param sheet         要设置的sheet.



     * @param promptTitle   标题



     * @param promptContent 内容



     * @param firstRow      开始行



     * @param endRow        结束行



     * @param firstCol      开始列



     * @param endCol        结束列



     * @return 设置好的sheet.



     */



    private static HSSFSheet setHSSFPrompt(HSSFSheet sheet, String promptTitle, String promptContent, int firstRow,



                                          int endRow, int firstCol, int endCol) {



        // 构造constraint对象



        DVConstraint constraint = DVConstraint.createCustomFormulaConstraint("DD1");



        // 四个参数分别是:起始行、终止行、起始列、终止列



        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);



        // 数据有效性对象



        HSSFDataValidation dataValidationView = new HSSFDataValidation(regions, constraint);



        dataValidationView.createPromptBox(promptTitle, promptContent);



        sheet.addValidationData(dataValidationView);



        return sheet;



    }



 



    /**



     * 设置某些列的值只能输入预制的数据,显示下拉框.



     *



     * @param sheet    要设置的sheet.



     * @param textlist 下拉框显示的内容



     * @param firstRow 开始行



     * @param endRow   结束行



     * @param firstCol 开始列



     * @param endCol   结束列



     * @return 设置好的sheet.



     */



    private static HSSFSheet setHSSFValidation(HSSFSheet sheet, String[] textlist, int firstRow, int endRow,



                                              int firstCol, int endCol) {



        // 加载下拉列表内容



        DVConstraint constraint = DVConstraint.createExplicitListConstraint(textlist);



        // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列



        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);



        // 数据有效性对象



        HSSFDataValidation dataValidationList = new HSSFDataValidation(regions, constraint);



        sheet.addValidationData(dataValidationList);



        return sheet;



    }



 



    /**



     * 解析导出值 0=男,1=女,2=未知



     *



     * @param propertyValue 参数值



     * @param converterExp  翻译注解



     * @return 解析后值



     * @throws Exception



     */



    private static String convertByExp(String propertyValue, String converterExp) throws Exception {



        try {



            String[] convertSource = converterExp.split(",");



            for (String item : convertSource) {



                String[] itemArray = item.split("=");



                if (itemArray[0].equals(propertyValue)) {



                    return itemArray[1];



                }



            }



        } catch (Exception e) {



            throw e;



        }



        return propertyValue;



    }



 



    /**



     * 编码文件名



     */



    /*private static String encodingFilename(String filename) {



        filename = UUID.randomUUID().toString() + "_" + filename + ".xls";



        return filename;



    }*/



}

第四步:使用:(该方法最好是返回void或者返回null),否则后台会报错(不影响运行)

    @PostMapping("/export")



    @ResponseBody



    public void export()



    {



        ExcelUtil<User> excelUtil = new ExcelUtil<>(User.class);



        //要导出的数据集



        List<User> list = getList();



        excelUtil.exportExcel(list, "userInformation.xlsx", ServletUtils.getResponse());



    }

附件:前端代码:

exportExcel() {



    let link = document.createElement('a');



    link.style.display = 'none'



    axios({



        url: 'http://test.cih.net/user/pageExport',



        methods: "get",



        data: {},



        headers: {



            token: 'eyJ0eXB1234bklkIjoie1wiZWnm7jwkJtbvdcnqo'



        }



    }).then((res) => {



        let blob = new Blob([res.data], {



            type: "application/vnd.ms-excel"



        }); // 2.获取请求返回的response对象中的blob 设置文件类型,这里以excel为例



        let url = window.URL.createObjectURL(blob); // 3.创建一个临时的url指向blob对象



 



        // 4.创建url之后可以模拟对此文件对象的一系列操作,例如:预览、下载



        let a = document.createElement("a");



        a.href = url;



        a.download = "导出表格.xlsx";



        a.click();



        // 5.释放这个临时的对象url



        window.URL.revokeObjectURL(url);



    })



}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值