在我们日常工作中经常需要导入和导出我们的员工数据,所以本次我们完善此功能
poi :poi就是批量的操作文件或数据的导入以及导出 ,但是因为其使用起来需要过多的编辑代码,所以我们在此采用easypoi。
国内有很多开源项目对poi进行了封装,大大减少代码量,使其能够更简单的被我们使用并提高开发效率,例如EasyPoi,Excel4J,HuTools等优秀的开源项目。我们这次以EasyPoi为例
Easypoi功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员 就可以方便的写出Excel出,Excel模板导出,Excel导入,Word模板导出,通过简单的注解和模板 语言(熟悉的表达式语法),完成以前复杂的写法。
特点:
设计精巧,使用简单
接口丰富,扩展简单
默认值多,write less do more
AbstractView支持,web导出可以简单明了
<dependency>
<groupId>cn.afterturngroupId>
<artifactId>easypoi-spring-boot-starterartifactId>
<version>4.1.3version>
dependency>
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;
再去修改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;
}
//通过流的形式传出去: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();
}
}
}
导入时,因为在我们的excel表中所给出的民族name,政治面貌name等,但我们需要获取到对应的民族id,政治面貌id,职称id,职位id等。有两种方法
我们选择第二种方法实现
@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("导入失败!");
}