Spring Boot 与 EasyExcel 携手:复杂 Excel 表格高效导入导出实战
数据的并行导出与压缩下载:EasyExcel:实现大规模数据的并行导出与压缩下载
构建高效排队导出:解决多人同时导出Excel导致的服务器崩溃
前言
在企业级应用开发中,常常需要处理复杂的 Excel 表格数据。本方案将 Spring Boot 强大的后端框架与 EasyExcel 这一高效的 Excel 处理工具进行整合,实现了复杂 Excel 表格的导入与导出功能。
对于导入功能,能够轻松应对包含多种数据类型、复杂结构以及大量数据的 Excel 文件。通过合理的配置和处理流程,确保数据的准确性和完整性,将 Excel 中的数据快速导入到系统中,为后续的数据处理和业务逻辑提供有力支持。
在导出方面,能够根据系统中的数据生成结构复杂、格式规范的 Excel 表格。可以自定义表头、样式、格式等,满足不同业务场景下对 Excel 报表的需求。无论是生成详细的业务数据报表,还是复杂的统计分析结果,都能通过这个整合方案轻松实现。
组件介绍
EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。
Alibaba EasyExcel的核心类是EasyExcel
类。
案例
1、简单的读操作
/*** 最简单的读* 1. 创建excel对应的实体对象 参照{@link DemoData}* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}* 3. 直接读即可*/
@Test
public void simpleRead() {String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
}
2、简单的写操作
/*** 最简单的写* 1. 创建excel对应的实体对象 参照{@link com.alibaba.easyexcel.test.demo.write.DemoData}* 2. 直接写即可*/
@Test
public void simpleWrite() {String fileName = TestFileUtil.getPath() + "write" + System.currentTimeMillis() + ".xlsx";// 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭// 如果这里想使用03 则 传入excelType参数即可EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
}
项目基本信息
一、单个sheet&表头合并
1、添加pom.xml依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.1</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>SpringBoot-easyexcel</artifactId><version>0.0.1-SNAPSHOT</version><name>SpringBoot-easyexcel</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><!-- Web组件 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- easyexcel --><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.1</version></dependency><!-- commons-lang3 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.8.1</version></dependency><!-- lombok插件 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
2. 创建数据模型
创建一个数据模型类,用于表示Excel中的一行数据。例如,我们有一个包含用户信息的复杂Excel表格:
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.metadata.data.WriteCellData;
import lombok.Builder;
import lombok.Data;import java.util.Date;@Data
@Builder
public class UserData{@ExcelProperty(value = "用户ID", index = 0)@ColumnWidth(10)private Long userId;@ExcelProperty(value = "用户名称", index = 1)@ColumnWidth(10)private String userName;@ExcelProperty(value = {"基本信息", "手机号码"}, index = 2)@ColumnWidth(20)private String userPhone;@ExcelProperty(value = {"基本信息", "电子邮箱"}, index = 3)@ColumnWidth(20)private String userEmail;@ExcelProperty(value = {"基本信息", "地址"}, index = 4)@ColumnWidth(20)private String userAddress;@ExcelProperty(value = "注册时间", index = 5)@ColumnWidth(20)private Date registerTime;@ExcelProperty(value = "性别,男:红色/女:绿色")@ColumnWidth(30)private WriteCellData<String> gender;/*** 忽略这个字段*/@ExcelIgnoreprivate Integer age;
}
3. 创建导出服务
创建一个服务类,用于实现Excel的导出功能:
import com.alibaba.excel.EasyExcel;
import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List; @Service
public class ExcelExportService { public void exportUsers(List<UserData> userDataList, HttpServletResponse response) throws IOException { // 设置响应类型response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");// 设置编码格式response.setCharacterEncoding("utf-8");// 设置URLEncoder.encode 防止中文乱码String fileName = URLEncoder.encode("信息表", "UTF-8").replaceAll("\\+", "%20");// 设置响应头response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");EasyExcel.write(response.getOutputStream(), UserData.class).inMemory(true).sheet("用户信息表").doWrite(userDataList);}private static WriteCellData<String> buildCellData(String gender) {// 设置单个单元格多种样式WriteCellData<String> cellData = new WriteCellData<>();// 设置单个单元格的填充类型cellData.setType(CellDataTypeEnum.RICH_TEXT_STRING);RichTextStringData richTextStringData = new RichTextStringData();cellData.setRichTextStringDataValue(richTextStringData);richTextStringData.setTextString(gender);WriteFont writeFont = new WriteFont();if ("男".equalsIgnoreCase(gender)) {//设置颜色为红色writeFont.setColor(IndexedColors.RED.getIndex());} else if ("女".equalsIgnoreCase(gender)) {//设置颜色为绿色writeFont.setColor(IndexedColors.GREEN.getIndex());}//应用颜色字体richTextStringData.applyFont(writeFont);return cellData;}
}
4. 创建导入服务
导入的数据模型
import java.util.Date;import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.metadata.data.WriteCellData;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;@Data
@Builder
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class UserData {private Long userId;private String userName;private Integer age;private String userPhone;private String userEmail;private String userAddress;private Date registerTime;private String gender;
}
创建一个服务类,用于实现Excel的导入功能:
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.excel.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;@Slf4j
@Service
public class ExcelImportService {/*** 每隔一定数量的数据存储到数据库,可根据实际情况调整。*/private static final int BATCH_COUNT = 100;/*** 手机号正则表达式校验。*/private static final Pattern PHONE_REGEX = Pattern.compile("^1[0-9]{10}$");/*** 缓存要导入的数据列表。*/private List<UserData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);/*** 错误信息列表。*/private final List<String> errorMsgList = new ArrayList<>();// 假设这里有一个数据访问层的接口引用private UserDataRepository userDataRepository;public ExcelImportService(UserDataRepository userDataRepository) {this.userDataRepository = userDataRepository;}/*** 导入 Excel 文件并保存数据到数据库。** @param excelFilePath Excel 文件路径。*/public void importExcel(String excelFilePath) {EasyExcel.read(excelFilePath, UserData.class, new CustomAnalysisEventListener()).sheet().doRead();}class CustomAnalysisEventListener extends AnalysisEventListener<UserData> {@Overridepublic void invoke(UserData userData, AnalysisContext analysisContext) {log.info("解析到一条数据:{}", userData);int rowIndex = analysisContext.readRowHolder().getRowIndex();String name = userData.getUserName();String phone = userData.getUserPhone();String gender = userData.getGender();String email = userData.getUserEmail();Integer age = userData.getAge();String address = userData.getUserAddress();// 只有全部校验通过的对象才能被添加到下一步if (nameValid(rowIndex, name) && phoneValid(rowIndex, phone) && genderValid(rowIndex, gender) &&emailValid(rowIndex, email) && ageValid(rowIndex, age) && addressValid(rowIndex, address)) {cachedDataList.add(userData);}// 达到 BATCH_COUNT 了,存储到数据库并清理列表if (cachedDataList.size() >= BATCH_COUNT) {saveDataToDatabase();cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);}}@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {log.info("所有数据解析完成!全部校验通过的数据有{}条", cachedDataList.size());// 保存剩余数据到数据库saveDataToDatabase();}@Overridepublic void onException(Exception exception, AnalysisContext context) throws Exception {if (exception instanceof RuntimeException) {throw exception;}int index = context.readRowHolder().getRowIndex() + 1;errorMsgList.add("第" + index + "行解析错误");}@Overridepublic void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {int totalRows = context.readSheetHolder().getApproximateTotalRowNumber() - 1;int maxNum = 2000;if (totalRows > maxNum) {errorMsgList.add("数据量过大,单次最多上传2000条");throw new RuntimeException("数据量过大,单次最多上传2000条");}}}/*** 将缓存的数据保存到数据库。*/private void saveDataToDatabase() {userDataRepository.saveAll(cachedDataList);}public List<String> getErrorMsgList() {return errorMsgList;}/*** 名称的校验。** @param rowIndex 行数。* @param name 名称。*/private Boolean nameValid(Integer rowIndex, String name) {if (StringUtils.isBlank(name)) {errorMsgList.add("第" + rowIndex + "行,'姓名'不能为空");return false;}return true;}/*** 手机号的校验。** @param rowIndex 行数。* @param phone 手机号。*/private Boolean phoneValid(int rowIndex, String phone) {if (StringUtils.isBlank(phone)) {errorMsgList.add("第" + rowIndex + "行,'手机号'不能为空");return false;}return true;}/*** 性别的校验。** @param rowIndex 行数。* @param gender 性别。*/private Boolean genderValid(int rowIndex, String gender) {if (StringUtils.isBlank(gender)) {errorMsgList.add("第" + rowIndex + "行,'性别'不能为空");return false;}return true;}/*** 地址的校验。** @param rowIndex 行数。* @param address 地址。*/private Boolean addressValid(int rowIndex, String address) {// 校验地址是否为空if (StringUtils.isBlank(address)) {errorMsgList.add("第 " + rowIndex + " 行,'地址'不能为空");return false;}return true;}/*** 年龄的校验。** @param rowIndex 行数。* @param age 年龄。*/private Boolean ageValid(int rowIndex, Integer age) {// 校验年龄是否为空if (Objects.isNull(age)) {errorMsgList.add("第 " + rowIndex + " 行'年龄'不能为空");return false;}return true;}/*** 邮箱的校验。** @param rowIndex 行数。* @param email 邮箱。*/private Boolean emailValid(int rowIndex, String email) {// 校验邮箱是否为空if (StringUtils.isBlank(email)) {errorMsgList.add("第 " + rowIndex + " 行'邮箱'不能为空");return false;}return true;}
}
5. 创建控制器
创建一个控制器类,用于处理Excel的导入与导出请求:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List; @RestController
@RequestMapping("/excel")
public class ExcelController { @Autowired private ExcelExportService excelExportService; @Autowired private ExcelImportService excelImportService;@Autowired private UserService userService; @GetMapping("/export") public void exportUsers(HttpServletResponse response, @RequestParam(value = "data", required = false) List<UserData> userDataList) throws IOException { // 判断userDataList是否为空,为空就去数据库查询数据,后执行导出操作 if (userDataList == null || userDataList.isEmpty()) { // 从数据库或其他地方获取数据 userDataList = userService.findAll();for (UserData userData: userDataList) {// 修改性别单元格的样式excelExportService.buildCellData(userData.getGender)} }excelExportService.exportUsers(userDataList, response); } @PostMapping("/import") public String importUsers(@RequestParam("file") MultipartFile file) { try { String filePath = "/path/to/upload/" + file.getOriginalFilename(); file.transferTo(new java.io.File(filePath)); excelImportService.importExcel(filePath); return "导入成功"; } catch (Exception e) { e.printStackTrace(); return "导入失败"; } }
}
6. 运行项目并测试
启动Spring Boot项目,然后你可以通过以下URL进行测试:
-
导出Excel文件:
http://localhost:8080/excel/export
(可以传递一个data
参数,包含要导出的用户数据)
-
导入Excel文件:
http://localhost:8080/excel/import
(上传一个Excel文件)‘
二、多个sheet导出
1、创建数据模型
城市实体类
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Builder;
import lombok.Data;@Data
@Builder
public class City{@ExcelProperty(value = "城市名称", index = 0)@ColumnWidth(10)private String cityName;@ExcelProperty(value = "城市介绍", index = 1)@ColumnWidth(60)private String cityDesc;
}
公司实体类
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Builder;
import lombok.Data;@Data
@Builder
public class Company{@ExcelProperty(value = "公司名称", index = 0)@ColumnWidth(10)private String companyName;@ExcelProperty(value = "公司创始人", index = 1)@ColumnWidth(10)private String companyBoss;@ExcelProperty(value = "公司总基地", index = 2)@ColumnWidth(10)private String companyBase;@ExcelProperty(value = "公司简介", index = 3)@ColumnWidth(50)private String companyDesc;
}
2、创建导出服务
创建一个服务类,用于实现Excel的导出功能:
import com.alibaba.excel.EasyExcel;
import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List; @Service
public class ExcelExportAllService { public void exportUsers(List<UserData> userDataList,List<CityList> cityList,List<CompanyList> companyList, HttpServletResponse response) throws IOException { // 设置响应类型response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");// 设置编码格式response.setCharacterEncoding("utf-8");// 设置URLEncoder.encode 防止中文乱码String fileName = URLEncoder.encode("信息表", "UTF-8").replaceAll("\\+", "%20");// 设置响应头response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");// 多个sheet的输出需要使用ExcelWriter类,这里想要下载成功,需要输出到OutputStream中try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).inMemory(true).build()) {// 创建用户信息表的sheet,写入用户信息数据,1代表sheet的位置是第一个WriteSheet userInfoSheet = EasyExcel.writerSheet(0, "用户信息表").head(UserData.class).build();excelWriter.write(userDataList, userInfoSheet);// 创建城市信息表的sheet,写入城市信息数据,2代表sheet的位置是第二个WriteSheet cityInfoSheet = EasyExcel.writerSheet(1, "城市信息表").head(City.class).build();excelWriter.write(cityList, cityInfoSheet);// 创建公司信息表的sheet,写入公司信息数据,3代表sheet的位置是第三个WriteSheet companyInfoSheet = EasyExcel.writerSheet(2, "公司信息表").head(Company.class).build();excelWriter.write(companyList, companyInfoSheet);}}
}
3、创建控制器
创建一个控制器类,用于处理Excel的导入与导出请求
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List; @RestController
@RequestMapping("/excelAll")
public class ExcelAllController { @Autowired private ExcelExportAllService excelExportAllService; @Autowired private UserDataService userService;@Autowired private CompanyService companyService; @Autowired private CityService cityService; @GetMapping("/export") public void exportUsers(HttpServletResponse response, @RequestParam(value = "userDataList", required = false) List<UserData> userDataList,@RequestParam(value = "companyList", required = false) List<Company> companyList,@RequestParam(value = "cityList", required = false) List<City> cityList) throws IOException { // 判断userDataList是否为空,为空就去数据库查询数据,后执行导出操作 if (userDataList == null || userDataList.isEmpty()) { // 从数据库或其他地方获取数据 userDataList = userService.findAll(); }if (companyList== null || companyList.isEmpty()) { // 从数据库或其他地方获取数据 companyList= companyService.findAll(); }if (cityList== null || cityList.isEmpty()) { // 从数据库或其他地方获取数据 cityList= cityService.findAll(); }excelExportAllService.exportUsers(userDataList,cityList,companyList, response); } }
4. 运行项目并测试
启动Spring Boot项目,然后你可以通过以下URL进行测试:
-
导出Excel文件:
http://localhost:8080/excelAll/export
多个sheet导出
相关文章:

Spring Boot 与 EasyExcel 携手:复杂 Excel 表格高效导入导出实战
数据的并行导出与压缩下载:EasyExcel:实现大规模数据的并行导出与压缩下载 构建高效排队导出:解决多人同时导出Excel导致的服务器崩溃 SpringBoot集成EasyExcel 3.x: 前言 在企业级应用开发中,常常需要处理复杂的 …...

什么是严肃游戏,严肃游戏本地化的特点是什么?
“严肃游戏”是一种交互式数字体验,不仅用于娱乐,还用于教育、培训或解决问题。与主要关注乐趣和参与度的传统游戏不同,严肃游戏的目标不仅仅是娱乐,比如教授特定技能、模拟现实生活场景或提高对重要问题的认识。它们用于医疗保健…...

ceph补充介绍
SDS-ceph ceph介绍 crushmap 1、crush算法通过计算数据存储位置来确定如何存储和检索,授权客户端直接连接osd 2、对象通过算法被切分成数据片,分布在不同的osd上 3、提供很多种的bucket,最小的节点是osd # 结构 osd (or device) host #主…...

2024/11/1 408 20题
b d c c a b d c c...

Python相关类库使用问题
文章目录 前言 一、pandas是什么? 二、使用步骤 1.引入库 2.读入数据 总结 前言 在工作中不时遇到新的需求,需要用到新的类库,以此篇专门记录Python类库使用过程中遇到的问题与解决 一、Python是什么? Python是一种高级编…...

ESP32/ESP8266开发板单向一对多ESP-NOW无线通信
ESP32/ESP8266开发板单向一对多ESP-NOW无线通信 简介读取ESP32/ESP8266接收方Receiver的MAC地址ESP32/ESP8266发送方Sender程序ESP32/ESP8266接收方Receiver程序ESP-NOW通信验证总结 简介 本实验通过ESP-NOW无线通信协议实现多个ESP32/ESP 8266开发板向ESP32开发板发送数据。例…...

动态规划-回文串问题——5.最长回文子串
1.题目解析 题目来源:5.最长回文子串——力扣 测试用例 2.算法原理 1.状态表示 判断回文子串需要知道该回文子串的首尾下标,所以需要一个二维数组且数据类型为bool类型来存储每个子字符串是否为回文子串, 即dp[i][j]:以第i个位置为起始&a…...

rtp协议:rtcp包发送和接收规则和报告!
RTCP Packet Send and Receive Rules: 发送和接收 RTCP 包的规则在此列出。允许在多播环境或多点单播环境中运行的实现必须满足第 6.2 节中的要求。这样的实现可以使用本节定义的算法来满足这些要求,或者可以使用其他算法,只要其性能等同或更…...
label数据(或自定义数据集)转imagenet(用于mmclassification)
理论上用于分类的图像一般都不需要用labelme来标注的,笔者是因为刚好手上有这么一组数据,所以就顺带处理了。labelme标注完的数据每张还包含了一个json文件,这个在分类任务中用不上。具体的mmclassification使用方法在我的另一篇文章里有&…...
WebMvcConfigurer
WebMvcConfigurer是Spring MVC框架中的一个核心接口,它允许开发者自定义Spring MVC的配置,以满足应用程序的特定需求。通过实现这个接口,开发者可以注册拦截器、添加视图控制器、配置视图解析器等,而无需使用XML配置。以下是对Web…...

Sigrity Power SI VR noise Metrics check模式如何进行电源噪声耦合分析操作指导
SSigrity Power SI VR noise Metrics check模式如何进行电源噪声耦合分析操作指导 Sigrity Power SI的VR noise Metrics check模式本质上是用来评估和观测器件的电源网络的耦合对于信号的影响,输出S参数以及列出具体的贡献值。 以下图为例...

Python+Appium+Pytest+Allure自动化测试框架-安装篇
文章目录 安装安装ADT安装NodeJs安装python安装appium安装Appium Server(可选)安装Appium-Inspector(可选)安装allure安装pytest PythonAppiumPytestAllure框架的安装 Appium是一个开源工具,是跨平台的,用于…...
Python的socket使用
在 Python 中,可以使用 socket 模块编写一个支持多个客户端连接的服务端。常见的实现方式包括使用多线程、多进程或异步 I/O。下面以多线程为例展示如何编写一个服务端,来同时接收和处理多个客户端的连接。 多线程服务端代码示例 这个示例服务端代码中…...

如何快速搭建一个3D虚拟展厅?
随着元宇宙概念的兴起,一个全新的虚拟、立体数字空间正逐步成为我们生活的一部分。在这个空间里,用户可以沉浸其中,进行丰富的交互操作,体验前所未有的无限可能。而如何快速搭建一个属于自己的元宇宙3D虚拟展厅,正成为…...
Android webview 打开本地H5项目(Cocos游戏以及Unity游戏)
webview打开本地Html文件 1.在路径前面加上file:// String filePath"file://"path;webView.loadUrl( filePath);2.打开权限 <uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE" />3.启用JavaScript 设置本地访问权限 webVi…...

解决项目中图片出不来的bug
在页面端图片呈现割裂状: 查看代码: 将代码改成: 即可正常显示图片。...

手机实时提取SIM卡打电话的信令声音-新的篇章(三、Android虚拟声卡探索)
手机实时提取SIM卡打电话的信令声音-新的篇章(三、Android虚拟声卡探索) 前言 前面的篇章中,我们从理论方向和实际市面上出现的音频线传输声音的方式,讨论绕开手机对SIM卡电话通话声音的封锁场景的可行性,并实际选购几款数字和模拟的USB转接…...

REST APIs与微服务:关键差异
在构建基于微服务的应用程序时RESYful API和微服务这两个术语经常相伴出现。然而,它们指的是截然不同的东西。 了解 RESTful API 和微服务之间差异的最简单方式是这样: 微服务:它们是构成更大规模基于微服务的应用程序的单个服务和功能&…...
【网安案例学习】反向蛮力攻击Reverse Brute Force Attack
【故事一】 在一个温暖的秋日下午,Jack坐在旧金山一家宁静的咖啡馆里,准备开始他的最新写作项目:追溯反向蛮力攻击的起源和发展。这是一个他一直想深入挖掘的主题,因为它揭示了网络安全世界中一个鲜为人知却极具影响力的故事。 …...
TCP/IP网络编程:理解网络编程和套接字
TCP/IP网络编程:理解网络编程和套接字 网络编程又叫做套接字编程,是因为在网络编程中依赖使用套接字(socket),网络编程一般是C/S架构,即客户端/服务器模式,在服务器端依赖套接字绑定自身接口,并开启监听客户端连接&am…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
全面解析各类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? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

MySQL:分区的基本使用
目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...
比特币:固若金汤的数字堡垒与它的四道防线
第一道防线:机密信函——无法破解的哈希加密 将每一笔比特币交易比作一封在堡垒内部传递的机密信函。 解释“哈希”(Hashing)就是一种军事级的加密术(SHA-256),能将信函内容(交易细节…...