easyExcel 数据导入

news2024/12/26 0:01:29

前言

这段时间做了excel 数据导入,用的阿里巴巴的easyExcel 的代码。下面是官网和githab 代码地址。需要将github 上的代码拉下来,方便查看demo.关于Easyexcel | Easy ExcelEasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目,在尽可能节约内存的情况下支持读写百M的Excel。https://easyexcel.opensource.alibaba.com/docs/current/

GitHub - alibaba/easyexcel: 快速、简洁、解决大文件内存溢出的java处理Excel工具快速、简洁、解决大文件内存溢出的java处理Excel工具. Contribute to alibaba/easyexcel development by creating an account on GitHub.https://github.com/alibaba/easyexcel 

 仔细查看上面的代码,模仿上面的代码就可以写出来了。

操作步骤

一,创建对象

对象不能使用@Accessors(chain = true) 注解,不然会出现读取不到数据的情况

@Getter
@Setter
@EqualsAndHashCode
public class DemoData {
    private String string;
    private Date date;
    private Double doubleData;
}

二,随便创建一个简单的类,不需要任何配置。

只需要根据官网demo来实现或者继承他们自己的内部类即可,创建的类放哪里都行

// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class DemoDataListener implements ReadListener<DemoData> {    

}

三,了解继承类的各个方法

3.1 invokeHead 方法是用来读取表头的。

 @Override
    public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {}

使用invokeHead 方法需要我们先定义哪几行是表头,下面代码中的.headRowNumber(3) 可以定义哪几行是表头。3待办前三行都是表头,invokeHead 方法会读取前三行,我们可以根据invokeHead 来校验表头

EasyExcel.read(file.getInputStream(), YclJzLqJcVo.class, yclJzLqExcelDataListener).sheet().headRowNumber(3).doRead();

3.2 invoke 是用来读取数据内容的,在invokeHead 方法运行完后就会运行invoke 方法。来读取数据内容。

@Override
public void invoke(YclJzLqJcVo data, AnalysisContext context) {}

3.3  所有数据解析完成了 都会来调用

@Override
public void doAfterAllAnalysed(AnalysisContext context) {}

四,导入并且返回异常数据提示信息

4.1 实体类设置 

@ExcelProperty(index = 1, value = "进场日期")

 @ExcelProperty注解中的index 属性代表该字段读取的excel 上的第几列,index =1 代表该字段读取excel 上的第二列,index =0 读取第一列。

 

package easttrans.pitchdatacore.domain.core;

import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.Serializable;
import java.util.Date;

/**
 * <p>
 * 
 * </p>
 *
 * @author guankong
 * @since 2022-10-26
 */
@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="改性沥青模板映射类", description="")
public class YclGxLqJcVo extends CommonVo implements Serializable {

    private static final long serialVersionUID=1L;

    @ApiModelProperty(value = "id")
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    @ExcelProperty(index = 0, value = "序号")
    @ApiModelProperty(value = "序号")
    private Integer serialNum;

    @ExcelProperty(index = 1, value = "进场日期")
    @ApiModelProperty(value = "进场日期")
    private Date enterDate;

    @ExcelProperty(index = 2, value = "品牌及标号")
    @ApiModelProperty(value = "品牌及标号")
    private String brand;

    @ExcelProperty(index = 3, value = "堆放地点")
    @ApiModelProperty(value = "堆放地点")
    private String place;

    @ExcelProperty(index = 4, value = "用途")
    @ApiModelProperty(value = "用途面层")
    private String ratio;

    @ExcelProperty(index = 5, value = "质保单编号")
    @ApiModelProperty(value = "质保单编号")
    private String qaNum;

    @ExcelProperty(index = 6, value = "同批数量(t)")
    @ApiModelProperty(value = "同批数量(t)")
    private Double count;

    @ExcelProperty(index = 7, value = "委托单或任务单编号")
    @ApiModelProperty(value = "委托单或任务单编号")
    private String taskNum;

    @ExcelProperty(index = 8, value = "针入度0.1mm")
    @ApiModelProperty(value = "针入度0.1mm")
    private Double zrd;


}

4.2  拦截器设置

这里AnalysisEventListener<YclJzLqJcVo> 可以设置成泛型AnalysisEventListener<T>


@Slf4j
public final  class YclJzLqExcelDataListener extends AnalysisEventListener<YclJzLqJcVo> {

    private final YclLqJcVo yclLqJcVo;

    private YclLqJcService yclLqJcService;
    /**
     * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 100;
    private List<YclJzLqJcVo> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    /**
     * 存储异常提醒消息
     */
    private Map<String, Object> result = new HashMap<>();
    /**
     * excel表头是否正确,false 有误,true 正确。
     */
    private boolean format = false;

    /**
     * 头信息
     */
    Map<Integer, String> headMap = new HashMap<>();

    /**
     * 返回提示语
     */
    public List<ImportTips> tips = new ArrayList<>();

    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     *
     * @param
     */
    public YclJzLqExcelDataListener(YclLqJcService yclLqJcService,YclLqJcVo yclLqJcVo) {
        this.yclLqJcService = yclLqJcService;
        this.yclLqJcVo = yclLqJcVo;
    }


    /**
     * 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。
     *
     * @param exception
     * @param context
     * @throws Exception
     */
    @Override
    public void onException(Exception exception, AnalysisContext context)   {
        log.error("解析失败,但是继续解析下一行:{}", exception.getMessage());
        int col = 0,row =0;
        String title = "";
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
            log.error("第{}行,第{}列解析异常,数据为:{}", excelDataConvertException.getRowIndex(),
                    excelDataConvertException.getColumnIndex(), excelDataConvertException.getCellData());
            col = excelDataConvertException.getColumnIndex();
            row = excelDataConvertException.getRowIndex();
            title = this.headMap.get(col);

        }
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        this.headMap = headMap;
    }


    /**
     * 这里会一行行的返回头
     *
     * @param headMap
     * @param context
     */
    @Override
    public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
        log.info("解析到一条头数据:{}", JSON.toJSONString(headMap));
        // 如果想转成 Map<Integer,String>
        // 方案1: 不要implements ReadListener 而是 extends AnalysisEventListener
        // 方案2: 调用 ConverterUtils.convertToStringMap(headMap, context) 自动会转换
        Map<Integer, String> integerStringMap = ConverterUtils.convertToStringMap(headMap, context);
        String s = integerStringMap.get(0);
        if (s != null && s.equals(Constants.JZ_Asp_Mob_Ins_Account)){
            //如果表头包含该内容,则为true
            format = true;
        }
        
    }

    @Override
    public void invoke(YclJzLqJcVo data, AnalysisContext context) {
        result.put("format",format);
        if (!format){
            //format 为false 时
            throw new ExcelAnalysisStopException(Constants.formatTemplateNoTrue);
        }

        //查询改性沥青数据库,判断该数据库中的报告编号是否与cachedDataList 中的报告编号重复,重复不导入
        LambdaQueryWrapper<YclLqJcVo> yclJzLqJcVoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        yclJzLqJcVoLambdaQueryWrapper.eq(YclLqJcVo::getReportNum,data.getReportNum());
        yclJzLqJcVoLambdaQueryWrapper.eq(YclLqJcVo::getType,Constants.JZLQ_TYPE);

        List<YclLqJcVo> list = yclLqJcService.list(yclJzLqJcVoLambdaQueryWrapper);
        if (list.size()>0){
            //表示有数据,该数据不能新增进数据库
            saveTips(context.readRowHolder().getRowIndex(),Constants.Duplicate_Import_Information,tips);
            return;
        }

        
        cachedDataList.add(data);
        if (cachedDataList.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        saveData();

        log.info("所有数据解析完成!");
    }

    /**
     * 加上存储数据库
     */
    private void saveData() {
    
        yclLqJcService.saveBatch(collect);
        log.info("存储数据库成功!");
    }

    /**
     * 返回数据
     * @return 返回读取的数据集合
     **/
    public Map<String,Object> getResult(){
        return result;
    }

    /**
     * 设置读取的数据集合
     * @param result 设置读取的数据集合
     **/
    public void setResult(Map<String,Object> result) {
        this.result = result;
    }

  

}

