当前位置: 首页 > news >正文

Java 读取Excel模板中的数据到实体类

目录

  • 一. 前提条件
    • 1.1 需求
    • 1.2 分析
  • 二. 准备
    • 2.1 自定义注解
    • 2.2 封装Excel的实体类
  • 三. 前台
  • 四. Controller层
  • 五. Service层💪💪💪
  • 六. 效果


一. 前提条件

1.1 需求

  • 从指定的Excel模板中读取数据,将读取到的数据存储到数据库中。

在这里插入图片描述

1.2 分析

  • 需要用到 poi 读取Excel
  • 使用自定义注解标记Excel单元格的行,列,数据类型方便读取数据
  • 需要使用 hibernate validation 校验数据
  • 前台需要使用 FormData() 对象向后台传入文件,需要指定只能上传Excel类型的文件
  • 读取到的数据依次的get和set到entity中很麻烦,需要用到 反射 进行封装

二. 准备

2.1 自定义注解

  • 校验项目不为空
import javax.validation.Constraint;
import javax.validation.constraints.NotEmpty;
import javax.validation.Payload;
import javax.validation.ReportAsSingleViolation;
import java.lang.annotation.*;@Documented
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {})
@NotEmpty
@ReportAsSingleViolation
public @interface ValidateNotEmpty {String msgArgs() default "";// 1001E=请输入{msgArgs}。String message() default "{1001E}";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}
  • 标记Excel单元格的行,列,属性信息的注解
import java.lang.annotation.*;@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface ExcelCellAnnotation {// Excel单元格行的indexint rowIndex() default 0;// Excel单元格列的indexint columnIndex() default 0;// Excel单元格列的类型,默认是字符串类型java.lang.Class type() default String.class;
}

2.2 封装Excel的实体类

  • 以「契約者申請日」这个项目为例说明
    • 在Excel模板中的位置为第2行
    • 在Excel模板中的位置为第22列
    • 在Excel模板中的数据类型为 Date 类型
import lombok.Data;import java.util.Date;@Data
public class ExcelEntity {/*** 契約者申請日*/@ValidateNotEmpty(msgArgs = "契約者申請日")@ExcelCellAnnotation(rowIndex = 1, columnIndex = 21, type = Date.class)private String keiyakushaShinseibi;/*** フリガナ*/@ValidateNotEmpty(msgArgs = "フリガナ")@ExcelCellAnnotation(rowIndex = 4, columnIndex = 5)private String furikana;/*** 契約者(氏名)*/@ValidateNotEmpty(msgArgs = "契約者(氏名)")@ExcelCellAnnotation(rowIndex = 5, columnIndex = 5)private String keiyakuShaName;/*** 性別_男*/@ExcelCellAnnotation(rowIndex = 5, columnIndex = 20)private String sexMan;/*** 性別_女*/@ExcelCellAnnotation(rowIndex = 5, columnIndex = 22)private String sexWoman;/*** 契約者住所*/@ValidateNotEmpty(msgArgs = "契約者住所")@ExcelCellAnnotation(rowIndex = 8, columnIndex = 5)private String keiyakushaJyusho;/*** 契約者連絡先_携帯*/@ValidateNotEmpty(msgArgs = "契約者連絡先_携帯")@ExcelCellAnnotation(rowIndex = 10, columnIndex = 8)private String keiyakushaPhone;/*** 契約者連絡先_メール*/@ValidateNotEmpty(msgArgs = "契約者連絡先_メール")@ExcelCellAnnotation(rowIndex = 10, columnIndex = 16)private String keiyakushaMail;
}

三. 前台

