Springboot+EasyExcel导入导出

为什么要用EasyExcel

由于apache poi和jxl,excelPOI都有一个严重的问题,就是非常消耗内存,特别处理数据量多时,速度慢并且时有异常发生,所以改用由阿里研发的easyExcel更可靠一些,它的官方建议对于1000行以内的采用原来poi的写法一次读写,但于1000行以上的数据,有用了一行行进行解析的方案,这样避免了内存的溢出。

 

怎么用EasyExcel

       其实可以直接去看官方文档或者去github拉源码,地址:https://www.yuque.com/easyexcel/doc/easyexcel,以下是我根据官方文档写的demo,有不对或者可以优化的地方欢迎指出来

 

项目结构

Springboot+EasyExcel导入导出_第1张图片

 

Maven配置



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.2.6.RELEASE
         
    
    com.zjh
    designmodel
    0.0.1-SNAPSHOT
    designmodel
    Demo project for Spring Boot

    
        1.8
    

    
        
            commons-lang
            commons-lang
            2.5
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            com.baomidou
            mybatis-plus-boot-starter
            3.2.0
        
        
            com.baomidou
            mybatis-plus
            3.2.0
        
        
        
            com.alibaba
            easyexcel
            2.0.5
        
        
            com.alibaba
            druid
        
        
            mysql
            mysql-connector-java
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
            
                
                    org.junit.vintage
                    junit-vintage-engine
                
            
        
        
            org.projectlombok
            lombok
        
        
            org.springframework.boot
            spring-boot-starter-aop
        
















    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


 

 

实体类

package com.zjh.designmodel.easyexcel.entiy;

import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * @Author: zjh
 * @Description:
 * @Date: Created in 2020/5/20 9:56
 * Modified by:
 */
@Data
@TableName("user")
public class User extends Common{

    @TableId(type = IdType.AUTO)
    private Integer id;

    //学生学号
    @TableField(value = "number")
    @ExcelProperty("学号")
    private Integer number;

}
package com.zjh.designmodel.easyexcel.entiy;

import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.zjh.designmodel.easyexcel.converter.PositionConverter;
import lombok.Data;

/**
 * @Author: zjh
 * @Description:
 * @Date: Created in 2020/5/20 18:30
 * Modified by:
 */
@TableName("teacher")
@Data
public class Teacher extends Common{
    @TableId(type = IdType.AUTO)
    private Integer id;

    @TableField(value = "position")
    @ExcelProperty(value = "职位",converter = PositionConverter.class)
    //1.班主任 2.普通教师
    private Integer position;

    //教师编号
    @TableField(value = "number")
    @ExcelProperty("教师编号")
    private Integer number;
}
package com.zjh.designmodel.easyexcel.entiy;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.baomidou.mybatisplus.annotation.TableField;
import com.zjh.designmodel.easyexcel.converter.SexConverter;
import lombok.Data;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

/**
 * @Author: zjh
 * @Description:
 * @Date: Created in 2020/5/20 14:14
 * Modified by:
 */
@Data
public class Common {
    @TableField(value = "name")
    @ExcelProperty("名字")
    private String name;

    @TableField(value = "sex")
    @ExcelProperty(value = "性别",converter = SexConverter.class)
    //1.男 2.女
    private Integer sex;

    @TableField(value = "create_time")
    @ExcelProperty("创建时间")
    private Long createTime;
}

 

持久层

package com.zjh.designmodel.easyexcel.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zjh.designmodel.easyexcel.entiy.Teacher;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * @Author: zjh
 * @Description:
 * @Date: Created in 2020/5/28 11:41
 * Modified by:
 */
@Mapper
public interface TeacherMapper   {
    @Insert({""})
    int save(@Param("teacherList") List teacherList);

    @Select("select * from teacher")
    List getTeacherList();
}
package com.zjh.designmodel.easyexcel.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zjh.designmodel.easyexcel.entiy.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * @Author: zjh
 * @Description:
 * @Date: Created in 2020/5/20 10:04
 * Modified by:
 */
@Mapper
public interface UserMapper {
    @Insert({""})
    int save(@Param("userList") List userList);


    @Select("select * from user")
    List getUserList();
}

业务层

