本文是介绍利用POI导出数据到Excel表格中,并且需要合并单元格。第一次写觉得还是有点难度的,当时花了一天的时间写这个导出,不过最后完成了,也没有觉得它很难。只要掌握它实现的原理,不管怎么的导出都可以解决
导出结果先看一下 (根据选择的时间段导出的,所以表头是循环设置的。下面代码有)
实现思路:
1、得到我们需要导出的数据(这个就很简单了,从数据库里查)
2、一如既往的导入jar包等等(找jar包就自己找了)
3、创建一个Excel表格--->XSSFWorkbook xssfWorkbook = new XSSFWorkbook();
XSSFWorkbook 和HSSFWorkbook 都可以,只是针对Excel版本不一样,XSSFWorkbook 是2007版之后的
4、创建Excel表格的sheet-->XSSFSheet xssfSheet = xssfWorkbook.createSheet("监控点统计");
5、设置一下单元格样式
6、合并单元格
7、循环得到的值,一行一行的插入到Excel表格中
8、导出操作。这样就是大概的思路了
以下是我的这个业务实现的代码,里面都有很详细的注释
1、承载数据的实体类
package com.byavs.drwisas.system.domain.vo;
import io.swagger.annotations.ApiModelProperty;
/**
* @author Created by jovin .
* @date Created on 18:52 2020/3/10.
*/
public class CountAimAmountVo {
@ApiModelProperty("设备编号")
private String deviceCode;
@ApiModelProperty("设备名称")
private String cameraName;
/**
* 第二主键IntId
* 相机ID
*/
@ApiModelProperty("第二主键intId")
private Integer cameraID;
/**
* 状态 1-未开启 2-暂停 3-执行中 4-异常 5-已完成 6-已关闭(手动关闭)
*/
@ApiModelProperty("状态 1-未开启 2-暂停 3-执行中 4-异常 5-已完成 6-已关闭(手动关闭)")
private Integer status;
/**
* 统计日、格式yyyyMMdd
*/
@ApiModelProperty("统计日、格式yyyyMMdd")
private Integer countDay;
/**
* 人体目标数
*/
@ApiModelProperty("人体目标数")
private Long pedestrianCount;
/**
* 人脸目标数
*/
@ApiModelProperty("人脸目标数")
private Long faceCount;
/**
* 机动车目标数
*/
@ApiModelProperty("机动车目标数")
private Long vehicleCount;
/**
* 非机动车目标数
*/
@ApiModelProperty("非机动车目标数")
private Long nonMotorCount;
/**
* 状态描述,如果异常状态,就应该填异常原因
*/
@ApiModelProperty("状态描述,如果异常状态,就应该填异常原因")
private String statusDesc;
//set和get方法就省了
}
2、导出到Excel表格的代码
/**
* 监控点位目标数统计导出
*
* @param qo
* @param
*/
@ApiOperation(value = "监控点位目标数统计导出.xlsx")
@PostMapping(value = "/export")
public void exportCount(@ApiParam(value = "监控点位目标数统计", required = false)
@RequestBody(required = false) ExportCountQo qo,
HttpServletResponse response) throws IOException {
//得到需要导出的数据、export()方法在下面。
Map<Integer, List<CountAimAmountVo>> map = taskService.export(qo);
//这两个是用来创建导出文件名称的
String startTime = DateUtil.format2String(qo.getStartDate(), DateUtil.DATE_CHS_SMALL);
String endTime = DateUtil.format2String(qo.getEndDate(), DateUtil.DATE_CHS_SMALL);
String filename = startTime + "-" + endTime + "监控点目标数统计" + ".xlsx";
//1、创建工作本、就是你的Excel表格(XSSFWorkbook是用在2007版本的,之前的用HSSFWorkbook,本文使用XSSFWorkbook,操作其实一样)
XSSFWorkbook xssfWorkbook = new XSSFWorkbook();
//2、新建工作表(就是Excel表格中下方的sheet)
XSSFSheet xssfSheet = xssfWorkbook.createSheet("监控点统计");
//3、单元格样式(因为要合并单元格,所有就设置了单元格的样式居中,还有其他样式自己可以去网上找,有很多)
CellStyle cellStyle = xssfWorkbook.createCellStyle();
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);//单元格水平居中
cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//单元格垂直居中
//4、创建行(此处是第一行,Excel表格中都是从第0行、第0列开始的)
XSSFRow row = xssfSheet.createRow(0);
//合并单元格(设备编号),从导出结果可以看出,第一行和第二行需要合并的,只有第一列
merge(cellStyle, xssfSheet, row, 0, 1, 0, 0, 0, "设备编号");
//合并单元格(设备名称),从导出结果可以看出,第一行和第二行需要合并的,只有第二列
merge(cellStyle, xssfSheet, row, 0, 1, 1, 1, 1, "设备名称");
//目标数统计表头设计(因为这个业务是根据选择的时间而导出的,所以表头需要循环设置。count表示多少天)
int count = (int) DateUtil.subtractOfDay(qo.getEndDate(), qo.getStartDate());
//创建第二行
XSSFRow row1 = xssfSheet.createRow(1);
for (int i = 0; i <= count; i++) {
int firstCol = (i) * 5 + 2;
int lastCol = (i + 1) * 5 + 1;
//得到当前要存储的日期
Date date = DateUtil.addDays(qo.getStartDate(), i);
String strDate = DateUtil.format2String(date, DateUtil.DATE_CHS_SMALL);
String countDay = strDate.substring(5);
merge(cellStyle, xssfSheet, row, 0, 0, firstCol, lastCol, firstCol, countDay);
//创建单元格
row1.createCell(firstCol).setCellValue("状态");
row1.createCell(firstCol + 1).setCellValue("人体");
row1.createCell(firstCol + 2).setCellValue("人脸");
row1.createCell(firstCol + 3).setCellValue("机动车");
row1.createCell(firstCol + 4).setCellValue("非机动车");
}
int i = 1;
//遍历map集合、找到同一台设备的所有数据、再次遍历list集合,分别按照不同的统计日期添加值
for (Map.Entry<Integer, List<CountAimAmountVo>> countMap : map.entrySet()) {
//创建行、从第三行开始
i = i + 1;
int n = 0;
XSSFRow row2 = xssfSheet.createRow(i);
List<CountAimAmountVo> list = countMap.getValue();
list.sort((o1, o2) -> {
Integer countDay1 = o1.getCountDay();
Integer countDay2 = o2.getCountDay();
if (countDay1 > countDay2) {
return 1;
} else {
return -1;
}
});
row2.createCell(0).setCellValue(list.get(0).getDeviceCode());//添加设备编号
row2.createCell(1).setCellValue(list.get(0).getCameraName());//添加设备名称
for (CountAimAmountVo countAimVo : list) {
n = n + 1;
int firstCol = (n - 1) * 5 + 2;
switch (countAimVo.getStatus()) {
case 6:
row2.createCell(firstCol).setCellValue(TaskStatusEnum.CLOSE.message);//添加状态
break;
case 3:
row2.createCell(firstCol).setCellValue(TaskStatusEnum.DOING.message);//添加状态
break;
case 4:
row2.createCell(firstCol).setCellValue(TaskStatusEnum.EXCEPTION.message);//添加状态
break;
case 5:
row2.createCell(firstCol).setCellValue(TaskStatusEnum.FINISH.message);//添加状态
break;
case 1:
row2.createCell(firstCol).setCellValue(TaskStatusEnum.NOT_BEGIN.message);//添加状态
break;
default:
break;
}
row2.createCell(firstCol + 1).setCellValue(countAimVo.getPedestrianCount());//添加人体
row2.createCell(firstCol + 2).setCellValue(countAimVo.getFaceCount());//添加人脸
row2.createCell(firstCol + 3).setCellValue(countAimVo.getVehicleCount());//添加机动车
row2.createCell(firstCol + 4).setCellValue(countAimVo.getNonMotorCount());//添加非机动车
}
}
//导出到Excel
outExportFile(xssfWorkbook, filename, response);
}
/**
* 合并单元格(其实就4个坐标的点合并成一个单元格)
*
* @param cellStyle 合并单元格的样式
* @param xssfSheet Excel表格的sheet
* @param row 第几行
* @param firstRow 合并开始行
* @param lastRow 合并结束行
* @param firstCol 合并开始列
* @param lastCol 合并结束列
* @param columnIndex 从第几列开始
* @param cellValue 单元格的值
*/
private void merge(CellStyle cellStyle, XSSFSheet xssfSheet, XSSFRow row, int firstRow, int lastRow, int firstCol, int lastCol, int columnIndex, String cellValue) {
//指定合并开始行、合并结束行 合并开始列、合并结束列
CellRangeAddress rangeAddress = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol);
xssfSheet.addMergedRegion(rangeAddress);
//创建单元格,指定起始列号,从0开始
XSSFCell cell = row.createCell(columnIndex);
cell.setCellValue(cellValue);//单元格赋值
cell.setCellStyle(cellStyle);//设置单元格样式
}
/**
* 数据导出
*
* @param xssfWorkbook
* @param filename
* @param response
* @throws IOException
*/
public void outExportFile(XSSFWorkbook xssfWorkbook, String filename, HttpServletResponse response) throws IOException {
BufferedOutputStream fos = null;
try {
response.setContentType("application/x-msdownload");
response.addHeader("Content-Disposition", "attachment; filename=" + filename);
response.setCharacterEncoding("UTF-8");
fos = new BufferedOutputStream(response.getOutputStream());
xssfWorkbook.write(fos);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fos != null) {
fos.close();
}
}
}
3、得到数据库里的数据export()方法
/**
* 得到需要导出的监控点统计数据
*
* @param qo
* @return
*/
public Map<Integer , List<CountAimAmountVo>> export(ExportCountQo qo){
//将时间转为yyyyMMdd格式
Integer startDay = Integer.valueOf(DateUtil.format2String(qo.getStartDate(),DateUtil.DATE_DIGIT_SMALL));
Integer endDay = Integer.valueOf(DateUtil.format2String(qo.getEndDate(),DateUtil.DATE_DIGIT_SMALL));
Query query = new Query();
query.addCriteria(Criteria.where("countDay").gte(startDay).lte(endDay));
List<String> cameraIds = qo.getCameraIdList();
List<Camera> cameraList = null;
List<Integer> intIds = null;
if (!CollectionUtils.isEmpty(cameraIds)){
cameraList = cameraService.findCameraByIds(cameraIds);
intIds = cameraList.stream().map(Camera::getIntid).collect(Collectors.toList());
}
if (!CollectionUtils.isEmpty(intIds)){
query.addCriteria(new Criteria("cameraID").in(intIds));
}
List<CountAimAmount> countAimAmountList = mongoTemplate.find(query, CountAimAmount.class);
logger.info("=========在MongoDB里一共找到了:"+ countAimAmountList.size()+"条数据============");
List<CountAimAmountVo> list = BeanCopyUtil.cloneObject(countAimAmountList, CountAimAmountVo.class);
//得到所有的cameraID==》intId集合
List<Integer> intIdList = list.stream().map(CountAimAmountVo::getCameraID).collect(Collectors.toList());
Map<Integer , List<CountAimAmountVo>> map = new HashMap<>();
for (Integer integer : intIdList){
List<CountAimAmountVo> countAimAmountVoList = new ArrayList<>();
for (CountAimAmountVo countAimAmountVo : list){
if (countAimAmountVo.getCameraID().equals(integer)){
countAimAmountVoList.add(countAimAmountVo);
}
}
map.put(integer,countAimAmountVoList);
}
return map;
}