  • 通过accept="application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"来实现只能上传Excel类型的数据
  • 上传成功或者失败都需要把文件上传input中的value置为空,保证同一个文件可以上传多次
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><input type="file" id="excel" accept="application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"/><button id="btn">上传</button>
</body>
<script src="https://code.jquery.com/jquery-3.6.3.js"></script>
<script>$(function () {$("#btn").click(function () {const formData = new FormData();formData.append("excelFile", $("#excel").get(0).files[0]);$.ajax({url: `/poi/excel`,type: 'POST',data: formData,processData: false,contentType: false,success: function (data, status, xhr) {console.log(data);},error(xhr, textStatus, errorMessage) {console.log(textStatus);},complete(jqXHR, textStatus) {// 清空上传的文件,保证可以多次上传同一个文件$("#excel").val("");}});})})
</script>
</html>

四. Controller层

  • 通过MultipartHttpServletRequest来获取前台上传到后台的文件
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;import java.util.List;@Controller
@RequestMapping("/poi")
public class PoiController {@Autowiredprivate PoiService service;@GetMapping("/init")public ModelAndView init() {ModelAndView modelAndView = new ModelAndView();modelAndView.setViewName("poiTest");return modelAndView;}// 处理上传到后台的文件@PostMapping("/excel")public ResponseEntity<Void> handleExcel(MultipartHttpServletRequest request) throws Exception {// 获取前台传入的文件List<MultipartFile> file = request.getMultiFileMap().get("excelFile");MultipartFile multipartFile = file.get(0);// 将Excel中的文件读取到Entity中ExcelEntity excelEntity = new ExcelEntity();service.readExcel(multipartFile, excelEntity);// 对Excel中的数据进行校验service.validateExcelData(excelEntity);// 告知操作成功return ResponseEntity.noContent().build();}
}

五. Service层💪💪💪

import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.multipart.MultipartFile;import javax.validation.ConstraintViolation;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;@Service
public class PoiService implements InitializingBean {// set方法private final static String methodAction = "set";// Excel单元格格式化对象private final static DataFormatter formatter = new DataFormatter();// 日期格式化对象private static DateFormat dateformat = null;// 输入校验对象@Autowiredprivate LocalValidatorFactoryBean validator;// 进行一些初始化操作@Overridepublic void afterPropertiesSet() {// 指定日期的格式化dateformat = new SimpleDateFormat("yyyy-MM-dd");}// 读取Excel中的数据public void readExcel(MultipartFile multipartFile, ExcelEntity excelEntity) throws Exception {// 获取sheet页对象InputStream inputStream = multipartFile.getInputStream();XSSFWorkbook sheets = new XSSFWorkbook(inputStream);XSSFSheet sheet = sheets.getSheetAt(0);// 单元格中的值String cellValue = "";// 获取类上的所有属性(public和private都可以获取到)Field[] fields = excelEntity.getClass().getDeclaredFields();for (Field field : fields) {// 如果该属性中没有ExcelCellAnnotation注解的话,跳过ExcelCellAnnotation annotation = field.getAnnotation(ExcelCellAnnotation.class);if (ObjectUtils.isEmpty(annotation)) {continue;}// 根据行列的index,获取当前的单元格对象XSSFCell cell = sheet// 获取属性上注解标记的单元格的行index.getRow(annotation.rowIndex())// 获取属性上注解标记的单元格的列index.getCell(annotation.columnIndex());// 获取属性上注解标记的单元格的类型Class valueType = annotation.type();// 根据当前单元格的类型获取单元格的值if (Date.class == valueType) {cellValue = dateformat.format(cell.getDateCellValue());} else if (String.class == valueType) {cellValue = formatter.formatCellValue(cell);}// 通过反射将单元格的值动态封装到实体类中String methodName = methodAction + StringUtils.capitalize(field.getName());Method setMethod = ReflectionUtils.findMethod(excelEntity.getClass(), methodName, cellValue.getClass());ReflectionUtils.invokeMethod(setMethod, excelEntity, cellValue);}}// 对Excel中的数据进行校验public void validateExcelData(ExcelEntity excelEntity) {// 使用自定义注解对excel数据进行校验并打印Set<ConstraintViolation<ExcelEntity>> validateResults = validator.validate(excelEntity);for (ConstraintViolation<ExcelEntity> validateResult : validateResults) {System.out.println(validateResult.getMessage());}// 打印excel中获取到的数据System.out.println(excelEntity);}
}

六. 效果

在这里插入图片描述

相关文章:

Java 读取Excel模板中的数据到实体类

目录一. 前提条件1.1 需求1.2 分析二. 准备2.1 自定义注解2.2 封装Excel的实体类三. 前台四. Controller层五. Service层&#x1f4aa;&#x1f4aa;&#x1f4aa;六. 效果一. 前提条件 1.1 需求 从指定的Excel模板中读取数据&#xff0c;将读取到的数据存储到数据库中。 1.2…...

【java基础】Socket网络编程

文章目录说明InetAddress介绍Socket介绍ServerSocket介绍实现简单的Socket通信总结说明 这里介绍下如何在java里面进行socket编程 InetAddress介绍 这个类表示一个Internet协议(IP)地址&#xff0c;我们可以通过ip或者主机名来构建这个类 Testpublic void t1() throws Except…...

转发和重定向区别

转发和重定向 1.0 面试提问 定义不同跳转的方式不同数据共享不同最终的URL地址不同代码实现不同 1. 转发 1.1 概念 转发实际上在服务器端进行页面的跳转操作&#xff0c;请求转发&#xff1a;一种在服务器内部的资源的跳转的方式。 访问A&#xff0c;A请求转发了B&#xff0c…...

java面试题(持续更新)

java面试题&#xff08;持续更新&#xff09; java 基础 java面向对象有哪些特征 面向对象的三大特征&#xff1a;封装、继承、多态 封装&#xff1a;隐藏了类的内部实现机制&#xff0c;可以在不影响使用的情况下改变类的内部结构&#xff0c;同时也保护了数据&#xff0c;…...

【花雕学AI】09:发挥ChatGPT最大潜力——产生高质量内容的九种方法和建议

人工智能&#xff08;AI&#xff09;是当今科技领域最热门和最有前景的话题之一&#xff0c;它已经渗透到了我们生活和工作的方方面面&#xff0c;给我们带来了许多便利和惊喜。而在AI的众多分支中&#xff0c;自然语言处理&#xff08;NLP&#xff09;是最贴近人类的一个领域&…...

实战打靶集锦-013-Loly

**写在前面&#xff1a;**记录博主的一次打靶经历 目录1. 主机发现2. 端口扫描3. 服务枚举4. web服务探查4.1 WordPress探测4.2 使用metasploit4.3 使用wpscan4.4 阶段性回顾5. 提权5.1 弱密码提权5.2 操作系统信息枚举5.3 定时任务枚举5.4 passwd信息枚举5.5 可执行文件枚举5.…...

程序员OKR学习法

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl OKR管理法 OKR&#xff08;Objectives and Key Results&#xff09;管理法是一种目标管理方法&#xff0c;旨在通过制定明确的目标和可量化的关键结果来帮助组织、团队和个人…...

【从零开始学习 UVM】6.6、UVM 激励产生 —— UVM Virtual Sequence【重要】

文章目录 使用virtual sequencer不使用virtual sequencervirtual sequence是一个容器,用于在环境中的virtual sequencer上启动多个sequence。 这个virtual sequence通常由一个具有对真实sequencers句柄的virtual sequencers执行。 需要virtual sequence的原因是当您需要在不…...

蓝桥杯:阶乘约数

蓝桥杯&#xff1a;阶乘约数https://www.lanqiao.cn/problems/1020/learning/ 目录 题目描述 填空题&#xff1a;答案是 39001250856960000 题目分析 AC代码(Java) 暴力 线性筛 题目描述 填空题 定义阶乘 n!123⋅⋅⋅n。 请问 100! &#xff08;100 的阶乘&#xff09;有…...

最大数字

[蓝桥杯 2022 国 B] 最大数字 题目描述 给定一个正整数 NNN。你可以对 NNN 的任意一位数字执行任意次以下 2 种操作: 将该位数字加 111。如果该位数字已经是 999&#xff0c;加 111 之后变成 000。 将该位数字减 111。如果该位数字已经是 000&#xff0c;减 111 之后变成 99…...

【java进阶08:异常】finally关键字、自定义异常类、用户业务作业、军队武器作业

java中的异常处理机制 异常在java中以类和对象的形式存在&#xff0c;那么异常的继承结构是怎样的&#xff1f;我们可以使用UML图来描述以下继承结构 画UML图的工具&#xff1a;Rational Rose、starUML等 Object下有Throwable&#xff08;可抛出的&#xff09; Throwable下有两…...

#课程笔记# 电路与电子技术基础 课堂笔记 第6章 半导体器件的基本特性

6.1 半导体基础知识 6.1.1 本征半导体 完全纯净的、结构完整的半导体称为本征半导体。 常用的半导体材料有硅和锗&#xff0c;它们都是四价元素&#xff0c;原子最外层轨道有四个价电子。 若将纯净的半导体制成晶体&#xff0c;则原子形成排列整齐的点阵。 点阵是由共价键提供…...

skimage.filters.apply_hysteresis_threshold详解

本文内容均参考scipy1.9.1scipy1.9.1scipy1.9.1版本的源码&#xff0c;若有任何不当欢迎指出 我们截取官方注释如下&#xff1a; def apply_hysteresis_threshold(image, low, high):"""Apply hysteresis thresholding to image.This algorithm finds regions …...

一、基础算法5:前缀和与差分 模板题+算法模板(前缀和,子矩阵的和,差分,差分矩阵)

文章目录算法模板前缀和模板子矩阵的和模板差分模板差分矩阵模板模板题前缀和原题链接题目题解子矩阵的和原题链接题目题解差分原题链接题目题解差分矩阵原题链接题目题解算法模板 前缀和模板 S[i] a[1] a[2] ... a[i] a[l] ... a[r] S[r] - S[l - 1]子矩阵的和模板 S[i…...

Python矩阵分解之QR分解

文章目录QR和RQ分解其他函数QR和RQ分解 记AAA为方阵&#xff0c;P,QP, QP,Q分别为正交单位阵和上三角阵&#xff0c;则形如AQRAQRAQR的分解为QR分解&#xff1b;形如ARQARQARQ的分解为RQ分解。 在scipy.linalg中&#xff0c;为二者提供了相同的参数&#xff0c;除了待分解矩阵…...

随机森林程序

n_estimators:数值型取值 含义&#xff1a;森林中决策树的个数&#xff0c;默认是10 criterion:字符型取值 含义&#xff1a;采用何种方法度量分裂质量&#xff0c;信息熵或者基尼指数&#xff0c;默认是基尼指数 max_features:取值为int型, float型, string类型…...

每日一练2627——变态跳台阶快到碗里来不用加减乘除做加法三角形

文章目录变态跳台阶思路&#xff1a;代码&#xff1a;快到碗里来思路&#xff1a;代码&#xff1a;不用加减乘除做加法思路&#xff1a;代码&#xff1a;三角形思路&#xff1a;代码&#xff1a;变态跳台阶 题目链接&#xff1a; 思路&#xff1a; 这个题目很容易理解&#…...

LeetCode-146. LRU 缓存

目录LRU理论题目思路代码实现一代码实现二题目来源 146. LRU 缓存 LRU理论 LRU 是 Least Recently Used 的缩写&#xff0c;这种算法认为最近使用的数据是热门数据&#xff0c;下一次很大概率将会再次被使用。而最近很少被使用的数据&#xff0c;很大概率下一次不再用到。当缓…...

#课程笔记# 电路与电子技术基础 课堂笔记 第3章 电路分析的几个定理

3.1 叠加定理 激励&#xff1a;电流源或电压源 响应&#xff1a;电流或电压 叠加定理一般用于已知激励或响应中的一种&#xff0c;求另一种。做法就是&#xff0c;每次只求一个激励作用下的响应&#xff0c;将其他激励置零&#xff0c;置零的具体做法是&#xff0c;电压源变…...

推迟参数设计的自适应反步控制和自适应神经网络的反步控制设计

推迟参数设计的自适应反步控制和自适应神经网络的反步控制设计 目录推迟参数设计的自适应反步控制和自适应神经网络的反步控制设计前言匹配与非匹配1. 基于自适应反步控制的非匹配条件下的系统控制器设计问题描述控制器设计小结2. 基于自适应反步控制和推迟参数设计的非匹配条件…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

掌握 HTTP 请求:理解 cURL GET 语法

cURL 是一个强大的命令行工具&#xff0c;用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中&#xff0c;cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

用鸿蒙HarmonyOS5实现国际象棋小游戏的过程

下面是一个基于鸿蒙OS (HarmonyOS) 的国际象棋小游戏的完整实现代码&#xff0c;使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├── …...

k8s从入门到放弃之Pod的容器探针检测

k8s从入门到放弃之Pod的容器探针检测 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;容器探测是指kubelet对容器执行定期诊断的过程&#xff0c;以确保容器中的应用程序处于预期的状态。这些探测是保障应用健康和高可用性的重要机制。Kubernetes提供了两种种类型…...