当前位置:网站首页>Implementation of easyexcel's function of merging cells with the same content and dynamic title
Implementation of easyexcel's function of merging cells with the same content and dynamic title
2022-06-27 05:19:00 【Programmer Ah Q】
I believe many students have used EasyExcel Done export function , Now Q Also encountered a demand , Is to export Excel Vertical cells with the same contents in the are merged , Then you need to give Excel Set dynamic title , Then adjust the format definition , The implementation process of this function is now recorded , Give the students a reference to avoid stepping on the same pit .
jar Package version :
One 、 Original version
The result of the export :

Corresponding entity class code :
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentLoopMerge;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import lombok.*;
import java.io.Serializable;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Data
@ContentRowHeight(30)
@HeadRowHeight(40)
@ColumnWidth(25)
public class StudentExportVo implements Serializable {
private static final long serialVersionUID = -5809782578272943999L;
@ExcelProperty(value = " School ", order = 1)
@ContentLoopMerge(eachRow = 3)
private String school;
@ExcelProperty(value = " full name ", order = 2)
private String name;
@ExcelProperty(value = " Gender ", order = 3)
private String sex;
@ExcelProperty(value = " Age ", order = 4)
private String age;
@ExcelProperty(value = " City ", order = 5)
private String city;
@ExcelProperty(value = " remarks ", order = 6)
private String remarks;
}Corresponding business code :
@ApiOperation(value = " Export student information ", notes = " Export student information ")
@PostMapping("/exportStudent")
public void exportStudent(@RequestBody String str, HttpServletResponse response) {
List<StudentExportVo> list = this.getStudentExportVos();
ExcelUtils.writeExcel(response, StudentExportVo.class, list, " Export student information ", "sheet1");
}
// Data manufacturing
private List<StudentExportVo> getStudentExportVos() {
List<StudentExportVo> list = new ArrayList<>();
StudentExportVo v1 = new StudentExportVo();
v1.setSchool(" Peking University, ");
v1.setName(" Zhang San ");
v1.setSex(" male ");
v1.setAge("20");
v1.setCity(" Beijing ");
v1.setRemarks(" nothing ");
list.add(v1);
StudentExportVo v2 = new StudentExportVo();
v2.setSchool(" Peking University, ");
v2.setName(" Li Si ");
v2.setSex(" male ");
v2.setAge("22");
v2.setCity(" Shanghai ");
v2.setRemarks(" nothing ");
list.add(v2);
StudentExportVo v3 = new StudentExportVo();
v3.setSchool(" Peking University, ");
v3.setName(" Wang Wu ");
v3.setSex(" Woman ");
v3.setAge("22");
v3.setCity(" Qingdao ");
v3.setRemarks(" nothing ");
list.add(v3);
StudentExportVo v4 = new StudentExportVo();
v4.setSchool(" Tsinghua University ");
v4.setName(" Zhao Liu ");
v4.setSex(" Woman ");
v4.setAge("21");
v4.setCity(" Chongqing ");
v4.setRemarks(" nothing ");
list.add(v4);
StudentExportVo v5 = new StudentExportVo();
v5.setSchool(" Wuhan University ");
v5.setName(" Wang Qiang ");
v5.setSex(" male ");
v5.setAge("24");
v5.setCity(" Changsha ");
v5.setRemarks(" nothing ");
list.add(v5);
StudentExportVo v6 = new StudentExportVo();
v6.setSchool(" Wuhan University ");
v6.setName(" Zhao Yan ");
v6.setSex(" Woman ");
v6.setAge("21");
v6.setCity(" Shenzhen ");
v6.setRemarks(" nothing ");
list.add(v6);
StudentExportVo v7 = new StudentExportVo();
v7.setSchool(" Xiamen University ");
v7.setName(" six thousand ");
v7.setSex(" Woman ");
v7.setAge("21");
v7.setCity(" Guangzhou ");
v7.setRemarks(" nothing ");
list.add(v7);
return list;
}Two 、 Use the annotated version
The result of the export :

