EasyExcel下载带下拉框和批注模板

EasyExcel下载带下拉框和批注模板

一、 代码实现

  1. controller下载入口
java 复制代码
/**
     *下载excel模板
     * @author youlu
     * @date 2023/8/14 17:31
     * @param response
     * @param request
     * @return void
     */
    @PostMapping("/downloadTemplate")
    public void downloadExcel(HttpServletResponse response, HttpServletRequest request) throws IOException {
    	//查询字典数据,用于模板下拉框和批注说明使用
        Map<String, List<SysDictData>> dictDataMap = dictDataService.selectDictDataMapByDictTypeAndStatus("worksheet", "0");
        //获取供应商类型,不同供应商类型展示的下拉框和批注会有不一样
        Boolean supplier = getSupplierBoolean();
        ParamThreadLocal.setParam(supplier);
        try {
            long currentTimeMillis = System.currentTimeMillis();
            String name = "工单模板_" + currentTimeMillis;
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode(name, "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), TWorkSheetReadVO.class).inMemory(true)
                    .registerWriteHandler(new CommentWriteHandler(dictDataMap)) //加下拉框的拦截器
                    .registerWriteHandler(new CustomSheetWriteHandler(dictDataMap)) //加批注的拦截器
                    .build();
            WriteSheet writeSheet = EasyExcel.writerSheet("工单模板").build();
            excelWriter.write(Lists.newArrayList(), writeSheet);
            excelWriter.finish();
        } finally {
            ParamThreadLocal.clearParam();
        }
    }
  1. 实体对象
java 复制代码
package com.smy.ows.project.worksheet.domain.vo;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.HeadStyle;
import com.alibaba.excel.converters.date.DateStringConverter;
import com.alibaba.excel.enums.poi.FillPatternTypeEnum;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.smy.framework.base.DesensitizationAnnotation;
import com.smy.ows.project.worksheet.enums.SheetLevelEnums;
import com.smy.ows.project.worksheet.enums.WorkSheetStatus;
import com.smy.ows.util.*;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 客诉工单对象 t_work_sheet
 *
 * @author youlu
 * @date 2023-01-11
 */
@Data
public class TWorkSheetReadVO implements Serializable {
    private static final long serialVersionUID = 5924360788178861972L;

    /**
     * 客诉标题
     */
    @ExcelProperty(value = "客诉标题", index = 0)
    @ColumnWidth(20)
    private String complaintHeadline;
    /**
     * @see SheetLevelEnums
     */
    @ExcelProperty(value = "优先级", index = 1, converter = PriorityIntegerStringConverter.class)
    @ColumnWidth(10)
    @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 40)
    private Integer priority;

    @ExcelProperty(value = "客户姓名", index = 2)
    @ColumnWidth(20)
    @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 40)
    private String custName;

    /**
     * 客户号
     */
    @ExcelProperty(value = "客户号", index = 3)
    @ColumnWidth(20)
    private String custNo;

    @DesensitizationAnnotation
    @ExcelProperty(value = "客户手机号", index = 4)
    @ColumnWidth(20)
    @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 40)
    private String custMobile;

    @DesensitizationAnnotation
    @ExcelProperty(value = "客户身份证", index = 5)
    @ColumnWidth(30)
    private String custIdNo;

    /**
     * 投诉时间
     */
    @ExcelProperty(value = "投诉时间(yyyy-MM-dd HH:mm:ss)", index = 6, converter = DateStringConverter.class)
    @ColumnWidth(40)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date complaintTime;
    //反馈渠道
    @ExcelProperty(value = "反馈渠道", index = 7, converter = ChannelStringStringConverter.class)
    @ColumnWidth(15)
    @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 40)
    private String feedbackChannel;


    @ExcelProperty(value = "工单类型", index = 8, converter = TypeIntegerStringConverter.class)
    @ColumnWidth(15)
    @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 40)
    private Integer type;

    @ExcelProperty(value = "业务类型", index = 9, converter = BizTypeIntegerStringConverter.class)
    @ColumnWidth(15)
    @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 40)
    private Integer bizType;

    @DesensitizationAnnotation
    @ExcelProperty(value = "客户联系方式", index = 10)
    @ColumnWidth(15)
    private String custContactMobile;

    /**
     * 所属资方
     */
    @ExcelProperty(value = "所属资方", index = 11)
    @ColumnWidth(15)
    private String capital;

    @ExcelProperty(value = "投诉内容", index = 12)
    @ColumnWidth(30)
    @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 40)
    private String content;

    /**
     * @see WorkSheetStatus
     */
    @ExcelProperty(value = "工单状态", index = 13, converter = StatusIntegerStringConverter.class)
    @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 40)
    @ColumnWidth(15)
    private Integer status;

    @ExcelProperty(value = "处理结果", index = 14, converter = ResultIntegerStringConverter.class)
    @ColumnWidth(15)
    private Integer result;
    /**
     * 处理情况
     */
    @ExcelProperty(value = "处理情况", index = 15)
    @ColumnWidth(15)
    private String handingInfo;

}
  1. 下拉框拦截器
