使用easy_poi完成excel的导入导出

easy_poi简介

POI 工具类,Excel的快速导入导出,Excel模板导出,Word模板导出,可以仅仅5行代码就可以完成Excel的导入导出,修改导出格式简单粗暴,快速有效,easypoi值得你尝试
这个是来自于官网文档的介绍,对于相比较与其他类似于poi、easyExcel等同等的excel操作库的优缺点,这里不做比较,分享的是关于如何快速的使用easy_poi完成数据的导入导出。

快速导出

注解导出

常用注解
@Excel : 必须使用的注解,简单的导出使用这一个z注解即可 常用的属性包含name:excel的列名 needMerge 是否需要合并纵向单元格,主要用于字段为List格式的  type 导出类型 1 文本2 图片 3 函数 10 数字 默认的是文本
@ExcelTarget 用于限定导出实体,一般用来通用设置 如行高、文字大小等
@ExcelEntity 用来标记字段里面是不是还有导出实体类
@ExcelCollection 一对多的集合注解,用来标记集合是否被数据以及集合的整体排序
@ExcelIgnore 用于需循环引用中忽略这个字段进行导出

关于注解的其他参数 详情参见:

http://doc.wupaas.com/docs/easypoi/easypoi-1c0u4mo8p4ro8

下面我们进入实际的导出工作

1.定义导出实体类
@Data
public class ImportBillInfoVO extends BillInfoBaseBO implements IExcelModel,Serializable,IExcelDataModel  {

    private static final long serialVersionUID = 1L;

    /**
     * id
     */
    private Integer id;
    /**
     * 企业id
     */
    private Integer companyId;
    /**
     * 水表用户账号
     */
    @Excel(name = "*用户编号")
    private String waterNumber;
    /**
     * 用户姓名
     */
    @Excel(name = "*用户姓名")
    private String waterUsername;
    /**
     * 水表用户电话
     */
    @Excel(name = "用户电话")
    private String waterMobile;
    /**
     * 总金额
     */
    @Excel(name = "*总金额")
    private BigDecimal totalPrice;
    /**
     * 用水量单位:吨
     */
    @Excel(name = "*用水量")
    private BigDecimal waterVolume;
    /**
     * 用水量增减差异单位:吨正数用水量增加,负数,用水量减少
     */
    @Excel(name = "用水量增减")
    private BigDecimal waterVolumeDifference;
    /**
     * 最迟缴费日期日期格式
     */
    @Excel(name = "最迟缴费日期", importFormat = "yyyy-MM-dd")
    private String latestPayDate;

