1、介绍
官网地址:https://www.yuque.com/easyexcel
特点:
1、Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是 非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或 者JVM频繁的full gc。
2、EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。EasyExcel能大大减 少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一 行行读取数据,逐个解析。
3、EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理 (AnalysisEventListener)。
2、应用场景
1、数据导入:减轻录入工作量
2、数据导出:统计信息归档
3、数据传输:异构系统之间数据传输
3、要实现的效果
sql
CREATE TABLE `edu_subject` ( `id` char(19) NOT NULL COMMENT '课程类别ID', `title` varchar(10) NOT NULL COMMENT '类别名称', `parent_id` char(19) NOT NULL DEFAULT '0' COMMENT '父ID', `sort` int unsigned NOT NULL DEFAULT '0' COMMENT '排序字段', `gmt_create` datetime NOT NULL COMMENT '创建时间', `gmt_modified` datetime NOT NULL COMMENT '更新时间', PRIMARY KEY (`id`), KEY `idx_parent_id` (`parent_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=COMPACT COMMENT='课程科目';
转成->
3、使用
3.1、pom依赖导入
温馨提示:以下版本不能更换,换了可能会不行
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.1.1</version> </dependency> <!--xls--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.17</version> </dependency>
3.2、controller
package com.zhz.serviceedu.controller; import com.zhz.common.utils.R; import com.zhz.serviceedu.service.EduSubjectService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; /** * <p> * 课程科目 前端控制器 * </p> * * @author zhz * @since 2021-07-03 */ @RestController @RequestMapping("/eduservice/subject") @CrossOrigin @Api(tags = "课程科目") public class EduSubjectController { @Autowired private EduSubjectService eduSubjectService; /** * 添加课程分类,获取上传过来的文件,把文件内容读取出来 */ @PostMapping("/addSubject") @ApiOperation(value = "添加课程分类,获取上传过来的文件,把文件内容读取出来") public R addSubject(MultipartFile file){ //上传过来的excel文件 eduSubjectService.saveSubject(file,eduSubjectService); return R.ok(); } }
3.3、interface
package com.zhz.serviceedu.service; import com.zhz.serviceedu.entity.EduSubject; import com.baomidou.mybatisplus.extension.service.IService; import org.springframework.web.multipart.MultipartFile; /** * <p> * 课程科目 服务类 * </p> * * @author zhz * @since 2021-07-03 */ public interface EduSubjectService extends IService<EduSubject> { /** * 添加课程信息 * * @author zhz * @date 2021/07/02 02:18 * @param file 文件对象,用于获取excel文件 * @param eduSubjectService 方便监听器部分引用 */ void saveSubject(MultipartFile file, EduSubjectService eduSubjectService); }
3.4、impl
package com.zhz.serviceedu.service.impl; import com.alibaba.excel.EasyExcel; import com.zhz.serviceedu.entity.EduSubject; import com.zhz.serviceedu.entity.excel.SubjectData; import com.zhz.serviceedu.listener.SubjectExcelListener; import com.zhz.serviceedu.mapper.EduSubjectMapper; import com.zhz.serviceedu.service.EduSubjectService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.InputStream; /** * <p> * 课程科目 服务实现类 * </p> * * @author zhz * @since 2021-07-03 */ @Service public class EduSubjectServiceImpl extends ServiceImpl<EduSubjectMapper, EduSubject> implements EduSubjectService { /** * 添加课程信息 * * @param file 文件对象,用于获取excel文件 * @param eduSubjectService * @author zhz * @date 2021/07/02 02:18 */ @Override public void saveSubject(MultipartFile file, EduSubjectService eduSubjectService) { try { //文件输入流 InputStream in = file.getInputStream(); //调用方法进行读取 EasyExcel.read(in, SubjectData.class,new SubjectExcelListener(eduSubjectService)).sheet().doRead(); }catch (Exception e){ e.printStackTrace(); } } }
3.5、listener
package com.zhz.serviceedu.listener; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.zhz.servicebase.execptionhandler.GuliException; import com.zhz.serviceedu.entity.EduSubject; import com.zhz.serviceedu.entity.excel.SubjectData; import com.zhz.serviceedu.service.EduSubjectService; import lombok.extern.slf4j.Slf4j; import org.springframework.util.StringUtils; /** * @author zhouhengzhe * @Description: excel监听器 * @date 2021/7/3上午2:28 */ @Slf4j public class SubjectExcelListener extends AnalysisEventListener<SubjectData> { /** * 创建有参数构造,传递subjectService用于操作数据库 * 因为SubjectExcelListener不能交给spring去管理,所以需要自己new,不能注入对象 * 此处一定要是public,不然永远获取不到对象 */ public EduSubjectService eduSubjectService; public SubjectExcelListener() { } public SubjectExcelListener(EduSubjectService eduSubjectService) { this.eduSubjectService = eduSubjectService; } /** * 读取excel内容,一行一行进行读取,此处全是业务处理 * @param subjectData * @param analysisContext */ @Override public void invoke(SubjectData subjectData, AnalysisContext analysisContext) { log.info("进入方法调用"); if (StringUtils.isEmpty(subjectData)){ throw new GuliException(20001,"文件数据为空"); } //一行一行去读取excel内容,每次读取有两个值,第一个值为一级分类,第二个值为二级分类 //判断一级分类是否重复 EduSubject existOneSubject = this.existOneSubject(eduSubjectService, subjectData.getOneSubjectName()); if (StringUtils.isEmpty(existOneSubject)){ existOneSubject=new EduSubject(); existOneSubject.setParentId("0"); //一级分类名称 existOneSubject.setTitle(subjectData.getOneSubjectName()); eduSubjectService.save(existOneSubject); } //获取一级分类的pid值 String pid=existOneSubject.getId(); //添加二级分类 // 判断二级分类是否重复 EduSubject existTwoSubject = this.existTwoSubject(eduSubjectService, subjectData.getTwoSubjectName(), pid); if (StringUtils.isEmpty(existTwoSubject)){ existTwoSubject=new EduSubject(); existTwoSubject.setParentId(pid); //二级分类名称 existTwoSubject.setTitle(subjectData.getTwoSubjectName()); eduSubjectService.save(existTwoSubject); } } /** * 读取完成后执行 */ @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { } /** * 判断一级分类是否重复 * 因为课程的的parent_id为0时,代表是一级分类,并且一级分类数据不重复 * @param eduSubjectService * @param name * @return */ private EduSubject existOneSubject(EduSubjectService eduSubjectService,String name){ QueryWrapper<EduSubject> wrapper=new QueryWrapper<>(); wrapper.eq("title",name); wrapper.eq("parent_id","0"); EduSubject subject = eduSubjectService.getOne(wrapper); return subject; } /** * 判断二级分类是否重复 * * @param eduSubjectService * @param name * @param pid * @return */ private EduSubject existTwoSubject(EduSubjectService eduSubjectService,String name,String pid){ QueryWrapper<EduSubject> wrapper=new QueryWrapper<>(); wrapper.eq("title",name); wrapper.eq("parent_id",pid); EduSubject eduSubject = eduSubjectService.getOne(wrapper); return eduSubject; } }
3.6、小细节,实体类pojo
因为mybatisplus生成的实体类的主键生成策略是IdType.ID_WORKER,所以需要修改成IdType.ID_WORKER_STR,否则会有转换问题
package com.zhz.serviceedu.entity; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.IdType; import java.util.Date; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import java.io.Serializable; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; /** * <p> * 课程科目 * </p> * * @author zhz * @since 2021-07-03 */ @Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) @ApiModel(value="EduSubject对象", description="课程科目") public class EduSubject implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty(value = "课程类别ID") @TableId(value = "id", type = IdType.ID_WORKER_STR) private String id; @ApiModelProperty(value = "类别名称") private String title; @ApiModelProperty(value = "父ID") private String parentId; @ApiModelProperty(value = "排序字段") private Integer sort; @ApiModelProperty(value = "创建时间") @TableField(fill = FieldFill.INSERT) private Date gmtCreate; @ApiModelProperty(value = "更新时间") @TableField(fill = FieldFill.INSERT_UPDATE) private Date gmtModified; }
3.7、其余,swagger集成,R类统一返回,统一日志等,请看我其他博客
统一日志:https://blog.csdn.net/zhouhengzhe/article/details/118078080
统一返回值:https://blog.csdn.net/zhouhengzhe/article/details/118065066
统一异常:https://blog.csdn.net/zhouhengzhe/article/details/118064739
swagger集成:https://blog.csdn.net/zhouhengzhe/article/details/118063779