4.3 controller 层设置


    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
    @ApiOperation(value = "沥青进场检验台账导入数据", notes = "沥青进场检验台账导入数据")
    public EastTransResult importExcel(@RequestParam("file") MultipartFile file, YclLqJcVo yclLqJcVo) throws IOException {
        EastTransResult<Object> eastTransResult = new EastTransResult<>();
        //两个判断,第一个是表头,第二个是内容(哪一行的数据不对)
            //type 等于2 为改性沥青,先判断第一行导入模板的表头是否准确
            YclGxLqExcelDataListener yclGxLqExcelDataListener = new YclGxLqExcelDataListener(yclLqJcService, yclLqJcVo);
            EasyExcel.read(file.getInputStream(), YclGxLqJcVo.class, yclGxLqExcelDataListener).sheet().headRowNumber(3).doRead();
            Map<String, Object> result = yclGxLqExcelDataListener.getResult();
            boolean format = (boolean) result.get("format");
            eastTransResult = new EastTransResult(200, null, "请求成功");
            if (!format) {
                //表头错误
                eastTransResult = new EastTransResult(403, null, "该模板不正确");
            }

        }
        return eastTransResult;
    }

返回的数据是 Map<String, Object> result ,可以看下listener 类里面的result 是怎么定义的,先创建了一个 

private Map<String, Object> result = new HashMap<>();

 然后设置了该result 的get,set 方法。

public Map<String,Object> getResult(){
    return result;
}

public void setResult(Map<String,Object> result) {
    this.result = result;
}

 然后可以在listener 类里面result.put("key","val");

