<!-- 处理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)
,这里必须要把这个链式调用的功能给关了
,不然导数据时,不能封装成对应的实体类,网上查了很多,没有找到具体原因(因为这一个问题,也浪费我好长时间,特此记录一下!)。。。
编写的实体类需要继承 AnalysisEventListener
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
类
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("状态异常");
}
}
}
这些注解一般在导出excel的时候用
在定义的实体类头上用(类注解)
@ColumnWith 列宽
@ContentFontStyle 文本字体样式
@ContentLoopMerge 文本合并
@ContentRowHeight 文本行高度
@ContentStyle 文本样式
@HeadFontStyle 标题字体样式
@HeadRowHeight 标题高度
@HeadStyle 标题样式
@ExcelIgnore 忽略项
@ExcelIgnoreUnannotated 忽略未注解
在定义的实体类属性上用(字段注解)
@ExcelProperty
@ColumnWith 列宽
参数 含义 value 通过标题文本对应 index 通过文本行号对应 order 排序 converter 需要写一个该字段的转换类,如上面的实体类
设置列宽度,只有一个参数value,value的单位是字符长度,最大可以设置255个字符,因为一个excel单元格最大可以写入的字符个数就是255个字符。这个注解可以在类上用,则设置全局列宽
参数 含义 fontName 字体名称 fontHeightInPoints 字体高度 italic 是否斜体 strikeout 是否设置删除水平线 color 字体颜色 typeOffset 偏移量 underline 下划线 bold 是否加粗 charset 编码格式
参数 含义 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 设置自动单元格自动大小
参数 含义 fontName 设置字体名称 fontHeightInPoints 设置字体高度 italic 设置字体是否斜体 strikeout 是否设置删除线 color 设置字体颜色 typeOffset 设置偏移量 underline 设置下划线 charset 设置字体编码 bold 设置字体是否加粗