    /**
     * 上次水量刻度
     */
    @Excel(name = "上次水量刻度")
    private BigDecimal lastVolume;
    /**
     * 当前水量刻度
     */
    @Excel(name = "当前水量刻度")
    private BigDecimal nowVolume;
    /**
     * 用水渠道:居民生活用水,工业用水等
     */
    @Excel(name = "用水渠道")
    private String waterChannel;
    /**
     * 地址
     */
    @Excel(name = "地址")
    private String address;
    /**
   }

这里使用了lombok去掉了手写get set 无意使用lombok的同学 可以手动补全get set

2.进行导出

使用dao层完成对导出对象的查询后 进行参数的封装

使用

Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("用水账单信息","账单"),
            StudentEntity .class, list);# ExportParams

获取workbook对象,获取对象完成后 有两种处理方式

a).保存文件至本地
File file = new File(Objects.requireNonNull(BillTest.class.getClassLoader().getResource("")).getPath() + File.separator + "filename.xlsx");
FileOutputStream fileOutputStream = new FileOutputStream(file);
workbook.write(fileOutputStream);
b).输出前端进行下载
public static void export(HttpServletResponse response, Workbook workbook, String fileName) throws IOException {
    response.reset();
    response.setContentType("application/x-msdownload");
    response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
    ServletOutputStream outStream = null;

    try {
        outStream = response.getOutputStream();
        workbook.write(outStream);
    } finally {
        outStream.close();
    }

}

示例:

public void testExportByInterface() throws IOException {
    ArrayList<ImportBillInfoBO> bos = new ArrayList<>();
    for (int i = 0; i <10; i++) {
        ImportBillInfoBO importBillInfoBO = new ImportBillInfoBO();
        importBillInfoBO.setWaterNumber("2134141");
        importBillInfoBO.setWaterUsername("周一");
        importBillInfoBO.setWaterMobile("13777777777");
        bos.add(importBillInfoBO);
    }
    Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("用水账单信息", "账单"), ImportBillInfoBO.class, bos);
    log.info(Objects.requireNonNull(BillTest.class.getClassLoader().getResource("")).getPath() + File.separator + "test.xlsx");
    File file = new File(Objects.requireNonNull(BillTest.class.getClassLoader().getResource("")).getPath() + File.separator + "test.xlsx");
    FileOutputStream fileOutputStream = new FileOutputStream(file);
    workbook.write(fileOutputStream);
}

至此,注解导出实现

模板导出

模板函数
空格分割
三目运算 {{test ? obj:obj2}}
n: 表示 这个cell是数值类型 {{n:}}
le: 代表长度{{le:()}} 在if/else 运用{{le:() > 8 ? obj1 : obj2}}
fd: 格式化时间 {{fd:(obj;yyyy-MM-dd)}}
fn: 格式化数字 {{fn:(obj;###.00)}}
fe: 遍历数据,创建row
!fe: 遍历数据不创建row
$fe: 下移插入,把当前行,下面的行全部下移.size()行,然后插入
#fe: 横向遍历
v_fe: 横向遍历值
!if: 删除当前列 {{!if:(test)}}
单引号表示常量值 '' 比如'1' 那么输出的就是 1
&NULL& 空格
]] 换行符 多行遍历导出
sum: 统计数据

这里介绍几个最常用的:

{{fe:list item.one}}:代表这里对数据的命名为list的对象进行遍历,里面的元素item  这里展示item的one属性值
{{data}}:将数据中的data属性在这里展示
1.定义模板

使用easy_poi完成excel的导入导出_第1张图片#### 2.模板导出

封装导出参数

@Data
public class ExportByModel4EasyPoiBO implements Serializable {
    private HttpServletResponse response;
    private String modelPath;
    private Integer headingStartRow = 1;
    private Integer headingRows = 1;
    private String sheetName;
    private String fileName;
    private Map<String, Object> excelInfos;

}
@RequestMapping("/exportBillInfo")
public void exportBillInfo(BillInfoQueryBO billInfoQueryBO, HttpServletResponse response) {
    log.info("【账单管理】- 账单信息导出,入参billInfoQueryBO = {}", JSONUtil.toJsonStr(billInfoQueryBO));
    SysUserAndCompanyEntity userEntity = ShiroUtils.getUserEntity();
    Integer companyId = userEntity.getCompanyId();
    billInfoQueryBO.setCompanyId(companyId);
    ExportByModel4EasyPoiBO exportByModel4EasyPoiBO = billInfoService.exportBillInfo(billInfoQueryBO);
    try {
        exportByModel4EasyPoiBO.setResponse(response);
        Workbook book = ExcelUtils.getWorkBook(exportByModel4EasyPoiBO);
        ExcelUtils.export(exportByModel4EasyPoiBO.getResponse(), book, exportByModel4EasyPoiBO.getFileName());
    } catch (Exception e) {
        log.error("导出表格出错", e);
    }
}

@Override
public ExportByModel4EasyPoiBO exportBillInfo(BillInfoQueryBO billInfoQueryBO) {
    List<ExportBillInfoVO> billInfoVOList = billInfoMapper.exportBillInfo(billInfoQueryBO);
    String path = "static/model/billInfoRecord.xls";
    // 封装excle导出对象
    ExportByModel4EasyPoiBO exportByModel4EasyPoiBo = new ExportByModel4EasyPoiBO();
    Map<String, Object> excelMap = new HashMap<>(64);
    excelMap.put("date", GetTimeUtil.format("yyyy-MM-dd HH:mm:ss", new Date()));
    //导出list集合orderList
    excelMap.put("list", billInfoVOList);
    exportByModel4EasyPoiBo.setExcelInfos(excelMap);
    exportByModel4EasyPoiBo.setFileName("账单信息表.xlsx");
    exportByModel4EasyPoiBo.setModelPath(path);
    return exportByModel4EasyPoiBo;
}

public class ExcelUtils {
    private static final Logger log = LoggerFactory.getLogger(ExcelUtils.class);

    public ExcelUtils() {
    }

    public static void export(HttpServletResponse response, Workbook workbook, String fileName) throws IOException {
        response.reset();
        response.setContentType("application/x-msdownload");
        response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
        ServletOutputStream outStream = null;

        try {
            outStream = response.getOutputStream();
            workbook.write(outStream);
        } finally {
            outStream.close();
        }

    }


    public static Workbook getWorkBook(ExportByModel4EasyPoiBO exportByModel4EasyPoiBo) {
        TemplateExportParams param = new TemplateExportParams(exportByModel4EasyPoiBo.getModelPath(), true, new String[]{exportByModel4EasyPoiBo.getSheetName()});
        if (param == null) {
            throw new RuntimeException("模板文件加载错误" + exportByModel4EasyPoiBo.getModelPath());
        } else {
            param.setHeadingStartRow(exportByModel4EasyPoiBo.getHeadingStartRow());
            param.setHeadingRows(exportByModel4EasyPoiBo.getHeadingRows());
            Workbook book = ExcelExportUtil.exportExcel(param, exportByModel4EasyPoiBo.getExcelInfos());
            return book;
        }
    }
}

快速导入

导入

导入的注解使用和导出的注解使用相同。第一步仍旧是定义导入实体类

1.定义导入实体类
@Data
public class ImportBillInfoBO extends BillInfoBaseBO implements IExcelModel,Serializable,IExcelDataModel  {

    private static final long serialVersionUID = 1L;

    /**
     * id
     */
    private Integer id;
    /**
     * 企业id
     */
    private Integer companyId;
    /**
     * 水表用户账号
     */
    @Excel(name = "*用户编号")
    private String waterNumber;
    /**
     * 用户姓名
     */
    @Excel(name = "*用户姓名")
    private String waterUsername;
    /**
     * 水表用户电话
     */
    @Excel(name = "用户电话")
    private String waterMobile;
    /**
     * 总金额
     */
    @Excel(name = "*总金额")
    private BigDecimal totalPrice;
    /**
     * 用水量单位:吨
     */
    @Excel(name = "*用水量")
    private BigDecimal waterVolume;
    /**
     * 用水量增减差异单位:吨正数用水量增加,负数,用水量减少
     */
    @Excel(name = "用水量增减")
    private BigDecimal waterVolumeDifference;
    /**
     * 最迟缴费日期日期格式
     */
    @Excel(name = "最迟缴费日期", importFormat = "yyyy-MM-dd")
    private String latestPayDate;