后面在controller 中获取该类listener 的getResult 方法就可以获取这个map 了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/71708.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]Python计算机毕业设计SSM基于与协同过滤算法的竞赛项目管理(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

可重复读实现原理

浅解释 概念 1、InnoDB 在每行记录后面保存两个隐藏的列&#xff0c;分别保存了数据行的创建版本号和删除版本号。每开始一个新的事务&#xff0c;系统版本号都会递增。事务开始时刻的系统版本号会作为事务的版本号&#xff0c;用来和查询到的每行记录的创建版本号对比。 2、i…

RKMEDIA--VP使用

本章描述rkmedia vp模块 即视频一入四处功能的介绍。 使用场景&#xff1a;主要用在DVR/DMS产品上&#xff0c;需要多路视频节点的输入和获取。 可以rv1126/rv1109可以外接模拟高清RX芯片&#xff08;NVP6188,TP2815等&#xff09;&#xff0c;达到8路camera输入的能力。 在…

PLSQL导出、导入数据 和 同步数据 以及 navicat 里同步数据 以及解决plsql导出数据乱码问题

PLSQL导出、导入数据 和 同步数据 以及 navicat 里同步数据 以及解决plsql导出数据乱码问题1. 导出数据1.1 导出.pde文件1.2 导出sql文件1.2.1 导出sql压缩文件1.2.1 导出问题——乱码 与 解决乱码问题1. 尝试解决方式12. 尝试解决方式23. 直接换PLSQ版本&#xff08;最终解决问…

Traysoft AddTapi.NET 支持多条线路

Traysoft AddTapi.NET 支持多条线路 使用Traysoft AddTapi。您可以轻松地将手机功能添加到C#、VB.NET和C应用程序中。添加Tapi。NET将为您提供开发移动应用程序所需的一切。包括&#xff1a;电话呼叫、接收者ID、语音邮件、警告系统、电话呼叫跟踪和监控。添加Tapi。NET继续联系…

微服务框架 SpringCloud微服务架构 25 黑马旅游案例 25.3 我附近的酒店

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构25 黑马旅游案例25.3 我附近的酒店25.3.1 直接开干25 黑马旅游案例 25.3 …

计算机组成大题分析(四)

假设计算机 M 的主存地址为 24 位,按字节编址,采用分页存储管理方式,虚拟地址为 30 位,页大小为 4KB,TLB 采用 2 路组相联方式 和LRU 替换策略,一共8组。请回答一下问题。 (1) 虚拟地址中有哪几位表示虚页号? 哪几位表示内存地址? (2)己知访问 TLB 时虚页号高位部分用作 TLB…

留学Assignment写作语法错误怎么改正?

如何避免Assignment写作中的一些语法错误&#xff0c;在留学生提交论文要求进行润色修改时&#xff0c;经常会碰到一些语法上的错误&#xff0c;这都是英语水平的问题&#xff0c;同时也与自身的习惯相关&#xff0c;下面小编说一下Assignment写作的语法错误的几种情况&#xf…

浙江省AAA级“守合同重信用”公示企业

浙江省“守合同重信用”企业公示&#xff0c;是市场监管部门依企业自愿申请&#xff0c;对符合公示条件企业前两个年度内的合同履约信息向社会公示的行政指导行为。 浙江省“守合同重信用”企业公示实行逐级推荐、分级公示、动态管理制度。企业住所地县级市场监管局受理企业公示…

你还在使用swagger?试试这个吧

文章目录easyyapi插件使用1. 安装插件2. 配置插件3. 编写javadoc4. 上传接口javadoc5. 登录YApi,查看项目接口easyyapi插件使用 1. 安装插件 打开idea的Settings–>Plugins,查找easyyapi插件安装。 2. 配置插件 安装成功后&#xff0c;再次打开Settings–>OtherSett…

公司小程序小程序毕业设计,企业小程序系统设计与实现,微信小程序毕业设计论文怎么写毕设源码开题报告需求分析怎么做

项目背景和意义 目的&#xff1a;本课题主要目标是设计并能够实现一个基于微信小程序公司企业站系统&#xff0c;前台用户使用小程序&#xff0c;后台管理使用基PHP开发&#xff0c;存储使用Mysql数据库&#xff1b;通过后台添加公司信息、资讯、产品等&#xff0c;用户通过小程…

vue+element+electron仿微信实现

一.仿得太像了有木有~ 1.登录窗口 2.主窗口 二.构思&#xff0c;以微信设计布局构思 以微信布局构思&#xff0c;参考element提供的组件&#xff1b;element提供的tabs标签页刚好能实现切换效果&#xff0c;element tabs 标签页&#xff1b;element tabs标签页虽然能达到切换…

如果把网络原理倒过来看,从无到有,一切如此清晰

从物理层到数据链路层 也从上篇我们创造一个计算机网络&#xff0c;你会去怎么设计&#xff1f;&#xff0c;追溯到计算机网络互联的本质就是通信问题&#xff0c;所以从物理层解决使用何种信号来传输比特的问题。 再从物理设备中的集线器&#xff0c;聊到二层的交换机&#…

零基础CSS入门教程(9)——背景颜色和背景图片

本章目录1.任务目标2.背景颜色3.背景图片4.小结1.任务目标 我们前几小节学习了如何设置字体格式&#xff0c;我们这一小节学习一下如何设置背景颜色和图片 2.背景颜色 我们可以通过background-color给标签设置背景颜色&#xff0c;例如&#xff1a; <!DOCTYPE html> …

【世界杯限定】致敬梅西,用Python刻画足球场上的战神

最近卡塔尔世界杯正在火热的进行着&#xff0c;相信球迷们一定不会错过每一场精彩的比赛吧&#xff0c;在看球的同时&#xff0c;小伙伴们不要忘记自己的学习与工作哦&#xff0c;本人纯属路人&#xff0c;虽然不是很懂球&#xff0c;但是很喜欢梅西&#xff0c;所以我开始关注…

云边协同下的统一应用管理: 基于 OpenYurt 和 KubeVela 的解决方案

作者&#xff1a;乔中沛&#xff08;伊灵&#xff09; 背景 随着万物互联场景的逐渐普及&#xff0c;边缘设备的算力也不断增强&#xff0c;如何借助云计算的优势满足复杂多样化的边缘应用场景&#xff0c;让云原生技术延伸到端和边缘成为了新的技术挑战&#xff0c;“云边协…

RNA-seq 详细教程:样本质控(6)

学习目标 了解计数数据变换方法的重要性了解 PCA (principal component analysis)了解如何使用 PCA 和层次聚类评估样本质量1. 质控 DESeq2 工作流程的下一步是 QC&#xff0c;其中包括样本和基因程度上&#xff0c;以对计数数据执行 QC 检查&#xff0c;以帮助我们确保样本或重…

[附源码]Python计算机毕业设计Django右脑开发教育课程管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;我…

iOS现有APP上架流程​

一. 登录App Store Connect​ 1.登录App Store Connect(apple.com)账号密码登录​ 2.点击“我的App”-->”选中升级的APP”-->创建新的APP版本号​ 输入版本的升级内容--》然后点击右上角的“存储”按钮&#xff0c;保存本次修改。​ 上传更新App Store安装包​ Xcode-…

【Rust日报】2022-12-07 测量 Rust 中 HashMap 的开销

测量 Rust 中 HashMap 的开销在处理将大量数据放入 HashMap的项目时&#xff0c;作者开始注意到 HashMap 占用了大量内存并对最小内存使用量进行了粗略计算&#xff0c;得到的常驻内存是预期的两倍多。我们都知道 HashMaps 以空间换取时间。通过使用更多空间&#xff0c;我们能…