easyExcel数据导入功能

一、添加依赖
 <!-- 处理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&&paramMap.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设置字体是否加粗
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值