EasyExcel简单使用

EasyExcel简单使用

​ 之前一直用的Apache POI来做数据的导入导出,但听说阿里的EasyExcel也拥有POI的功能的同时,在处理大数据量的导入导出的时候性能上比POI更好,所以就来尝试使用一下

导入Maven依赖:
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.2.1</version> <!-- 请检查并使用最新稳定版本 -->
</dependency>
导出数据功能
导出模型类

​ 定义一个导出数据模型类,用于设置excel文件的格式,通过注解的方式可以定义excel中的格式
@ColumnWidth(20) 设置excel中列的宽度为20;

@HeadStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER) 设置文本内容是否居中;

@HeadFontStyle(bold = BooleanEnum.FALSE) 设置字体是否加粗;

@ExcelProperty(value = “电话”, index = 0) 设置了excel中的标题,value则是标题内容,index则是内容所在的列的位置

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@ColumnWidth(20)
@HeadStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)
@HeadFontStyle(bold = BooleanEnum.FALSE)
public class PmembersExportVO {@ColumnWidth(15)@ExcelProperty(value = "电话", index = 0)private String mobile;@ColumnWidth(15)@ExcelProperty(value = "姓名", index = 1)private String realname;@ColumnWidth(10)@ExcelProperty(value = "性别", index = 2)private String gender;@ColumnWidth(10)@ExcelProperty(value = "省份", index = 3)private String resideprovince;@ColumnWidth(10)@ExcelProperty(value = "城市", index = 4)private String residecity;@ColumnWidth(10)@ExcelProperty(value = "区/县", index = 5)private String residedist;@ColumnWidth(20)@ExcelProperty(value = "地址", index = 6)private String address;@ColumnWidth(12)@ExcelProperty(value = "公历生日", index = 7)private String birth;@ColumnWidth(12)@ExcelProperty(value = "农历生日", index = 8)private String yinlibirth;@ColumnWidth(12)@ExcelProperty(value = "是否闰月", index = 9)private String isLeapMonth;}
controller代码
    @ApiOperation("导出居士信息")@ApiImplicitParams({@ApiImplicitParam(name = "weiqingview_backend_token", value = "token", required = true, dataType = "String", paramType = "header"),@ApiImplicitParam(name = "uniacid", value = "Unicid", required = true, dataType = "Integer", paramType = "query")})@GetMapping("/export")public void export(@RequestParam Map<String, Object> params, HttpServletResponse response) {mcMembersService.exportExcel(params, response);}
service代码

​ 通过查询数据库中的数据,并封装到List集合中,调用EasyExcel的write方法即可将集合中的数据写入生成excel文件供下载

public void export(Map<String, Object> params, HttpServletResponse response) {Integer uniacid = Integer.valueOf(params.get("uniacid").toString());List<McMembers> mcMembersList = this.list(new QueryWrapper<McMembers>().eq("isBeliever", 1).eq("uniacid", uniacid));List<PmembersExportVO> pmembersExportVOList = mcMembersList.stream().map(m -> {PmembersExportVO pmembersExportVO = new PmembersExportVO();pmembersExportVO.setAddress(m.getAddress());pmembersExportVO.setMobile(m.getMobile());pmembersExportVO.setGender(ObjectUtils.isEmpty(m.getGender()) ? "" : m.getGender().equals(0) ? "女" : "男");pmembersExportVO.setBirth(m.getBirth());pmembersExportVO.setYinlibirth(m.getYinlibirth());pmembersExportVO.setRealname(m.getRealname());pmembersExportVO.setResidedist(m.getResidedist());pmembersExportVO.setResidecity(m.getResidecity());pmembersExportVO.setResideprovince(m.getResideprovince());pmembersExportVO.setIsLeapMonth(ObjectUtils.isEmpty(m.getIsLeapMonth()) ? "否" : m.getIsLeapMonth() == 1 ? "是" : "否");return pmembersExportVO;}).collect(Collectors.toList());//        // 导出Excel
//        EasyExcel.write("居士信息数据.xls", PmembersExportVO.class)
                .head(headersList) // 设置表头
//                .sheet("用户信息")
//                .doWrite(pmembersExportVOList);// 设置响应头response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");String fileName = null;try {fileName = URLEncoder.encode("居士信息数据.xlsx", "UTF-8");response.setHeader("Content-Disposition", "attachment;filename=" + fileName);EasyExcel.write(response.getOutputStream(), PmembersExportVO.class).sheet("用户信息").doWrite(pmembersExportVOList);} catch (UnsupportedEncodingException e) {log.error("导出居士信息报错 UnsupportedEncodingException:{}", e);} catch (IOException e) {log.error("导出居士信息报错 IOException:{}", e);}}

image-20240511105026375

导入数据功能:
导入数据模型类

​ 我这里用的跟导出数据类基本一致,所以也就改了个类名

​ 只要用@ExcelProperty指定对应列的信息就行,其他指定格式的注解其实可以忽略

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@ColumnWidth(20)
@HeadStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)
@HeadFontStyle(bold = BooleanEnum.FALSE)
public class ImportPmcMembersDTO {@ColumnWidth(15)@ExcelProperty(value = "电话", index = 0)private String mobile;@ColumnWidth(15)@ExcelProperty(value = "姓名", index = 1)private String realname;@ColumnWidth(10)@ExcelProperty(value = "性别", index = 2)private String gender;@ColumnWidth(10)@ExcelProperty(value = "省份", index = 3)private String resideprovince;@ColumnWidth(10)@ExcelProperty(value = "城市", index = 4)private String residecity;@ColumnWidth(10)@ExcelProperty(value = "区/县", index = 5)private String residedist;@ColumnWidth(20)@ExcelProperty(value = "地址", index = 6)private String address;@ColumnWidth(12)@ExcelProperty(value = "公历生日", index = 7)private String birth;@ColumnWidth(12)@ExcelProperty(value = "农历生日", index = 8)private String yinlibirth;@ColumnWidth(12)@ExcelProperty(value = "是否闰月", index = 9)private String isLeapMonth;}
controller代码