Corresponding entity class code :
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Data
@ContentRowHeight(30)
@HeadRowHeight(40)
@ColumnWidth(25)
public class StudentExportVo implements Serializable {
private static final long serialVersionUID = -5809782578272943999L;
@ExcelProperty(value = {" Student information "," School "}, order = 1)
@ContentLoopMerge(eachRow = 3)
private String school;
@ExcelProperty(value = {" Student information "," full name "}, order = 2)
private String name;
@ExcelProperty(value = {" Student information "," Gender "}, order = 3)
private String sex;
@ExcelProperty(value = {" Student information "," Age "}, order = 4)
private String age;
@ExcelProperty(value = {" Student information "," City "}, order = 5)
private String city;
@ExcelProperty(value = {" Student information "," remarks "}, order = 6)
private String remarks;
}Corresponding business code : ditto
Be careful :
@ContentLoopMerge(eachRow = 3) You can merge cells , But it merges by the specified number of rows , It is not possible to merge the same content
@ExcelProperty(value = {" Student information "," remarks "}, It can realize multiple titles , But the title is fixed , It's not dynamic
3、 ... and 、 Custom modification
The result of the export :

Corresponding entity class code :
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Data
@ContentRowHeight(30)
@HeadRowHeight(40)
@ColumnWidth(25)
public class StudentExportVo implements Serializable {
private static final long serialVersionUID = -5809782578272943999L;
@ExcelProperty(value = {" Student information "," School "}, order = 1)
//@ContentLoopMerge(eachRow = 3)
private String school;
@ExcelProperty(value = {" Student information "," full name "}, order = 2)
private String name;
@ExcelProperty(value = {" Student information "," Gender "}, order = 3)
private String sex;
@ExcelProperty(value = {" Student information "," Age "}, order = 4)
private String age;
@ExcelProperty(value = {" Student information "," City "}, order = 5)
private String city;
@ExcelProperty(value = {" Student information "," remarks "}, order = 6)
private String remarks;
}Corresponding business code :
@ApiOperation(value = " Export student information ", notes = " Export student information ")
@PostMapping("/exportStudent")
public void exportStudent(@RequestBody String dynamicTitle, HttpServletResponse response) {
List<StudentExportVo> list = this.getStudentExportVos();
try {
String fileName = " Student information ";
fileName = URLEncoder.encode(fileName, "UTF-8");
response.setContentType("application/json;charset=utf-8");
response.setCharacterEncoding("utf-8");
response.addHeader("Pargam", "no-cache");
response.addHeader("Cache-Control", "no-cache");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
ServletOutputStream output = response.getOutputStream();
// Columns to be merged
int[] mergeColumeIndex = {0};
// Start merging after the second line
int mergeRowIndex = 2;
// Set dynamic title
List<List<String>> headers = this.getHeaders(" Student information " + dynamicTitle);
// The head's strategy
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
// The background is set to white
headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
/*WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short)20);
headWriteCellStyle.setWriteFont(headWriteFont);*/
// Content strategy
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
// You need to specify FillPatternType by FillPatternType.SOLID_FOREGROUND Otherwise, the background color cannot be displayed . The head defaults FillPatternType So you don't have to specify
//contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
// The background is green
//contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
// Set up Word wrap
contentWriteCellStyle.setWrapped(true);
// Set up Vertical center
contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// Set up Horizontal center
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
/*WriteFont contentWriteFont = new WriteFont();
// font size
contentWriteFont.setFontHeightInPoints((short)20);
contentWriteCellStyle.setWriteFont(contentWriteFont);*/
// The strategy is The head is the pattern of the head Content is the style of content Other strategies can be implemented by themselves
HorizontalCellStyleStrategy horizontalCellStyleStrategy =
new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
EasyExcel.write(output, StudentExportVo.class)
.sheet(" Student information ")
.head(headers)
.registerWriteHandler(new ExcelMergeHandler(mergeRowIndex, mergeColumeIndex))
.registerWriteHandler(horizontalCellStyleStrategy)
// .registerWriteHandler(new SimpleColumnWidthStyleStrategy(30))
.registerWriteHandler(new AbstractColumnWidthStyleStrategy() {
@Override
protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
Sheet sheet = writeSheetHolder.getSheet();
int columnIndex = cell.getColumnIndex();
if(columnIndex == 5){
// Column width 100
sheet.setColumnWidth(columnIndex, 10000);
}else {
// Column width 50
sheet.setColumnWidth(columnIndex, 5000);
}
// Row height 40
sheet.setDefaultRowHeight((short) 4000);
}
})
.doWrite(list);
output.flush();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
private List<List<String>> getHeaders(String dynamicTitle) {
List<List<String>> headers=new ArrayList<>();
List<String> schoolHead=new ArrayList<>();
schoolHead.add(dynamicTitle);
schoolHead.add(" School ");
List<String> nameHead=new ArrayList<>();
nameHead.add(dynamicTitle);
nameHead.add(" full name ");
List<String> sexHead=new ArrayList<>();
sexHead.add(dynamicTitle);
sexHead.add(" Gender ");
List<String> ageHead=new ArrayList<>();
ageHead.add(dynamicTitle);
ageHead.add(" Age ");
List<String> cityHead=new ArrayList<>();
cityHead.add(dynamicTitle);
cityHead.add(" City ");
List<String> remarksHead=new ArrayList<>();
remarksHead.add(dynamicTitle);
remarksHead.add(" remarks ");
headers.add(schoolHead);
headers.add(nameHead);
headers.add(sexHead);
headers.add(ageHead);
headers.add(cityHead);
headers.add(remarksHead);
return headers;
}
// Data manufacturing
private List<StudentExportVo> getStudentExportVos() {
List<StudentExportVo> list = new ArrayList<>();
StudentExportVo v1 = new StudentExportVo();
v1.setSchool(" Peking University, ");
v1.setName(" Zhang San ");
v1.setSex(" male ");
v1.setAge("20");
v1.setCity(" Beijing ");
v1.setRemarks(" nothing ");
list.add(v1);
StudentExportVo v2 = new StudentExportVo();
v2.setSchool(" Peking University, ");
v2.setName(" Li Si ");
v2.setSex(" male ");
v2.setAge("22");
v2.setCity(" Shanghai ");
v2.setRemarks(" nothing ");
list.add(v2);
StudentExportVo v3 = new StudentExportVo();
v3.setSchool(" Peking University, ");
v3.setName(" Wang Wu ");
v3.setSex(" Woman ");
v3.setAge("22");
v3.setCity(" Qingdao ");
v3.setRemarks(" nothing ");
list.add(v3);
StudentExportVo v4 = new StudentExportVo();
v4.setSchool(" Tsinghua University ");
v4.setName(" Zhao Liu ");
v4.setSex(" Woman ");
v4.setAge("21");
v4.setCity(" Chongqing ");
v4.setRemarks(" nothing ");
list.add(v4);
StudentExportVo v5 = new StudentExportVo();
v5.setSchool(" Wuhan University ");
v5.setName(" Wang Qiang ");
v5.setSex(" male ");
v5.setAge("24");
v5.setCity(" Changsha ");
v5.setRemarks(" nothing ");
list.add(v5);
StudentExportVo v6 = new StudentExportVo();
v6.setSchool(" Wuhan University ");
v6.setName(" Zhao Yan ");
v6.setSex(" Woman ");
v6.setAge("21");
v6.setCity(" Shenzhen ");
v6.setRemarks(" nothing ");
list.add(v6);
StudentExportVo v7 = new StudentExportVo();
v7.setSchool(" Xiamen University ");
v7.setName(" six thousand ");
v7.setSex(" Woman ");
v7.setAge("21");
v7.setCity(" Guangzhou ");
v7.setRemarks(" nothing ");
list.add(v7);
return list;
}Merge cells with the same content processing class :ExcelMergeHandler
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.util.CellRangeAddress; import java.util.List;
public class ExcelMergeHandler implements CellWriteHandler {
private int[] mergeColumnIndex;
private int mergeRowIndex;
public ExcelMergeHandler() {
}
public ExcelMergeHandler(int mergeRowIndex, int[] mergeColumnIndex) {
this.mergeRowIndex = mergeRowIndex;
this.mergeColumnIndex = mergeColumnIndex;
}
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
// Current row
int curRowIndex = cell.getRowIndex();
// Current column
int curColIndex = cell.getColumnIndex();
if (curRowIndex > mergeRowIndex) {
for (int i = 0; i < mergeColumnIndex.length; i++) {
if (curColIndex == mergeColumnIndex[i]) {
mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
break;
}
}
}
}
/**
* Merge the current cell up
*
* @param writeSheetHolder
* @param cell Current cell
* @param curRowIndex Current row
* @param curColIndex Current column
*/
private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();
// Compare the current cell data with the previous cell data
Boolean dataBool = preData.equals(curData);
// Notice here : Because I decide whether to merge according to the project name , So get the data in the second column of each row and compare it with the data in the first column of the previous row , If equal, merge ,getCell The value of the inside , Is the subscript of the project name column
String s1 = cell.getRow().getCell(0).getStringCellValue();
String s2 = cell.getSheet().getRow(curRowIndex - 1).getCell(0).getStringCellValue();
/*BigDecimal d1 = new BigDecimal(cell.getRow().getCell(0).getNumericCellValue());
BigDecimal d2 = new BigDecimal(cell.getSheet().getRow(curRowIndex - 1).getCell(0).getNumericCellValue());*/
Boolean bool = s1.compareTo(s2) == 0 ? true:false;
// The original
// Boolean bool = cell.getRow().getCell(1).getStringCellValue().equals(cell.getSheet().getRow(curRowIndex - 1).getCell(1).getStringCellValue());
if (dataBool && bool) {
Sheet sheet = writeSheetHolder.getSheet();
List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
boolean isMerged = false;
for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
CellRangeAddress cellRangeAddr = mergeRegions.get(i);
// If the previous cell has been merged , The original merging unit is removed first , Add the merge cell again
if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
sheet.removeMergedRegion(i);
cellRangeAddr.setLastRow(curRowIndex);
sheet.addMergedRegion(cellRangeAddr);
isMerged = true;
}
}
// If the previous cell is not merged , Add a new merging unit
if (!isMerged) {
CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);
sheet.addMergedRegion(cellRangeAddress);
}
}
}
}summary :
1、 When using custom to merge cells with the same content , Annotations in entity classes @ContentLoopMerge Need to get rid of it. , Otherwise it will be affected
2、 Such as content merging in this customized code 、 Set dynamic title 、 Content 、 And the width and font of each column can be set according to the custom policy , For specific usage, please refer to the code notes , Use as needed
3、 You can refer to the official website for more information https://alibaba-easyexcel.github.io/index.html
Last :
I believe that the first two export methods are used by students very skillfully , The focus is on the third custom export method , There are many custom usage scenarios like this , I hope to encounter similar scenarios in the development , Just take the code and use it directly , Take fewer detours .
边栏推荐
- Microservice system design -- message caching service design
- Microservice system design -- Distributed timing service design
- Microservice system design -- microservice invocation design
- neo4j数据库导出
- Leetcode99 week race record
- 013 basics of C language: C pointer
- 流媒体协议初探(MPEG2-TS、RTSP、RTP、RTCP、SDP、RTMP、HLS、HDS、HSS、MPEG-DASH)
- How pychart installs packages
- Basic concepts of neo4j graph database
- 洛谷P4683 [IOI2008] Type Printer 题解
猜你喜欢

