EasyExcel导出带下拉选数据的Excel数据导入模板

2023-11-23 03:40

本文主要是介绍EasyExcel导出带下拉选数据的Excel数据导入模板,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

#因为项目中需要导入一些信息,但是这些信息比较不常见,且在项目字典数据中维护有这些数据,所以在导出模板的时候,把这些数据一并导出,可以减少用户的编写,避免在导入的时候因为数据错误,发生一些业务问题

直接开始​​​​​​​

一、首先引入依赖   easyexcel依赖

<!--easyexcel依赖--><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.10</version></dependency>

二、创建自定义注解

import java.lang.annotation.*;/*** 标注导出的列为下拉框类型,并为下拉框设置内容*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelSelected {/*** 固定下拉内容*/String[] source() default {};/*** 动态下拉内容*/Class<? extends ExcelDynamicSelect>[] sourceClass() default {};/*** 设置下拉框的起始行,默认为第二行*/int firstRow() default 1;/*** 设置下拉框的结束行,默认为最后一行*/int lastRow() default 0x10000;
}

三、解析自定义注解接口


public interface ExcelDynamicSelect {/*** 获取动态生成的下拉框可选数据* @return 动态生成的下拉框可选数据*/String[] getSource();
}

四、创建一个实体类,(这边以我项目内的演示)

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import lombok.Data;
import org.springblade.basicdata.service.impl.DeptTemplateServiceImpl;
import org.springblade.basicdata.service.impl.SchoolTemplateServiceImpl;
import org.springblade.basicdata.service.impl.StationlateServiceImpl;
import org.springblade.basicdata.service.impl.ZgTypeslateServiceImpl;import java.io.Serializable;@Data
@HeadRowHeight(20)
@ContentRowHeight(18)
public class TeacherExcel implements Serializable {private static final long serialVersionUID = 1L;/*** 职工编号*/@ExcelProperty(index = 0, value = "职工编号")@ColumnWidth(20)private String no;/*** 姓名*/@ExcelProperty(index = 1, value = "姓名")@ColumnWidth(30)private String name;/*** 身份证*/@ExcelProperty(index = 2, value = "身份证号")@ColumnWidth(25)private String idCard;/*** 电话*/@ExcelProperty(index = 3, value = "联系电话")@ColumnWidth(15)private String phone;/*** 学校id*///需要自定义实现  SchoolTemplateServiceImpl,下面有具体的实现方式@ExcelSelected(sourceClass = SchoolTemplateServiceImpl.class)@ExcelProperty(index = 4, value = "校区")@ColumnWidth(45)private String schoolName;/*** 部门*///需要自定义实现  DeptTemplateServiceImpl,下面有具体的实现方式@ExcelSelected(sourceClass = DeptTemplateServiceImpl.class)@ExcelProperty(index = 5, value = "部门")@ColumnWidth(45)private String bumenName;/*** 岗位类别*///需要自定义实现  StationlateServiceImpl,下面有具体的实现方式@ExcelSelected(sourceClass = StationlateServiceImpl.class)@ExcelProperty(index = 6, value = "岗位类别")@ColumnWidth(15)private String station;/*** 职工类型*///需要自定义实现  ZgTypeslateServiceImpl,下面有具体的实现方式@ExcelSelected(sourceClass = ZgTypeslateServiceImpl.class)@ExcelProperty(index = 7, value = "职工类型")@ColumnWidth(15)private String zhigongleibie;/*** 备注*/@ExcelProperty(index = 8, value = "备注")@ColumnWidth(15)private String remarks;}

五、重点是以下的代码

1、以岗位类型为例,展示数据的实现方式

创建StationlateServiceImpl实现类,实现方法 为我自己的业务需求,你们可以根据你们的情况去修改,这边返回给注解的是一个字符串的数组,也就是需要导出的下拉选数据


import java.util.List;
import java.util.stream.Collectors;/*** 岗位类别下拉选数据实现类*/
public class StationlateServiceImpl implements ExcelDynamicSelect {private static IDictClient dictClient;static {dictClient = SpringUtil.getBean(IDictClient.class);}@Overridepublic String[] getSource() {R<List<Dict>> dictClientList =dictClient.getList(DictEnum.POST_TYPE.getName());if(Func.isNotEmpty(dictClientList) && dictClientList.getCode() == 200){if(Func.isNotEmpty(dictClientList.getData())){return Func.toStrArray(dictClientList.getData().stream().map(Dict::getDictValue).collect(Collectors.joining(",")));}}return new String[0];}
}

Func.toStrArray方法就是讲给定的逗号拼接的字符串转为字符串数组,这个百度一下,一大堆

六、EasyExcelUtil工具类

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.write.metadata.WriteSheet;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;@Slf4j
public class EasyExcelUtil {/*** 创建即将导出的sheet页(sheet页中含有带下拉框的列)* @param head 导出的表头信息和配置* @param sheetNo sheet索引* @param sheetName sheet名称* @param <T> 泛型* @return sheet页*/public static <T> WriteSheet writeSelectedSheet(Class<T> head, Integer sheetNo, String sheetName) {Map<Integer, ExcelSelectedResolve> selectedMap = resolveSelectedAnnotation(head);return EasyExcel.writerSheet(sheetNo, sheetName).head(head).registerWriteHandler(new SelectedSheetWriteHandler(selectedMap)).build();}/*** 解析表头类中的下拉注解* @param head 表头类* @param <T> 泛型* @return Map<下拉框列索引, 下拉框内容> map*/private static <T> Map<Integer, ExcelSelectedResolve> resolveSelectedAnnotation(Class<T> head) {Map<Integer, ExcelSelectedResolve> selectedMap = new HashMap<>();// getDeclaredFields(): 返回全部声明的属性;getFields(): 返回public类型的属性Field[] fields = head.getDeclaredFields();for (int i = 0; i < fields.length; i++){Field field = fields[i];// 解析注解信息ExcelSelected selected = field.getAnnotation(ExcelSelected.class);ExcelProperty property = field.getAnnotation(ExcelProperty.class);if (selected != null) {ExcelSelectedResolve excelSelectedResolve = new ExcelSelectedResolve();String[] source = excelSelectedResolve.resolveSelectedSource(selected);if (source != null && source.length > 0){excelSelectedResolve.setSource(source);excelSelectedResolve.setFirstRow(selected.firstRow());excelSelectedResolve.setLastRow(selected.lastRow());if (property != null && property.index() >= 0){selectedMap.put(property.index(), excelSelectedResolve);} else {selectedMap.put(i, excelSelectedResolve);}}}}return selectedMap;}public static boolean isIDNumber(String IDNumber) {if (IDNumber == null || "".equals(IDNumber)) {return false;}// 定义判别用户身份证号的正则表达式(15位或者18位,最后一位可以为字母)String regularExpression = "(^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|" +"(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)";//假设18位身份证号码:41000119910101123X  410001 19910101 123X//^开头//[1-9] 第一位1-9中的一个      4//\\d{5} 五位数字           10001(前六位省市县地区)//(18|19|20)                19(现阶段可能取值范围18xx-20xx年)//\\d{2}                    91(年份)//((0[1-9])|(10|11|12))     01(月份)//(([0-2][1-9])|10|20|30|31)01(日期)//\\d{3} 三位数字            123(第十七位奇数代表男,偶数代表女)//[0-9Xx] 0123456789Xx其中的一个 X(第十八位为校验值)//$结尾//假设15位身份证号码:410001910101123  410001 910101 123//^开头//[1-9] 第一位1-9中的一个      4//\\d{5} 五位数字           10001(前六位省市县地区)//\\d{2}                    91(年份)//((0[1-9])|(10|11|12))     01(月份)//(([0-2][1-9])|10|20|30|31)01(日期)//\\d{3} 三位数字            123(第十五位奇数代表男,偶数代表女),15位身份证不含X//$结尾boolean matches = IDNumber.matches(regularExpression);//判断第18位校验值if (matches) {if (IDNumber.length() == 18) {try {char[] charArray = IDNumber.toCharArray();//前十七位加权因子int[] idCardWi = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};//这是除以11后,可能产生的11位余数对应的验证码String[] idCardY = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};int sum = 0;for (int i = 0; i < idCardWi.length; i++) {int current = Integer.parseInt(String.valueOf(charArray[i]));int count = current * idCardWi[i];sum += count;}char idCardLast = charArray[17];int idCardMod = sum % 11;if (idCardY[idCardMod].toUpperCase().equals(String.valueOf(idCardLast).toUpperCase())) {return true;} else {return false;}} catch (Exception e) {e.printStackTrace();return false;}}return false;}return matches;}public static  boolean isMobile(String phone){Pattern p = null;Matcher m = null;boolean b = false;// 验证手机号String s2="^[1](([3|5|6|7|8|9][\\d])|([4][4,5,6,7,8,9])|([6][2,5,6,7])|([7][^9])|([9][1,8,9]))[\\d]{8}$";if(StringUtils.isNotBlank(phone)){p = Pattern.compile(s2);m = p.matcher(phone);b = m.matches();}return b;}}

七、导出接口

/** 教师入职Excel模板导出 */@ApiLog("教师入职Excel模板导出")@GetMapping("export-template")@ApiOperationSupport(order = 7)@ApiOperation(value = "教师入职Excel模板导出")public void exportTeacher(HttpServletResponse response, HttpServletRequest request) {String filename = "教师入职信息导入模板";try {String userAgent = request.getHeader("User-Agent");if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {// 针对IE或者以IE为内核的浏览器:filename = java.net.URLEncoder.encode(filename, "UTF-8");} else {// 非IE浏览器的处理:filename = new String(filename.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);}response.setContentType("application/vnd.ms-excel");response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"", filename + Func.formatDateTime(new Date()) + ".xlsx"));response.setHeader("Cache-Control", "no-cache");response.setHeader("Pragma", "no-cache");response.setDateHeader("Expires", -1);response.setCharacterEncoding("UTF-8");ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();WriteSheet writeSheet = EasyExcelUtil.writeSelectedSheet(TeacherExcel.class, 0, "教师入职信息数据表");excelWriter.write(new ArrayList<String>(), writeSheet);excelWriter.finish();} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}

八、导出效果图

完结,有问题欢迎指正

这篇关于EasyExcel导出带下拉选数据的Excel数据导入模板的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/415080

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

Hadoop集群数据均衡之磁盘间数据均衡

生产环境,由于硬盘空间不足,往往需要增加一块硬盘。刚加载的硬盘没有数据时,可以执行磁盘数据均衡命令。(Hadoop3.x新特性) plan后面带的节点的名字必须是已经存在的,并且是需要均衡的节点。 如果节点不存在,会报如下错误: 如果节点只有一个硬盘的话,不会创建均衡计划: (1)生成均衡计划 hdfs diskbalancer -plan hadoop102 (2)执行均衡计划 hd

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi