Easy Excel使用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

Easy Excel使用:excel导入导出

一、Easy Excel是什么?

EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。 他能让你在不用考虑性能、内存的等因素的情况下,快速完成Excel的读、写等功能。
官网地址:https://easyexcel.opensource.alibaba.com/docs/current/quickstart/write

二、使用步骤

1.引入依赖

代码如下(示例):

 <!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
 <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>easyexcel</artifactId>
      <version>2.1.1</version>
  </dependency>
  <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.10</version>
  </dependency>

2.工具类

代码如下(示例):

package com.cb.referral.common.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import com.cb.common.basic.exceptions.CBBusinessException;
import com.cb.referral.common.annotation.ExcelImportValid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @description 导出工具类
 */
@Slf4j
public class ExcelUtil {

    /**
     * 导出
     * @param response
     * @param fileName 文件名称
     * @param clazz 导出类.class
     * @param list 数据
     * @param <T> 泛型
     */
    public static<T> void export(HttpServletResponse response, String fileName, Class<T> clazz, List<T> list){
        try {
            //设置相关参数
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码
            fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
            response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), clazz).sheet(fileName).doWrite(list);
        }catch (Exception e){
           log.info("导出异常", e);
           throw new CBBusinessException("导出异常");
        }
    }


    /**
     * excel导入
     * @param file 文件
     * @param clazz
     * @return
     * @param <T>
     */
    public static<T> List<T> importData(MultipartFile file, Class<T> clazz){
        try {
            if (Objects.isNull(file)) {
                throw new CBBusinessException("文件不能为空");
            }
            String name = file.getOriginalFilename();
            //校验文件大小
            if (file.getSize() > 10485760) {
                log.error("上传文件过大,请上传10M以内的文件!");
                throw new CBBusinessException("上传文件过大,请上传10M以内的文件!");
            }
            if (StrUtil.isEmpty(name) || (!name.endsWith(".xlsx") && !name.endsWith(".xls"))) {
                log.error("文件格式错误!");
                throw new CBBusinessException("文件格式错误!");
            }
            //读取文件
            return  EasyExcel.read(file.getInputStream())
                    .registerReadListener(new AnalysisEventListener<T>() {
                        @Override
                        public void invoke(T t, AnalysisContext analysisContext) {
                        	// 校验值是否为空
                            ExcelImportValid.valid(t);
                        }

                        @Override
                        public void doAfterAllAnalysed(AnalysisContext analysisContext) {

                        }

                        /**
                         * 校验标题头是否一致
                         * @param headMap 标题头
                         * @param context context
                         */
                        @Override
                        public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
                            log.info("解析到一条表头数据:{}", JSON.toJSONString(headMap));
                            List<String> voHead = new ArrayList<>();
                            Field[] fields = clazz.getDeclaredFields();
                            for (Field field : fields) {
                                if (field.isAnnotationPresent(ExcelProperty.class)) {
                                    ExcelProperty myField2 = field.getAnnotation(ExcelProperty.class);
                                    voHead.add(myField2.value()[0]);
                                }
                            }
                            int i=0;
                            for(Integer key : headMap.keySet()){
                                log.info("表头数据校验:"+headMap.get(key));
                                if(headMap.get(key) == null ){
                                    throw new CBBusinessException("第"+(i+1)+"列表头格式不正确!");
                                }
                                if(i == voHead.size()){
                                    throw new CBBusinessException("上传文件表头超过模板列数,正确表头为:"+voHead);
                                }
                                if(!headMap.get(key).equals(voHead.get(i))){
                                    throw new CBBusinessException("第"+(i+1)+"列【"+headMap.get(key)+"】附近表头模板异常!\n正确表头顺序为:\n"+voHead+ "!");
                                }
                                i++;
                            }
                        }
                    })
                    .head(clazz)
                    .sheet(0)
                    .headRowNumber(1)
                    .doReadSync();
        }catch (Exception e){
            log.error("文件导入异常!", e);
            throw new CBBusinessException(e.getMessage());
        }
    }
}

3.实体字段非空校验注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelValid {
    String message() default "导入有未填入的字段";
}

package com.cb.referral.common.annotation;

import com.cb.common.basic.exceptions.CBBusinessException;

import java.lang.reflect.Field;
import java.util.Objects;

/**
 * @description Excel导入字段校验
 */
public class ExcelImportValid {
    /**
     * Excel导入字段校验
     * @param object 校验的JavaBean 其属性须有自定义注解
     */
    public static void valid(Object object) {
        Field[] fields = object.getClass().getDeclaredFields();
        for (Field field : fields) {
            //设置可访问
            field.setAccessible(true);
            //属性的值
            Object fieldValue = null;
            try {
                fieldValue = field.get(object);
            } catch (IllegalAccessException e) {
                throw new CBBusinessException(field.getAnnotation(ExcelValid.class).message());
            }
            //是否包含必填校验注解
            boolean isExcelValid = field.isAnnotationPresent(ExcelValid.class);
            if (isExcelValid && Objects.isNull(fieldValue)) {
                throw new CBBusinessException(field.getAnnotation(ExcelValid.class).message());
            }

        }
    }
}

实体使用注解:
@ExcelIgnore 不参与导入导出
@ExcelProperty excel标题头列值
@ExcelValid 校验非空
@ColumnWidth excel列宽度

@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "ICD-10诊断编码-导入")
public class BdrIcd10DiagnosisCodeImportDTO {

    @ApiModelProperty(name = "diseaseName", value = "疾病名称")
    @ExcelProperty(value = "疾病名称")
    @ExcelValid(message = "疾病名称不能为空")
    @ColumnWidth(30)
    private String diseaseName;

    @ApiModelProperty(name = "mainCode", value = "主要编码")
    @ExcelProperty(value = "主要编码")
    @ColumnWidth(30)
    private String mainCode;

    @ApiModelProperty(name = "additionalCode", value = "附加编码")
    @ExcelProperty(value = "附加编码")
    @ColumnWidth(30)
    private String additionalCode;

    @ApiModelProperty(name = "code", value = "编码(主要编码+附加编码)")
    @ExcelIgnore
    private String code;
}

4.使用

导出::

ExcelUtil.export(response, "ICD-10诊断编码", BdrIcd10DiagnosisCodeExcelDTO.class, excelList);

导入:

List<BdrIcd10DiagnosisCodeImportDTO> list = ExcelUtil.importData(file, BdrIcd10DiagnosisCodeImportDTO.class);

下载导入模板:

ExcelUtil.export(response, "ICD-10诊断编码导入模板", BdrIcd10DiagnosisCodeImportDTO.class, ListUtil.empty());

总结

学无止境

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值