基于HuTool工具类ExcelWriter合并单元格并且使用 jdk1.8 lambda表达式
效果如下:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by Intellij IDEA. Copyright@ zqy
*
* @Author: zqy
* @Date: 2021/8/11
* @Description: excel表头注解
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HeaderName {
String value() default "";
}
import java.io.Serializable;
import java.math.BigDecimal;
import cn.stylefeng.guns.modular.business.annotation.HeaderName;
import lombok.Data;
/**
* Created by Intellij IDEA. Copyright@ zqy
*
* @Author: zqy
* @Date: 2021/8/2
* @Description:
*/
/**
* 材料实验
*/
@Data
public class MaterialsTestExcelVO implements Serializable {
private static final long serialVersionUID = -3621354299691315539L;
/**
* 来源名称
*/
@HeaderName("来源名称")
private String msName;
/**
* 材料名称
*/
@HeaderName("材料名称")
private String mName;
/**
* 上端材料
*/
@HeaderName("上端材料")
private String materialSpringSide;
/**
* 下端材料
*/
@HeaderName("下端材料")
private String materialCarriageSide;
/**
* 温度
*/
@HeaderName("温度")
private String temp;
/**
* 相对湿度
*/
@HeaderName("相对湿度")
private String relattiveHumiduty;
/**
* 压力
*/
@HeaderName("压力")
private Integer normalForce;
/**
* 批次名称
*/
@HeaderName("批次名称")
private String batch;
/**
* 速度
*/
@HeaderName("速度")
private String relativeVelocity;
/**
* 啸叫率
*/
@HeaderName("啸叫率")
private BigDecimal groanGate;
/**
* 滑动摩擦力
*/
@HeaderName("滑动摩擦力")
private BigDecimal dynFrictForce;
/**
* 静摩擦力
*/
@HeaderName("静摩擦力")
private BigDecimal statFrictForce;
/**
* 测试时间
*/
@HeaderName("测试时间")
private String testTime;
}
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import lombok.SneakyThrows;
/***
* @Description: 导出数据查询
* @Author: zqy
* @Date: 2021/8/12 14:56
* @Param: dto response
* @Return: void
*/
@SneakyThrows
@Override
public void export(MaterialsTestListSearchDTO dto, HttpServletResponse response) {
List<MaterialsTestExcelVO> voList = testMapper.findExcelList(dto);
downloadReport(voList, response);
}
/***
* @Description: 下载数据
* @Author: zqy
* @Date: 2021/8/12 14:57
* @Param: voList response
* @Return: void
*/
public void downloadReport(List<MaterialsTestExcelVO> voList, HttpServletResponse response) throws IOException {
// 定义基础数据
List<String> rowHead = loadRowHead(MaterialsTestExcelVO.class);
ExcelWriter writer = ExcelUtil.getBigWriter();
// 写入标题
writer.writeHeadRow(rowHead);
// 获取导出数据
List<List<Object>> rows = loadRowList(voList, writer);
// 导出数据
// 一次性写出内容,使用默认样式,强制输出标题
writer.write(rows, true);
// response为HttpServletResponse对象
response.setContentType("application/vnd.ms-excel;charset=utf-8");
// test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
response.setHeader("Content-Disposition", "attachment;filename=file.xlsx");
ServletOutputStream out = response.getOutputStream();
writer.flush(out, true);
// 此处记得关闭输出Servlet流
IoUtil.close(out);
}
/***
* @Description: 封装导出数据,并合并列
* @Author: zqy
* @Date: 2021/8/12 14:59
* @Param: voList writer
* @Return: java.util.List>
*/
private List<List<Object>> loadRowList(List<MaterialsTestExcelVO> voList, ExcelWriter writer) {
// 定义启始行
int index = 1;
int index2 = 1;
int index3 = 1;
int index4 = 1;
List<List<Object>> rows = new LinkedList<>();
// 按照姓名分组数据汇总处理(lambda表达式,不了解可以百度)
Map<String, List<MaterialsTestExcelVO>> msGroupMaps = voList.stream()
.collect(Collectors.groupingBy(MaterialsTestExcelVO::getMsName, LinkedHashMap::new, Collectors.toList()));
for (Map.Entry<String, List<MaterialsTestExcelVO>> listEntry : msGroupMaps.entrySet()) {
List<MaterialsTestExcelVO> msList = listEntry.getValue();
// 根据数据条数设置合并单元格信息
if (msList.size() == 1) {// 一条数据不合并
index = index + msList.size();
index2 = index2 + msList.size();
index3 = index3 + msList.size();
index4 = index4 + msList.size();
} else {
// 规则编写
writer.merge(index, index + msList.size() - 1, 0, 0, null, true);
// 标题
index = index + msList.size();
// 按照编码进行分组
Map<String, List<MaterialsTestExcelVO>> mGroupMaps = msList.stream().collect(
Collectors.groupingBy(MaterialsTestExcelVO::getMName, LinkedHashMap::new, Collectors.toList()));
for (Map.Entry<String, List<MaterialsTestExcelVO>> list2Entry : mGroupMaps.entrySet()) {
List<MaterialsTestExcelVO> mList = list2Entry.getValue();
// 根据数据条数设置合并单元格信息
if (mList.size() == 1) {// 一条数据不合并
index2 = index2 + mList.size();
index3 = index3 + mList.size();
index4 = index4 + mList.size();
} else {
// 规则编写
writer.merge(index2, index2 + mList.size() - 1, 1, 1, null, true);
index2 = index2 + mList.size();
// 按照编码进行分组
Map<String, List<MaterialsTestExcelVO>> ssGroupMaps =
mList.stream().collect(Collectors.groupingBy(MaterialsTestExcelVO::getMaterialSpringSide,
LinkedHashMap::new, Collectors.toList()));
for (Map.Entry<String, List<MaterialsTestExcelVO>> list3Entry : ssGroupMaps.entrySet()) {
List<MaterialsTestExcelVO> ssList = list3Entry.getValue();
// 根据数据条数设置合并单元格信息
if (ssList.size() == 1) {// 一条数据不合并
index3 = index3 + ssList.size();
index4 = index4 + ssList.size();
} else {
// 规则编写
writer.merge(index3, index3 + ssList.size() - 1, 2, 2, null, true);
index3 = index3 + ssList.size();
// 按照编码进行分组
Map<String,
List<MaterialsTestExcelVO>> csGroupMaps = ssList.stream()
.collect(Collectors.groupingBy(MaterialsTestExcelVO::getMaterialCarriageSide,
LinkedHashMap::new, Collectors.toList()));
for (Map.Entry<String, List<MaterialsTestExcelVO>> list4Entry : csGroupMaps
.entrySet()) {
List<MaterialsTestExcelVO> csList = list4Entry.getValue();
// 根据数据条数设置合并单元格信息
if (csList.size() == 1) {// 一条数据不合并
index4 = index4 + csList.size();
} else {
// 规则编写
writer.merge(index4, index4 + csList.size() - 1, 3, 3, null, true);
index4 = index4 + csList.size();
}
}
}
}
}
}
}
// 保存数据
msList.forEach(sList -> {
List<Object> rowA = null;
rowA = CollUtil.newArrayList(sList.getMsName(), sList.getMName(), sList.getMaterialSpringSide(),
sList.getMaterialCarriageSide(), sList.getTemp(), sList.getRelattiveHumiduty(), sList.getBatch(),
sList.getNormalForce(), sList.getRelativeVelocity(), sList.getGroanGate(), sList.getDynFrictForce(), sList.getStatFrictForce(),
sList.getTestTime());
rows.add(rowA);
});
}
return rows;
}
/***
* @Description: 封装表头
* @Author: zqy
* @Date: 2021/8/12 15:00
* @Param: albumClass 实体类class
* @Return: java.util.List
*/
private List<String> loadRowHead(Class<?> albumClass) {
List<String> rowHead = new ArrayList<>();
// 获取 实体类 中所有的字段
Field[] declaredFields = albumClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
// 这里设置为 true 才可以访问到 实体类中的 private 字段
declaredField.setAccessible(true);
// 获取字段所对应的注解
HeaderName annotation = declaredField.getAnnotation(HeaderName.class);
if (null != annotation) {
// 有注解 则 获取 注解的值(表头名称)
rowHead.add(annotation.value());
}
}
return rowHead;
}
借鉴地址