JAVA一对多EXCEL导出
在实际开发中,数据库里面一对多的形式是普遍的事情,比如本次业务中,是一个举报模块,首先需要填写举报人信息,然后可以举报多个员工或者合作伙伴,那么这里就是一个举报人对应多个员工或者合作伙伴。
在后台管理页面里的表格里,我是每行只展示的举报人的消息,通过添加一个“查看详情”的按钮,可以打开新的页面查看被举报人的详细信息,这样算是比较合理的。但是需要对这些信息做一个Excel导出功能的话,该怎么在Excel里展示信息比较合理呢?我想到的就是合并单元格的形式。首先看看后台页面的展示情况:
现在利用EasyPoi这个三方库实现的是导出功能能够合并单元格,EasyPoi官方文档
实现
StaffExcel类,即被举报员工信息类
@Data
@Accessors(chain = true)
@ExcelTarget("ReportInfoExcel")
public class StaffExcel {
@Excel(name = "id",isColumnHidden = true)
private String id;
@Excel(name = "姓名", width = 20)
private String username;
@Excel(name = "工号", width = 20)
private String cardNum;
@Excel(name = "部门", width = 20)
private String dept;
@Excel(name = "职位", width = 20)
private String position;
}
PartnerExcel类,即被举报合作伙伴类
@Data
@Accessors(chain = true)
@ExcelTarget("ReportInfoExcel")
public class PartnerExcel {
@Excel(name = "id",isColumnHidden = true)
private String id;
@Excel(name = "姓名", width = 20)
private String username;
@Excel(name = "职位", width = 20)
private String position;
@Excel(name = "公司", width = 20)
private String company;
}
Excel要展示的实体类,即举报人信息和被举报人的一对多VO类
@Data
@Accessors(chain = true)
public class ReportInfoExcel {
//isColumnHidden表示此栏是否在Excel表里面展示
@Excel(name = "id",isColumnHidden = true,needMerge = true)
private String id;
//needMerge一定要加
@Excel(name = "举报人姓名", width = 20, needMerge = true)
private String reportUsername;
@Excel(name = "手机号", width = 20, needMerge = true)
private String tel;
@Excel(name = "邮箱", width = 20, needMerge = true)
private String email;
@ExcelCollection(name = "举报员工信息")
private List<StaffExcel> staffExcels;
@ExcelCollection(name = "举报合作伙伴信息")
private List<PartnerExcel> partnerExcels;
}
Controller
@GetMapping("export")
public void export(HttpServletResponse response) {
try {
// 设置响应输出的头类型
response.setHeader("content-Type", "application/vnd.ms-excel");
// 设置下载的Excel名称,以当前时间为文件后缀,DateUtil为Hutool工具包里的工具类
String dateTime = DateUtil.formatDateTime(new Date());
String fileName = "user"+dateTime+".xls";
response.setHeader("Content-Disposition", "attachment;filename="+fileName);
// excel信息部分
List<ReportInfoExcel> exportList = new LinkedList<>();
//此处为了演示,手动输入的数据,没有从数据库查数据,实际开发中从数据库中查数据
//创建ReportInfoExcel中List<StaffExcel>对象
List<StaffExcel> staffList = new LinkedList<>();
StaffExcel staff = new StaffExcel();
staff.setId("1")
.setUsername("李四")
.setCardNum("123456789")
.setDept("开发部门")
.setPosition("java开发");
//这里往list中加了两次staffExcel,模拟一对多的关系
staffList.add(staff);
staffList.add(staff);
//创建ReportInfoExcel中List<PartnerExcel>对象
List<PartnerExcel> partnerList = new LinkedList<>();
PartnerExcel partner = new PartnerExcel();
partner.setId("2")
.setUsername("张三")
.setCompany("微软公司")
.setPosition("java开发");
//这里往list中加了两次staffExcel,模拟一对多的关系
partnerList.add(partner);
partnerList.add(partner);
partnerList.add(partner);
ReportInfoExcel reportInfo = new ReportInfoExcel();
reportInfo.setId("2")
.setTel("132********")
.setEmail("77@qq.com")
.setReportUsername("王五")
//将上面创建的list对象添加进去
.setPartnerExcels(partnerList)
.setStaffExcels(staffList);
//reportInfo代表一行数据,exportList则是reportInfo的list集合,这里测试三行
exportList.add(reportInfo);
exportList.add(reportInfo);
exportList.add(reportInfo);
ExportParams exportParams = new ExportParams();
// 设置sheet得名称
exportParams.setSheetName("员工报表1");
Map<String, Object> map = new HashMap<>();
// title的参数为ExportParams类型,目前仅仅在ExportParams中设置了sheetName
map.put("title", exportParams);
// 模版导出对应得实体类型,即包含了List的对象
map.put("entity", ReportInfoExcel.class);
// sheet中要填充得数据
map.put("data", exportList);
List<Map<String, Object>> sheetsList = new ArrayList<>();
sheetsList.add(map);
//创建excel文件的方法
Workbook workbook = ExcelExportUtil.exportExcel(sheetsList, ExcelType.HSSF);
//通过response输出流直接输入给客户端
ServletOutputStream outputStream = response.getOutputStream();
workbook.write(outputStream);
outputStream.flush();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
测试下载好的Excel文档:
以上这些代码,直接复制进项目里面,再调export这个接口就可以直接实现下载,可以试一试。
后记
开发中也遇到了一个问题,下载后的Excel文件排序有问题,如下图:
上图中总是会有多行,调试了多种还是不行,最后发现是ReportInfoExcel类中的id字段没有加needMerge=true,本来以为这个字段用了isColumnHidden = true就不会再Excel中展示了所以没在意,最后排查了一个小时才找到原因,所以一定要记住,一对多情况下,这个“一”里面的所以字段都要加上needMerge=true。
用EasyPoi实现Excel表格的下载对比传统的Workbook或者阿里的EasyExcel确实还是挺简单易用的,而且利用response直接输出生成好的文件,比传统的先生成Excel文件到磁盘,再调一次接口去下载形式更简便,也省去了磁盘空间的占用,具体的@Excel之类的注解可以查看官方文档,里面还有很多别的功能,需要的时候也可以使用。