• SpringBoot实现Excel导入导出


    SpringBoot实现Excel导入导出

    在我们平时工作中经常会遇到要操作Excel的功能,比如导出个用户信息或者订单信息的Excel报表。你肯定听说过

    POI这个东西,可以实现。但是POI实现的API确实很麻烦,它需要写那种逐行解析的代码(类似Xml解析)。今天

    给大家推荐一款非常好用的Excel导入导出工具EasyPoi,希望对大家有所帮助!

    1、EasyPoi简介

    用惯了SpringBoot的朋友估计会想到,有没有什么办法可以直接定义好需要导出的数据对象,然后添加几个注

    解,直接自动实现Excel导入导出功能?

    EasyPoi正是这么一款工具,如果你不太熟悉POI,想简单地实现Excel操作,用它就对了!

    EasyPoi的目标不是替代POI,而是让一个不懂导入导出的人也能快速使用POI完成Excel的各种操作,而不是看很

    多API才可以完成这样的工作。

    项目官网:https://gitee.com/lemur/easypoi

    2、集成

    在SpringBoot中集成EasyPoi非常简单,只需添加easypoi-spring-boot-starter依赖即可,真正的开箱即

    用!

    2.1 pom依赖

    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0modelVersion>
    	<parent>
    		<groupId>org.springframework.bootgroupId>
    		<artifactId>spring-boot-starter-parentartifactId>
    		<version>2.5.6version>
    		<relativePath/>
    	parent>
    	<groupId>com.easypoigroupId>
    	<artifactId>spring-boot-easypoiartifactId>
    	<version>0.0.1-SNAPSHOTversion>
    	<name>spring-boot-easypoiname>
    	<description>pringBoot实现Excel导入导出description>
    
    	<properties>
    		<java.version>1.8java.version>
    	properties>
    
    	<dependencies>
    
    		<dependency>
    			<groupId>org.springframework.bootgroupId>
    			<artifactId>spring-boot-starterartifactId>
    		dependency>
    
    		<dependency>
    			<groupId>org.springframework.bootgroupId>
    			<artifactId>spring-boot-starter-testartifactId>
    			<scope>testscope>
    		dependency>
    
    		<dependency>
    			<groupId>cn.afterturngroupId>
    			<artifactId>easypoi-spring-boot-starterartifactId>
    			<version>4.4.0version>
    		dependency>
    
    		
    		<dependency>
    			<groupId>io.springfoxgroupId>
    			<artifactId>springfox-boot-starterartifactId>
    			<version>3.0.0version>
    		dependency>
    
            
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <optional>trueoptional>
            dependency>
    
    		
    		<dependency>
    			<groupId>org.springframework.bootgroupId>
    			<artifactId>spring-boot-starter-webartifactId>
    		dependency>
    
    		<dependency>
    			<groupId>org.springframework.bootgroupId>
    			<artifactId>spring-boot-starter-actuatorartifactId>
    		dependency>
    
    		<dependency>
    			<groupId>org.springframework.bootgroupId>
    			<artifactId>spring-boot-starter-aopartifactId>
    		dependency>
    
    	dependencies>
    
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.springframework.bootgroupId>
    				<artifactId>spring-boot-maven-pluginartifactId>
    			plugin>
    		plugins>
    	build>
    
    project>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    2.2 结果集封装

    package com.easypoi.common.api;
    
    /**
     * 封装API的错误码
     */
    public interface IErrorCode {
        
        long getCode();
    
        String getMessage();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    package com.easypoi.common.api;
    
    /**
     * 枚举了一些常用API操作码
     */
    public enum ResultCode implements IErrorCode {
        
        SUCCESS(200, "操作成功"),
        FAILED(500, "操作失败"),
        VALIDATE_FAILED(404, "参数检验失败"),
        UNAUTHORIZED(401, "暂未登录或token已经过期"),
        FORBIDDEN(403, "没有相关权限");
        private long code;
        private String message;
    
        private ResultCode(long code, String message) {
            this.code = code;
            this.message = message;
        }
    
        public long getCode() {
            return code;
        }
    
        public String getMessage() {
            return message;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    package com.easypoi.common.api;
    
    /**
     * 通用返回对象
     */
    public class CommonResult<T> {
        private long code;
        private String message;
        private T data;
    
        protected CommonResult() {
        }
    
        protected CommonResult(long code, String message, T data) {
            this.code = code;
            this.message = message;
            this.data = data;
        }
    
        /**
         * 成功返回结果
         *
         * @param data 获取的数据
         */
        public static <T> CommonResult<T> success(T data) {
            return new CommonResult<T>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data);
        }
    
        /**
         * 成功返回结果
         *
         * @param data    获取的数据
         * @param message 提示信息
         */
        public static <T> CommonResult<T> success(T data, String message) {
            return new CommonResult<T>(ResultCode.SUCCESS.getCode(), message, data);
        }
    
        /**
         * 失败返回结果
         *
         * @param errorCode 错误码
         */
        public static <T> CommonResult<T> failed(IErrorCode errorCode) {
            return new CommonResult<T>(errorCode.getCode(), errorCode.getMessage(), null);
        }
    
        /**
         * 失败返回结果
         *
         * @param message 提示信息
         */
        public static <T> CommonResult<T> failed(String message) {
            return new CommonResult<T>(ResultCode.FAILED.getCode(), message, null);
        }
    
        /**
         * 失败返回结果
         */
        public static <T> CommonResult<T> failed() {
            return failed(ResultCode.FAILED);
        }
    
        /**
         * 参数验证失败返回结果
         */
        public static <T> CommonResult<T> validateFailed() {
            return failed(ResultCode.VALIDATE_FAILED);
        }
    
        /**
         * 参数验证失败返回结果
         *
         * @param message 提示信息
         */
        public static <T> CommonResult<T> validateFailed(String message) {
            return new CommonResult<T>(ResultCode.VALIDATE_FAILED.getCode(), message, null);
        }
    
        /**
         * 未登录返回结果
         */
        public static <T> CommonResult<T> unauthorized(T data) {
            return new CommonResult<T>(ResultCode.UNAUTHORIZED.getCode(), ResultCode.UNAUTHORIZED.getMessage(), data);
        }
    
        /**
         * 未授权返回结果
         */
        public static <T> CommonResult<T> forbidden(T data) {
            return new CommonResult<T>(ResultCode.FORBIDDEN.getCode(), ResultCode.FORBIDDEN.getMessage(), data);
        }
    
        public long getCode() {
            return code;
        }
    
        public void setCode(long 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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117

    2.3 Swagger配置

    package com.easypoi.config;
    
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import springfox.documentation.builders.ApiInfoBuilder;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.service.ApiInfo;
    import springfox.documentation.service.Contact;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    
    /**
     * Swagger2API文档的配置
     */
    @Configuration
    @EnableSwagger2
    public class Swagger2Config {
        @Bean
        public Docket createRestApi() {
            return new Docket(DocumentationType.SWAGGER_2)
                    .apiInfo(apiInfo())
                    .select()
                    //为当前包下controller生成API文档
                    .apis(RequestHandlerSelectors.basePackage("com.easypoi.controller"))
                    //为有@Api注解的Controller生成API文档
                    .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                    //为有@ApiOperation注解的方法生成API文档
                    .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                    .paths(PathSelectors.any())
                    .build();
        }
    
        private ApiInfo apiInfo() {
            return new ApiInfoBuilder()
                    .title("SwaggerUI演示")
                    .description("mall-tiny")
                    .contact(new Contact("macro", null, null))
                    .version("1.0")
                    .build();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    2.4 启动类

    package com.easypoi;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class SpringBootEasypoiApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringBootEasypoiApplication.class, args);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.5 配置文件

    server:
      port: 8088
    
    springfox:
      documentation:
        enabled: true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.6 实体类

    package com.easypoi.domain;
    
    import cn.afterturn.easypoi.excel.annotation.Excel;
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    
    import java.util.Date;
    
    /**
     * 购物会员
     */
    @Data
    @EqualsAndHashCode(callSuper = false)
    public class Member {
        @Excel(name = "ID", width = 10)
        private Long id;
    
        @Excel(name = "用户名", width = 20, needMerge = true)
        private String username;
    
        private String password;
    
        @Excel(name = "昵称", width = 20, needMerge = true)
        private String nickname;
    
        @Excel(name = "出生日期", width = 20, format = "yyyy-MM-dd")
        private Date birthday;
    
        @Excel(name = "手机号", width = 20, needMerge = true, desensitizationRule = "3_4")
        private String phone;
    
        private String icon;
    
        @Excel(name = "性别", width = 10, replace = {"男_0", "女_1"})
        private Integer gender;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    package com.easypoi.domain;
    
    import cn.afterturn.easypoi.excel.annotation.Excel;
    import cn.afterturn.easypoi.excel.annotation.ExcelCollection;
    import cn.afterturn.easypoi.excel.annotation.ExcelEntity;
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    
    import java.util.Date;
    import java.util.List;
    
    /**
     * 订单
     */
    @Data
    @EqualsAndHashCode(callSuper = false)
    public class Order {
    
        @Excel(name = "ID", width = 10, needMerge = true)
        private Long id;
    
        @Excel(name = "订单号", width = 20, needMerge = true)
        private String orderSn;
    
        @Excel(name = "创建时间", width = 20, format = "yyyy-MM-dd HH:mm:ss", needMerge = true)
        private Date createTime;
    
        @Excel(name = "收货地址", width = 20, needMerge = true)
        private String receiverAddress;
    
        @ExcelEntity(name = "会员信息")
        private Member member;
    
        @ExcelCollection(name = "商品列表")
        private List<Product> productList;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    package com.easypoi.domain;
    
    import cn.afterturn.easypoi.excel.annotation.Excel;
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    
    import java.math.BigDecimal;
    
    /**
     * 商品
     */
    @Data
    @EqualsAndHashCode(callSuper = false)
    public class Product {
        @Excel(name = "ID", width = 10)
        private Long id;
    
        @Excel(name = "商品SN", width = 20)
        private String productSn;
    
        @Excel(name = "商品名称", width = 20)
        private String name;
    
        @Excel(name = "商品副标题", width = 30)
        private String subTitle;
    
        @Excel(name = "品牌名称", width = 20)
        private String brandName;
    
        @Excel(name = "商品价格", width = 10)
        private BigDecimal price;
    
        @Excel(name = "购买数量", width = 10, suffix = "件")
        private Integer count;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    2.7 工具类

    package com.easypoi.util;
    
    import cn.hutool.core.io.IoUtil;
    import cn.hutool.core.io.resource.ClassPathResource;
    import cn.hutool.json.JSONArray;
    import cn.hutool.json.JSONUtil;
    
    import java.nio.charset.Charset;
    import java.util.List;
    
    /**
     * 从本地获取JSON数据的工具类
     */
    public class LocalJsonUtil {
    
        /**
         * 从指定路径获取JSON并转换为List
         *
         * @param path        json文件路径
         * @param elementType List元素类型
         */
        public static <T> List<T> getListFromJson(String path, Class<T> elementType) {
            ClassPathResource resource = new ClassPathResource(path);
            String jsonStr = IoUtil.read(resource.getStream(), Charset.forName("UTF-8"));
            JSONArray jsonArray = new JSONArray(jsonStr);
            return JSONUtil.toList(jsonArray, elementType);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    LocalJsonUtil工具类,可以直接从resources目录下获取JSON数据并转化为对象。

    2.8 字段处理器

    package com.easypoi.handler;
    
    import cn.afterturn.easypoi.handler.impl.ExcelDataHandlerDefaultImpl;
    import cn.hutool.core.util.StrUtil;
    import com.easypoi.domain.Member;
    
    /**
     * 自定义字段处理
     */
    public class MemberExcelDataHandler extends ExcelDataHandlerDefaultImpl<Member> {
    
        @Override
        public Object exportHandler(Member obj, String name, Object value) {
            if("昵称".equals(name)){
                String emptyValue = "暂未设置";
                if(value==null){
                    return super.exportHandler(obj,name,emptyValue);
                }
                if(value instanceof String&&StrUtil.isBlank((String) value)){
                  return super.exportHandler(obj,name,emptyValue);
                }
            }
            return super.exportHandler(obj, name, value);
        }
    
        @Override
        public Object importHandler(Member obj, String name, Object value) {
            return super.importHandler(obj, name, value);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    2.9 处理器

    package com.easypoi.controller;
    
    import cn.afterturn.easypoi.entity.vo.NormalExcelConstants;
    import cn.afterturn.easypoi.excel.ExcelImportUtil;
    import cn.afterturn.easypoi.excel.entity.ExportParams;
    import cn.afterturn.easypoi.excel.entity.ImportParams;
    import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
    import cn.afterturn.easypoi.view.PoiBaseView;
    import com.easypoi.common.api.CommonResult;
    import com.easypoi.domain.Member;
    import com.easypoi.domain.Order;
    import com.easypoi.domain.Product;
    import com.easypoi.handler.MemberExcelDataHandler;
    import com.easypoi.util.LocalJsonUtil;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.ModelMap;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestPart;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.multipart.MultipartFile;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.List;
    
    /**
     * EasyPoi导入导出测试Controller
     */
    @Controller
    @Api(tags = "EasyPoiController", description = "EasyPoi导入导出测试")
    @RequestMapping("/easyPoi")
    public class EasyPoiController {
    
        @ApiOperation(value = "导出会员列表Excel")
        @RequestMapping(value = "/exportMemberList", method = RequestMethod.GET)
        public void exportMemberList(ModelMap map,
                                     HttpServletRequest request,
                                     HttpServletResponse response) {
            List<Member> memberList = LocalJsonUtil.getListFromJson("json/members.json", Member.class);
            ExportParams params = new ExportParams("会员列表", "会员列表", ExcelType.XSSF);
            //对导出结果进行自定义处理
            MemberExcelDataHandler handler = new MemberExcelDataHandler();
            handler.setNeedHandlerFields(new String[]{"昵称"});
            params.setDataHandler(handler);
            map.put(NormalExcelConstants.DATA_LIST, memberList);
            map.put(NormalExcelConstants.CLASS, Member.class);
            map.put(NormalExcelConstants.PARAMS, params);
            map.put(NormalExcelConstants.FILE_NAME, "memberList");
            PoiBaseView.render(map, request, response, NormalExcelConstants.EASYPOI_EXCEL_VIEW);
        }
    
        @ApiOperation("从Excel导入会员列表")
        @RequestMapping(value = "/importMemberList", method = RequestMethod.POST)
        @ResponseBody
        public CommonResult importMemberList(@RequestPart("file") MultipartFile file) {
            ImportParams params = new ImportParams();
            params.setTitleRows(1);
            params.setHeadRows(1);
            try {
                List<Member> list = ExcelImportUtil.importExcel(
                        file.getInputStream(),
                        Member.class, params);
                return CommonResult.success(list);
            } catch (Exception e) {
                e.printStackTrace();
                return CommonResult.failed("导入失败!");
            }
        }
    
        @ApiOperation(value = "导出订单列表Excel")
        @RequestMapping(value = "/exportOrderList", method = RequestMethod.GET)
        public void exportOrderList(ModelMap map,
                                    HttpServletRequest request,
                                    HttpServletResponse response) {
            List<Order> orderList = getOrderList();
            ExportParams params = new ExportParams("订单列表", "订单列表", ExcelType.XSSF);
            //导出时排除一些字段
            params.setExclusions(new String[]{"ID", "出生日期", "性别"});
            map.put(NormalExcelConstants.DATA_LIST, orderList);
            map.put(NormalExcelConstants.CLASS, Order.class);
            map.put(NormalExcelConstants.PARAMS, params);
            map.put(NormalExcelConstants.FILE_NAME, "orderList");
            PoiBaseView.render(map, request, response, NormalExcelConstants.EASYPOI_EXCEL_VIEW);
        }
    
        private List<Order> getOrderList() {
            List<Order> orderList = LocalJsonUtil.getListFromJson("json/orders.json", Order.class);
            List<Product> productList = LocalJsonUtil.getListFromJson("json/products.json", Product.class);
            List<Member> memberList = LocalJsonUtil.getListFromJson("json/members.json", Member.class);
            for (int i = 0; i < orderList.size(); i++) {
                Order order = orderList.get(i);
                order.setMember(memberList.get(i));
                order.setProductList(productList);
            }
            return orderList;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100

    2.10 测试

    接下来介绍下EasyPoi的使用,以会员信息和订单信息的导入导出为例,分别实现下简单的单表导出和具有关联信

    息的复杂导出。

    2.10.1 简单导出

    我们以会员信息列表导出为例,使用EasyPoi来实现下导出功能,看看是不是够简单!

    • 首先创建一个会员对象Member,封装会员信息;

    • 在此我们就可以看到EasyPoi的核心注解@Excel,通过在对象上添加@Excel注解,可以将对象信息直接导出

      到Excel中去,下面对注解中的属性做个介绍;

      • name:Excel中的列名;

      • width:指定列的宽度;

      • needMerge:是否需要纵向合并单元格;

      • format:当属性为时间类型时,设置时间的导出导出格式;

      • desensitizationRule:数据脱敏处理,3_4表示只显示字符串的前3位和后4位,其他为*号;

      • replace:对属性进行替换;

      • suffix:对数据添加后缀。

    • 接下来我们在Controller中添加一个接口,用于导出会员列表到Excel,导出的member.json的内容:

    [
      {
        "id": 1,
        "username": "admin",
        "password": null,
        "nickname": "Admin",
        "birthday": "1994-12-31",
        "phone": "18790000000",
        "icon": null,
        "gender": 0
      },
      {
        "id": 2,
        "username": "macro",
        "password": null,
        "nickname": "Macro",
        "birthday": "1995-01-31",
        "phone": "18791000000",
        "icon": null,
        "gender": 0
      },
      {
        "id": 3,
        "username": "andy",
        "password": null,
        "nickname": "Andy",
        "birthday": "1995-02-28",
        "phone": "18792000000",
        "icon": null,
        "gender": 1
      },
      {
        "id": 4,
        "username": "ruby",
        "password": null,
        "nickname": "Ruby",
        "birthday": "1995-03-31",
        "phone": "18793000000",
        "icon": null,
        "gender": 1
      },
      {
        "id": 5,
        "username": "tom",
        "password": null,
        "nickname": "",
        "birthday": "1995-03-31",
        "phone": "18793000000",
        "icon": null,
        "gender": 1
      }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    运行项目,直接通过Swagger访问接口,注意在Swagger中访问接口无法直接下载,需要点击返回结果中的下载按

    钮才行,访问地址:http://localhost:8088/swagger-ui/

    在这里插入图片描述

    在这里插入图片描述

    下载完成后,查看下文件,一个标准的Excel文件已经被导出了。

    memberList.xlsx文件内容:

    在这里插入图片描述

    2.10.2 简单导入

    导入功能实现起来也非常简单,下面以会员信息列表的导入为例。

    • 在Controller中添加会员信息导入的接口,这里需要注意的是使用@RequestPart注解修饰文件上传参数,否

      则在Swagger中就没法显示上传按钮了;

    • 然后在Swagger中测试接口,选择之前导出的Excel文件即可,导入成功后会返回解析到的数据。

    在这里插入图片描述

    得到的结果:

    {
      "code": 200,
      "message": "操作成功",
      "data": [
        {
          "id": 1,
          "username": "admin",
          "password": null,
          "nickname": "Admin",
          "birthday": "1994-12-30T16:00:00.000+00:00",
          "phone": "187****0000",
          "icon": null,
          "gender": 0
        },
        {
          "id": 2,
          "username": "macro",
          "password": null,
          "nickname": "Macro",
          "birthday": "1995-01-30T16:00:00.000+00:00",
          "phone": "187****0000",
          "icon": null,
          "gender": 0
        },
        {
          "id": 3,
          "username": "andy",
          "password": null,
          "nickname": "Andy",
          "birthday": "1995-02-27T16:00:00.000+00:00",
          "phone": "187****0000",
          "icon": null,
          "gender": 1
        },
        {
          "id": 4,
          "username": "ruby",
          "password": null,
          "nickname": "Ruby",
          "birthday": "1995-03-30T16:00:00.000+00:00",
          "phone": "187****0000",
          "icon": null,
          "gender": 1
        },
        {
          "id": 5,
          "username": "tom",
          "password": null,
          "nickname": "暂未设置",
          "birthday": "1995-03-30T16:00:00.000+00:00",
          "phone": "187****0000",
          "icon": null,
          "gender": 1
        }
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    2.10.3 复杂导出

    当然EasyPoi也可以实现更加复杂的Excel操作,比如导出一个嵌套了会员信息和商品信息的订单列表,下面我们来

    实现下!

    • 首先添加商品对象Product,用于封装商品信息;

    • 然后添加订单对象Order,订单和会员是一对一关系,使用@ExcelEntity注解表示,订单和商品是一对多关

      系,使用@ExcelCollection注解表示,Order就是我们需要导出的嵌套订单数据;

    • 接下来在Controller中添加导出订单列表的接口,由于有些会员信息我们不需要导出,可以调用

      ExportParams中的setExclusions方法排除掉;

    • 在Swagger中访问接口测试,导出订单列表对应Excel;

    products.json的内容:

    [
      {
        "id": 1,
        "productSn": "7437788",
        "name": "小米8",
        "subTitle": "全面屏游戏智能手机 6GB+64GB 黑色 全网通4G 双卡双待",
        "brandName": "小米",
        "price": 2699,
        "count": 1
      },
      {
        "id": 2,
        "productSn": "7437789",
        "name": "红米5A",
        "subTitle": "全网通版 3GB+32GB 香槟金 移动联通电信4G手机 双卡双待",
        "brandName": "小米",
        "price": 649,
        "count": 1
      },
      {
        "id": 3,
        "productSn": "7437799",
        "name": "Apple iPhone 8 Plus",
        "subTitle": "64GB 红色特别版 移动联通电信4G手机",
        "brandName": "苹果",
        "price": 5499,
        "count": 1
      }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    orders.json的内容:

    [
      {
        "id": 1,
        "orderSn": "201809150101000001",
        "createTime": "2021-10-10 17:02:28",
        "receiverAddress": "广东省深圳市"
      },
      {
        "id": 1,
        "orderSn": "201809150101000002",
        "createTime": "2021-10-11 17:02:28",
        "receiverAddress": "江苏省南京市"
      },
      {
        "id": 1,
        "orderSn": "201809150101000003",
        "createTime": "2021-10-12 17:02:28",
        "receiverAddress": "江苏省苏州市"
      }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    • 下载完成后,查看下文件,EasyPoi导出复杂的Excel也是很简单的!

    在这里插入图片描述

    2.10.4 自定义处理

    如果你想对导出字段进行一些自定义处理,EasyPoi也是支持的,比如在会员信息中,如果用户没有设置昵称,我

    们添加下暂未设置信息。

    • 我们需要添加一个处理器继承默认的ExcelDataHandlerDefaultImpl类,然后在exportHandler方法中实

      现自定义处理逻辑;

    • 然后修改Controller中的接口,调用MemberExcelDataHandler处理器的setNeedHandlerFields设置需要

      自定义处理的字段,并调用ExportParamssetDataHandler设置自定义处理器;

    • 再次调用导出接口,我们可以发现昵称已经添加默认设置了。

    上面的代码已经是自定义处理过的。

    //对导出结果进行自定义处理
    MemberExcelDataHandler handler = new MemberExcelDataHandler();
    handler.setNeedHandlerFields(new String[]{"昵称"});
    params.setDataHandler(handler);
    
    • 1
    • 2
    • 3
    • 4

    3、总结

    体验了一波EasyPoi,它使用注解来操作Excel的方式确实非常好用。如果你想生成更为复杂的Excel的话,可以考

    虑下它的模板功能。

  • 相关阅读:
    HTML 学习笔记(七)列表
    网络会议室解决方案可以根据项目需求量身定制
    JavaEE、Spring
    Redis内存淘汰策略
    k8s实战案例之部署Nginx+Tomcat+NFS实现动静分离
    如何在VScode中让printf输出中文
    字节码进阶之方法调用指令详解
    java入门, private static final
    坚持自学软件测试,半年的辛苦没有白费,不过才拿到10k的offer
    神经网络阈值是什么意思,神经网络的权值和阈值
  • 原文地址:https://blog.csdn.net/qq_30614345/article/details/134341144