• 云e办(后端)——导入导出员工数据(EasyPoi注解使用)


    云e办(后端)——导入导出员工数据(EasyPoi注解使用)

    在我们日常工作中经常需要导入和导出我们的员工数据,所以本次我们完善此功能

    在这里插入图片描述

    一、EasyPoi注解使用

    介绍:

    poi :poi就是批量的操作文件或数据的导入以及导出 ,但是因为其使用起来需要过多的编辑代码,所以我们在此采用easypoi。

    国内有很多开源项目对poi进行了封装,大大减少代码量,使其能够更简单的被我们使用并提高开发效率,例如EasyPoi,Excel4J,HuTools等优秀的开源项目。我们这次以EasyPoi为例

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

    特点:

    设计精巧,使用简单
    接口丰富,扩展简单
    默认值多,write less do more
    AbstractView支持,web导出可以简单明了

    二、导出员工数据前期准备

    1、添加依赖
    
    <dependency>
       <groupId>cn.afterturngroupId>
       <artifactId>easypoi-spring-boot-starterartifactId>
       <version>4.1.3version>
    dependency>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    2、修改员工类

    EasyPoi最大的特点是:可以通过注解定义导出的字段。

    • 普通属性:员工类使用注解@Excel 定义了需要导出的属性, name 为导出的列名, width 可以定义列的宽度, format可以定义导入和导出的日期格式

    • 实体类对象作为属性:员工类中还有其他类作为属性,例如民族,政治面貌,职称,职位等。这些使用@ExcelEntity 标记为实体类。
      并且在该实体类对象中加入注解 @Excel即可。

    修改pojo包下的Employee类
    employee类是员工类:

    /**
         * @Excel 注解的部分参数:
         * name:导出到excel的列名
         * width:是导入到excel时,表格的宽度
         * suffix = "年"  后缀,比如说工龄是1年
         */
        ----------------------   ----------------------
        /**
         * 民族、婚姻政治面貌、部门、职位等肯定不是导入导出id,而是导出对应的表中的名字
         * 以民族为例子:
         * 民族nation是一个对象,也是POJO类,那怎么定义实体类呢?
         * 第一步:加入注解 @ExcelEntity
         * 第二部:修改POJO类 加入:@Excel(name = "民族")
         *
         * -- 那么会通过注解ExcelEntity表示是一个实体类,从而导入真实的数据
         *
         */
    
    	@ApiModelProperty(value = "入职日期")
        @JsonFormat(pattern = "yyyy-MM-dd",timezone = "Asia/Shanghai")
        @Excel(name = "入职日期",width = 20, format = "yyyy-MM-dd")
        private LocalDate beginDate;
    
        @ApiModelProperty(value = "在职状态")
        @Excel(name = "在职状态")
        private String workState;
    
        @ApiModelProperty(value = "工号")
        @Excel(name = "工号")
        private String workID;
    
        @ApiModelProperty(value = "合同期限")
        @Excel(name = "合同期限",suffix = "年")
        private Double contractTerm;
        	/**
    	 * 表中有很多外界id,都需要对应外界的表中。
    	 * 表需要对应pojo的对象中
    	 */
    	@ApiModelProperty(value = "民族")
    	//在正常的员工表中是不存在的
    	@TableField(exist=false)
    	@ExcelEntity(name = "民族")
    	private Nation nation;
    	
    	
    	@ApiModelProperty(value = "政治面貌")
    	@TableField(exist = false)
    	@ExcelEntity(name = "政治面貌")
    	private PoliticsStatus politicsStatus;
    
        @ApiModelProperty(value = "部门")
        @TableField(exist = false)
        @ExcelEntity(name = "部门")
        private Department department;
    
        @ApiModelProperty(value = "职称")
        @TableField(exist = false)
        @ExcelEntity(name = "职称")
        private Joblevel joblevel;
    
        @ApiModelProperty(value = "职位")
        @TableField(exist= false)
        @ExcelEntity(name = "职位")
        private Position position;
    
        @ApiModelProperty(value = "工资账套")
        @TableField(exist = false)
        private Salary salary;
    
    
    
    • 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

    再去修改nation类中的代码:

    package com.xxxx.server.pojo;
    
    import cn.afterturn.easypoi.excel.annotation.Excel;
    import com.baomidou.mybatisplus.annotation.TableName;
    import com.baomidou.mybatisplus.annotation.IdType;
    import com.baomidou.mybatisplus.annotation.TableId;
    import java.io.Serializable;
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.*;
    import lombok.experimental.Accessors;
    
    @Data
    //of: 要重写的属性。 以name重写了Equals和hashcode。表示以name重写了equals/hashcode以及写完了
    //当新建对象的时候,可以直接把name放进去,表示得到一个唯一的。:有参构造
    @RequiredArgsConstructor
    @NoArgsConstructor
    @EqualsAndHashCode(callSuper = false,of = "name")
    @Accessors(chain = true)
    @TableName("t_nation")
    @ApiModel(value="Nation对象", description="")
    public class Nation implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        @ApiModelProperty(value = "id")
        @TableId(value = "id", type = IdType.AUTO)
        private Integer id;
    
        @ApiModelProperty(value = "民族")
        @Excel(name = "民族")
        //非空的,写新的有参构造时,name是必填的。
        @NonNull
        private String name;
    }
    
    
    
    • 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

    在这里插入图片描述

    三、导出数据

    controller
    • 获取员工的数据
    • 准备导出的参数(表名、sheet名字、导出的excel类型) 【ExportParams类准备参数】
    • 将数据导出(导出的参数、实体类对象、导出的具体数据)【ExcelExporUtil导出工具类】
    • 通过流的形式进行导出【Response】
        //通过流的形式传出去:httpServletResponse response
        // produces通过流形式传输,解决乱码
        @ApiOperation(value = "导出员工数据")
        @GetMapping(value = "/export",produces = "application/octet-stream")
        public void exportEmployee(HttpServletResponse response) throws UnsupportedEncodingException {
            //获取当前员工的数据-具体的数据
            List<Employee> list = iEmployeeService.getEmployee(null);
            /**
             * 导出的参数:
             *  导出员工的数据:(文件名的名字,sheet表名,excel的版本)
             *  excel :
             *  03: HSSF - 提供读写Microsoft Excel XLS格式档案的功能。03打不开07
             *  07: XSSF - 提供读写Microsoft Excel OOXML XLSX格式档案的功能。07能打开03
             *
             *   03的HSSF比07的XSSF优点:
             *      1.速度快
             *      2.兼容性好。03打不开07, 07能打开03
             */
            ExportParams params = new ExportParams("员工表","sheet员工表", ExcelType.HSSF);
    
            /**
             * ExcelExportUtil导出工具类:(导出的参数、对象类名.class、具体的数据)
             *  返回的是Workbook。是poi的一个类。相当于工作簿(工作簿就是一个Excel)
             */
            Workbook book = ExcelExportUtil.exportExcel(params, Employee.class, list);
    
            /**
             * response。输出流形式 输出workboo
             *
             * 导出需要一些请求头的响应信息
             * 防止中文乱码
             */
            ServletOutputStream out = null;
            try{
                //流形式,设置一个头
                response.setHeader("content-type","application/octet-stream");
                //防止中文乱码
                response.setHeader("content-disposition","attachment;filename="+
                        URLEncoder.encode("员工表.xls","UTF-8"));
                out = response.getOutputStream();
                book.write(out);
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                try{
                    out.flush();
                    out.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    
    
    • 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

    四、导入员工

    导入时,因为在我们的excel表中所给出的民族name,政治面貌name等,但我们需要获取到对应的民族id,政治面貌id,职称id,职位id等。有两种方法

    • 根据name属性的值去数据库查询对应的id,显然在循环里面不断去查询数据库非常消耗性能,不推荐
    • 取巧:重写equals和hashCode方法,只要name属性的值一致就表示对象一致。前提是name属性的值基本不会变动。
      (例如民族。民族、政治面貌都是固定不变的。那么name属性是唯一的,那么就能根据name属性能知道创建对象的对象是唯一的。对象是唯一的话,那么就可以拿到对象的id)

    我们选择第二种方法实现

    1、导入准备:重写equals和hashCode方法

    在这里插入图片描述

    2、controller。
    @ApiOperation(value = "导入员工数据")
        @PostMapping("/import")
        public RespBean importEmployee(MultipartFile file){
            //创建导入对象
            ImportParams params = new ImportParams();
            //去掉标题第一行
            params.setTitleRows(1);
      /**
             * 导入 流的形式、POJO对象类的字节码、数据--- 返回的是数据
             *
             * 导入完成后,pojo.Employee-nation是有值的
             * pojo.nation拿到的就是name 是因为:
             *  Excel注解,ExcelEntiy注解:
             *      能通过汉族名字获取到它是nation.ExcelEntiy就知道了是对象里面的,从而得到name
             *  如何获得name的id呢?
             *
             *      for循环
             *      重写了hashcode方法,也准备了有参构造。
             *      1.从excel导入的数据中,拿到了nation对象,对象里面有name,id是空的
             *      2.查询所有的nationList,获取对象索引下标:重写了equals和hashcode,
             *          通过name名字去nationList比较。能获取一样的对象.从而得到下标。
             *      3.通过nationList.get(下标).getId() 获取完整的对象:有id,name\
             *      4.在从id,name中获取id。 将id放入到employee中。
             *
             *  if插入:saveBatch批量插入。 插入集合
             *
             */
            List<Nation> nationlList = nationService.list();
            List<PoliticsStatus> politicsStatusList = politicsStatusService.list();
            List<Department> departmentList = departmentService.list();
            List<Joblevel> joblevelList = joblevelService.list();
            List<Position> positionList = positionService.list();
            try{
                List<Employee> list = ExcelImportUtil.importExcel(file.getInputStream(), Employee.class, params);
                list.forEach(employee -> {
                    //民族id
                    employee.setNationId(nationlList.get(nationlList.indexOf(
                            new Nation(employee.getNation().getName()))).getId());
                    //政治面貌id
                    employee.setPoliticId(politicsStatusList.get(politicsStatusList.indexOf(
                            new PoliticsStatus(employee.getPoliticsStatus().getName()))).getId());
                    //部门id
                    employee.setDepartmentId(departmentList.get(departmentList.indexOf(new
                            Department(employee.getDepartment().getName()))).getId());
                    //职称id
                    employee.setJobLevelId(joblevelList.get(joblevelList.indexOf(new
                            Joblevel(employee.getJoblevel().getName()))).getId());
                    //职位id
                    employee.setPosId(positionList.get(positionList.indexOf(new
                            Position(employee.getPosition().getName()))).getId());
                });
                if (iEmployeeService.saveBatch(list)){
                    return RespBean.success("导入成功!");
                }
                return RespBean.error("导入失败!");
            } catch (Exception e){
                e.printStackTrace();
            }
            return RespBean.error("导入失败!");
        }
    
    
    
    • 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
  • 相关阅读:
    ChainForge:衡量Prompt性能和模型稳健性的GUI工具包
    GCC编译器
    联想小新 win10电脑系统安装教程
    【记录】PyCharm 安装 preprocess 模块(库)|| 在 PyCharm 中安装 preprocess 失败,故而在 终端 安装
    项目总结-商品购买流程
    探花交友_第2章-完善个人信息与MongoDB入门
    慢SQL治理经验总结
    HFSS脚本建模入门
    开年第一弹:产品经理找工作的心酸故事
    【中秋国庆不断更】HarmonyOS对通知类消息的管理与发布通知(上)
  • 原文地址:https://blog.csdn.net/xiangqian0721/article/details/127746535