java实现利用阿里巴巴开源的easyexcel进行对excel表格的导入和导出[附完整代码]

简介: java实现利用阿里巴巴开源的easyexcel进行对excel表格的导入和导出[附完整代码]

前言

平常的功能大家应该都会用到导入导出excel的功能,比如通过读excel的方式将excel的数据导入到数据库中。当然实现的方式有很多,今天我介绍的是利用阿里开源的easyexcel项目来完成功能。大家也可以自己看easyexcel的文档进行开发。当然这里因为刚好工作的时候用到了,所以将自己写的demo分享出来,大家就可以更快节省时间完成功能,大家可以参考,也可以直接拿来用,实际在你们自己的开发过程当中适当修改。


一、引入easyexcel的maven

        <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.8</version>
    </dependency>


首先springBoot项目结构大家看一下,除了最简单的三层架构,dao、service和controller,这里还需要用到listener

二、读取excel代码示例

1、bean需要和excel的列对应

可以通过index和name将bean和excel的列对应起来,但是官方不建议index和name同时夹杂在一起用,顾名思义,在一个bean中要么就是用index,要么就是用name对应


eg:@ExcelProperty(index = 2)


eg:@ExcelProperty("日期标题")


demo

package com.xxx.xxxx.xxxx;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
 * Created by yjl on 2019/12/25.
 */
@Data
public class RoomMonitorCoverDataBean {
    private String TIME_ID; //时间
    @ExcelProperty(index = 0)
    private String PROV_NAME; //省
    @ExcelProperty(index = 1)
    private String AREA_NAME; //地市
    @DateTimeFormat("yyyy年MM月")
    @ExcelProperty(index = 2)
    private String MONTH_DESC; //月份,DateTimeFormat表示对日期进行格式化,不要的可以去掉
    public String getTIME_ID() {
        return TIME_ID;
    }
    public void setTIME_ID(String TIME_ID) {
        this.TIME_ID = TIME_ID;
    }
    public String getPROV_NAME() {
        return PROV_NAME;
    }
    public void setPROV_NAME(String PROV_NAME) {
        this.PROV_NAME = PROV_NAME;
    }
    public String getAREA_NAME() {
        return AREA_NAME;
    }
    public void setAREA_NAME(String AREA_NAME) {
        this.AREA_NAME = AREA_NAME;
    }
    public String getMONTH_DESC() {
        return MONTH_DESC;
    }
    public void setMONTH_DESC(String MONTH_DESC) {
        this.MONTH_DESC = MONTH_DESC;
    }
}


2、Controller层

很简单,就注入service,引用service的方法,我们在service里进行入参的判断或者其他业务处理等,这里我就直接放一个impl的了,interface是一样的名字,放一个没有实现的方法就可以了,当然你也可以不要那个interface

demo

@RequestMapping("/mrePortController")
public class MrePortControllerCSVImpl implements IMrePortControllerCSV {
  @Autowired
  private MrePortServiceCSV mrePortServiceCSV;
  @RequestMapping(value = "/saveRoomMonitorCoverData", method = RequestMethod.POST)
  @Override
  public JSONObject saveRoomMonitorCoverData(MultipartFile file, String timeType, String userArea) {
        return mrePortServiceCSV.saveRoomMonitorCoverData(file, timeType,userArea);
  }
}

3、service层

这里我们进行逻辑判断,可以对入参或者其他一些东西进行判断,

主要功能是

// 将excel表中的数据入库
// 有个很重要的点 xxxxxListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
// 这里 需要指定读用哪个class去读,默认读取第一个sheet 文件流会自动关闭
EasyExcel.read(file.getInputStream(), RoomMonitorCoverDataBean.class, new RoomMonitorCoverDataListener(mrePortDao,tableName,timeType)).sheet().doRead();

demo