es6 0622三

【NIPS 2017】PointNet++:度量空间中点集的深层次特征学习

Qt使用Valgrind分析内存泄漏

How JQ gets the ID name of an element

快速排序(非递归)和归并排序

RTP 发送PS流工具(已经开源)

Microservice system design -- Distributed timing service design

RTP sending PS stream tool (open source)

微信小程序WebSocket使用案例

Tsinghua University open source software mirror website
随机推荐
QT using Valgrind to analyze memory leaks
Experience oceanbase database under win10
Microservice system design -- microservice monitoring and system resource monitoring design
微服务系统设计——统一鉴权服务设计
Redis高可用集群(哨兵、集群)
leetcode-20. Valid parentheses -js version
How JQ gets the reciprocal elements
使用域名转发mqtt协议,避坑指南
STM32关闭PWM输出时,让IO输出固定高或低电平的方法。
Execution rules of pytest framework
齐纳二极管 稳压二极管 SOD123封装 正负区分
Vue学习笔记(五)Vue2页面跳转问题 | vue-router路由概念、分类与使用 | 编程式路由导航 | 路由组件的缓存 | 5种路由导航守卫 | 嵌套路由 | Vue2项目的打包与部署
Codeforces Round #802 (Div. 2)
Unity point light disappears
STM32 reads IO high and low level status
Py2neo basic syntax
Laptop does not have WiFi option solution
Redis high availability cluster (sentry, cluster)
Quick sort (non recursive) and merge sort
【622. 设计循环队列】