一、添加依赖
<!-- 处理excel文件用的依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.7</version>
</dependency>
二、实体类
package com.entiy;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.*;
import java.io.Serializable;
import com.util.excel.ResultCountConverter;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* @Description
* @Author Medo
* @Date 2022-04-06
*
* 做文件导入功能,不能添加Accessors注解
*/
@Data
//@Accessors(chain = true)
@TableName("pm_result_count")
public class PmResultCount implements Serializable {
private static final long serialVersionUID = 5615839369261894843L;
/**
* id
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 应用名称
*/
@ExcelProperty(value = "项目")
private String projectName;
/**
* 归属年月
*/
private Date belongDate;
/**
* 用户总量(个)
*/
@ExcelProperty(value = "用户总量(个)",converter = ResultCountConverter.class)
private Integer userCount;
/**
* 登录情况(人次)
*/
@ExcelProperty(value = "登录情况(人次)",converter = ResultCountConverter.class)
private Integer loginConut;
/**
* 点击量(PV-/个)
*/
@ExcelProperty(value = "点击量(PV-/个)",converter = ResultCountConverter.class)
private Integer pvCount;
/**
* 新增数据量(条)
*/
@ExcelProperty(value = "新增数据量(条)",converter = ResultCountConverter.class)
private Integer increasCount;
/**
* 新增数据处理量(条)
*/
@ExcelProperty(value = "新增数据处理量(条)",converter = ResultCountConverter.class)
private Integer dataProcess;
/**
* 新增信息发布量(条)
*/
@ExcelProperty(value = "新增信息发布量(条)",converter = ResultCountConverter.class)
private Integer infoCount;
/**
* 模型总量(个)
*/
@ExcelProperty(value = "模型总量(个)",converter = ResultCountConverter.class)
private Integer modelCount;
/**
* 客服(次)
*/
@ExcelProperty(value = "客服(次)",converter = ResultCountConverter.class)
private Integer servicesCount;
/**
* 培训(次)
*/
@ExcelProperty(value = "培训(次)",converter = ResultCountConverter.class)
private Integer trainCount;
/**
* 数据总量(条)
*/
@ExcelProperty(value = "数据总量(条)",converter = ResultCountConverter.class)
private Integer dataCount;
/**
* 其它(注明事项及数量)(运维)
*/
@ExcelProperty(value = "其它(注明事项及数量)",index = 11)
private String ywRemark;
/**
* 功能模块/模板(个)
*/
@ExcelProperty(value = "功能模块/模板(个)",converter = ResultCountConverter.class)
private Integer modules;
/**
* 功能/页面(个)
*/
@ExcelProperty(value = "功能/页面(个)",converter = ResultCountConverter.class)
private Integer function;
/**
* 功能点/组件(个)
*/
@ExcelProperty(value = "功能点/组件(个)",converter = ResultCountConverter.class)
private Integer pointFunction;
/**
* 其它(注明事项及数量)(软件)
*/
@ExcelProperty(value = "其它(注明事项及数量)",index = 15)
private String rjRemark;
/**
* 更新人
*/
private String updator;
/**
* 更新时间
*/
private Date updateTime;
/**
* 备用,暂未使用,可进行修改
*/
private String by1;
private String by2;
/**
* 创建时间
*/
private String createTime;
/**
* 创建人
*/
private String creator;
}
说明:
我集成里lombok,因为图方便写了一个通过数据库自动生成实体类的Generate POJOs.groovy
文件,定义了一个链式调用的注解@Accessors(chain = true)
,这里必须要把这个链式调用的功能给关了
,不然导数据时,不能封装成对应的实体类,网上查了很多,没有找到具体原因(因为这一个问题,也浪费我好长时间,特此记录一下!)。。。
三、编写通用的Listener的实体类
编写的实体类需要继承 AnalysisEventListener<T>
package com.util.excel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.extension.service.IService;
import com.util.UserUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.lang.reflect.Field;
import java.util.*;
@Slf4j
public class ExcelListener<T> extends AnalysisEventListener<T> {
private IService<T> iService;
/**
* 自定义需要传递的参数
*/
private Map<String,Object> paramMap;
private List<T> rows = new ArrayList<>();
//这个是我的业务需要,可以把这个给去了。。
private String creatorString = UserUtils.getPmUser().getName();
private static int BATCH_COUNT = 2000; //最大行数,防止内存占用过多没有及时放入数据库 oom
public ExcelListener(IService<T> iService){
this.iService = iService;
}
public ExcelListener(IService<T> iService,Map<String,Object> paramMap){
this.paramMap = paramMap;
this.iService = iService;
}
public ExcelListener(){}
/**
* entity 是每一行数据映射的对象
* @param entity
* @param context
*/
@Override
public void invoke(T entity, AnalysisContext context) {
//System.out.println("当前行:"+context.getCurrentRowNum());
Class<?> entityClass = entity.getClass();
try {
//这里通过反射,设置一些无法通过excel导入设置的通用数据。。
Field createTime = entityClass.getDeclaredField("createTime");
createTime.setAccessible(true);
createTime.set(entity, DateFormatUtils.format(new Date(),"yyyy-MM-dd HH:mm:ss"));
Field creator = entityClass.getDeclaredField("creator");
creator.setAccessible(true);
creator.set(entity,creatorString);
/**
* 处理自定义的参数值
*/
if (paramMap!=null&¶mMap.size()>0){
Set<String> keySet = paramMap.keySet();
for (String s : keySet) {
Field field = entityClass.getDeclaredField(s);
field.setAccessible(true);
Class<?> type = field.getType();
System.out.println(type);
field.set(entity,paramMap.get(s));
}
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
System.err.println("此实体类,设置类型失败");
}
rows.add(entity);
if (rows.size()>=BATCH_COUNT){
doSomething();
rows.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
//最后把剩下的执行完
doSomething();
log.info("read {} rows %n", rows.size());
rows.clear();
}
private void doSomething() {
//入库调用接口
// int i = iService.hashCode();
//System.out.println(rows);
iService.saveBatch(rows);
}
public List<T> getRows() {return rows;}
public void setRows(List<T> rows) {
this.rows = rows;
}
}
我这个通用模板可以满足我目前的需求,各位有更好的可以进行修改
四、调用
@PostMapping("xxxImport")
@ResponseBody
public String xxxImport(MultipartFile file,String belongDate){
//将需要自己定义的属性,向下传递
LinkedMap<String, Object> map = new LinkedMap<>();
map.put("belongDate",belongDate);
ExcelListener listener = new ExcelListener(resultCountService,map);
try {
EasyExcel.read(file.getInputStream(),PmResultCount.class,listener).headRowNumber(2).sheet().doRead();//headRowNumber标识从第几行开始读取正式数据
return JsonModel.toResult(new JsonModel("导入成功!","suc"));
} catch (IOException e) {
e.printStackTrace();
return JsonModel.toResult(new JsonModel("导入失败!","err"));
}
}
五、调用的工具类
JsonModel
封装的一个返回前台的JSON类
import com.alibaba.fastjson.JSON;
import lombok.Data;
@Data
public class JsonModel {
private String code; //状态码
private String msg; //返回的显示信息
private Object data; //返回的数据
private String status; //返回的状态(成功or失败)
public JsonModel(String msg, String status) {
this.msg = msg;
this.status = status;
}
public JsonModel() {
}
public JsonModel(String msg, Object data, String status) {
this.msg = msg;
this.data = data;
this.status = status;
}
public static String toResult(JsonModel jsonModel){
return JSON.toJSONString(jsonModel);
}
}
ResultCountConverter
编写的一个数据转换类,需要实现Converter<T>
类
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import org.thymeleaf.util.StringUtils;
/**
* @author Medo丶
* @Description
*/
public class ResultCountConverter implements Converter<Integer> {
@Override
public Class supportJavaTypeKey() {
return null;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return null;
}
//数据导入时,excel里需要转换为实体类时某个字段时的方法
@Override
public Integer convertToJavaData(CellData cellData, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {
String value = cellData.toString();
if (value == null || StringUtils.isEmptyOrWhitespace(value) || "/".equals(value)){
return 0;
}else{
Integer integer = Integer.valueOf(value);
return integer;
}
}
//excel导出时,实体类某字段需要转换为excel里数据时的方法
@Override
public CellData convertToExcelData(Integer value, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {
//0 正常 1 异常(状态码)
if (value == null) {
return new CellData("");
} else if (value == 0) {
return new CellData("正常");
} else if (value == 1) {
return new CellData("异常");
} else {
return new CellData("状态异常");
}
}
}
六、easyExcel常用注解
这些注解一般在导出excel的时候用
在定义的实体类头上用(类注解)
@ColumnWith 列宽
@ContentFontStyle 文本字体样式
@ContentLoopMerge 文本合并
@ContentRowHeight 文本行高度
@ContentStyle 文本样式
@HeadFontStyle 标题字体样式
@HeadRowHeight 标题高度
@HeadStyle 标题样式
@ExcelIgnore 忽略项
@ExcelIgnoreUnannotated 忽略未注解
在定义的实体类属性上用(字段注解)
@ExcelProperty
@ColumnWith 列宽
@ExcelProperty
参数 含义 value 通过标题文本对应 index 通过文本行号对应 order 排序 converter 需要写一个该字段的转换类,如上面的实体类
@ColumnWith
设置列宽度,只有一个参数value,value的单位是字符长度,最大可以设置255个字符,因为一个excel单元格最大可以写入的字符个数就是255个字符。这个注解可以在类上用,则设置全局列宽
@ContentFontStyle
参数 含义 fontName 字体名称 fontHeightInPoints 字体高度 italic 是否斜体 strikeout 是否设置删除水平线 color 字体颜色 typeOffset 偏移量 underline 下划线 bold 是否加粗 charset 编码格式
@ContentStyle
参数 含义 dataFormat 日期格式 hidden 设置单元格使用此样式隐藏 locked 设置单元格使用此样式锁定 quotePrefix 在单元格前面增加`符号,数字或公式将以字符串形式展示 horizontalAlignment 设置是否水平居中 wrapped 设置文本是否应换行。将此标志设置为true通过在多行上显示使单元格中的所有内容可见 verticalAlignment 设置是否垂直居中 rotation 设置单元格中文本旋转角度。03版本的Excel旋转角度区间为-90°90°,07版本的Excel旋转角度区间为0°180° indent 设置单元格中缩进文本的空格数 borderLeft 设置左边框的样式 borderRight 设置右边框样式 borderTop 设置上边框样式 borderBottom 设置下边框样式 leftBorderColor 设置左边框颜色 rightBorderColor 设置右边框颜色 topBorderColor 设置上边框颜色 bottomBorderColor 设置下边框颜色 fillPatternType 设置填充类型 fillBackgroundColor 设置背景色 fillForegroundColor 设置前景色 shrinkToFit 设置自动单元格自动大小
@HeadFontStyle
参数 含义 fontName 设置字体名称 fontHeightInPoints 设置字体高度 italic 设置字体是否斜体 strikeout 是否设置删除线 color 设置字体颜色 typeOffset 设置偏移量 underline 设置下划线 charset 设置字体编码 bold 设置字体是否加粗