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

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

一、 代码实现

  1. controller下载入口
/**
     *下载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. 实体对象
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. 下拉框拦截器
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. 批注拦截器
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自定义拦截器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/374327.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python下字符串操作

目录 一&#xff1a;连接字符串 二&#xff1a;字符串切片 三&#xff1a;字符串查找 四&#xff1a;字符串替换 五&#xff1a;字符串大小写转换 六&#xff1a;字符串分割 七&#xff1a;字符串去除空格和特殊字符 八&#xff1a;字符串长度 九&#xff1a;检查字符…

【CSS】css如何实现字体大小小于12px?

【CSS】css如何实现字体大小小于12px? 问题解决方案transform: scale(0.5)&#xff08;常用&#xff09;SVG 矢量图设置text 问题 文字需要显示为12px&#xff0c;但是小于12px的&#xff0c;浏览器是显示不来的 解决方案 transform: scale(0.5)&#xff08;常用&#xff0…

比较迭代次数最小的结构

( A, B )---6*30*2---( 1, 0 )( 0, 1 ) 让网络的输入有6个节点&#xff0c;训练集AB各由6张二值化的图片组成&#xff0c;让B全是0&#xff0c; 所以差值结构的尺寸为6*6&#xff0c;在这6*6的范围中迭代次数最小的结构是什么&#xff1f; 迭代次数 迭代次数 - - - 12842…

OpenWrt之有线中继无缝漫游mesh组网详解

文章目录 前言什么是MeshMesh的优点检查OpenWrt的设置选项设置WIFI设置KVRNAS ID设置教程 移动域 / Mobility Domain设置教程 重关联截止时间 / Reassociation Deadline设置教程 FT协议 / Fast Transition / FT protocol设置教程 本地生成 PMK / Generate PMK locally设置教程 …

java设计模式之中介者模式

中介者模式&#xff08;Mediator Pattern&#xff09; 基本介绍 中介者模式&#xff0c;用一个中介对象来封装一系列的对象交互。中介者使各个对象不需要显式地相互引用&#xff0c;从而使其解耦松散。而且可以独立地改变它们之间的交互。中介者模式属于行为型模式。比如MVC模…

vue3+echarts:Vue中使用echarts从后端获取数据并赋值显示

//由于前后端交互,所以使用axios发送请求 const Count ref(null); //设备种类数值 const Name ref(null); //设备种类名称 //设备种类 饼图 const pieChart () > {const getpieChart echarts.init(document.getElementById("deviceKind"));// 创建图标getpieC…

Windows11安装运行Linux(Ubuntu)

一、安装windows支持 输入windows打开界面 选择虚拟机监控程序平台、适用于linux的子系统、虚拟机平台 在 Windows 系统中&#xff0c;"虚拟机平台"和"虚拟机监控程序平台"是两个与虚拟化相关的功能&#xff0c;但它们各自有着不同的作用和用途。 虚拟机…

【FPGA】高云FPGA之IP核的使用->PLL锁相环

FPGA开发流程 1、设计定义2、设计输入3、分析和综合4、功能仿真5、布局布线6、时序仿真7、IO分配以及配置文件&#xff08;bit流文件&#xff09;的生成8、配置&#xff08;烧录&#xff09;FPGA9、在线调试 1、设计定义 使用高云内置IP核实现多路不同时钟输出 输入时钟50M由晶…

【PostgreSQL内核学习(二十六) —— (共享数据缓冲区)】

共享数据缓冲区 概述共享数据缓冲区管理共享缓冲区管理的核心功能包括&#xff1a; 共享数据缓冲区的组织结构初始化共享缓冲池BufferDesc 结构体InitBufferPool 函数 如何确定请求的数据页面是否在缓冲区中&#xff1f;BufferTag 结构体RelFileNode 结构体ForkNumber 结构体Re…

高速接口PCB布局指南(二)通用高速信号布线

高速接口PCB布局指南&#xff08;二&#xff09;通用高速信号布线 1.PCB材料编织2.高速信号布线长度3.高速信号布线长度匹配4.高速信号参考平面 tips&#xff1a;资料主要来自网络&#xff0c;仅供学习使用。 1.PCB材料编织 在常见的 PCB 材料上为差分信号布线时&#xff0c;…

【Iceberg学习二】Branch和Tag在Iceberg中的应用

Iceberg 表元数据保持一个快照日志&#xff0c;记录了对表所做的更改。快照在 Iceberg 中至关重要&#xff0c;因为它们是读者隔离和时间旅行查询的基础。为了控制元数据大小和存储成本&#xff0c;Iceberg 提供了快照生命周期管理程序&#xff0c;如 expire_snapshots&#xf…

知识图谱问答:构建人机自然交互的桥梁

目录 前言1 基本概念1.1 图灵测试1.2 特定领域的问答系统1.3 知识图谱问答1.4 典型应用与系统 2 智能问答系统分类2.1 问句类型分类2.2 系统来源分类 3 实现知识图谱问答主要技术方法3.1 基于问句模板的方法3.2 基于语义解析的方法3.3 基于检索排序的方法3.4 基于深度学习的方法…

代码随想录算法训练营第十二天 | 239. 滑动窗口最大值,347.前 K 个高频元素 [栈与队列篇]

代码随想录算法训练营第十二天 LeetCode 239. 滑动窗口最大值题目描述思路参考代码总结 LeetCode 347.前 K 个高频元素题目描述思路参考代码 LeetCode 239. 滑动窗口最大值 题目链接&#xff1a;239. 滑动窗口最大值 文章讲解&#xff1a;代码随想录#239. 滑动窗口最大值 视频讲…

现货黄金突破2050美元 后续还会涨吗?

一两个月以前&#xff0c;受美联储降息预期影响&#xff0c;现货黄金价格一度强势上涨&#xff0c;并且刷新历史新高。随后&#xff0c;市场不断消化降息预期&#xff0c;金价逐步回落&#xff0c;盘中一度下探2000大关。在今年的一季度&#xff0c;行情再度发生变化&#xff0…

华为5G沸沸扬扬!那你知道三防平板网络是什么类型呢!

近日&#xff0c;华为在5G的事件在热搜上可是着实的火了一把啊&#xff01;让小编想起一款来自亿道信息EM-I22K-5G的一款三防平板产品&#xff0c;你知道是什么网络类型的呢&#xff1f; EM-I22K-5G 不知道&#xff1f;没关系呀&#xff01;小编可以为你普及亿道信息EM-I22K-5G…

寒假作业-day5

TCP和UDP区别 TCP ----稳定 1、提供面向连接的&#xff0c;可靠的数据传输服务&#xff1b; 2、传输过程中&#xff0c;数据无误、数据无丢失、数据无失序、数据无重复&#xff1b; 3、数据传输效率低&#xff0c;耗费资源多&#xff1b; 4、数据收发是不同步的&#xff1b; UD…

软件价值8-站点连通性检查

站点连通性检查&#xff0c;即看网站是否能访问得通&#xff0c;实用价值不大&#xff0c;不过用来作软件应用入门还不错。 代码&#xff1a; import urllib.request import tkinter as tkdef test_connectivity():window tk.Tk()window.geometry(600x400)window.resizable(F…

性能实测:分布式存储 ZBS 与集中式存储 HDS 在 Oracle 数据库场景表现如何

作者&#xff1a;深耕行业的 SmartX 金融团队 金鑫 在金融客户的基础架构环境中&#xff0c;HDS 是一种被广泛使用的存储解决方案。作为集中式存储的代表之一&#xff0c;HDS 拥有高性能、高可用性和可扩展性的企业级存储特点&#xff0c;适用于实时数据处理、虚拟化和灾难备份…

阿里云游戏服务器一年费用多少?

阿里云游戏服务器租用价格表&#xff1a;4核16G服务器26元1个月、146元半年&#xff0c;游戏专业服务器8核32G配置90元一个月、271元3个月&#xff0c;阿里云服务器网aliyunfuwuqi.com分享阿里云游戏专用服务器详细配置和精准报价&#xff1a; 阿里云游戏服务器租用价格表 阿…

论文阅读-Transformer-based language models for software vulnerability detection

「分享了一批文献给你&#xff0c;请您通过浏览器打开 https://www.ivysci.com/web/share/biblios/D2xqz52xQJ4RKceFXAFaDU/ 您还可以一键导入到 ivySCI 文献管理软件阅读&#xff0c;并在论文中引用 」 本文主旨&#xff1a;本文提出了一个系统的框架来利用基于Transformer的语…