@Component
public class MrePortServiceCSVImpl implements MrePortServiceCSV {
  @Autowired
  private MrePortDao mrePortDao;
    private Logger logger = LoggerFactory.getLogger(this.getClass());
  @Override
  public JSONObject saveRoomMonitorCoverData(MultipartFile file, String timeType,String userArea) {
        JSONObject jo = new JSONObject();
      try {
            //可以进行必传参数校验等
      //这里省略不写了
           //导入示例:excel名称:小小鱼儿小小林_浙江201912.xlsx
            String fileName = file.getOriginalFilename().replaceAll("\\.xlsx|\\.xls","");
            System.out.println("file.getName():"+file.getName()+",file.getOriginalFilename():"+file.getOriginalFilename());
            String[] split = fileName.split("_");
            String file_tableName = split[0]; //文件名称表名称
            String file_areaNameAndDate = split[1]; //文件名称地市和月份 eg:浙江201912
            //String file_version = split[2]; //文件名称版本号
            if ("小小鱼儿小小林".equals(file_tableName)){ //只能上传该名称的文件
                String file_areaName = file_areaNameAndDate.substring(0, 2); //文件名称地市
                String file_date = file_areaNameAndDate.substring(2); //文件名称月份
                if (userArea.equals(file_areaName)){ //只能上传自己权限范围内的地市数据
                    //Long currentDate = Long.parseLong(getCurrentDate("yyyyMM"));
                    String currentDate = getCurrentDate("yyyyMM");
                    if (currentDate.equals(file_date)){ //只能上传当月的数据
                       String tableName = "xxxxxxxxx";
                        // 将excel表中的数据入库
                        // 有个很重要的点 xxxxxListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
                        // 这里 需要指定读用哪个class去读,默认读取第一个sheet 文件流会自动关闭
                        EasyExcel.read(file.getInputStream(), RoomMonitorCoverDataBean.class, new RoomMonitorCoverDataListener(mrePortDao,tableName,timeType)).sheet().doRead();
                        jo.put("msg","导入成功");
                        jo.put("resultCode",0);
                        jo.put("response","success");
                    }else {
                        jo.put("msg","您只能上传当月"+currentDate+"的数据");
                        jo.put("resultCode",-1);
                        jo.put("response","");
                        return jo;
                    }
                }else {
                    jo.put("msg","您暂时没有权限上传"+file_areaName+"的数据");
                    jo.put("resultCode",-1);
                    jo.put("response","");
                    return jo;
                }
            }else {
                jo.put("msg","请选择《小小鱼儿小小林》文件再上传");
                jo.put("resultCode",-1);
                jo.put("response","");
                return jo;
            }
    }catch (IOException i){
      i.printStackTrace();
            jo.put("msg","IOException,请重试");
            jo.put("resultCode",-1);
            jo.put("response","");
    } catch (Exception e){
      e.printStackTrace();
            jo.put("msg","导入异常,请重试");
            jo.put("resultCode",-1);
            jo.put("response","");
    }
    return jo;
  }
}

4、listener层

注意这个不是mvc的三层架构,这里加listener是因为easyexcel需要用到,实际上解析excel的过程就是在这里实行的,如果要对解析出来的每一行数据或者其中的一列进行另外的判断或者做其他处理,是要到这个类里面写逻辑


RoomMonitorCoverDataListener.java


demo

/**
 * Created by yjl on 2019/12/27.公众号:zygxsq
 */
public class RoomMonitorCoverDataListener extends AnalysisEventListener<RoomMonitorCoverDataBean> {
    private Logger LOGGER = LoggerFactory.getLogger(this.getClass());
    private static final int BATCH_COUNT = 1000; //每隔1000条存数据库,然后清理list ,方便内存回收
    List<RoomMonitorCoverDataBean> list = new ArrayList<RoomMonitorCoverDataBean>();
    MrePortDao mrePortDao;
    String timeType;
    String tableName;
    /**
     * 如果使用了spring,请使用有参构造方法。每次创建Listener的时候需要把spring管理的类传进来
     */
    public RoomMonitorCoverDataListener(){}
    public RoomMonitorCoverDataListener(MrePortDao mrePortDao) {
        this.mrePortDao = mrePortDao;
    }
    public RoomMonitorCoverDataListener(MrePortDao mrePortDao,String timeType) {
        this.mrePortDao = mrePortDao;
        this.timeType = timeType;
    }
    public RoomMonitorCoverDataListener(MrePortDao mrePortDao,String tableName,String timeType) {
        this.mrePortDao = mrePortDao;
        this.tableName = tableName;
        this.timeType = timeType;
    }
    /**
     * 这个每一条数据解析都会来调用
     * @param data
     * @param analysisContext
     */
    @Override
    public void invoke(RoomMonitorCoverDataBean data, AnalysisContext analysisContext) {
        LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
        //------------------begin------------------------
        // 这里对excel表里的数据进行逻辑处理、筛选等,如果不需要对表里的数据进行处理,这里可以删除
        String area_name = data.getAREA_NAME();
        String month_desc = data.getMONTH_DESC();
        //先删除表里已经存在的,再保存新的
        mrePortDao.deleteTableData(tableName,timeType," AREA_NAME='"+area_name+"' AND MONTH_DESC='"+month_desc+"' ");
        //-------------------end-----------------------
        list.add(data);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (list.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            list.clear();
        }
    }
    /**
     * 所有数据解析完成了 都会来调用
     * @param analysisContext
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        saveData();
        LOGGER.info("所有数据解析完成!");
    }
    /**
     * 加上存储数据库
     */
    private void saveData() {
        LOGGER.info("{}条数据,开始存储数据库!", list.size());
        mrePortDao.saveRoomMonitorCoverData(list,timeType);
        LOGGER.info("存储数据库成功!");
    }
}


