EasyExcel上传文件并使用Postman测试

一、编写EsayExcel上传Excel文件接口

EasyExcel官方文档例子比较详细有需要的可以点击查看官方文档
前提需要导入EasyExcel的jar包:

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

Swagger注解jar包(可以不要):

		<dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.8.0</version>
        </dependency>

1.Controller编写

package com.my.test.member.biz.controller;

import com.alibaba.excel.EasyExcel;
import com.my.test.member.api.R;
import com.my.test.member.api.dto.MemberDTO;
import com.my.test.member.biz.listerer.DataListener;
import io.swagger.annotations.Api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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;


/**
 * excel管理
 */
@RestController
@RequestMapping("/test")
@Api(value = "/excel", description = "excel管理", tags = {"excel管理"})
public class ExcelUploadController {

    private static final Logger logger = LoggerFactory.getLogger(ExcelUploadController.class);

    @Autowired
    private IMemberService memberService;

    /**
     * 上传接口
     * @param file
     * @return
     */
    @PostMapping("/upload")
    public R upload(MultipartFile file) {
        try {
            EasyExcel.read(file.getInputStream(), MemberDTO.class, new DataListener(memberService)).sheet().doRead();
        }catch (Exception e){
            e.printStackTrace();
            logger.error("上传excel失败,失败信息:"+e.getMessage());
            return R.fail("系统繁忙,请稍后再试!");
        }
        return R.ok();
    }

}

2.Listener编写

Listener是处理数据的关键类

package com.my.test.member.biz.listerer;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.my.test.member.api.dto.MemberDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

public class DataListener extends AnalysisEventListener<MemberDTO> {


    private static final Logger LOGGER = LoggerFactory.getLogger(DataListener.class);


    /**
     * 因为DataListener 不能被spring管理,所以每次读取excel都要new DataListener,如果DataListener里面用到spring管理的对象,比如操作需要数据库的话Service和Dao可以通过构造方法传进来
     */
    private IMemberService memberService;

    /**
     * 每读取1000条数据进行校验身份证,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 1000;

    List<MemberDTO> list = new ArrayList<>();


    public DataListener(IMemberService memberService) {
        this.memberService = memberService;
    }

    /**
     * 这个方法每一条数据解析都会来调用-easyExcel会自动过滤掉excel中的第一行(默认第一行为列名)
     * 只有解析到数据才会调用,如果上传的是空excel的话该方法不会调用
     *
     * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     */
    @Override
    public void invoke(MemberDTO data, AnalysisContext context) {
        LOGGER.info("解析到一条数据:{}", data.toString());
        list.add(data);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (list.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            list.clear();
        }
    }

    /**
     * 所有数据解析完成了 都会来调用
     * 也就是每次请求接口就会调用一次该方法,空excel也会调用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        saveData();
        LOGGER.info("所有数据检测完成!");
    }

    /**
     * 加上存储数据库
     */
    private void saveData() {
        LOGGER.info("{}条数据,开始存储数据库!", list.size());
        if (list.size() > 0){
            memberService.saveBatch(list);
        }
        LOGGER.info("存储数据库成功!");
    }

}

3.接受excel数据转换类DTO

package com.my.test.member.api.dto;

import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModelProperty;

/**
 * easyExcel官方建议列和类属性的对应要么通过下标要么通过名字不建议都有
 *  * @ExcelProperty(index = 2)下标:从0开始,2表示第三列;@ExcelProperty("字符串标题")名称匹配
 *  * 不写@ExcelProperty注解的情况下默认使用的下标对应映射,在excel格式不做任何修改的情况下不写也能满足当前需求,如果用户修改了excel格式不写@ExcelProperty注解的话会导致数据映射关系错误类型不一致导致赋值错误
 *  * 所以建议使用@ExcelProperty("字符串标题")名称匹配的形式
 **/
public class MemberDTO {
    @ApiModelProperty("姓名")
    @ExcelProperty("姓名")
    private String name;

    @ApiModelProperty("身份证号码")
    @ExcelProperty("身份证号")
    private String idCard;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getIdCard() {
        return idCard;
    }

    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }

    @Override
    public String toString() {
        return "MemberDTO{" +
                "name='" + name + '\'' +
                ", idCard='" + idCard + '\'' +
                '}';
    }
}

4.应答体类R

package com.my.test.member.api;

import com.my.test.member.api.constant.CodeConstant;
import io.swagger.annotations.ApiModelProperty;

import java.io.Serializable;

public class R<T> implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 返回编码
     */
    @ApiModelProperty("应答状态码0-成功1-失败")
    private int code;

    /**
     * 返回消息
     */
    @ApiModelProperty("应答消息")
    private String message;

    /**
     * 返回数据
     */
    @ApiModelProperty("数据")
    private T data;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public static R ok() {
        return setResult(CodeConstant.SUCCESS,CodeConstant.OK_MSG,null);
    }


    public static <T> R ok(String msg,T data) {
        return setResult(CodeConstant.SUCCESS,msg,data);
    }

    public static <T> R ok(T data) {
        return setResult(CodeConstant.SUCCESS,CodeConstant.OK_MSG,data);
    }
    public static <T> R ok(int code,String message,T data) {
        return setResult(code,message,data);
    }

    public static R ok(int code,String message) {
        return setResult(code,message,null);
    }

    public static R fail() {
        return setResult(CodeConstant.FAIL,CodeConstant.FAIL_MSG,null);
    }

    public static R fail(String message) {
        return setResult(CodeConstant.FAIL,message,null);
    }


    public static <T> R fail(String msg,T data) {
        return setResult(CodeConstant.FAIL,msg,data);
    }

    public static <T> R fail(T data) {
        return setResult(CodeConstant.FAIL,CodeConstant.FAIL_MSG,data);
    }

    public static <T> R fail(int code,String message,T data) {
        return setResult(code,message,data);
    }

    public static R fail(int code,String message) {
        return setResult(code,message,null);
    }



    private static <T> R<T> setResult(int code,String message,T data){
        R<T> result = new R();
        result.setCode(code);
        result.setMessage(message);
        result.setData(data);
        return result;
    }
}

5.应答状态常量类

package com.my.test.member.api.constant;

public class CodeConstant {
    /**
     * 成功code标识
     */
    public static final int SUCCESS = 0;

    /**
     * 失败code标识
     */
    public static final int FAIL = 1;

    /**
     * 消息提示成功
     */
    public static final String OK_MSG = "OK";

    /**
     * 消息提示失败
     */
    public static final String FAIL_MSG = "FAIL";

}

到此上传接口编写完毕,DTO和R根据自己项目实际情况定义

二、Postman测试接口

在这里插入图片描述
在这里插入图片描述
如果你测试或和前端对接时遇到异常“the request was rejected because no multipart boundary was found”异常,原因是requests模块会自动处理在Header中设置"Content-type:multipart/form-data"不需要代码中设置Content-type,如果前端在调用接口时加上了Content-type,去掉后可以正常上传excel文件。

上传非Excel文件报错如下:
在这里插入图片描述
excel有数据但是映射不到类上会出现这个错误,也就是excel中的数据的列名和类中的@ExcelProperty(“姓名”)对应不上:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值