    /**
     * 上次水量刻度
     */
    @Excel(name = "上次水量刻度")
    private BigDecimal lastVolume;
    /**
     * 当前水量刻度
     */
    @Excel(name = "当前水量刻度")
    private BigDecimal nowVolume;
    /**
     * 用水渠道:居民生活用水,工业用水等
     */
    @Excel(name = "用水渠道")
    private String waterChannel;
    /**
     * 地址
     */
    @Excel(name = "地址")
    private String address;
    /**
   }

@Override
public Integer getRowNum() {
    return rowNum;
}
@Override
public void setRowNum(Integer rowNum) {
    this.rowNum = rowNum+1;
}

@Override
public String getErrorMsg() {
    return errorMsg;
}

@Override
public void setErrorMsg(String errorMsg) {
    this.errorMsg = errorMsg;
}

注意:这里继承IExcelModel IExcelDataModel 并重写了获取行号和错误信息 是为了我们在导入的时候向前端输出经过过滤的错误数据并展示给用户

账单示例
在这里插入图片描述

2.逻辑处理
@RequestMapping("/importBillInfo")
public DataResponse importBillInfo(MultipartFile excelFile) throws IOException {
    log.info("【账单管理】- 账单信息导入");
    log.info(" excelFileName = {}", excelFile.getOriginalFilename());
    if (BeanUtil.isEmpty(excelFile.getOriginalFilename())) {
        throw new ValidateException("必要参数为空");
    } else {
        String originalFilename = excelFile.getOriginalFilename();
        String[] split = originalFilename.split("\\.");
        String fileFormat = split[split.length - 1];
        if (!"xls".equals(fileFormat) && !"xlsx".equals(fileFormat)) {
            throw new ValidateException("文件格式不正确!");
        }
    }
    ImportBillInfoVO importBillInfoVO = billInfoService.importBillInfo(excelFile);
    return DataResponse.successWithResult(importBillInfoVO);
}

@Override
public ImportBillInfoVO importBillInfo(MultipartFile excelFile) throws IOException {
    // 存储文件成为临时文件
    String tempFilePath = System.getProperty("java.io.tmpdir") +File.separator+excelFile.getOriginalFilename();
    File tempFile = new File(tempFilePath);
    excelFile.transferTo(tempFile);
    // 进行文件读取
    ImportParams importParams = new ImportParams();
    // 标题 有一个是1 有两个是2  没有是0 默认
    importParams.setTitleRows(2);
    // 表头 有标题是1  没标题是0
    importParams.setHeadRows(1);
    // 获取集合
    List<BillInfoBaseBO> importBillInfoLiSt = ExcelImportUtil.importExcel(tempFile, ImportBillInfoBO.class, importParams);
    log.info("导入文件读取完成,读取的到数据{}", JSONUtil.toJsonStr(importBillInfoLiSt));
    //移除不符和参数要求的数据
    if(CollectionUtil.isEmpty(importBillInfoLiSt)){
        throw new ValidateException("未读取到有效数据,请检查导入内容!");
    }
    List<ImportBillInfoFailVO> importBillInfoFailVOList = new ArrayList<>();
    ImportBillInfoVO importBillInfoVO = new ImportBillInfoVO();
    importBillInfoVO.setImportTotalLine(importBillInfoLiSt.size());
    Iterator<BillInfoBaseBO> iterator = importBillInfoLiSt.iterator();
    while (iterator.hasNext()){
        BillInfoBaseBO billInfoBaseBO = iterator.next();
        try{
            BillInfoValidateServiceImpl.baseValidate(billInfoBaseBO);
            billInfoBaseBO.setCompanyId(ShiroUtils.getUserAndCompanyEntity().getCompanyId());
        } catch (Exception e){
            ImportBillInfoFailVO importBillInfoFailVO = new ImportBillInfoFailVO();
            log.info("参数过滤异常,加入异常数据内容,message = {}",e.getMessage());
            BeanUtil.copyProperties(billInfoBaseBO,importBillInfoFailVO);
            importBillInfoFailVO.setFailReason(e.getMessage());
            importBillInfoFailVOList.add(importBillInfoFailVO);
            iterator.remove();
        }
    }
    Integer successLine = 0;
    if (CollectionUtil.isNotEmpty(importBillInfoLiSt)){
        successLine = insertBatch(importBillInfoLiSt);
    }
    importBillInfoVO.setSuccessLine(successLine);
    importBillInfoVO.setFailLine(importBillInfoFailVOList.size());
    importBillInfoVO.setImportBillInfoFailVOList(importBillInfoFailVOList);
    //进行批量新增
    return importBillInfoVO;
}

展示导入信息内容

importBillInfoVO

@Data
public class ImportBillInfoVO implements Serializable {

    /**
     * 成功条目数
     */
    private Integer successLine;
    /**
     * 失败条目数
     */
    private Integer failLine;
    /**
     * 上传总条目数
     */
    private Integer importTotalLine;
    /**
     * 失败数据及失败原因
     */
    private List<ImportBillInfoFailVO> importBillInfoFailVOList;

}