java 复制代码
package com.smy.ows.util;

import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.handler.context.SheetWriteHandlerContext;
import com.smy.ows.common.core.domain.entity.SysDictData;
import com.smy.ows.common.utils.ParamThreadLocal;
import com.smy.ows.project.worksheet.constant.WorksheetDictTypeConstant;
import com.smy.ows.project.worksheet.enums.WorkSheetStatus;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.util.CellRangeAddressList;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 自定义拦截器.
 *
 * @author youlu
 */
public class CustomSheetWriteHandler implements SheetWriteHandler {

    private  Map<String, List<SysDictData>> notationMap;

    public CustomSheetWriteHandler(Map<String, List<SysDictData>> notationMap) {
        this.notationMap = notationMap;
    }

    @Override
    public void afterSheetCreate(SheetWriteHandlerContext context) {
        DataValidationHelper helper = context.getWriteSheetHolder().getSheet().getDataValidationHelper();
        Map<Integer, String[]> mapDropDown = this.getIntegerMap();
        for (Integer integer : mapDropDown.keySet()) {
        	//起始行,结束行,元素位置(ExcelProperty中的value值)
            CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 65535, integer, integer);
            String[] strings = mapDropDown.get(integer);
            DataValidationConstraint constraint = helper.createExplicitListConstraint(strings);
            DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList);
            context.getWriteSheetHolder().getSheet().addValidationData(dataValidation);
        }
    }

    private Map<Integer, String[]> getIntegerMap() {
     	//map中key对应,ExcelProperty中的value值。map中value对应下拉框的值
        Map<Integer, String[]> mapDropDown = new HashMap<>();
        for (String key : notationMap.keySet()) {
            String[] strings = notationMap.get(key).stream().map(k -> k.getDictLabel()).toArray(String[]::new);
            if (WorksheetDictTypeConstant.WORKSHEET_RESULT.equals(key)) {
                mapDropDown.put(14, strings);
            } else if (WorksheetDictTypeConstant.WORKSHEET_TYPE.equals(key)) {
                mapDropDown.put(8, strings);
            } else if (WorksheetDictTypeConstant.WORKSHEET_BIZ_TYPE.equals(key)) {
                mapDropDown.put(9, strings);
            } else if (WorksheetDictTypeConstant.WORKSHEET_PRIORITY.equals(key)) {
                mapDropDown.put(1, strings);
            } else if (WorksheetDictTypeConstant.WORKSHEET_FEEDBACK_CHANNEL.equals(key)) {
                mapDropDown.put(7, strings);
            }
        }
        Boolean supplier = (Boolean) ParamThreadLocal.getParam();
        if (supplier) {
            //供应商 和 资方的,工单状态只能选择【待分配】
            mapDropDown.put(13, new String[]{WorkSheetStatus.PENDING.getDesc()});
            //其他的工单状态只能选择【待分配】和 【已处理】
        } else {
            mapDropDown.put(13, new String[]{WorkSheetStatus.PENDING.getDesc(), WorkSheetStatus.FINISHED.getDesc()});
        }
        return mapDropDown;
    }
}
  1. 批注拦截器
java 复制代码
package com.smy.ows.util;

import com.alibaba.excel.util.BooleanUtils;
import com.alibaba.excel.write.handler.RowWriteHandler;
import com.alibaba.excel.write.handler.context.RowWriteHandlerContext;
import com.google.common.collect.Lists;
import com.smy.ows.common.core.domain.entity.SysDictData;
import com.smy.ows.project.worksheet.constant.WorksheetDictTypeConstant;
import com.smy.ows.project.worksheet.enums.WorkSheetStatus;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 自定义拦截器.新增注释,第一行头加批注
 *
 * @author Jiaju Zhuang
 */
public class CommentWriteHandler implements RowWriteHandler {

    private final Map<String, List<SysDictData>> notationMap;

    public CommentWriteHandler(Map<String, List<SysDictData>> notationMap) {
        this.notationMap = notationMap;
    }


