提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
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());
总结
学无止境