5、dao层

因为我们这里还是用的springJPA,所以大家可以看到上面我处理excel中的数据,要对原来数据库中的数据进行删除的时候,还是用拼接的那种格式,这里大家要结合自己的框架进行修改,相信作为技术人,你们改改还是可以的,如果有遇到不会改的,可以关注我的公众号:zygxsq,公众号里有我的微信方式,可以联系我


demo

/**
 * Created by yjl on 2019/12/20.
 */
@Component
public class MrePortDaoImpl implements MrePortDao {
  @PersistenceContext
  private EntityManager em;
  @Autowired
  protected JdbcTemplate jdbcTemplate;
  private Logger logger = LoggerFactory.getLogger(this.getClass());
  @Transactional
  @Override
  public Integer saveRoomMonitorCoverData(List<RoomMonitorCoverDataBean> params, String timeType) {
    String tableName = "xxxxxxx";
    StringBuilder sql = new StringBuilder();
    sql.append("INSERT INTO  ")
        .append(tableName)
        .append("(")
        .append("TIME_ID,") //时间
        .append("PROV_NAME,") //省
        .append("AREA_NAME,") //地市
        .append("MONTH_DESC,") //月份
        .append(")VALUES(")
        .append("?,?,?,?")
        .append(")")
        ;
    int[] len = jdbcTemplate.batchUpdate(sql.toString(), new BatchPreparedStatementSetter() {
      @Override
      public void setValues(PreparedStatement ps, int i) throws SQLException {
        RoomMonitorCoverDataBean pojo = params.get(i);
        String month_desc = pojo.getMONTH_DESC();
        String time_id = month_desc.replaceAll("\\D","")+"000000";
        ps.setString(1,time_id); //时间
        ps.setString(2,pojo.getPROV_NAME()); //省
        ps.setString(3,pojo.getAREA_NAME()); //地市
        ps.setString(4,month_desc); //月份
      }
      @Override
      public int getBatchSize() {
        return params.size();
      }
    });
    return len.length;
  }
    @Transactional
    @Modifying
    @Query
    @Override
    public Integer deleteTableData(String tableName, String timeType, String whereInfo) {
      String sql="DELETE FROM "+tableName+" WHERE 1=1 AND "+whereInfo;
        logger.info("删除表"+tableName+"里"+whereInfo+"的数据sql:"+sql);
        int deleteCnt = em.createNativeQuery(sql).executeUpdate();
        logger.info("成功删除"+tableName+"表中"+whereInfo+"的"+deleteCnt+"条数据");
        return deleteCnt;
    }
}

二、导出excel代码示例

待更新