    @Override
    public void afterRowDispose(RowWriteHandlerContext context) {
        if (BooleanUtils.isTrue(context.getHead())) {
            Sheet sheet = context.getWriteSheetHolder().getSheet();
            Drawing<?> drawingPatriarch = sheet.createDrawingPatriarch();
            // 在第一行 第二列创建一个批注

            String priorityDesc = Optional.ofNullable(notationMap.get(WorksheetDictTypeConstant.WORKSHEET_PRIORITY)).orElse(Lists.newArrayList()).stream()
                    .map(k -> k.getDictValue() + ":" + k.getDictLabel()).collect(Collectors.joining("\r\n"));
             //对应要加批注的元素的ExcelProperty中的value值       
            Comment comment = drawingPatriarch.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short)1, 0, (short)2, 1));
            comment.setString(new XSSFRichTextString(priorityDesc));
            // 将批注添加到单元格对象中
            sheet.getRow(0).getCell(1).setCellComment(comment);
			//对应要加批注的元素的ExcelProperty中的value值
            Comment comment6 = drawingPatriarch.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short)6, 0, (short)2, 1));
            comment6.setString(new XSSFRichTextString("yyyy-MM-dd HH:mm:ss"));
            sheet.getRow(0).getCell(6).setCellComment(comment6);

            String channelDesc = Optional.ofNullable(notationMap.get(WorksheetDictTypeConstant.WORKSHEET_FEEDBACK_CHANNEL)).orElse(Lists.newArrayList()).stream()
                    .map(k -> k.getDictValue() + ":" + k.getDictLabel()).collect(Collectors.joining("\r\n"));
            Comment comment7 = drawingPatriarch.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short) 7, 0, (short) 2, 1));
            comment7.setString(new XSSFRichTextString(channelDesc));
            sheet.getRow(0).getCell(7).setCellComment(comment7);

            String typeDesc = Optional.ofNullable(notationMap.get(WorksheetDictTypeConstant.WORKSHEET_TYPE)).orElse(Lists.newArrayList()).stream()
                    .map(k -> k.getDictValue() + ":" + k.getDictLabel()).collect(Collectors.joining("\r\n"));
            Comment comment8 = drawingPatriarch.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short) 8, 0, (short) 2, 1));
            comment8.setString(new XSSFRichTextString(typeDesc));
            sheet.getRow(0).getCell(8).setCellComment(comment8);

            String bizDesc = Optional.ofNullable(notationMap.get(WorksheetDictTypeConstant.WORKSHEET_BIZ_TYPE)).orElse(Lists.newArrayList()).stream()
                    .map(k -> k.getDictValue() + ":" + k.getDictLabel()).collect(Collectors.joining("\r\n"));
            Comment comment9 = drawingPatriarch.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short) 9, 0, (short) 2, 1));
            comment9.setString(new XSSFRichTextString(bizDesc));
            sheet.getRow(0).getCell(9).setCellComment(comment9);


            String statusDesc = Arrays.stream(WorkSheetStatus.values()).map(k -> k.getCode() + ":" + k.getDesc()).collect(Collectors.joining("\r\n"));
            Comment comment13 = drawingPatriarch.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short) 13, 0, (short) 2, 1));
            comment13.setString(new XSSFRichTextString(statusDesc));
            sheet.getRow(0).getCell(13).setCellComment(comment13);

            String resultDesc = Optional.ofNullable(notationMap.get(WorksheetDictTypeConstant.WORKSHEET_RESULT)).orElse(Lists.newArrayList()).stream()
                    .map(k -> k.getDictValue() + ":" + k.getDictLabel()).collect(Collectors.joining("\r\n"));
            Comment comment14 = drawingPatriarch.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short) 14, 0, (short) 2, 1));
            comment14.setString(new XSSFRichTextString(resultDesc));
            sheet.getRow(0).getCell(14).setCellComment(comment14);

        }
    }
}

二、实现效果

  1. 批注效果
  2. 下拉框效果

三、参考文档

easyExcel自定义拦截器

相关推荐
WaaTong2 分钟前
Java反射
java·开发语言·反射
九圣残炎36 分钟前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
wclass-zhengge38 分钟前
Netty篇(入门编程)
java·linux·服务器
Re.不晚1 小时前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
雷神乐乐1 小时前
Maven学习——创建Maven的Java和Web工程,并运行在Tomcat上
java·maven
码农派大星。1 小时前
Spring Boot 配置文件
java·spring boot·后端
顾北川_野1 小时前
Android 手机设备的OEM-unlock解锁 和 adb push文件
android·java
江深竹静,一苇以航1 小时前
springboot3项目整合Mybatis-plus启动项目报错:Invalid bean definition with name ‘xxxMapper‘
java·spring boot
confiself2 小时前
大模型系列——LLAMA-O1 复刻代码解读
java·开发语言
Wlq04152 小时前
J2EE平台
java·java-ee