用easypoi实现数据库的Excel导入导出操作
Apache POI 简介
ApachePOI是用Java编写的免费开源的跨平台的JavaAPI,ApachePOI提供API给Java程序对MicrosoftOffice格式档案读和写的功能,其中使用最多的就是使用POI操作Excel文件。
使用:https://blog.csdn.net/qq_44316726/article/details/105495959
缺点:
1.对于复杂的Excel模板样式需要编写大量的代码实现
2.大数据量的读取/导成效率低下,甚至可能内存溢出
EasyPoi简介
为了解决上述poi的缺点,国内有很多开源项目对poi进行了封装,大大减少代码量,使其能够更简单的被我们使用并提高开发效率,例如EasyPoi,Excel4J,HuTools等优秀的开源项目。我们这次以EasyPoi为例
easypoi功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员就可以方便的写出Excel导出,Excel模板导出,Excel导入,Word模板导出,通过简单的注解和模板语言(熟悉的表达式语法),完成以前复杂的写法。
开发文档:http://doc.wupaas.com/docs/easypoi/easypoi-1c0u4mo8p4ro8
Maven依赖
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.3.0</version>
</dependency>
@Excel注解,在需要导出的实体类中的字段上加上
@ApiModelProperty(value = "出生日期")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "Asia/Shanghai")
@Excel(name = "出生日期", width = 20, format = "yyyy-MM-dd",suffix = "年")
// 在导出的Excel表中会有个 “出生日期” 的列
// 每一行数据后都用 “年”
private LocalDate birthday;
@ExcelEntity 注解,在实体类中还存在子实体类在其上加上
@ApiModelProperty(value = "民族")
@TableField(exist = false)
@ExcelEntity(name = "民族")
private Nation nation;
在Nation实体类中需要导出的字段上加上: @Excel
@ApiModelProperty(value = "民族")
@Excel(name = "民族")
@NonNull
private String name;
导出接口:
编写Controller
@Api(tags = "Excel导入导出")
@RestController
@RequestMapping("/api")
public class ExcelController {
@ApiOperation("员工数据导出Excel")
// produces = "application/octet-stream" :设置用流的形式输出
@GetMapping(value = "/excel/export", produces = "application/octet-stream")
public void exportEmpToExcel(HttpServletResponse response) {
List<Employee> list = employeeService.getEmployeeAll(); // 查询数据库得到全部数据
// 1 : 在Excel表中的表头 (第一行) 2 :sheet名字 3 : 导出 Excel 类型 HSSF 03版 导出数据的比 XSSF 07版的速度要快 ,且 HSSF 03版 兼容性高
ExportParams params = new ExportParams("员工数据表", "员工表", ExcelType.HSSF);
// 使用EasyPoi提供的工具类:ExcelExportUtil.exportExcel(ExportParams entity, Class<?> pojoClass,Collection<?> dataSet): params, Employee.class, list ;; 得到 Workbook:POI 提供的工作铺 对象
Workbook workbook = ExcelExportUtil.exportExcel(params, Employee.class, list);
// ServletOutputStream out = null;
try {
// 流形式
response.setHeader("content-type", "application/octet-stream");
// 防止中文乱码
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode("员工表", "UTF-8") + ".xls");
workbook.write(response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
workbook.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
导入接口:
在处理 政治面貌、部门… 这些用通过实体类中的子实体类中的名字在输入数据库的时候只需要设置他们的 Id 所以:
-
在拿到这些值之后通过这个名字到数据库查找得到每一个的 id 在进行设置 ;这个方法对数据库的负载过大:这里一条数据需要查 5 次数据库 ,这里不推荐使用
-
这里的子实体类中的name属性不会经常变动 ,如 民族这个 ,所以这里我们可以来重写 Equals HashCode 方法 ,在获取到这个把name之后表示拿到的这个实体类是唯一的,因为唯一所以我们就能拿到唯一的 id ,再进行设置
使用@EqualsAndHashCode(callSuper = false, of = “name”):不使用EqualsAndHashCode方法,并用 name 属性来重写,使用@RequiredArgsConstructor来加入使用name属性的有参构造 Nation(String)来唯一建立这个对象,设置属性name非空
@Data
@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 = "民族")
@NonNull
private String name;
}
controller类
@ApiOperation("员工数据Excel导入数据库")
@PostMapping(value = "/excel/import", produces = "application/octet-stream")
public RespBean importExcel(MultipartFile filename) {
ImportParams params = new ImportParams();
// 去掉标题行
params.setTitleRows(1);
//只需查这一次
List<Nation> nationList = notionService.getNotions();
List<PoliticsStatus> politicsStatusList = politicsService.getPoliticsStatus();
List<Department> departmentList = departmentService.getList();
List<JobLevel> joblevelList = jobLevelService.getAll();
List<Position> positionList = positionService.getPosList();
try {
List<Employee> list = ExcelImportUtil.importExcel(filename.getInputStream(), Employee.class, params);
list.forEach(employee -> {
// 民族id
employee.setNationId(nationList.get(nationList.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 (employeeService.saveBatch(list)) {//利用mybatisplus中的saveBatch方法批量插入
return RespBean.success("导入员工信息成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
}
return RespBean.warning("导入员工信息失败!");
}
功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
}
return RespBean.warning(“导入员工信息失败!”);
}