Fork me on GitHub

EasyExcel实现Excel的导入导出

前言:最近练习简单项目过程中使用Excel的导入导出较多,特来记录一下相关代码逻辑

 

准备工作

1. 首先在pom.xml文件中引入相关依赖

 

其他依赖若有需要可以引入

<!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> </dependency> <!--mybatis-plus 代码生成器--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> </dependency> <!--mybatis-plus 代码模板生成器引擎--> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> </dependency> <!-- junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <!--阿里巴巴Easy Excel --> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> </dependency> <!-- xml --> <dependency> <groupId>org.apache.xmlbeans</groupId> <artifactId>xmlbeans</artifactId> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.5</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency>

 

 

2. 在controller层中创建一个AdminAttendanceDictController.java文件

相关代码如下

package com.xxx.student.core.controller.dict; import com.alibaba.excel.EasyExcel; import com.sun.deploy.net.URLEncoder; import com.xxx.student.common.exception.BusinessException; import com.xxx.student.common.result.R; import com.xxx.student.common.result.ResponseEnum; import com.xxx.student.core.pojo.dto.AttendanceExcelDTO; import com.xxx.student.core.service.AttendanceService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; /** * @author Li */ @Api(tags = "数据字典管理") @RestController @Slf4j @CrossOrigin @RequestMapping("/admin/core/dictAttendance") public class AdminAttendanceDictController { @Resource private AttendanceService attendanceService; @ApiOperation("Excel日常考勤信息数据的导出") @GetMapping("/export") public void export(HttpServletResponse response) throws IOException { response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); // 这里URLEncoder.encode可以防止中文乱码 当然和easyExcel没有关系 String fileName = URLEncoder .encode("日常考勤数据字典列表", "UTF-8").replaceAll("\\+", "%20"); response .setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); EasyExcel .write(response.getOutputStream(), AttendanceExcelDTO.class) .sheet("数据字典") .doWrite(attendanceService.listDictData()); } @ApiOperation("Excel日常考勤信息数据的批量导入") @PostMapping("/import") public R batchImport(@ApiParam(value = "Excel数据字典文件", required = true) @RequestParam("file") MultipartFile file) { try { InputStream inputStream = file.getInputStream(); attendanceService.importData(inputStream); return R.ok().message("数据字典批量导入成功"); } catch (Exception e) { // 文件上传错误 throw new BusinessException(ResponseEnum.UPLOAD_ERROR, e); } } }

 

 

3.我们注意到AdminAttendanceExcelDto.java还未定义

所以我们需要新建一个AdminAttendanceExcelDto.java文件,代码如下

package com.xxx.student.core.pojo.dto; import com.alibaba.excel.annotation.ExcelIgnore; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.format.DateTimeFormat; import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ContentRowHeight; import com.alibaba.excel.annotation.write.style.HeadRowHeight; import com.xxx.student.core.util.LocalDateTimeConverter; import lombok.Data; import java.time.LocalDateTime; /** * <p> * * </p> * * @author lsh * @since 2021-07-25 */ @Data @ContentRowHeight(15) //设置行高 @HeadRowHeight(20) //设置表头高度 @ColumnWidth(20) //设置列宽 public class AttendanceExcelDTO { @ExcelProperty(index = 0,value = "学生学号") private Long studentNo; @ExcelProperty(index = 1,value = "考勤时间",converter = LocalDateTimeConverter.class) private LocalDateTime attendanceTime; @ExcelProperty(index = 2,value = "考勤地点") private String attendanceLocation; @ExcelProperty(index = 3,value = "宿舍号") private Integer dormitoryNo; @ExcelIgnore @DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒") @ExcelProperty(value = "创建时间") private LocalDateTime createTime; @ExcelIgnore @ExcelProperty(value = "更新时间") private LocalDateTime updateTime; @ExcelIgnore @ExcelProperty(value = "逻辑删除") private Boolean deleted; }

 

4. 这里我们又使用到了一个用于转换LocalDateTime的一个工具类

package com.xxx.student.core.util; 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 java.time.LocalDateTime; import java.time.format.DateTimeFormatter; /** * 自定义转换器,转换LocalDateTime * @author Li */ public class LocalDateTimeConverter implements Converter<LocalDateTime> { @Override public Class<LocalDateTime> supportJavaTypeKey() { return LocalDateTime.class; } @Override public CellDataTypeEnum supportExcelTypeKey() { return CellDataTypeEnum.STRING; } @Override public LocalDateTime convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return LocalDateTime.parse(cellData.getStringValue(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); } @Override public CellData<String> convertToExcelData(LocalDateTime value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return new CellData<>(value.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); } }

 

5.我们还需要创建一个AttendanceExcelDictDTOListener.java作为监听器来帮助我们检测导入的情况

继承 AnalysisEventListener<AttendanceExcelDTO>,泛型为我们要实现的ExcelDTO对象

package com.xxx.student.core.listener; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.util.CollectionUtils; import com.xxx.student.core.mapper.AttendanceMapper; import com.xxx.student.core.pojo.dto.AttendanceExcelDTO; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; /** * @author Li */ @Slf4j @NoArgsConstructor public class AttendanceExcelDictDTOListener extends AnalysisEventListener<AttendanceExcelDTO> { // 数据列表 ArrayList<AttendanceExcelDTO> list = new ArrayList<>(); private AttendanceMapper attendanceMapper; // 每隔10条数据批量存入一次数据 static final int BATCH_COUNT = 5; // 每次创建Listener的时候需要把spring管理的类传进来 public AttendanceExcelDictDTOListener(AttendanceMapper attendanceMapper){ this.attendanceMapper = attendanceMapper; } @Override public void invoke(AttendanceExcelDTO data, AnalysisContext context) { log.info("解析到一条记录:{}", data); // 将数据存入到数据列表 list.add(data); // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM if(list.size() >= BATCH_COUNT){ // 调用mapper层的save方法 savaData(); // 存储完成清理 list list.clear(); } } /** * 所有数据解析完成了 都会来调用 * * @param context . */ @Override public void doAfterAllAnalysed(AnalysisContext context) { // 当剩余的记录数不足BATCH_COUNT时,最终一次性存储数据 savaData(); log.info("所有数据解析完成"); } private void savaData(){ log.info("{} 条数据存储到数据库", list.size()); // 调用mapper层的save方法 SAVE list对象 if(!CollectionUtils.isEmpty(list)) { attendanceMapper.insertBatch(list); } //TODO log.info("{} 条数据被存储到数据库成功", list.size()); } }

 

 6.service层创建一个名为AttendanceService的接口文件部分代码如下

package com.xxx.student.core.service; import com.xxx.student.core.pojo.dto.AttendanceExcelDTO; import com.xxx.student.core.pojo.entity.Attendance; import com.baomidou.mybatisplus.extension.service.IService; import java.io.InputStream; import java.util.List; import java.util.Map; /** * <p> * 服务类 * </p> * * @author lsh */ public interface AttendanceService extends IService<Attendance> { /** * * @return Excel导出 */ List<AttendanceExcelDTO> listDictData(); /** * * @param inputStream Excel导入 */ void importData(InputStream inputStream); }

 

7.ServiceImpl部分代码如下

@Slf4j @Service public class AttendanceServiceImpl extends ServiceImpl<AttendanceMapper, Attendance> implements AttendanceService { private final QueryWrapper<Attendance> attendanceQueryWrapper = new QueryWrapper<>(); @Resource private AttendanceMapper attendanceMapper; @Override public List<AttendanceExcelDTO> listDictData() { List<Attendance> list = baseMapper.selectList(null); //创建ExcelDictDTO列表,将Dict列表转换成ExcelDictDTO列表 ArrayList<AttendanceExcelDTO> excelDictDTOList = new ArrayList<>(list.size()); // 遍历dict列表 list.forEach(dict -> { AttendanceExcelDTO attendanceExcelDTO = new AttendanceExcelDTO(); BeanUtils.copyProperties(dict, attendanceExcelDTO); excelDictDTOList.add(attendanceExcelDTO); }); return excelDictDTOList; } @Override public void importData(InputStream inputStream) { EasyExcel .read(inputStream, AttendanceExcelDTO.class, new AttendanceExcelDictDTOListener(baseMapper)) .excelType(ExcelTypeEnum.XLSX) .sheet() .doRead(); log.info("Excel导入成功"); } }

 

8.mapper层

/** * * @param list 批量插入 */ void insertBatch(ArrayList<AttendanceExcelDTO> list);

 

9.mapper.xml文件

<insert id="insertBatch"> INSERT INTO `student_teacher_info`.`attendance`(`student_No`, `attendance_Time`, `attendance_Location`, `dormitory_No`) VALUES<foreach collection="list" separator="," item="item" index="index">(#{item.studentNo}, #{item.attendanceTime}, #{item.attendanceLocation}, #{item.dormitoryNo})</foreach> </insert>

 

10.实体类Attendance

@Data @EqualsAndHashCode(callSuper = false) @ApiModel(value="Attendance对象", description="日常考勤") public class Attendance implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty(value = "学生学号") @TableId(value = "student_No", type = IdType.INPUT) // 用户输入 private Long studentNo; @JsonFormat(shape = JsonFormat.Shape.STRING,pattern = "yyyy-MM-dd HH:mm:ss") @ApiModelProperty(value = " 考勤时间") @TableField("attendance_Time") private LocalDateTime attendanceTime; @ApiModelProperty(value = "考勤地点") @TableField("attendance_Location") private String attendanceLocation; @ApiModelProperty(value = "宿舍号") @TableField("dormitory_No") private Integer dormitoryNo; @ApiModelProperty(value = "创建时间",example = " ") private LocalDateTime createTime; @ApiModelProperty(value = "更新时间",example = " ") private LocalDateTime updateTime; @ApiModelProperty(value = "逻辑删除(1:已删除,0:未删除)") @TableField("is_deleted") @TableLogic private Boolean deleted; }

 

至此:导入导出模块基本完成

 


__EOF__

本文作者Hui Li
本文链接https://www.cnblogs.com/leedev-blog/p/15212016.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Hui_Li  阅读(1306)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示