相关文章
|
2月前
|
人工智能 Kubernetes Java
回归开源,两位 Java 和 Go 程序员分享的开源贡献指引
Higress是一个基于Istio和Envoy的云原生API网关,支持AI功能扩展。它通过Go/Rust/JS编写的Wasm插件提供可扩展架构,并包含Node和Java的console模块。Higress起源于阿里巴巴,解决了Tengine配置重载及gRPC/Dubbo负载均衡问题,现已成为阿里云API网关的基础。本文介绍Higress的基本架构、功能(如AI网关、API管理、Ingress流量网关等)、部署方式以及如何参与开源贡献。此外,还提供了有效的开源贡献指南和社区交流信息。
382 33
|
3月前
|
人工智能 缓存 自然语言处理
全球首款开源通用型AI智能体上线!Suna:自动处理Excel/爬数据/写报告等复杂任务一句话搞定
Suna是由Kortix推出的开源通用型AI智能体项目,通过自然语言交互实现浏览器自动化、文件管理、数据分析等复杂任务处理,支持自托管部署,为研究分析和日常工作提供智能辅助。
837 1
全球首款开源通用型AI智能体上线!Suna:自动处理Excel/爬数据/写报告等复杂任务一句话搞定
|
3月前
|
数据采集 监控 Oracle
GraalVM 24 正式发布阿里巴巴贡献重要特性 —— 支持 Java Agent 插桩
阿里巴巴是 GraalVM 全球顾问委员会的唯一中国代表,阿里云程序语言与编译器团队和可观测团队合作实现了 GraalVM 应用的无侵入可观测能力,并在 ARMS 平台上线了该功能。目前在 GraalVM 24 中发布的是支持 Java agent 的第一步,其余能力将在 GraalVM 的后续版本中陆续发布。
296 21
|
2月前
|
人工智能 Java 程序员
JManus - 面向 Java 开发者的开源通用智能体
JManus 是一个以 Java 为核心、完全开源的 OpenManus 实现,隶属于 Spring AI Alibaba 项目。它旨在让 Java 程序员更便捷地使用 AI 技术,支持多 Agent 框架、网页配置 Agent、MCP 协议和 PLAN-ACT 模式。项目在 GitHub 上已获近 3k star,可集成多个大模型如 Claude 3.5 和 Qwen3。开发者可通过 IDE 或 Maven 快速运行项目,体验智能问答与工具调用功能。欢迎参与开源共建,推动通用 AI Agent 框架发展。
5205 62
|
1月前
|
NoSQL Java Redis
推荐一款好用的开源免费Java CMS内容管理站群系统
Java开源内容管理系统(JProcms),基于SpringCloud、SpringBoot、MyBatisPlus、Vue3等技术构建,采用Apache-2.0协议,支持免费商用。系统具备自定义字段存储与可视化设计、API制作网站群页面等功能,强调简单灵活的设计理念,降低二次开发成本。支持多种数据库、消息队列和认证方式,提供SaaS多租户、动态权限菜单、工作流配置等强大功能,同时集成阿里云、腾讯云服务,适用于高效建站与内容管理。
219 4
|
25天前
|
文字识别 监控 Java
顺丰同城抢单辅助脚本,顺丰骑士抢单辅助免封号,自动抢单神器【java版开源】
这是一套OCR实时检测订单列表并自动右滑的完整代码方案,适用于学习研究。代码包含四个主要模块:OCR处理(文字识别)、价格分析
|
3月前
|
人工智能 Java 决策智能
Java版Manus实现来了,Spring AI Alibaba发布开源OpenManus实现
此次官方发布的 Spring AI Alibaba OpenManus 实现,包含完整的多智能体任务规划、思考与执行流程,可以让开发者体验 Java 版本的多智能体效果。它能够根据用户的问题进行分析,操作浏览器,执行代码等来完成复杂任务等。
1153 57
|
1月前
|
人工智能 自然语言处理 前端开发
上线几天,轻松斩获10k,开源通用AI智能体Suna:一句话自动处理Excel/爬数据/写报告,程序员私人助理诞生!
Suna是由Kortix推出的全球首个开源通用型AI Agent,可通过自然语言对话自动完成浏览器操作、数据分析、系统管理等复杂任务。它具有“执行力”,能像人类员工一样理解指令并操作数字工具,支持自托管保障数据安全,适用于市场分析、学术研究、企业办公等场景。Suna的核心优势在于实现“语言→行动”的转化,适合需要实际操作的任务,如爬虫、报表生成和网站部署。项目地址为:https://github.com/kortix-ai/suna。
152 0
|
7月前
|
人工智能 自然语言处理 Java
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
FastExcel 是一款基于 Java 的高性能 Excel 处理工具,专注于优化大规模数据处理,提供简洁易用的 API 和流式操作能力,支持从 EasyExcel 无缝迁移。
1507 65
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
|
4月前
|
JavaScript 前端开发 数据可视化
20.6K star!Excel级交互体验!这款开源Web表格神器绝了!
Handsontable 是一款功能强大的 JavaScript 数据表格组件,提供类 Excel 的交互体验。支持实时协作、数据绑定、公式计算等企业级功能,可轻松集成到 React/Vue/Angular 等主流框架。
313 11