EasyPOI报表的使用及对象嵌套的Excel报表导入导出

EasyPOI报表

介绍

简介

easypoi功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员
就可以方便的写出Excel导出,Excel模板导出,Excel导入,Word模板导出,通过简单的注解和模板
语言(熟悉的表达式语法),完成以前复杂的写法 。

官网文档地址:http://doc.wupaas.com/docs/easypoi/easypoi-1c0u4mo8p4ro8

使用

		<!--easyPoi依赖 -->
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-spring-boot-starter</artifactId>
            <version>4.4.0</version>
        </dependency>

我是在Springboot项目中使用的,使用场景几乎都差不多,在此处使用注解进行配置

基本使用

项目环境搭建:

maven依赖:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!-- mybatis-plus 依赖 -->
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>3.4.2</version>
		</dependency>
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-generator</artifactId>
			<version>3.4.1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-freemarker</artifactId>
		</dependency>
		<!-- swagger2依赖 -->
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
			<version>2.8.0</version>
		</dependency>
		<!-- swagger-ui 依赖 -->
		<dependency>
			<groupId>com.github.xiaoymin</groupId>
			<artifactId>swagger-bootstrap-ui</artifactId>
			<version>1.9.6</version>
		</dependency>
		<!--easyPoi依赖 -->
		<dependency>
			<groupId>cn.afterturn</groupId>
			<artifactId>easypoi-spring-boot-starter</artifactId>
			<version>4.4.0</version>
		</dependency>

注意:
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.5.6</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

注意:

在项目中使用的springboot版本为2.5.6,该开始创建项目使用的是springboot给我推荐的依赖2.6.0,但是在使用中爆出Failed to start bean 'documentationPluginsBootstrapper';,这是使用swagger产生的问题,版本并不兼容,希望各位遇到这个bug时能够快速解决。

数据库:(随手建的,你们想尝试的话可以用一下)

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_person
-- ----------------------------
DROP TABLE IF EXISTS `t_person`;
CREATE TABLE `t_person`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  `age` int NULL DEFAULT NULL,
  `politicsId` int NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_person
-- ----------------------------
INSERT INTO `t_person` VALUES (1, 'zhangsan', 20, 1);
INSERT INTO `t_person` VALUES (3, '王五', 20, 3);
INSERT INTO `t_person` VALUES (4, '王五2', 24, 6);
INSERT INTO `t_person` VALUES (5, '王五5', 26, 8);
INSERT INTO `t_person` VALUES (6, '李四', 29, 10);
INSERT INTO `t_person` VALUES (7, '琪琪', 30, 5);
INSERT INTO `t_person` VALUES (8, '季泉', 24, 10);
INSERT INTO `t_person` VALUES (9, '汐海', 18, 13);
INSERT INTO `t_person` VALUES (10, 'zhangsan', 20, 1);
INSERT INTO `t_person` VALUES (11, '王五', 20, 3);
INSERT INTO `t_person` VALUES (12, '王五2', 24, 6);
INSERT INTO `t_person` VALUES (13, '王五5', 26, 8);
INSERT INTO `t_person` VALUES (14, '李四', 29, 10);
INSERT INTO `t_person` VALUES (15, '琪琪', 30, 5);
INSERT INTO `t_person` VALUES (16, '季泉', 24, 10);
INSERT INTO `t_person` VALUES (17, '汐海', 18, 13);

