Excel表格导入/导出数据工具类
Excel表格导入/导出数据工具
这里以java语言为类,实现一个简单且较通用的Excel表格数据导入工具类。
- 自定义注解 ExcelColumn
- 写导入工具类 ExcelImportUtil
自定义注解 ExcelColumn
@Retention(RetentionPolicy.RUNTIME)
@Target({java.lang.annotation.ElementType.FIELD})
public @interface ExcelColumn {/*** 字段的含义*/String name();/*** 配置列的名称,对应A,B,C,D....*/String column();/*** 是否导出数据*/boolean isExport() default true;
}
定义数据类
/*** 数据对象* @author*/
@Getter
@Setter
@ToString
public class DataDTO implements Serializable {@ExcelColumn(name = "*XXX", column = "A")private String a;@ExcelColumn(name = "xxx", column = "B")private String b;@ExcelColumn(name = "xxx", column = "C")private String c;// 导入时记录失败原因的字段 按需取private String errorMsg;}
}
Excel表格导入导出工具类代码:
@Slf4j
public class ExcelCustomUtil<T> {private static final String SUFFIX = "XLS";protected Class<T> clazz;public ExcelWithPicUtil(Class<T> clazz) {this.clazz = clazz;}/*** 批量导入, 每个sheet 数据格式一致* @param input* @param ignore 忽略前多少行,也就是从哪行开始读取数据* @return* @throws Exception*/public List<T> importBatch(InputStream input, Integer ignore, String suffix) throws Exception {List<T> newList = new ArrayList<>();Workbook workbook;if (SUFFIX.equalsIgnoreCase(suffix)) {workbook = new HSSFWorkbook(input);} else {workbook = new XSSFWorkbook(input);}Sheet sheet = workbook.getSheetAt(0);if(null != sheet){List<T> importProcessor = importProcessor(sheet, ignore);newList.addAll(importProcessor);}return newList;}/*** @param sheet* @param ignoreRow, 忽略前多少行* @return* @throws Exception*/protected List<T> importProcessor(Sheet sheet, Integer ignoreRow) throws Exception {log.info("执行导入操作");int maxCol = 0;List<T> list = new ArrayList<T>();int rows = sheet.getPhysicalNumberOfRows();log.info("importProcessor rows:{}", rows);if (rows > 0) {// 有数据时才处理List<Field> allFields = getMappedFiled(clazz, null);// 定义一个map用于存放列的序号和field.Map<Integer, Field> fieldsMap = new HashMap<>(16);for (Field field : allFields) {// 将有注解的field存放到map中.if (field.isAnnotationPresent(ExcelColumn.class)) {ExcelColumn attr = field.getAnnotation(ExcelColumn.class);// 获得列号int col = getExcelCol(attr.column());maxCol = Math.max(col, maxCol);fieldsMap.put(col, field);}}log.info("importProcessor fieldsMap:{}, maxCol:{}", JSON.toJSONString(fieldsMap), maxCol);// 默认第二行开始为数据行if (ignoreRow == null) {ignoreRow = 1;}for (int i = ignoreRow; i < rows; i++) {// 从第2行开始取数据,默认第一行是表头.Row row = sheet.getRow(i);boolean rowEmpty = isRowEmpty(row);log.info("importProcessor row:{}, rowEmpty:{}", i, rowEmpty);if (rowEmpty) {continue;}T entity = null;for (int j = 0; j <= maxCol; j++) {// 如果不存在实例则新建.entity = (entity == null ? clazz.newInstance() : entity);// 从map中得到对应列的field.Field field = fieldsMap.get(j);if (field == null) {continue;}// 取得类型,并根据对象类型设置值.Class<?> fieldType = field.getType();ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);Cell cell = row.getCell(j);if (cell != null) {CellType cellType = cell.getCellType();String c = getCellValue(cellType, cell);log.info("importProcessor row:{}, col:{}, cellType:{}, c:{}", i, j, cellType, c);try {if (String.class == fieldType){field.set(entity, c.trim());} else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) {Double dou = Double.parseDouble(c);field.set(entity, dou.intValue());} else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) {field.set(entity, Long.valueOf(c));} else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) {field.set(entity, Float.valueOf(c));} else if ((Short.TYPE == fieldType) || (Short.class == fieldType)) {field.set(entity, Short.valueOf(c));} else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) {field.set(entity, Double.valueOf(c));} else if (Character.TYPE == fieldType) {if ((c != null) && (c.length() > 0)) {field.set(entity, Character.valueOf(c.charAt(0)));}} else if (Date.class == fieldType) {}} catch (Exception e) {e.printStackTrace();}}}if (entity != null) {list.add(entity);}}}return list;}public static boolean isRowEmpty(Row row) {if (row == null) {return true;}int firstCellNum = row.getFirstCellNum();int lastCellNum = row.getLastCellNum();for (int i = firstCellNum; i < lastCellNum; i++) {Cell cell = row.getCell(i);if (cell != null && cell.getCellType() != CellType.BLANK) {return false;}}return true;}private String getCellValue(CellType cellType, Cell cell) {String c;if (cellType == CellType.NUMERIC) {DecimalFormat df = new DecimalFormat("0");c = df.format(cell.getNumericCellValue());} else if (cellType == CellType.BOOLEAN) {c = String.valueOf(cell.getBooleanCellValue());} else {c = cell.getStringCellValue();}return c;}/*** 将EXCEL中A,B,C,D,E列映射成0,1,2,3,4* @param col*/public static int getExcelCol(String col) {col = col.toUpperCase();// 从-1开始计算,字母重1开始运算。这种总数下来算数正好相同。int count = -1;char[] cs = col.toCharArray();for (int i = 0; i < cs.length; i++) {count += (cs[i] - 64) * Math.pow(26, cs.length - 1 - i);}return count;}/*** 表头(标题)格式设置** @param workbook* @return*/private CellStyle createTitleStyle(Workbook workbook) {log.info("创建表头格式 createTitleStyle");CellStyle cellStyle = workbook.createCellStyle();// 填充样式cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);// 填充色cellStyle.setFillForegroundColor(HSSFColor.HSSFColorPredefined.GREY_25_PERCENT.getIndex());// 水平居中cellStyle.setAlignment(HorizontalAlignment.CENTER);// 垂直居中cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);// 填充色cellStyle.setFillForegroundColor(IndexedColors.ROYAL_BLUE.getIndex());// 边框样式buildBorder(cellStyle, BorderStyle.THIN);// 字体设置Font font = workbook.createFont();font.setFontHeightInPoints((short) 11);font.setBold(true);font.setColor(IndexedColors.WHITE.getIndex());cellStyle.setFont(font);// 自动换行cellStyle.setWrapText(true);return cellStyle;}/*** 内容格式设置** @param workbook* @return*/private CellStyle createContentStyle(Workbook workbook) {log.info("创建表头格式 createTitleStyle");CellStyle cellStyle = workbook.createCellStyle();// 水平居中cellStyle.setAlignment(HorizontalAlignment.CENTER);// 垂直居中cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);// 字体设置Font font = workbook.createFont();font.setFontHeightInPoints((short) 11);cellStyle.setFont(font);// 自动换行cellStyle.setWrapText(true);return cellStyle;}/*** 设置边框** @param cellStyle* @param style*/private void buildBorder(CellStyle cellStyle, BorderStyle style) {cellStyle.setBorderBottom(style);cellStyle.setBorderTop(style);cellStyle.setBorderLeft(style);cellStyle.setBorderRight(style);}/*** 自适应宽度(中文支持)** @param sheet* @param size*/private void setSizeColumn(Sheet sheet, int size) {for (int columnNum = 0; columnNum < size; columnNum++) {int columnWidth = sheet.getColumnWidth(columnNum) / 256;for (int rowNum = 0; rowNum < sheet.getLastRowNum(); rowNum++) {Row currentRow;//当前行未被使用过if (sheet.getRow(rowNum) == null) {currentRow = sheet.createRow(rowNum);} else {currentRow = sheet.getRow(rowNum);}if (currentRow.getCell(columnNum) != null) {Cell currentCell = currentRow.getCell(columnNum);String value = "";CellType cellType = currentCell.getCellType();if (cellType == CellType.NUMERIC) {currentCell.setCellType(CellType.STRING);value = currentCell.getStringCellValue();} else if (cellType == CellType.STRING) {value = currentCell.getStringCellValue();}int length = value.getBytes().length;if (columnWidth < length) {columnWidth = length;}}}sheet.setColumnWidth(columnNum, columnWidth * 256);}}/*** 得到实体类所有通过注解映射了数据表的字段* 递归调用*/protected List<Field> getMappedFiled(Class clazz, List<Field> fields) {if (fields == null) {fields = new ArrayList<>();}// 得到所有定义字段Field[] allFields = clazz.getDeclaredFields();for (Field field : allFields) {if (field.isAnnotationPresent(ExcelColumn.class)) {fields.add(field);}}if (clazz.getSuperclass() != null && !clazz.getSuperclass().equals(Object.class)) {getMappedFiled(clazz.getSuperclass(), fields);}return fields;}/*** 将数据写入Excel* @param dataList* @param failData* @return*/public String writeDataToExcel(List<T> dataList, boolean failData) {String localFileDir = "/tmp/localFile";String fileName = UUID.randomUUID().toString() + ".xlsx";String localFilePath = FileUtils.createFile(localFileDir, fileName);File file = new File(localFilePath);try (Workbook workbook = writeDataToExcel(dataList, failData);FileOutputStream output = new FileOutputStream(file)) {workbook.write(output);output.flush();return localFilePath;} catch (Exception e) {log.error("writeDataToExcelAndUpload e:", e);throw new BusinessException("将数据写入excel异常");}}public Workbook writeDataToExcel(List<T> dataList, boolean failData) throws Exception{List<String> headerNames = new ArrayList<>();List<Field> fields = getMappedFiled(clazz, null);boolean hasPic = false;for (Field field : fields) {ExcelColumn excelColumn = field.getAnnotation(ExcelColumn.class);headerNames.add(excelColumn.name());}if (failData) {headerNames.add("失败原因");}XSSFWorkbook workbook = new XSSFWorkbook();XSSFSheet sheet = workbook.createSheet();// 创建第一栏,抬头栏XSSFRow headRow = sheet.createRow(0);headRow.setHeightInPoints(91);// 设置单元格类型CellStyle headStyle = createTitleStyle(workbook);// 创建抬头栏单元格for (int j = 0; j < headerNames.size(); j++) {XSSFCell cell = headRow.createCell(j);if (headerNames.get(j) != null) {cell.setCellValue(headerNames.get(j));cell.setCellStyle(headStyle);}}int size = dataList.size();int maxCol = headerNames.size();int fieldCol = fields.size();try {CellStyle contentStyle = createContentStyle(workbook);CellStyle errorMsgStyle = createErrorMsgStyle(workbook);for (int i = 0; i < size; i++) {XSSFRow row = sheet.createRow(i + 1);row.setHeightInPoints(60);T vo = dataList.get(i);XSSFCell cell;for (int j = 0; j < maxCol; j++) {// 当j > fieldCol时if (j > fieldCol - 1 && j == maxCol - 1) {Field field = clazz.getDeclaredField("errorMsg");field.setAccessible(true);Object o = field.get(vo);cell = row.createCell(j);cell.setCellStyle(errorMsgStyle);cell.setCellType(CellType.STRING);cell.setCellValue(o != null ? o.toString() : "");} else {Field field = fields.get(j);field.setAccessible(true);ExcelColumn attr = field.getAnnotation(ExcelColumn.class);cell = row.createCell(getExcelCol(attr.column()));if (field.getType() == String.class) {cell.setCellStyle(contentStyle);cell.setCellType(CellType.STRING);String cellValue = field.get(vo) == null ? "" : String.valueOf(field.get(vo));cell.setCellValue(cellValue);}}}}// 宽度自适应} catch (Exception e) {log.error("失败 e:", e);throw new Exception("失败");}return workbook;}
}
这个工具类只是展示了简单的字段导入/导出的读取,如果带图片或者其他特殊要求的字段,可以自定义规则读取。
相关文章:
Excel表格导入/导出数据工具类
Excel表格导入/导出数据工具 这里以java语言为类,实现一个简单且较通用的Excel表格数据导入工具类。 自定义注解 ExcelColumn写导入工具类 ExcelImportUtil 自定义注解 ExcelColumn Retention(RetentionPolicy.RUNTIME) Target({java.lang.annotation.ElementTy…...

Python自学之路--004:Python使用注意点(原始字符串‘r’\字符转换\‘wb’与‘w区别’\‘\‘与‘\\’区别)
目录 1、原始字符串‘r’ 2、字符转换问题 3、open与write函数’wb’与’w’区分 4、Python里面\与\\的区别 1、原始字符串‘r’ 以前的脚本通过Python2.7写的,通过Python3.12去编译发现不通用了,其实也是从一个初学者的角度去看待这些问题。 其中的\…...

javaEE进阶——SpringBoot与SpringMVC第一讲
文章目录 什么是springMVCSpringMVC什么是模型、视图、控制器MVC和SpringMVC的关系SpringMVC的使用第一个SpringMVC程序RestController什么是注解 那么RestController到底是干嘛的呢?RequestMapping 如何接收来自请求中的querystryingRequestParamRequestMapping(&q…...
LabVIEW和usrp连接实现ofdm通信系统 如何实现
1. 硬件准备 USRP设备:选择合适的USRP硬件(如USRP B210或N210),并确保其与计算机连接(通常通过USB或以太网)。天线:根据频段需求选择合适的天线。 2. 软件安装 LabVIEW:安装LabVI…...

NGINX SPRING HTTPS证书
服务器:xxx.xxx.xxx.56 客户端器:xxx.xxx.xxx.94##生成服务器证书和密钥容器 keytool -genkey -alias tas-server -keypass 250250 -keyalg RSA -keysize 2048 -validity 3650 -keystore D:\https证书\tas-server.jks -storepass 250250 -dname "C…...

WordPress插件Plus WebP,可将jpg、png、bmp、gif图片转为WebP
现在很多浏览器和CDN都支持WebP格式的图片了,不过我们以前的WordPress网站使用的图片都是jpg、png、bmp、gif,那么应该如何将它们转换为WebP格式的图片呢?推荐安装这款Plus WebP插件,可以将上传到媒体库的图片转为WebP格式图片&am…...
GitLab CI/CD的原理及应用详解(五)
本系列文章简介: 在当今快速变化的软件开发环境中,持续集成(Continuous Integration, CI)和持续交付(Continuous Delivery, CD)已经成为提高软件开发效率、确保代码质量以及快速响应市场需求的重要手段。Gi…...

连锁收银系统如何助力实体门店私域运营
作为实体门店,私域运营是提升客户黏性和增加复购率的重要策略之一。而连锁收银系统在私域运营中扮演了关键的角色,它不仅可以帮助门店管理客户信息和消费记录,还能够通过数据分析和营销功能提供个性化的服务和推广活动。下面看看连锁收银系统…...

JETBRAINS IDES 分享一个2099通用试用码!PhpStorm 2024 版 ,支持一键升级
文章目录 废话不多说上教程:(动画教程 图文教程)一、动画教程激活 与 升级(至最新版本) 二、图文教程 (推荐)Stage 1.下载安装 toolbox-app(全家桶管理工具)Stage 2 : 下…...
超级好用的C++实用库之MD5信息摘要算法
💡 需要该C实用库源码的大佬们,可搜索微信公众号“希望睿智”。添加关注后,输入消息“超级好用的C实用库”,即可获得源码的下载链接。 概述 MD5信息摘要算法是一种广泛使用的密码散列函数,由Ronald L. Rivest在1991年设…...

ssm132医院住院综合服务管理系统设计与开发+vue
医院住院综合服务管理系统的设计与实现 摘 要 互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。针对医院住院信息管理混乱&…...

在Linux上安装并启动Redis
目录 安装gcc环境 上传redis文件 启动redis-server 后台启动redis-server 查看redis启动状态 参考文章:Linux 安装 Redis 及踩坑 - 敲代码的阿磊 - 博客园 (cnblogs.com) 准备:打开VMware Workstation,创建一个虚拟机,进入管…...

vue3.0+antdv的admin管理系统vue-admin-beautiful推荐
前言 几年前,笔者自学了vue这一优秀的前端框架,但苦于没项目练手,无意间发现了vue-admin-beautiful这一优秀的前端集成框架。当时就使用它做了一很有意思的小项目---终端监控云平台,实现了前端和后台的整体功能。整体方案介绍参见…...
C# WinForm —— 20 RichTextBox 介绍
1. 简介 富文本框,拥有TextBox的所有功能,,但还有更多高级的文本输入和编辑功能,比如设置字体颜色、样式、段落、图片、超链接等 2. 常用属性 属性解释(Name)控件ID,在代码里引用的时候会用到,一般以 rtxt 开头Acce…...
springmvc数据绑定
数据绑定 数据绑定流程 springmvc框架将ServletRequest对象及目标方法的入参实例传递给WebDataBinderFactory实例,以创建DataBinder实例对象 DataBinder调用装配在springmvc上下文中的ConversionService组件进行数据类型转换、数据格式化工作。将Servlet中的请求信息…...

Milvus的存储/计算分离
前言 根据数据面与控制面相隔离的原则,从可扩展性和灾难恢复来看,Milvus由4个相互独立的层组成 访问层 由一系列无状态的代理组成,访问层是系统和用户之间的第一层,它主要是验证客户端请求和规整返回的结果 代理是无状态的&am…...
SHAP值是个什么值?
SHAP 值是个什么值? 起初,我们知道SHAP值代表了变量对于结局变量的贡献程度,然而,在做了一些SHAP分析之后,感觉有一些SHAP值还是有一些难以理解的地方,比如,为什么有负值?SHAP值为0…...
Django接口卡死一直没有返回响应
当Django接口出现卡死且没有返回响应时,可能是由于多种原因导致的。以下是一些排查和解决问题的步骤: 查看日志: 首先检查Django的日志,看看是否有任何错误或异常被记录。这可以帮助你确定问题的根源。 检查数据库连接࿱…...
7-139 有趣的括号
括号()的组合千奇百怪,Drizzle 想知道各种组合的括号可以是否合法 合法要求:每个同类型的左括号必须有与之对应的同类的右括号以正确的顺序闭合 要求: 输入:输入一个括号字符串 输出:输出是否合法,是则True,否则False 示例: 输入: (){}[]输出: True范围: 对于 1…...
解决qt5.12.12编译源码没有libqxcb的问题
最近要研究一下qt源码,因为设计到要修改源码,所以需要编译源码并替换修改的库文件运行验证。 我这里使用的是qt5.12.12版本,去官网上下载对应版本的安装包,安装时勾选上源码即可。 后面编译完发现,plugins/platforms/目录下没有生成库文件libqxcb.so,造成了一点麻烦。 设置 e…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...