​ 前端页面上传一个name是file的文件

    @ApiOperation("导入居士信息")@ApiImplicitParams({@ApiImplicitParam(name = "weiqingview_backend_token", value = "token", required = true, dataType = "String", paramType = "header"),@ApiImplicitParam(name = "uniacid", value = "Unicid", required = true, dataType = "Integer", paramType = "query"),@ApiImplicitParam(name = "file", value = "file", required = true, dataType = "MultipartFile", paramType = "query")})@PostMapping("/uploadExcel")public R uploadExcel(@RequestParam("file") MultipartFile file, @RequestParam Map<String, Object> params) {return mcMembersService.importExcel(file, params);}
service代码

​ 下面是接收controller传来的文件后,通过调用EasyExcel的read方法,直接进行导入操作

    public R importExcel(MultipartFile file, Map<String, Object> params) {// 检查文件是否为空if (file.isEmpty()) {return R.error("没有检测到文件"); // 返回错误页面}try {// 执行导入操作EasyExcel.read(file.getInputStream(), ImportPmcMembersDTO.class, new ImportPmcMembersListener(this, params)).sheet().doRead();// 返回上传成功页面return R.ok("导入excel成功");} catch (IOException e) {e.printStackTrace();return R.error("导入excel失败");}}

​ 下面是service中基本的添加数据的操作方法,导入数据插库的时候也直接调用,就不写新的插库方法了

public R pAdd(AddPmcMembersDTO addPmcMembersDTO, Map<String, Object> params) {McMembers mcMembers = new McMembers();BeanUtils.copyProperties(addPmcMembersDTO, mcMembers);mcMembers.setIsBeliever((byte) 1);Integer uniacid = Integer.parseInt(params.get("uniacid").toString());mcMembers.setUniacid(uniacid);if (this.save(mcMembers)) {return R.ok("添加成功");}return R.error("添加失败");}
listener代码

​ 上传的话需要定义一个listener,并继承AnalysisEventListener,这里的T类型就是上面定义的模型类的类型。

​ 如果是在listener中进行插库操作,那需要把service注入进来,但是在listener中不能用@Autowired,所以重写一个带参的构造方法,把注入好的service直接传进来使用即可,我下面将注入好的mcMembersService传递了进来,执行插库操作。下面的AddPmcMembersDTO是我另外定义的一个模型类,是用于界面上添加数据用的,这里直接转换后调用进行插库操作了。

​ 当然也可以在listener中先将excel中的数据都封装到List集合中,再统一将List中的数据插库也行。

public class ImportPmcMembersListener extends AnalysisEventListener<ImportPmcMembersDTO> {private McMembersService mcMembersService;private Map<String, Object> params;//通过构造方法,得到注入好的mcMembersServicepublic ImportPmcMembersListener(McMembersService mcMembersService, Map<String, Object> params) {this.mcMembersService = mcMembersService;this.params = params;}@Overridepublic void invoke(ImportPmcMembersDTO data, AnalysisContext context) {// 处理读取到的每行数据,例如保存到数据库System.out.println("读取到一行数据: " + data.toString());// 这里可以添加保存到数据库的逻辑AddPmcMembersDTO addPmcMembersDTO = new AddPmcMembersDTO();addPmcMembersDTO.setMobile(data.getMobile());addPmcMembersDTO.setRealname(data.getRealname());addPmcMembersDTO.setGender((byte) (ObjectUtils.isEmpty(data.getGender()) ? 0 : data.getGender().equals("男") ? 1 : 2));addPmcMembersDTO.setAddress(data.getAddress());addPmcMembersDTO.setBirth(data.getBirth());addPmcMembersDTO.setYinlibirth(data.getYinlibirth());addPmcMembersDTO.setResidedist(data.getResidedist());addPmcMembersDTO.setResidecity(data.getResidecity());addPmcMembersDTO.setResideprovince(data.getResideprovince());addPmcMembersDTO.setIsLeapMonth((byte) (ObjectUtils.isEmpty(data.getIsLeapMonth()) ? 0 : data.getIsLeapMonth().equals("是") ? 1 : 0));// 进行插库操作mcMembersService.pAdd(addPmcMembersDTO, params);}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 所有数据解析完毕后的回调System.out.println("所有数据解析完成");}

将一下excel数据进行导入操作

image-20240511112040930

用Api工具测试了下,上传成功

image-20240511112220656

查看数据库,数据也成功导入

image-20240511112302526

整体感觉挺好用的,对于不同的数据进行导入的话,其实可以再封装成通用的listener,这样不用每一个功能导入都去定义一个listener,这个等后面有空再折腾吧。

结束

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】基于 Jenkins+shell 实现更新服务所需文件 -->两种方式:ssh/Ansible

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

【北京迅为】《iTOP-3588从零搭建ubuntu环境手册》-第7章 安装VMwareTools

RK3588是一款低功耗、高性能的处理器&#xff0c;适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用&#xff0c;RK3588支持8K视频编解码&#xff0c;内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…

SeetaFace6人脸特征提取与对比C++代码实现Demo

SeetaFace6包含人脸识别的基本能力&#xff1a;人脸检测、关键点定位、人脸识别&#xff0c;同时增加了活体检测、质量评估、年龄性别估计&#xff0c;并且顺应实际应用需求&#xff0c;开放口罩检测以及口罩佩戴场景下的人脸识别模型。 官网地址&#xff1a;https://github.co…

基于yolov5+streamlit目标检测演示系统设计

YOLOv5与Streamlit&#xff1a;智能目标检测可视化展示介绍 随着人工智能技术的飞速发展&#xff0c;目标检测技术已成为推动智能化社会进步的关键技术之一。在众多目标检测算法中&#xff0c;YOLOv5以其卓越的性能和实时性&#xff0c;成为了业界的佼佼者。与此同时&#xff…

[算法][差分][延迟相差][leetcode]2960. 统计已测试设备

题目地址&#xff1a; https://leetcode.cn/problems/count-tested-devices-after-test-operations/description/ 解法一&#xff1a;暴力解法 class Solution {public int countTestedDevices(int[] batteryPercentages) {//特殊条件判断if(null batteryPercentages || ba…

Java后端初始化项目(项目模板)

介绍 emmmm&#xff0c;最近看了一些网络资料&#xff0c;也是心血来潮&#xff0c;想自己手工搭建一个java后端的初始化项目模板来简化一下开发&#xff0c;也就发一个模板的具体制作流程&#xff0c;&#xff08;一步一步搭建&#xff0c;从易到难&#xff09; ok&#xff…

Rust的协程机制:原理与简单示例

在现代编程中&#xff0c;协程&#xff08;Coroutine&#xff09;已经成为实现高效并发的重要工具。Rust&#xff0c;作为一种内存安全的系统编程语言&#xff0c;也采用了协程作为其并发模型的一部分。本文将深入探讨Rust协程机制的实现原理&#xff0c;并通过一个简单的示例来…

读天才与算法:人脑与AI的数学思维笔记25_涌现理论

1. 人工智能新闻 1.1. 人工智能新闻报道算法的核心是如何将未经处理的原始数据转换成新闻报道 1.2. 很少有记者为美联社决定使用机器来帮助报道这些新闻持反对意见 1.2.1. 像“Wordsmith”这样的算法&#xff0c;具有自动化的洞察力、科学的叙事能力&#xff0c;现在正被应用…

SpringSecurity安全过滤器工作原理

前面通过三篇文章&#xff0c;从底层代码的角度分析了SpringSecurity的初始化过程。 接下来我们就要具体看一下&#xff0c;Spring Security的安全过滤器初始化、装配好之后&#xff0c;到底是怎么工作的。 还是按图索骥 下面我们简单从底层源码分析一下&#xff0c;请求是怎…

leetcode——反转链表

206. 反转链表 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a;创建三个指针n1,n2,n3&#xff0c;遍历原链表&#xff0c;通过三者之间的关系将链表反转。下面给出图示&#xff1a; 下面给出题解代码&#xff1a; typedef struct ListNode ListNode; struct List…

【C++】vector的底层原理讲解及其实现

目录 一、认识vector底层结构 二、初始化vector的函数 构造函数拷贝构造赋值构造initializer_list构造迭代器区间构造 三、迭代器 四、数据的访问 五、容量相关的函数 六、关于数据的增删查改操作 一、认识vector底层结构 STL库中实现vector其实是用三个指针来完成的&#x…

C# OpenCvSharp Demo - Mat格式化输出、Mat序列化和反序列化

C# OpenCvSharp Demo - Mat格式化输出、Mat序列化和反序列化 目录 效果 项目 代码 下载 效果 直接输出&#xff1a;Mat [ 3*2*CV_8UC3, IsContinuousTrue, IsSubmatrixFalse, Ptr0x1eb73ef9140, Data0x1eb73ef91c0 ]格式化输出&#xff1a;默认风格[ 91, 2, 79, 179, …