-- ----------------------------
-- Table structure for t_politics_status
-- ----------------------------
DROP TABLE IF EXISTS `t_politics_status`;
CREATE TABLE `t_politics_status`  (
  `id` int UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '政治面貌',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_politics_status
-- ----------------------------
INSERT INTO `t_politics_status` VALUES (1, '中共党员');
INSERT INTO `t_politics_status` VALUES (2, '中共预备党员');
INSERT INTO `t_politics_status` VALUES (3, '共青团员');
INSERT INTO `t_politics_status` VALUES (4, '民革团员');
INSERT INTO `t_politics_status` VALUES (5, '民盟盟员');
INSERT INTO `t_politics_status` VALUES (6, '民建会员');
INSERT INTO `t_politics_status` VALUES (7, '民进会员');
INSERT INTO `t_politics_status` VALUES (8, '农工党党员');
INSERT INTO `t_politics_status` VALUES (9, '致公党党员');
INSERT INTO `t_politics_status` VALUES (10, '九三学社社员');
INSERT INTO `t_politics_status` VALUES (11, '台盟盟员');
INSERT INTO `t_politics_status` VALUES (12, '无党派民主人士');
INSERT INTO `t_politics_status` VALUES (13, '普通公民');

SET FOREIGN_KEY_CHECKS = 1;

代码已经上传到git:https://gitee.com/XuLiZhao/demo-easypoi

代码及解析

建议前往gitee上获取源码,我这边只对需要注意的点进行讲解。如有疑问请及时联系。

实体类

@Data
@EqualsAndHashCode(callSuper = false)
@TableName("t_person")
@ApiModel(value="Person对象", description="")
@ToString
public class Person implements Serializable {

    private static final long serialVersionUID = 1L;

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

    @ApiModelProperty(value = "姓名")
    @Excel(name = "姓名",width = 10)
    private String name;

    @ApiModelProperty(value = "年龄")
    @Excel(name = "年龄")
    private Integer age;

    @ApiModelProperty(value = "政治面貌")
    @TableField("politicsId")
    private Integer politicsId;

    @ApiModelProperty(value = "政治面貌")
    @ExcelEntity(name = "政治面貌")
    @TableField(exist = false)
    private PoliticsStatus politicsStatus;

}
@Data
@EqualsAndHashCode(callSuper = false,of = "name")
@RequiredArgsConstructor
@NoArgsConstructor
@TableName("t_politics_status")
@ApiModel(value="PoliticsStatus对象", description="")
@ToString
public class PoliticsStatus implements Serializable {

    private static final long serialVersionUID = 1L;

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

    @ApiModelProperty(value = "政治面貌")
    @Excel(name="政治面貌")
    @NonNull
    private String name;
    
}

这边两个实体类,Person类中包含PoliticsStatus类对象的属性,所以在数据导入或导出时,难度比单表要稍微大一点,需要额外注意。这里还有一个点要注意,就是EqualsAndHashCode这个注解的含义,稍后我会说明。@ExcelEntity是值表格参数为实体类,需要进入该实体类找到@Excel()注解说明的字段才会在表格上展示

Service层

这边没有进行什么有意义的业务处理,只是查询了数据库,获取到所需要的全部信息,为了方便起见,还是贴出来给大家看看。至于为什么还要传入参数id,那就是为了方便其他代码查询单条数据时的复用,毕竟你直接传一个null值就相当查询所有了。

@Service
public class PersonServiceImpl extends ServiceImpl<PersonMapper, Person> implements IPersonService {

    @Autowired
    private PersonMapper personMapper;
    @Override
    public List<Person> getPersons(Integer id) {
        return personMapper.getPersons(id);
    }
}

Mapper层

接口代码和service几乎差不多,只是多了一个方法体,我主要说明一下mapper.xml文件。在这边用了一个判断,也就是当id为null值时查询所有。返回结果使用resultMap格式,主要是在实体类中我添加了PoliticsStatus对象,但是数据库中并没有字段能够与之对应,然后再使用association为对象赋值。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xihai.mapper.PersonMapper">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.xihai.pojo.Person">
        <id column="id" property="id" />
        <result column="name" property="name" />
        <result column="age" property="age" />
        <result column="politicsId" property="politicsId" />
    </resultMap>

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, name, age, politicsId
    </sql>
    
    <!--PersonMap-->
    <resultMap id="PersonMap" type="com.xihai.pojo.Person" extends="BaseResultMap">
        <association property="politicsStatus" javaType="com.xihai.pojo.PoliticsStatus">
            <id column="pid" property="id"/>
            <result column="pname" property="name"/>
        </association>
    </resultMap>
    <select id="getPersons" resultMap="PersonMap">
        SELECT
            p.*,
            ps.id AS pid,
            ps.NAME AS pname 
        FROM
            t_person p,
            t_politics_status ps 
        WHERE
          p.politicsId = ps.id
        <if test="null != id">
            and p.id = #{id}
        </if>
        ORDER BY
        id  
    </select>

</mapper>

关键代码===导入&导出

@RestController
@RequestMapping("/person")
public class PersonController {

    @Autowired
    private IPersonService personService;
    @Autowired
    private IPoliticsStatusService politicsStatusService;

    @ApiOperation(value = "导出数据")
    @GetMapping(value = "/export",produces = "application/octet-stream")
    public void getPersons(HttpServletResponse resshujuponse){
        List<Person> persons =  personService.getPersons(null);
        for (Person person : persons) {
            System.out.println(person.toString());
        }
        //参数 第一个为表格的title,第二个为表格的sheetName
        ExportParams exportParams = new ExportParams("人员表", "人员表", ExcelType.HSSF);
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, Person.class, persons);
        ServletOutputStream outputStream = null;
        try {
            //设置流格式
            response.setHeader("content-type", "application/octet-stream");
            //设置编码
            response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode("人员表.xls", "UTF-8"));
            outputStream = response.getOutputStream();
            workbook.write(outputStream);
        }catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != outputStream) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @ApiOperation(value = "导入数据")
    @PostMapping(value = "/import")
    public Result exportPerson(MultipartFile file) {
        ImportParams importParams = new ImportParams();
        //去标表格的title行以免改行数据被导入
        importParams.setTitleRows(1);
        List<PoliticsStatus> politicsStatusList = politicsStatusService.list();
        try {
            //获取ExcelImport导入数据
            List<Person> list = ExcelImportUtil.importExcel(file.getInputStream(), Person.class, importParams);
            //遍历,通过对象中的名称找到该对象的id值
            list.forEach(person -> {
                person.setPoliticsId(politicsStatusList.get(politicsStatusList.indexOf(new PoliticsStatus(person.getPoliticsStatus().getName()))).getId());
            });
            if (personService.saveBatch(list)) {
                return Result.success("导入成功!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Result.error("导入失败,请稍后再试!");
    }
}

数据导出

导出时注意,你需要在GetMapping中添加produces = "application/octet-stream"属性,指定输出的格式,不然你只会看到一大堆的乱码,嘿嘿。之后便是创建导出参数对象,然后通过导出Excel工具类将需要在Excel为文件上输出的对象进行配置就行。@Excel(name=“政治面貌”)这个属性就是表示在Excel上的值,具体怎么称呼呢?如果你知道那亲告诉我一下,哈哈。输出时设置字符编码和响应流格式。使用完流后注意关闭哦。

数据导入

重点讲一下这串你们一时半会看不懂的代码吧:

list.forEach(person -> {
                person.setPoliticsId(politicsStatusList.get(politicsStatusList.indexOf(new PoliticsStatus(person.getPoliticsStatus().getName()))).getId());
            });

语句的产生主要是你在导入数据到数据库时插入的是对象id值,而Excel表中的是name值,如果你通过name值查询数据库,当有很多这种对象时你每次都要查,严重影响数据库性能。我这边就是使用了一种方法,通过name值获取对象id值。

以下内容可能混引起不适,亲耐心观看并思考:

  1. 通过查询所有方法可以得到数据库的所有的记录条数,将每条数据封装为一个java对象并用数组存储起来。
  2. 使用List接口的 indexOf() 方法可以获取对象所在集合中的位置,然后通过这个位置获取该对象的id值,由于list集合是从数据库里面取出来的数据,所以其中每个对象一定会有id值
  3. 但是问题又来了,就算你new出一个对象,如何又能去跟集合中的对象去比较获取相同值进而获取对象位置呢。要是对象相等必须要将对象中所参与比较的属性值都相等。那么我可不可以让需要的数据去比较呢?就比如我将Excel报表中的那个属性为name的值去比较?
  4. 这就要用到lombok插件为我们提供的@EqualsAndHashCode注解,在使用时,将指定的值参与比较,顾名思义,这个注解是针对Equals和HashCode方法的,它会重写这两个方法,也有可能是直接排除,反正不能用了。
  5. 当PoliticsStatus对象中只用name属性进行比较时,不就可以获取到对象的id了吗?@EqualsAndHashCode注解我会再写一篇博客来说明,到时配上源码让各位更深入理解。

再配几张项目截图吧,让诸位看看效果
这是导出截图:

在这里插入图片描述导入截图
在这里插入图片描述
结束,谢谢大家!大家有兴趣可以看看我另一篇关于Apache POI的,不过那篇写的很粗糙,但是知识很底层。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
easypoi导出excel循环嵌套的具体实现可以分为以下几个步骤: 1. 首先,定义一个模板模板中包含需要导出的数据的字段。 2. 在导出excel的方法中,创建一个Map对象,用来存储模板中的字段和对应的数据。 3. 将需要嵌套循环的数据以列表的形式获取到,并遍历该列表。 4. 在循环中,创建一个新的Map对象,用来存储当前循环中的数据。 5. 将当前循环中的数据添加到新的Map对象中。 6. 将新的Map对象添加到模板中对应的字段中。 7. 最后,使用easypoi提供的导出方法,将模板导出excel文件。 下面是一个示例代码,展示了如何使用easypoi导出excel循环嵌套: ```java @GetMapping("/exportExcel") public void exportExcel(HttpServletResponse response) { try { // 定义模板路径 TemplateExportParams templatePath = new TemplateExportParams("D:/WorkSpace/模板.xls"); // 创建模板数据的Map对象 Map<String, Object> map = new HashMap<>(); // 添加普通字段数据 map.put("index", "序号"); map.put("year", "年度"); // 获取需要循环嵌套的数据列表 List<one> list = dataOneService.list(); List<Project> projects = ProjectService.list(); // 创建嵌套循环的数据列表 List<Map<String, Object>> listMap = new ArrayList<>(); // 遍历需要循环嵌套的数据列表 for (one item : list) { // 创建当前循环数据的Map对象 Map<String, Object> itemMap = new HashMap<>(); // 将当前循环数据添加到Map对象中 itemMap.put("list", item); // 将当前循环数据的Map对象添加到嵌套循环的数据列表中 listMap.add(itemMap); } // 将嵌套循环的数据列表添加到模板数据的Map对象中 map.put("list", listMap); map.put("projects", projects); // 导出excel ExcelUtils.exportExcel(templatePath, map, "新导出文件.xlsx", response); } catch (Exception ex) { throw new BadRequestException(ex.getMessage()); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值