package com.zjh.designmodel.easyexcel.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.zjh.designmodel.easyexcel.entiy.Teacher;
import com.zjh.designmodel.easyexcel.entiy.User;
import org.apache.poi.ss.formula.functions.T;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * @Author: zjh
 * @Description:
 * @Date: Created in 2020/5/20 11:48
 * Modified by:
 */
public interface CommonService {
    void saveUser (List userList) throws IllegalAccessException, InstantiationException;
    void saveTeacher (List teacherList) throws IllegalAccessException, InstantiationException;

    void downLoad(HttpServletResponse response,Integer type) throws IllegalAccessException, IOException, InstantiationException;
}
package com.zjh.designmodel.easyexcel.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zjh.designmodel.easyexcel.entiy.Teacher;
import com.zjh.designmodel.easyexcel.entiy.User;
import com.zjh.designmodel.easyexcel.mapper.TeacherMapper;
import com.zjh.designmodel.easyexcel.mapper.UserMapper;
import com.zjh.designmodel.easyexcel.service.CommonService;
import com.zjh.designmodel.easyexcel.util.EasyExcelUtils;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: zjh
 * @Description:
 * @Date: Created in 2020/5/20 11:53
 * Modified by:
 */
@Service
@Repository
public class CommonServiceImpl implements CommonService {
    @Autowired
    UserMapper userMapper;

    @Autowired
    TeacherMapper teacherMapper;

    @Override
    public void saveUser(List list) throws IllegalAccessException, InstantiationException {
        userMapper.save(list);
    }

    @Override
    public void saveTeacher(List teacherList) throws IllegalAccessException, InstantiationException {
        teacherMapper.save(teacherList);
    }

    @Override
    public void downLoad(HttpServletResponse response, Integer type) throws IllegalAccessException, IOException, InstantiationException {
        if (type==1){//学生
            List users = userMapper.getUserList();
            EasyExcelUtils.download(response,User.class,users);
        }else {
            List teachers = teacherMapper.getTeacherList();
            EasyExcelUtils.download(response,Teacher.class,teachers);
        }
    }
}

Controller

package com.zjh.designmodel.easyexcel.controller;

import com.alibaba.excel.EasyExcel;
import com.zjh.designmodel.easyexcel.entiy.Teacher;
import com.zjh.designmodel.easyexcel.entiy.User;
import com.zjh.designmodel.easyexcel.listen.CommonListen;
import com.zjh.designmodel.easyexcel.service.CommonService;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
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;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * @Author: zjh
 * @Description:
 * @Date: Created in 2020/5/20 10:06
 * Modified by:
 */
@RestController
@RequestMapping("/easyexcel")
public class EasyExcelController {

    @Autowired
    CommonService commonService;

    @PostMapping("/import")
    //type=1代表导入的是学生的模板。type=2代表的是老师的模板
    public void simpleRead(MultipartFile file,HttpServletRequest request,Integer type) throws IOException {
        if(type==1){
            EasyExcel.read(file.getInputStream(), User.class,new CommonListen(commonService,User.class,"saveUser")).sheet().doRead();
        }else {
            EasyExcel.read(file.getInputStream(), Teacher.class,new CommonListen(commonService,Teacher.class,"saveTeacher")).sheet().doRead();

        }
    }

    @GetMapping("/downLoad")
    //type=1代表导入的是学生的模板。type=2代表的是老师的模板
    public void downLoad(HttpServletResponse response,Integer type) throws IOException, InstantiationException, IllegalAccessException {
        commonService.downLoad(response,type);
    }

}

监听(Listen)----这里的监听其实用的就是适配器模式

package com.zjh.designmodel.easyexcel.listen;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.zjh.designmodel.easyexcel.entiy.Common;
import com.zjh.designmodel.easyexcel.entiy.Teacher;
import com.zjh.designmodel.easyexcel.entiy.User;
import com.zjh.designmodel.easyexcel.service.CommonService;
import lombok.SneakyThrows;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.BeanUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

/**
 * @Author: zjh
 * @Description: 通用的监听,这样就不用一个模板一个监听了
 * @Date: Created in 2020/5/20 11:29
 * Modified by:
 */
public class CommonListen extends AnalysisEventListener {
    /**
     * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
     */
    private static final int BAUserCH_COUNUser = 5;
    //模板对应的实体类
    private Class tClass;
    //Controller层对应调用的方法名
    private String methodName;
    List list = new ArrayList();

