1、公式
package com.web.report.handler;
import com.alibaba.excel.context.WriteContext;
import com.alibaba.excel.metadata.csv.CsvCellStyle;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.util.List;
@Slf4j
public class CustomCellWriteHandler implements CellWriteHandler {
@Override
public void afterCellDispose(CellWriteHandlerContext context) {
Cell cell = context.getCell();
// 这里可以对cell进行任何操作
int rowIndex = cell.getRowIndex();
String cellValue = cell.getStringCellValue();
if (cellValue.startsWith("$$") && cellValue.endsWith("$$")) {
String statisType = cellValue.substring(2, cellValue.length() - 2);
String columnTitle = convertToTitle(cell.getColumnIndex() + 1);
switch (statisType) {
case "min":
cell.setCellFormula("min(" + columnTitle + (rowIndex + 5) + ":" + columnTitle + 1000000 + ")");
break;
case "max":
cell.setCellFormula("max(" + columnTitle + (rowIndex + 4) + ":" + columnTitle + 1000000 + ")");
break;
// case "testNum":
// cell.setCellFormula("COUNTA(A" + (rowIndex + 1 + 3) + ":A" + 1000000 + ")");
// break;
// case "median":
// cell.setCellFormula("MEDIAN(" + columnTitle + (rowIndex + 3) + ":" + columnTitle + 1000000 + ")");
// break;
case "avg":
cell.setCellFormula("IF(COUNT(" + columnTitle + (rowIndex + 3) + ":" + columnTitle + 1000000 + ")>0,AVERAGE(" + columnTitle + (rowIndex + 3) + ":" + columnTitle + 1000000 + "),0)");
break;
case "stddev":
cell.setCellFormula("IF(COUNT(" + columnTitle + (rowIndex + 2) + ":" + columnTitle + 1000000 + ")>1,STDEV(" + columnTitle + (rowIndex + 2) + ":" + columnTitle + 1000000 + "),0)");
break;
}
} else {
try {
Double value = Double.valueOf(cellValue);
cell.setCellValue(value);
} catch (Exception e) {
}
}
}
public String convertToTitle(int n) {
StringBuilder sb = new StringBuilder();
while(n > 0){
n--; // 重点
sb.append((char)(n % 26 + 'A'));
n /= 26;
}
sb.reverse();
return sb.toString();
}
}
2、合并
package com.web.report.handler;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
public class CustomMergeStrategy extends AbstractMergeStrategy {
private Integer columnLength;
private Sheet sheet;
public CustomMergeStrategy(Integer columnLength) {
this.columnLength = columnLength;
}
// 合并成一个单元格
private void mergeCommonColumn(Integer rowIndexStart, Integer rowIndexEnd,Integer columnIndexStart,Integer columnIndexEnd ) {
CellRangeAddress cellRangeAddress = new CellRangeAddress(rowIndexStart, rowIndexEnd, columnIndexStart, columnIndexEnd);
sheet.addMergedRegionUnsafe(cellRangeAddress);
}
@Override
protected void merge(Sheet sheet, Cell cell, Head head, Integer integer) {
this.sheet = sheet;
if (cell.getRowIndex() < 13) {
this.mergeCommonColumn(cell.getRowIndex(),cell.getRowIndex(),1,this.columnLength-1);
}
}
}
3、样式
package com.web.report.style;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import org.apache.poi.ss.usermodel.*;
public class StyleUtils {
/**
* 标题样式
* @return
*/
public static WriteCellStyle getHeadStyle(){
// 头的策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
// 背景颜色
// headWriteCellStyle.setFillForegroundColor(IndexedColors.LIGHT_TURQUOISE1.getIndex());
// headWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
// 字体
// WriteFont headWriteFont = new WriteFont();
// headWriteFont.setFontName("宋体");//设置字体名字
// headWriteFont.setFontHeightInPoints((short)14);//设置字体大小
// headWriteFont.setBold(true);//字体加粗
// headWriteCellStyle.setWriteFont(headWriteFont); //在样式用应用设置的字体;
//
// // 样式
// headWriteCellStyle.setBorderBottom(BorderStyle.THIN);//设置底边框;
// headWriteCellStyle.setBottomBorderColor((short) 0);//设置底边框颜色;
// headWriteCellStyle.setBorderLeft(BorderStyle.THIN); //设置左边框;
// headWriteCellStyle.setLeftBorderColor((short) 0);//设置左边框颜色;
// headWriteCellStyle.setBorderRight(BorderStyle.THIN);//设置右边框;
// headWriteCellStyle.setRightBorderColor((short) 0);//设置右边框颜色;
// headWriteCellStyle.setBorderTop(BorderStyle.THIN);//设置顶边框;
// headWriteCellStyle.setTopBorderColor((short) 0); //设置顶边框颜色;
//
// headWriteCellStyle.setWrapped(true); //设置自动换行;
headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);//设置水平对齐的样式为居中对齐;
headWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); //设置垂直对齐的样式为居中对齐;
headWriteCellStyle.setShrinkToFit(true);//设置文本收缩至合适
return headWriteCellStyle;
}
/**
* 内容样式
* @return
*/
public static WriteCellStyle getContentStyle(){
// 内容的策略
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
// 背景绿色
// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
// contentWriteCellStyle.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex());
// contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
// 设置字体
// WriteFont contentWriteFont = new WriteFont();
// contentWriteFont.setFontHeightInPoints((short) 12);//设置字体大小
// contentWriteFont.setFontName("宋体"); //设置字体名字
// contentWriteCellStyle.setWriteFont(contentWriteFont);//在样式用应用设置的字体;
//
// //设置样式;
// contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);//设置底边框;
// contentWriteCellStyle.setBottomBorderColor((short) 0);//设置底边框颜色;
// contentWriteCellStyle.setBorderLeft(BorderStyle.THIN); //设置左边框;
// contentWriteCellStyle.setLeftBorderColor((short) 0);//设置左边框颜色;
// contentWriteCellStyle.setBorderRight(BorderStyle.THIN);//设置右边框;
// contentWriteCellStyle.setRightBorderColor((short) 0);//设置右边框颜色;
// contentWriteCellStyle.setBorderTop(BorderStyle.THIN);//设置顶边框;
// contentWriteCellStyle.setTopBorderColor((short) 0); ///设置顶边框颜色;
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);// 水平居中
contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);// 垂直居中
contentWriteCellStyle.setWrapped(true); //设置自动换行;
// contentWriteCellStyle.setShrinkToFit(true);//设置文本收缩至合适
return contentWriteCellStyle;
}
}
4、 注解
package com.web.report.annotation;
import com.web.report.enums.HeaderLabelTypeEnum;
import com.web.report.enums.HeaderTypeEnum;
import java.lang.annotation.*;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface TableHeader {
/**
* 表头显示名称
* @return
*/
String[] label() default {"."};
/**
* 正数加在对开头,负数加在结尾
* @return
*/
int index() default 1;
/**
* 表头类型
* @return
*/
HeaderTypeEnum headerType() default HeaderTypeEnum.NORMAL;
HeaderLabelTypeEnum labelType() default HeaderLabelTypeEnum.NORMAL;
}
5、枚举
package com.web.report.enums;
public enum HeaderLabelTypeEnum {
NORMAL, CONFIG
}
package com.web.report.enums;
public enum HeaderTypeEnum {
NORMAL, FLAT
}
6、各种DTO
(1)TableHeaderConfigDTO
package com.web.report.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class TableHeaderConfigDTO {
private List labels;
private String value;
}
(2)WorkReportConditionDTO
package com.web.report.dto;
import com.web.enums.WorkProcedureResultEnum;
import com.web.report.annotation.TableHeader;
import com.web.report.enums.HeaderLabelTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class WorkReportConditionDTO {
@TableHeader(labelType = HeaderLabelTypeEnum.CONFIG, index = 1)
private TableHeaderConfigDTO ConditionDTO;
}
(3)WorkReportDTOT
package com.web.report.dto;
import com.web.report.annotation.TableHeader;
import com.web.report.enums.HeaderTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class WorkReportDTOT {
@TableHeader(index = 1, headerType= HeaderTypeEnum.FLAT)
private List serialNo;
@TableHeader(index = 2, headerType= HeaderTypeEnum.FLAT)
private List sequence;
@TableHeader(index = 3, headerType= HeaderTypeEnum.FLAT)
private List bin;
@TableHeader(index = 4, headerType= HeaderTypeEnum.FLAT)
private List workReportProcedureDTOS;
}
4、使用
@Component
@Slf4j
public class WorkReportUtilT {
@Autowired
private ProjectManageService projectManageService;
@Autowired
private WorkManageService workManageService;
@Autowired
private WorkResultService WorkResultService;
private static final Map code2Index = new HashMap<>();
private static final Map tmMap = new HashMap<>();
private static final List conditionsList = new ArrayList<>();
private static final List conditionValueList = new ArrayList<>();
public void buildReport(WorkManageVO work, String filePath) {
// 1.初始话报告内容
XinGanXianWorkReportDTOT workReportDTO = null;
// 2.判断文件是否存在,如果没有文件那就创建文件并添加表头,表头与数据分开写,防止表头合并
File file = new File(filePath);
if (!file.exists()) {
// 测试结果和头部
workReportDTO = buildWorkReportDTO(work, false);
List> listHead = buildReportHead(workReportDTO);
//
ExcelWriter excelWriter = EasyExcel.write(file).build();
// 合并单元格
CustomMergeStrategy customMergeStrategy = new CustomMergeStrategy(listHead.size());
// 只写测试结果头部
excelWriter.write(new ArrayList<>(),
EasyExcel.writerSheet(0).head(listHead).
registerWriteHandler(new CustomCellWriteHandler()).
registerWriteHandler(customMergeStrategy)
.build());
//这一步很关键,不然文件会损坏
excelWriter.finish();
excelWriter.close();
}
// 3. 报告内容为空的话,构建
if(workReportDTO == null){
workReportDTO = buildWorkReportDTO(work, false);
}
// 4.往文件中追加数据
List