EasyExcel在Java项目中的应用

328 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

今天在学习尚硅谷的课堂项目的导入导出Excel功能,在这里记录下使用EasyExcel的学习心得,和各位同学交流。如果对EasyExcel不是很熟悉的同学,可以参考这篇文章。本文的持久层框架是mybatisplus。

1.EasyExcel的导出功能

分析:其实导出Excel表格其实有两个步骤,一个是下载,一个是用EasyExcel将数据写到Excel里面,所以我们的实现步骤如下:

  1. 设置下载文件类型 mime类型
  2. 设置响应头信息Content-disposition。作用是:无论是什么格式文件都以下载方式打开

导入相关依赖:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.1.1</version>
</dependency>

准备相关数据库:

数据库的样子如下所示

image.png 准备相关的实体类:

数据表对应的实体类,@ApiModel @ApiModelProperty是swagger的注解,大家可以忽略这些注解

@Data
@ApiModel(description = "Subject")
@TableName("subject")
public class Subject {

   private static final long serialVersionUID = 1L;
   @ApiModelProperty(value = "id")
   private Long id;

   @ApiModelProperty(value = "创建时间")
   @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
   @TableField("create_time")
   private Date createTime;

   @ApiModelProperty(value = "更新时间")
   @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
   @TableField("update_time")
   private Date updateTime;

   @ApiModelProperty(value = "逻辑删除(1:已删除,0:未删除)")
   @JsonIgnore
   @TableLogic
   @TableField("is_deleted")
   private Integer isDeleted;

   @ApiModelProperty(value = "其他参数")
   @TableField(exist = false)
   private Map<String,Object> param = new HashMap<>();

   @ApiModelProperty(value = "类别名称")
   @TableField("title")
   private String title;

   @ApiModelProperty(value = "父ID")
   @TableField("parent_id")
   private Long parentId;

   @ApiModelProperty(value = "排序字段")
   @TableField("sort")
   private Integer sort;

   @ApiModelProperty(value = "是否包含子节点")
   @TableField(exist = false)
   private boolean hasChildren;

}

与Excel表格对应的实体类,如下所示:

@ExcelProperty的value值在进行写操作的时候起作用,它的作用是给创建的Excel表格设置表头。@ExcelProperty的index值在进行读操作的时候起作用,它的作用是指明Excel表格的列,index=0代表Excel表格里的第一列,index=2代表Excel表格里的第二列。

@Data
public class SubjectEeVo {

   @ExcelProperty(value = "id" ,index = 0)
   private Long id;

   @ExcelProperty(value = "课程分类名称" ,index = 1)
   private String title;

   @ExcelProperty(value = "上级id" ,index = 2)
   private Long parentId;

   @ExcelProperty(value = "排序" ,index = 3)
   private Integer sort;


}

controller代码:

是下载所以这个方法不需要什么返回值。

@Autowired
private SubjectService subjectService;

//课程分类导出
@GetMapping("exportData")
public void exportData(HttpServletResponse response){
    subjectService.exportData(response);
}

service接口和service接口实现类代码

void exportData(HttpServletResponse response);

service接口实现类主要功能就是下载以及将数据写到Excel表格。response.setContentType("application/vnd.ms-excel"),这行代码的作用是设置微软的Excel的数据类型。String fileName = URLEncoder.encode("课程分类", "UTF-8");这行代码的作用是设置下载文件的名字。 BeanUtils.copyProperties(类1,类2)是spring提供的方法,可以将类1的属性的值复制给类2的属性,前提是这两个类有属性是一样的,属性一样的才会复制。

//课程分类导出
@Override
public void exportData(HttpServletResponse response) {
    try {
        //设置下载信息,设置数据格式
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("课程分类", "UTF-8");//你会发现你下载的文件叫课程分类
        response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");

        //查询课程分类表所有数据
        List<Subject> subjectList = baseMapper.selectList(null);

        //将List<Subject> 转换成 List<SubjectEeVo>,因为实体类Subject和SubjectEeVo属性不同,SubjectEeVo才是我们要写进Excel
        List<SubjectEeVo> subjectEeVoList = new ArrayList<>();
        for (Subject subject: subjectList) {
            SubjectEeVo subjectEeVo = new SubjectEeVo();
            /*subjectEeVo.setId(subject.getId());
            subjectEeVo.setParentId(subject.getParentId());*/

            //可以将数据进行复制。找到属性一致的,进行复制。这是spring框架提供的,如果不喜欢,可以用上面传统的方式
            BeanUtils.copyProperties(subject,subjectEeVo);

            subjectEeVoList.add(subjectEeVo);
        }

        //EasyExcel写操作
        EasyExcel.write(response.getOutputStream(), SubjectEeVo.class)
                .sheet("课程分类")
                .doWrite(subjectEeVoList);
    }catch (Exception e){
        throw new GgktException(20001,"导出异常");
    }

}

上述就是主要的逻辑代码,完成以后,我们可以用过浏览器来访问对应的接口,结果如下所示:

image.png

image.png

2.EasyExcel的导入功能

导入功能其实就是上传功能,当文件上传之后,再用EasyExcel读取数据并存入数据库。

controller代码:

我是用swagger测试上传导入功能的,所以这里有@ApiOperation。MultipartFile是spring提供的参数,因为我们要进行上传,所以需要这个参数。

//课程分类导出
@ApiOperation("课程分类导入")
@PostMapping("importData")
public Result importData(MultipartFile file){
    subjectService.importData(file);
    return Result.ok(null);
}

service接口和service接口实现类代码:

void importData(MultipartFile file);

service接口实现类里面注入的SubjectListener是监听器。看过我前面提到的文章的同学,会发现那篇文章调用监听器是直接new一个监听器对象,我们现在是在spring的框架里面,所以我们不能这样做了,我们采用自动注入的方式。

@Autowired
private SubjectListener subjectListener;

//课程分类导入
@Override
public void importData(MultipartFile file) {
    try {
        EasyExcel.read(file.getInputStream(),SubjectEeVo.class,subjectListener).sheet().doRead();
    } catch (IOException e) {
        throw new GgktException(20001,"导入失败");
    }
}

监听器实现类

这个监听器主要是将Excel表格内容读取出来,并添加到数据库表。

@Component
public class SubjectListener extends AnalysisEventListener<SubjectEeVo> {

    //注入mapper
    @Autowired
    private SubjectMapper subjectMapper;

    //从第二行开始,逐行读取表格内容
    @Override
    public void invoke(SubjectEeVo subjectEeVo, AnalysisContext analysisContext) {
        Subject subject = new Subject();
        //SubjectEeVo转换成Subject,Subject是数据库表的实体类
        BeanUtils.copyProperties(subjectEeVo,subject);
        //添加
        subjectMapper.insert(subject);

    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
}

mapper类其实很简单,因为我们采用的是mybatisplus框架,所以很多方法已经实现好了。

@Repository
public interface SubjectMapper extends BaseMapper<Subject> {

}

实验结果如下图:

这是要导入的数据

image.png

导入过程

image.png 导入结果

image.png