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…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
Razor编程中@Html的方法使用大全
文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...
永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...
AD学习(3)
1 PCB封装元素组成及简单的PCB封装创建 封装的组成部分: (1)PCB焊盘:表层的铜 ,top层的铜 (2)管脚序号:用来关联原理图中的管脚的序号,原理图的序号需要和PCB封装一一…...
