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…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...