失败信息对象 ImportBillInfoFailVO

@Data
public class ImportBillInfoFailVO implements Serializable {
    /**
     * id
     */
    private Integer id;
    /**
     * 企业id
     */
    private Integer companyId;
    /**
     * 水表用户账号
     */
    private String waterNumber;
    /**
     * 用户姓名
     */
    private String waterUsername;
    /**
     * 水表用户电话
     */
    private String waterMobile;
    /**
     * 总金额
     */
    private BigDecimal totalPrice;
    /**
     * 用水量单位:吨
     */
    private BigDecimal waterVolume;
    /**
     * 用水量增减差异单位:吨正数用水量增加,负数,用水量减少
     */
    private BigDecimal waterVolumeDifference;
    /**
     * 最迟缴费日期
     */
    private String latestPayDate;
    /**
     * 上次水量刻度
     */
    private BigDecimal lastVolume;
    /**
     * 当前水量刻度
     */
    private BigDecimal nowVolume;
    /**
     * 用水渠道:居民生活用水,工业用水等
     */
    private String waterChannel;
    /**
     * 地址
     */
    private String address;
    /**
     * 预交金额
     */
    private String preStorage;
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    /**
     * 创建时间
     */
    private Timestamp createTime;
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    /**
     * 更新时间
     */
    private Timestamp updateTime;
    /**
     * 备注
     */
    @Builder.Default()
    private String remark;

    /**
     * 支付状态: 0-正常 1-支付中 2 支付成功
     */
    private Integer payState;

    /**
     * 支付成功时间
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Timestamp paySuccessTime;

    /**
     * 账单状态
     */
    private Integer billStatus;


    /**
     * 失败原因
     */
    private String failReason;


    /**
     * 失败条目行数
     */
    private Integer rowNum;
    }

在这里 我们就完成了excel的导入,并且将导入结果及导入失败的数据和原因返回给前端进行展示,并可以在前端生成文件进行下载,这样,就能很好的为用户提供导入的功能。

你可能感兴趣的:(java,web,spring,springboot,java,excel,poi)