    /**
     * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
     */
    private CommonService commonService;

    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     *
     * @param commonService
     */
    public CommonListen(CommonService commonService, Class tClass, String methodName) {
        this.commonService = commonService;
        this.tClass = tClass;
        this.methodName = methodName;
    }

    @SneakyThrows
    @Override
    public void invoke(T t, AnalysisContext analysisContext) {
        System.out.println(t.getClass().getName());
        //对象复制 -----这个地方是因为我们的项目是分布式项目,所以需要吧api层的实体类属性复制到device层
        // ,如果不是分布式项目的话直接用t就可以
        T newInstance = tClass.newInstance();
        BeanUtils.copyProperties(t, newInstance);
        System.out.println("newInstance" + newInstance.toString());
        list.add(newInstance);
        // 达到BAUserCH_COUNUser了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (list.size() >= BAUserCH_COUNUser) {
            saveData();
            // 存储完成清理 list
            list.clear();
        }
    }

    public void saveData() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method save = commonService.getClass().getMethod(methodName, List.class);
        save.invoke(commonService, list);
    }


    @SneakyThrows
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
        saveData();
    }
}
 
  

自定义转换器

package com.zjh.designmodel.easyexcel.converter;

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;

/**
 * 职责自定义转换器
 */
public class PositionConverter implements Converter {
    @Override
    public Class supportJavaTypeKey() {
        return Integer.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    /**
     * 这里读的时候会调用
     *
     * @param cellData
     *            NotNull
     * @param contentProperty
     *            Nullable
     * @param globalConfiguration
     *            NotNull
     * @return
     */
    @Override
    public Integer convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
                                     GlobalConfiguration globalConfiguration) {
        switch (cellData.getStringValue()){
            case "班主任":
                return 1;
            case "普通教师":
                return 2;
            default:
                return 0;
        }
    }

    /**
     * 这里是写的时候会调用
     *
     * @param value
     *            NotNull
     * @param contentProperty
     *            Nullable
     * @param globalConfiguration
     *            NotNull
     * @return
     */
    @Override
    public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty,
                                       GlobalConfiguration globalConfiguration) {

        switch (value){
            case 1:
                return new CellData("班主任");
            case 2:
                return new CellData("普通教师");
            default:
                return new CellData(String.valueOf(value));
        }

    }

}
package com.zjh.designmodel.easyexcel.converter;

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;

/**
 * 性别自定义转换器
 */
public class SexConverter implements Converter {
    @Override
    public Class supportJavaTypeKey() {
        return Integer.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    /**
     * 这里读的时候会调用
     *
     * @param cellData
     *            NotNull
     * @param contentProperty
     *            Nullable
     * @param globalConfiguration
     *            NotNull
     * @return
     */
    @Override
    public Integer convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
                                     GlobalConfiguration globalConfiguration) {
        switch (cellData.getStringValue()){
            case "男":
                return 1;
            case "女":
                return 2;
            default:
                return 0;
        }
    }

    /**
     * 这里是写的时候会调用 不用管
     *
     * @param value
     *            NotNull
     * @param contentProperty
     *            Nullable
     * @param globalConfiguration
     *            NotNull
     * @return
     */

    @Override
    public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty,
                                       GlobalConfiguration globalConfiguration) {
        switch (value){
            case 1:
                return  new CellData("男");
            case 2:
                return new CellData("女");
                default:
                    return new CellData(String.valueOf(value));
        }
    }

}

Util

package com.zjh.designmodel.easyexcel.util;

import com.alibaba.excel.EasyExcel;
import com.zjh.designmodel.easyexcel.entiy.User;
import org.apache.poi.ss.formula.functions.T;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * @Author: zjh
 * @Description:
 * @Date: Created in 2020/5/28 15:24
 * Modified by:
 */
public class EasyExcelUtils {
    public static void download(HttpServletResponse response, Class t, List list) throws IOException, IllegalAccessException, InstantiationException {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename=demo.xlsx");
        EasyExcel.write(response.getOutputStream(), t).sheet("模板").doWrite(list);
    }

}

测试导入

Springboot+EasyExcel导入导出_第2张图片

Springboot+EasyExcel导入导出_第3张图片

Springboot+EasyExcel导入导出_第4张图片

 

测试导出

Springboot+EasyExcel导入导出_第5张图片

 

 

 

你可能感兴趣的:(Springboot)