微服务中EasyPoi上传Excel文件带校验并返回错误信息

需要导入的包

 <!-- hutool工具包 -->
<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
 <!-- JSR 303 规范验证包 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.2.4.Final</version>
        </dependency>
        <!-- easypoi依赖 -->
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>${easypoi.version}</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-web</artifactId>
            <version>${easypoi.version}</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-annotation</artifactId>
            <version>${easypoi.version}</version>
        </dependency>

服务消费者

@PostMapping(value = "/batchAddGoodsByExcel")
    void batchAddGoodsByExcel(@RequestPart("file") MultipartFile file,
                              @RequestParam(value = "merchantId", required = true) String merchantId,
                              HttpServletResponse response) {
        String fileName = file.getOriginalFilename();
        log.info("文件名是:{}", fileName);
        Response fileResponse = goodsFeign.batchAddGoodsByExcel(file, merchantId);
        InputStream is = null;
        try {
            is = fileResponse.body().asInputStream();
            FileUtil.fileExportCommon("导入商品错误信息表.xls", is, response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Feign

@PostMapping(value = "/goods-item/batchAddGoodsByExcel", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    Response batchAddGoodsByExcel(@RequestPart("file") MultipartFile file, @RequestParam(value =
            "merchantId", required = true) String merchantId);

服务提供者

实体

获取错误消息需要实现IExcelModel类

@Data
public class ExcelAddGoods implements Serializable, IExcelModel {


    private static final long serialVersionUID = 6906719125697903013L;

    @Excel(name = "商品名称")
    @NotEmpty(message = "不能为空")
    private String goodsName;

    @Excel(name = "商品分组")
    @NotEmpty(message = "不能为空")
    private String goodsGroup;

    @Excel(name = "商品类目")
    @NotEmpty(message = "不能为空")
    private String goodsCategory;

    @Excel(name = "规格名称")
    @NotEmpty(message = "不能为空")
    private String specName;

    @Excel(name = "价格/元")
    @NotNull(message = "不能为空")
    private BigDecimal goodsPrice;

    @Excel(name = "包装费/元")
    @NotNull(message = "不能为空")
    private BigDecimal packagePrice;

    @Excel(name = "最大库存")
    @NotNull(message = "不能为空")
    @Max(value = 9999, message = "最多9999")
    @Min(value = 1, message = "最少为1")
    private Integer goodsMaxStock;

    @Excel(name = "属性")
    private String goodsAttributes;

    @Excel(name = "商品描述")
    private String goodsDesc;

    @Excel(name = "标签")
    private String goodsTag;

    @Excel(name = "最小购买量(默认无限制)")
    @NotNull(message = "不能为空")
    @Max(value = 99, message = "最多99")
    @Min(value = 0, message = "最少为0")
    private Integer minBuyNum;

    @Excel(name = "原材料")
    private String material;

    private String errorMsg;

    @Override
    public String getErrorMsg() {
        return errorMsg;
    }

    @Override
    public void setErrorMsg(String s) {
        this.errorMsg = s;
    }
}

下面这个实体是为了获取父类的错误消息的,最终返回的错误信息实体就是以这个实体返回的

@Data
public class ExcelAddGoodsFailed extends ExcelAddGoods {
    private static final long serialVersionUID = 6906719125697903013L;

    @Excel(name = "错误消息")
    private String errorMsg;

    @Override
    public String getErrorMsg() {
        return errorMsg;
    }

    @Override
    public void setErrorMsg(String s) {
        this.errorMsg = s;
    }

    public static ExcelAddGoodsFailed excelAddGoods2Failed(ExcelAddGoods excelAddGoods) {
        ExcelAddGoodsFailed failed = new ExcelAddGoodsFailed();
        failed.setErrorMsg(excelAddGoods.getErrorMsg());
        failed.setGoodsAttributes(excelAddGoods.getGoodsAttributes());
        failed.setGoodsCategory(excelAddGoods.getGoodsCategory());
        failed.setGoodsDesc(excelAddGoods.getGoodsDesc());
        failed.setGoodsGroup(excelAddGoods.getGoodsGroup());
        failed.setGoodsName(excelAddGoods.getGoodsName());
        failed.setGoodsMaxStock(excelAddGoods.getGoodsMaxStock());
        failed.setGoodsPrice(excelAddGoods.getGoodsPrice());
        failed.setGoodsTag(excelAddGoods.getGoodsTag());
        failed.setMaterial(excelAddGoods.getMaterial());
        failed.setMinBuyNum(excelAddGoods.getMinBuyNum());
        failed.setPackagePrice(excelAddGoods.getPackagePrice());
        failed.setSpecName(excelAddGoods.getSpecName());
        return failed;
    }

    public static List<ExcelAddGoodsFailed> excelAddGoods2Faileds(List<ExcelAddGoods> excelAddGoodsList) {
        List<ExcelAddGoodsFailed> failedList = new ArrayList<>();
        for (ExcelAddGoods excelAddGoods : excelAddGoodsList) {
            failedList.add(excelAddGoods2Failed(excelAddGoods));
        }
        return failedList;
    }
}
controller
@PostMapping(value = "/batchAddGoodsByExcel", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    void batchAddGoodsByExcel(@RequestPart("file") MultipartFile file, @RequestParam(value =
            "merchantId", required = true) String merchantId, HttpServletResponse response) {
        log.info("上传的文件名是:{},商家ID是:{}", file.getOriginalFilename(), merchantId);
        goodsItemService.batchAddGoodsByExcel(file, merchantId, response);
    }
service
@Override
    public void batchAddGoodsByExcel(MultipartFile file, String merchantId,
                                     HttpServletResponse response) {
        try {
            ExcelImportResult<ExcelAddGoods> result = ExcelUtil.importExcelMore(file, 0, 1,
                    ExcelAddGoods.class);
            // 这是校验成功的数据
            List<ExcelAddGoods> successList = result.getList();
            log.info("成功的数据是:{}", JSONUtil.toJsonStr(successList));

            //getFailWorkbook()和getFailList()里面的就是所有校验失败的excel数据
            List<ExcelAddGoods> failList = result.getFailList();
//            Workbook failWorkbook = result.getFailWorkbook();
            List<ExcelAddGoodsFailed> addGoodsFaileds = ExcelAddGoodsFailed.excelAddGoods2Faileds(failList);
            //将错误excel信息返回给客户端
            ExportParams exportParams = new ExportParams();
            Workbook workbook = ExcelExportUtil.exportExcel(exportParams, ExcelAddGoodsFailed.class, addGoodsFaileds);
            response.setHeader("content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("导入商品错误信息表", "UTF-8") +
                    ".xls");
            response.setCharacterEncoding("UTF-8");
            workbook.write(response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

工具类

@Slf4j
public class FileUtil {
    /**
     * @param fileName 文件名,需要带上后缀
     * @param is       文件输入流
     * @param response 返回流
     */
    public static void fileExportCommon(String fileName, InputStream is, HttpServletResponse response) {
        OutputStream os = null;
        try {
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName));
            IOUtils.copy(is, response.getOutputStream());
            response.flushBuffer();
//            os = response.getOutputStream();
//            byte[] b = new byte[1024];
//            int len;
//            while ((len = is.read(b)) != -1) {
//                os.write(b, 0, len);
//            }
//            response.flushBuffer();
        } catch (IOException e) {
            e.printStackTrace();
            log.error("文件下载失败....{}", e.getMessage());
        } finally {
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
导入工具
public class ExcelUtil {
/**
     * 
     * @param file 导入的文件
     * @param titleRows 标题占的行
     * @param headerRows 头占的行
     * @param pojoClass 实体对象
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> ExcelImportResult<T> importExcelMore(MultipartFile file, Integer titleRows, Integer headerRows,
                                                           Class<T> pojoClass) throws Exception {
        if (file == null) {
            return null;
        }
        ImportParams params = new ImportParams();
        //开启验证,代表导入这里是需要验证的(根据字段上的注解)
        params.setNeedVerify(true);
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        return ExcelImportUtil.importExcelMore(file.getInputStream(), pojoClass, params);
    }
}

测试

导入的Excel,故意导入有问题的文件。
image.png
结果
image.png

如果导入的Excel文件中有没校验通过的数据,那么就会自动将这些数据进行返回下载。如下:

image.png

** 这里只是演示了easypoi的基本的校验方式,还有自定义的方式可以使用,这里因为没使用到,所以没做展示,有需要了解的同学可以自行百度哈 **

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容