携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情
大家好! 我是慕歌,一只想教你学习 Spring Boot的野生coder! 欢迎来到慕歌的 Sping boot系列教程,希望通过这个教程带大家搭建基础的 Spring Boot项目,该教程所有知识点均来源于本人的真实开发!
前言
在前一节的分享中,慕歌向大家介绍了hutool 对我们开发的影响,以及如何使用基础的hutool 功能工具类辅助我们进行数据处理。这一节中慕歌将向大家介绍hutool 的实用用法,用hutool进行excel数据的导入,导出以及模板导出,这个功能在我们的后台开发中还是非常实用的功能。话不多说,下面开始正式教学。
导包:
excel 包完全依赖于hutool 工具包,不需要额外的引入,hutool all中已经包含了hutool 的全部工具包
<!-- hutool工具类 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.22</version>
</dependency>
开发:
首先确定我们要对那些表进行数据的导入导出,这里的建议是对数据更改不频繁的表进行数据的导入导出,而且对于数据的唯一性要求不高,否则在进行数据导入的过程中,需要进行复杂的逻辑处理。这里我使用的是组织的用户信息表,该表的数据只有组织自己进行维护,就可以使用标准导入。
/**
* 组织用户信息表
* @TableName cf_group_user
*/
@TableName(value ="cf_group_user")
@Data
public class GroupUser implements Serializable {
/**
* id
*/
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 组织id
*/
private Integer groupId;
/**
* 姓名
*/
@NotBlank(message = "姓名不可为空")
private String nickname;
/**
* 性别(0:默认,1:男,2:女)
*/
@NotBlank(message = "性别不可为空")
private Integer sex;
/**
* 出生日期
*/
@NotBlank(message = "出生日期不可为空")
private Date bornTime;
/**
* 形象照片
*/
@NotBlank(message = "形象照片不可为空")
private String photo;
/**
* 家庭地址
*/
@NotBlank(message = "家庭地址不可为空")
private String homeAddress;
/**
* 联系电话
*/
@NotBlank(message = "联系电话不可为空")
private Integer mobile;
/**
* 实名信息
*/
private String authId;
/**
* 职务信息
*/
@NotNull(message = "职务不可为空")
private String post;
}
create table cf_group_user
(
id int unsigned auto_increment comment 'id'
primary key,
group_id int unsigned not null comment '组织id',
nickname char(30) not null comment '姓名',
sex tinyint unsigned not null comment '性别(1:男,2:女)',
born_time datetime not null comment '出生日期',
photo varchar(255) not null comment '形象照片',
home_address varchar(255) not null comment '家庭地址',
mobile int not null comment '联系电话',
post varchar(255) not null comment '职务信息'
)
comment '组织用户信息表' collate = utf8_unicode_ci;
create index auth_id
on cf_group_user (auth_id);
create index group_id
on cf_group_user (group_id);
create index mobile
on cf_group_user (mobile);
在确定表后,我们需要选取那些字段是我们需要使用的,在excel 表中进行展示,需要用户填入,根据字段构建反射。
实现:
在工程中先确定使用的字段构建模板,根据字段构建excel 的模板。这里的示例如下:
//controller层
//返回模板
@RequestMapping("/getExcelTemplate")
public void getExcelTemplate(HttpServletResponse response) {
groupUserService.getExcelTemplate(response);
}
//sevice层
void getExcelTemplate(HttpServletResponse response);
//impl
@Override
public void getExcelTemplate(HttpServletResponse response) {
try {
// 1 读取对象
final ExcelReader reader = ExcelUtil.getReader(ResourceUtil.getStream("templates/group.xlsx"));
List<List<Object>> lists = reader.read();
ExcelWriter writer = ExcelUtil.getWriter(true);
writer.write(lists);
response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode("group.xlsx", "UTF-8"));
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
// 2 写出对象
ServletOutputStream outputStream = response.getOutputStream();
// 通过IO写出我们的表格对象
writer.flush(outputStream, true);
writer.close();
IoUtil.close(outputStream);
} catch (IOException e) {
log.error("EducationServiceImpl [export] 输出到响应流失败", e);
throw new APIException("导出Excel异常");
}
}
这里我使用的是三层构建,在controller 层中暴露接口,进行调用,所有的具体实现进行抽象。
//导入信息
@RequestMapping("/importStudent")
public R importStudent(@RequestParam MultipartFile file) {
try {
boolean userInfo = groupUserService.getUserInfo(file);
if(userInfo) return R.success();
} catch (IOException e) {
log.error("EducationController [getEducation] 获取输入流失败", e);
throw new APIException("获取输入流失败");
}
return R.error();
}
//导出信息
@RequestMapping("/export")
public void export(@RequestBody PageVo pageVo, HttpServletResponse response) {
groupUserService.export(pageVo, response);
}
void export(PageVo pageVo, HttpServletResponse response);
boolean getUserInfo(MultipartFile file) throws IOException;
@Override
public void export(PageVo pageVo, HttpServletResponse response) {
// 从数据库查出数据对象封装成map
final List<Map<String, Object>> educationList = this.page(new Page<>(pageVo.getPage(), pageVo.getLimit()), Wrappers.lambdaQuery()).getRecords()
.stream()
// 封装成 Map 并且放入 List
.map(item -> {
final Map<String, Object> map = new LinkedHashMap<>();
// 错误,这里需要根据表中字段名称进行命名
map.put("nickname", item.getNickname());
map.put("sex", item.getSex());
map.put("mobile", item.getMobile());
map.put("bornTime", item.getBornTime());
map.put("homeAddress", item.getHomeAddress());
map.put("post", item.getPost());
return map;
})
.collect(Collectors.toList());
// 准备将数据集合封装成Excel对象
ExcelWriter writer = ExcelUtil.getWriter(true);
// 通过工具类创建writer并且进行别名
writer.addHeaderAlias("nickname", "姓名");
writer.addHeaderAlias("sex", "性别( 0 表示男 , 1 表示 女)");
writer.addHeaderAlias("mobile", "电话");
writer.addHeaderAlias("bornTime", "出生日期");
writer.addHeaderAlias("homeAddress", "家庭地址");
writer.addHeaderAlias("post", "职位");
// 准备将对象写入我们的 List
writer.write(educationList, true);
try {
// 获取我们的输出流
final OutputStream output = response.getOutputStream();
response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode("group.xlsx", "UTF-8"));
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
writer.flush(output, true);
writer.close();
// 这里可以自行关闭资源或者写一个关闭资源的工具类
IoUtil.close(output);
} catch (IOException e) {
log.error("EducationServiceImpl [export] 输出到响应流失败", e);
throw new APIException("导出Excel异常");
}
}
@Override
public boolean getUserInfo(MultipartFile file) throws IOException {
ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
HashMap<String, String> head = new HashMap<>(6);
head.put("姓名","nickname");
head.put("性别( 0 表示男 , 1 表示 女)","sex");
head.put("电话","mobile");
head.put("出生日期", "bornTime");
head.put("家庭地址","homeAddress");
head.put("职位","post");
reader.setHeaderAlias(head);
List<GroupUser> read = reader.read(0, 1, GroupUser.class);
Group group = groupService.getOne(new QueryWrapper<Group>().eq("uid", UserConstant.USER_ID));
for (GroupUser user : read) {
user.setGroupId(group.getId());
//TODO 默认图片
user.setPhoto("https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png");
user.setStatus(1);
user.setCreateTime(new DateTime());
if(!this.save(user))return false;
}
return true;
}
使用hutool 进行excel 处理的时候,需要自己定义字段与excel 表头见的映射关系,这一点是比较麻烦的。但相比于其他excel的使用方式,这是一种非常简单的实现。
结语
这一章的分享到这里就结束了,下一节中还将带来邮件Mail服务的分享!
如果您觉得本文不错,欢迎点赞支持,您的关注是我坚持的动力!