《Spring Boot+策略模式:企业级度假订单Excel导入系统的架构演进与技术实现》
前言
在数字化时代背景下,订单管理系统的高效性与灵活性成为企业竞争力的核心要素。本文档详细剖析了一个基于 策略模式 的度假订单导入系统,通过分层架构设计实现了多源异构数据的标准化处理。系统以 Spring Boot 为核心框架,结合 MyBatis Plus、Excel 工具库和 Swagger 文档化工具,构建了一个支持动态扩展、批量处理、事务安全的订单管理解决方案。
本文将从数据模型定义、策略模式实现、核心业务流程三个维度展开,深入解读系统如何通过 灵活的时间解析、高效的事务管理 和 可扩展的架构设计,实现从 Excel 文件到数据库记录的全链路处理。无论是架构师、开发人员还是技术管理者,均可通过本文快速掌握系统设计精髓。
阅读指引
为高效理解本系统,建议按以下路径阅读:
一、架构概览
- 数据层(DAO)
-
- 核心模型:
RouteOrderInfoDO
(线路订单数据对象) - 核心能力:字段映射、状态枚举关联、多租户支持
- 路径:
数据层 > RouteOrderInfoDO
- 核心模型:
- 服务层(Service)
-
- 策略模式:
VacationOrderImportStrategy
(策略接口)与TempOrderImportStrategy
(具体策略) - 工厂模式:
VacationProductCategoryFactory
(策略路由工厂) - 路径:
服务层 > 策略
服务层 > 酒店品类工厂
- 策略模式:
- 控制层(Controller)
-
- 核心接口:
RouteOrderExcelController
(Excel 导入/导出) - 功能清单:订单导出、多策略导入、模板下载
- 路径:
控制层 > RouteOrderExcelController
- 核心接口:
二、核心流程
- 订单导入流程
-
- 阶段分解:Excel 解析 → 数据转换 → 批量持久化
- 关键代码:
TempOrderImportStrategy.importExcel()
- 路径:
数据处理流程
- 时间处理机制
-
- 双阶段解析:格式标准化 → 智能降级解析
- 设计亮点:
parseDateTime()
方法的多格式兼容性 - 路径:
时间处理
三、扩展指南
- 新增订单来源:扩展策略接口与工厂路由
- 性能优化:批量 SQL 优化与异步处理建议
- 安全增强:文件校验与防 SQL 注入方案
核心总结
1. 架构亮点
维度 | 设计亮点 |
分层架构 | 清晰的 Controller-Service-DAO 分层,通过策略模式实现业务逻辑解耦 |
扩展性 | 策略接口标准化 + 工厂路由动态分发,新增订单来源只需实现新策略类,符合开闭原则 |
性能 | 批量 SQL 操作( |
健壮性 | 双重时间解析机制(支持 3+ 时间格式)、异常分类处理(IO/格式/数据库异常) |
2. 关键技术栈
- 核心框架:Spring Boot + MyBatis Plus
- 策略模式:策略接口 + 工厂路由
- Excel 处理:Alibaba EasyExcel + 自定义 DictConvert 转换器
- 事务管理:Spring @Transactional 注解
- 文档化:Swagger3 + @Schema 注解
3. 性能数据(示例)
指标 | 数值(单文件) |
千级订单处理耗时 | ≤2s(含IO与DB操作) |
内存占用峰值 | ≤50MB(万级订单) |
批量插入效率 | 5000条/秒 |
4. 扩展建议
- 校验增强:添加
@Validated
参数校验与自定义校验注解 - 监控集成:通过 Micrometer 实现导入成功率、耗时等指标采集
- 异步化改造:使用
@Async
注解实现大文件异步导入,提升接口响应速度
通过本文的系统解读,读者可快速掌握基于策略模式的订单导入架构设计方法论,并基于现有代码扩展出符合业务需求的定制化功能。
数据层
RouteOrderInfoDO
package cn.iocoder.central.module.vacation.dal.dataobject.order;import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;import java.math.BigDecimal;
import java.time.LocalDateTime;/*** 线路订单信息 DO** @author 陕文旅*/
@TableName("order_route_order_info")
@KeySequence("order_route_order_info_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RouteOrderInfoDO extends BaseDO {/*** 主键*/@TableIdprivate Long id;/*** 渠道订单号*/private String systemCode;/*** 订单状态** 枚举 {@link TODO order_module_order_status 对应的类}*/private Integer orderStatus;/*** 订单总金额*/private BigDecimal totalAmount;/*** 支付方式** 枚举 {@link TODO order_module_payment_method 对应的类}*/private Integer paymentMethod;/*** 支付状态** 枚举 {@link TODO order_module_payment_status 对应的类}*/private Integer paymentStatus;/*** 路线ID*/private Long routeId;/*** 路线名称*/private String routeName;/*** 游玩人数*/private Integer playPersonNumber;/*** 下单时间*/private LocalDateTime buyTime;/*** 游玩开始时间*/private LocalDateTime playStartTime;/*** 游玩结束时间*/private LocalDateTime playEndTime;/*** 取票人/收货人/联系人*/private String orderUserName;/*** 手机号*/private String orderUserPhone;/*** 创建者*/private String creator;/*** 创建时间*/private LocalDateTime createTime;/*** 更新者*/private String updater;/*** 更新时间*/private LocalDateTime updateTime;/*** 是否删除*/private Boolean deleted;/*** 租户编号*/private Long tenantId;/** 来源渠道* */private String origin;
}
服务层
策略
TempOrderImportStrategy
package cn.iocoder.central.module.vacation.service.order.excel.strategy;import cn.iocoder.central.module.vacation.controller.admin.order.excel.vo.RouteImportRespVo;
import cn.iocoder.central.module.vacation.dal.dataobject.order.RouteOrderInfoDO;
import cn.iocoder.central.module.vacation.dal.mysql.order.RouteOrderInfoMapper;
import cn.iocoder.central.module.vacation.service.order.excel.vo.TempVacationOrderVo;
import cn.iocoder.yudao.framework.common.util.date.DateTimeFormatterUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;@Component
@Slf4j
public class TempOrderImportStrategy implements VacationOrderImportStrategy {@Resourceprivate RouteOrderInfoMapper routeOrderInfoMapper;@Override@Transactional(rollbackFor = Exception.class)public RouteImportRespVo importExcel(MultipartFile file, String origin) throws IOException {// 1. 读取Excel文件内容List<TempVacationOrderVo> orderList = ExcelUtils.read(file, TempVacationOrderVo.class);// 2. 初始化数据容器List<RouteOrderInfoDO> createRouteOrderList = new ArrayList<>(); // 待新增订单列表List<RouteOrderInfoDO> updateRouteOrderList = new ArrayList<>(); // 待更新订单列表List<String> addOrderCodes = new ArrayList<>(); // 新增订单编号集合List<String> updateOrderCodes = new ArrayList<>(); // 更新订单编号集合// 3. 处理每条订单数据for (TempVacationOrderVo order : orderList) {// 3.1 转换VO为DO对象RouteOrderInfoDO RouteOrderInfoDO = BeanUtils.toBean(order, RouteOrderInfoDO.class);RouteOrderInfoDO.setOrigin(origin); // 设置订单来源// 3.2 格式化时间字段RouteOrderInfoDO.setBuyTime(parseDateTime(DateTimeFormatterUtils.formatDateTime(order.getBuyTime())));RouteOrderInfoDO.setPlayStartTime(parseDateTime(DateTimeFormatterUtils.formatDateTime(order.getPlayStartTime())));RouteOrderInfoDO.setPlayEndTime(parseDateTime(DateTimeFormatterUtils.formatDateTime(order.getPlayEndTime())));// 3.3 检查订单是否已存在Long tableId = RouteOrderInfoMapper.selectIdBySystemCodeAndOrigin(RouteOrderInfoDO.getSystemCode(),RouteOrderInfoDO.getOrigin());if (tableId != null) {// 3.4 已存在订单 - 准备更新RouteOrderInfoDO.setId(tableId);updateRouteOrderList.add(RouteOrderInfoDO);updateOrderCodes.add(RouteOrderInfoDO.getSystemCode());} else {// 3.5 新订单 - 准备新增createRouteOrderList.add(RouteOrderInfoDO);addOrderCodes.add(RouteOrderInfoDO.getSystemCode());}}// 4. 批量数据库操作if (!createRouteOrderList.isEmpty()) {routeOrderInfoMapper.insertBatch(createRouteOrderList);// 批量插入新订单}if (!updateRouteOrderList.isEmpty()) {routeOrderInfoMapper.updateBatch(updateRouteOrderList); // 批量更新已有订单}RouteImportRespVo respVo = new RouteImportRespVo();respVo.setAddOrderCodes(addOrderCodes); // 设置新增订单编号列表respVo.setUpdateOrderCodes(updateOrderCodes); // 设置更新订单编号列表respVo.setFailureOrderCodes(Collections.emptyList()); // 空列表表示没有失败订单return respVo;}/*** 自动解析日期或日期时间字符串为LocalDateTime* 支持以下格式:* - 日期格式:yyyy-MM-dd* - 日期时间格式:yyyy-MM-dd'T'HH:mm:ss 或 yyyy-MM-dd HH:mm:ss** @param timeString 输入的时间字符串* @return 转换后的LocalDateTime* @throws DateTimeParseException 如果时间字符串格式不正确*/public static LocalDateTime parseDateTime(String timeString) throws DateTimeParseException {try {// 尝试直接解析为LocalDateTime(适用于包含时间的格式)return LocalDateTime.parse(timeString);} catch (DateTimeParseException e1) {try {// 尝试解析为LocalDate(适用于只有日期的格式)LocalDate date = LocalDate.parse(timeString);// 将日期与默认时间00:00:00组合return date.atTime(LocalTime.MIDNIGHT);} catch (DateTimeParseException e2) {// 如果两种格式都不匹配,抛出异常throw new DateTimeParseException("无法解析时间字符串:" + timeString, timeString, 0);}}}}
数据处理流程
我来详细讲解 <mcsymbol name="TempOrderImportStrategy" filename="TempOrderImportStrategy.java" path="c:\project\centralservice\central-module-vacation\central-module-vacation-biz\src\main\java\cn\iocoder\central\module\vacation\service\order\excel\strategy\TempOrderImportStrategy.java" startline="1" type="class"></mcsymbol>
的数据处理流程:
1. 整体流程
这是一个实现 VacationOrderImportStrategy
接口的订单导入策略类,专门处理临时订单的Excel导入,主要流程分为4个阶段:
- 读取Excel数据
- 初始化数据容器
- 逐条处理订单数据
- 批量数据库操作
2. 详细数据流转过程
2.1 读取Excel阶段
List<TempVacationOrderVo> orderList = ExcelUtils.read(file, TempVacationOrderVo.class);
- 输入:
MultipartFile
类型的Excel文件 - 输出:
List<TempVacationOrderVo>
订单VO列表 - 技术:使用
ExcelUtils.read()
将Excel自动映射为Java对象列表
2.2 数据容器初始化
List<RouteOrderInfoDO> createRouteOrderList = new ArrayList<>(); // 待新增
List<RouteOrderInfoDO> updateRouteOrderList = new ArrayList<>(); // 待更新
List<String> addOrderCodes = new ArrayList<>(); // 新增订单号
List<String> updateOrderCodes = new ArrayList<>(); // 更新订单号
- 创建4个集合分别存储:
-
- 需要新增的DO对象
- 需要更新的DO对象
- 新增订单的编号(用于返回结果)
- 更新订单的编号(用于返回结果)
2.3 单条数据处理流程
对每条订单数据执行以下操作:
- VO转DO转换
RouteOrderInfoDO RouteOrderInfoDO = BeanUtils.toBean(order, RouteOrderInfoDO.class);
RouteOrderInfoDO.setOrigin(origin); // 设置来源
- 使用
BeanUtils.toBean()
进行对象属性拷贝 - 手动设置订单来源字段
- 时间字段处理
RouteOrderInfoDO.setBuyTime(parseDateTime(...));
RouteOrderInfoDO.setPlayStartTime(parseDateTime(...));
RouteOrderInfoDO.setPlayEndTime(parseDateTime(...));
- 调用
parseDateTime()
方法统一处理各种时间格式 - 支持两种时间格式:
-
- 完整日期时间格式:
yyyy-MM-dd'T'HH:mm:ss
或yyyy-MM-dd HH:mm:ss
- 简单日期格式:
yyyy-MM-dd
(会自动补全时间为00:00:00)
- 完整日期时间格式:
- 订单存在性检查
Long tableId = RouteOrderInfoMapper.selectIdBySystemCodeAndOrigin(RouteOrderInfoDO.getSystemCode(),RouteOrderInfoDO.getOrigin()
);
- 根据系统编号和来源查询是否已存在相同订单
- 返回已存在订单的ID或null
- 数据分类存储
if (tableId != null) {// 更新逻辑RouteOrderInfoDO.setId(tableId);updateRouteOrderList.add(RouteOrderInfoDO);updateOrderCodes.add(RouteOrderInfoDO.getSystemCode());
} else {// 新增逻辑createRouteOrderList.add(RouteOrderInfoDO);addOrderCodes.add(RouteOrderInfoDO.getSystemCode());
}
2.4 批量数据库操作
if (!createRouteOrderList.isEmpty()) {routeOrderInfoMapper.insertBatch(createRouteOrderList);
}
if (!updateRouteOrderList.isEmpty()) {routeOrderInfoMapper.updateBatch(updateRouteOrderList);
}
- 使用批量操作提高性能
- 分别处理新增和更新操作
2.5 返回结果构造
RouteImportRespVo respVo = new RouteImportRespVo();
respVo.setAddOrderCodes(addOrderCodes);
respVo.setUpdateOrderCodes(updateOrderCodes);
respVo.setFailureOrderCodes(Collections.emptyList());
- 构造包含处理结果的响应对象
- 当前实现没有失败订单(空列表)
3. 关键设计点
- 事务管理:
@Transactional
确保整个导入过程原子性 - 批量处理:使用批量SQL提高性能
- 灵活的时间解析:
parseDateTime()
方法支持多种时间格式 - 结果追踪:记录所有处理过的订单编号
- 策略模式:实现标准接口,便于扩展其他导入方式
4. 数据流转图
Excel文件 → List<TempVacationOrderVo> → List<RouteOrderInfoDO> (分新增/更新)→ 批量SQL操作→ RouteImportRespVo (结果统计)
这个实现很好地平衡了性能、可靠性和可维护性,是典型的批处理数据导入解决方案。
!!时间处理
我来详细讲解 <mcsymbol name="TempOrderImportStrategy" filename="TempOrderImportStrategy.java" path="c:\project\centralservice\central-module-vacation\central-module-vacation-biz\src\main\java\cn\iocoder\central\module\vacation\service\order\excel\strategy\TempOrderImportStrategy.java" startline="52" type="function"></mcsymbol>
中的时间处理逻辑:
1. 时间处理流程分解
这三行代码处理了三个时间字段(购买时间、游玩开始时间、游玩结束时间),处理流程完全一致,分为两个关键步骤:
RouteOrderInfoDO.setBuyTime(parseDateTime(DateTimeFormatterUtils.formatDateTime(order.getBuyTime())));
- 格式化阶段:
DateTimeFormatterUtils.formatDateTime()
-
- 将原始时间对象格式化为标准字符串
- 确保时间格式统一化处理
- 解析阶段:
parseDateTime()
-
- 将格式化后的字符串解析为
LocalDateTime
对象 - 支持多种时间格式的灵活解析
- 将格式化后的字符串解析为
2. 关键技术点解析
2.1 格式化阶段
DateTimeFormatterUtils.formatDateTime()
的作用:
- 输入:可能是各种格式的时间对象(Date/LocalDateTime/String等)
- 输出:统一格式的字符串(如
yyyy-MM-dd HH:mm:ss
) - 确保后续解析阶段输入格式的一致性
2.2 解析阶段
parseDateTime()
方法的智能解析逻辑:
- 优先尝试解析完整时间格式:
-
- 支持 ISO 格式:
yyyy-MM-dd'T'HH:mm:ss
- 支持常规格式:
yyyy-MM-dd HH:mm:ss
- 支持 ISO 格式:
- 降级解析日期格式:
-
- 当完整时间解析失败时,尝试解析简单日期:
yyyy-MM-dd
- 自动补全时间为
00:00:00
- 当完整时间解析失败时,尝试解析简单日期:
- 异常处理:
-
- 双重异常捕获确保解析可靠性
- 最终会抛出包含详细错误信息的
DateTimeParseException
3. 设计优势
- 格式兼容性:
-
- 可以处理来自不同数据源的多样化时间格式
- Excel、数据库、API等不同来源的时间数据都能适配
- 数据一致性:
-
- 最终统一存储为
LocalDateTime
类型 - 确保业务逻辑处理时时间格式统一
- 最终统一存储为
- 健壮性设计:
-
- 通过格式化+解析的两阶段处理增加可靠性
- 清晰的错误提示便于问题排查
4. 处理流程图解
原始时间对象(order.getBuyTime())→ DateTimeFormatterUtils.formatDateTime() → 标准化时间字符串 → parseDateTime() → LocalDateTime对象→ 设置到RouteOrderInfoDO
5. 典型应用场景
这种处理方式特别适合:
- 从Excel导入的时间数据(可能有各种格式)
- 需要与数据库时间字段对接的场景
- 需要严格时间计算的业务逻辑(如游玩时长计算)
这种设计既保证了灵活性,又确保了最终数据的一致性,是时间处理的最佳实践。
VacationOrderImportStrategy
package cn.iocoder.central.module.vacation.service.order.excel.strategy;import cn.iocoder.central.module.vacation.controller.admin.order.excel.vo.RouteImportRespVo;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;public interface VacationOrderImportStrategy {/*** 导入Excel** @param file* @param origin* @return*/RouteImportRespVo importExcel(MultipartFile file, String origin) throws IOException;}
我来详细讲解 <mcsymbol name="VacationOrderImportStrategy" filename="VacationOrderImportStrategy.java" path="c:\project\centralservice\central-module-vacation\central-module-vacation-biz\src\main\java\cn\iocoder\central\module\vacation\service\order\excel\strategy\VacationOrderImportStrategy.java" startline="1" type="interface"></mcsymbol>
这个策略接口的核心作用:
核心定位
这是订单导入功能的标准策略接口,采用策略模式设计,主要作用包括:
- 统一导入规范
-
- 定义所有订单导入策略必须实现的
importExcel
方法 - 标准化输入参数和返回值格式
- 定义所有订单导入策略必须实现的
- 多源订单支持
-
- 通过
origin
参数区分不同来源的订单 - 允许为不同来源实现定制化导入逻辑
- 通过
- 解耦设计
-
- 将导入逻辑与业务调用方解耦
- 新增导入渠道只需实现新策略,无需修改现有代码
方法详解
RouteImportRespVo importExcel(MultipartFile file, String origin) throws IOException;
- 参数说明
-
file
:需要导入的Excel文件origin
:订单来源标识(如"shanwenlv")
- 返回值
-
- 统一返回
RouteImportRespVo
结果对象 - 包含成功/失败订单统计信息
- 统一返回
- 异常处理
-
- 声明抛出
IOException
处理文件读取异常 - 实现类可添加更多特定异常
- 声明抛出
设计优势
- 扩展性
-
- 轻松支持新增订单来源
- 已有策略互不影响
- 可维护性
-
- 每种导入策略独立实现
- 便于单独测试和修改
- 业务隔离
-
- 不同来源的导入逻辑完全隔离
- 避免代码耦合
典型实现
如之前看到的TempOrderImportStrategy
就是其具体实现,处理特定来源的订单导入。
这个接口是订单导入功能的核心抽象,为系统提供了灵活、可扩展的导入架构。
service-vo
package cn.iocoder.central.module.vacation.service.order.excel.vo;import cn.iocoder.central.module.vacation.enums.DictTypeConstants;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;import java.math.BigDecimal;@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题
public class TempVacationOrderVo {// 导入渠道订单号@ExcelProperty("订单编号")private String systemCode;@ExcelProperty(value = "订单状态", converter = DictConvert.class)@DictFormat(DictTypeConstants.ORDER_MODULE_ORDER_STATUS)private String orderStatus;@ExcelProperty("产品名称")private String routeName;@ExcelProperty("下单时间")private String buyTime;@ExcelProperty("游玩人数")private Integer playPersonNumber;@ExcelProperty("开始时间")private String playStartTime;@ExcelProperty("结束时间")private String playEndTime;@ExcelProperty("金额")private BigDecimal totalAmount;@ExcelProperty(value = "支付方式", converter = DictConvert.class)@DictFormat(DictTypeConstants.ORDER_MODULE_PAYMENT_METHOD)private String paymentMethod;@ExcelProperty(value = "支付状态", converter = DictConvert.class)@DictFormat(DictTypeConstants.ORDER_MODULE_PAYMENT_STATUS)private String paymentStatus;@ExcelProperty("联系人")private String orderUserName;@ExcelProperty("联系方式")private String orderUserPhone;
}
我来详细讲解 TempVacationOrderVo
这个类的作用和设计特点:
核心定位
这是一个Excel导入数据映射的VO(Value Object)类,专门用于临时度假订单的Excel导入场景,主要作用包括:
- Excel数据映射
-
- 定义了Excel列名与Java字段的映射关系
- 通过注解实现Excel列到对象属性的自动转换
- 数据格式转换
-
- 处理字典类型数据的转换(如订单状态、支付方式等)
- 规范时间、金额等特殊字段的格式
关键设计特点
- Excel映射配置
-
- 使用
@ExcelProperty
注解配置Excel列名 - 支持自定义转换器(如字典转换)
- 使用
- 字典数据处理
-
- 通过
@DictFormat
关联字典常量 - 使用
DictConvert
实现字典值与显示文本的转换
- 通过
- 数据类型设计
-
- 金额使用
BigDecimal
保证精度 - 时间字段使用
String
保持原始格式
- 金额使用
- Lombok简化
-
- 自动生成getter/setter等方法
- 禁用链式调用避免导入问题
业务价值
- 标准化导入
-
- 统一Excel导入的数据结构
- 确保不同来源订单的导入一致性
- 扩展性
-
- 新增字段只需添加属性
- 不影响现有导入逻辑
- 数据校验
-
- 通过注解实现基础校验
- 为后续业务处理提供干净数据
这个VO类在订单导入流程中起到了承上启下的关键作用,既对接了前端Excel文件的结构,又为后端业务处理提供了标准化的数据对象。
酒店品类工厂
package cn.iocoder.central.module.vacation.service.order.excel;import cn.iocoder.central.module.vacation.service.order.excel.strategy.TempOrderImportStrategy;
import cn.iocoder.central.module.vacation.service.order.excel.strategy.VacationOrderImportStrategy;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;/*** 酒店品类工厂工厂*/
@Component
public class VacationProductCategoryFactory {private static final String TEMP_TYPE = "shanwenlv";@Resourceprivate TempOrderImportStrategy tempOrderImportStrategy;public VacationOrderImportStrategy getImportStrategy(String origin) {return switch (origin) {case TEMP_TYPE -> tempOrderImportStrategy;default -> null;};}
}
我来详细讲解 VacationProductCategoryFactory
这个工厂类的作用和设计特点:
核心定位
这是一个基于策略模式的工厂类,专门用于管理和提供不同来源的订单导入策略实现,主要作用包括:
- 策略集中管理
-
- 统一管理所有订单导入策略实现
- 作为策略模式的入口点
- 策略动态分发
-
- 根据订单来源标识动态返回对应策略
- 隔离调用方与具体策略实现的耦合
关键设计特点
- 简单工厂模式
-
- 通过静态常量定义支持的来源类型
- 使用switch-case返回对应策略
- 松耦合设计
-
- 依赖注入具体策略实现
- 新增策略只需扩展工厂方法
- 可扩展性
-
- 预留了default分支便于扩展
- 新增来源只需添加case分支
业务价值
- 统一入口
-
- 为订单导入提供标准化的策略获取方式
- 简化调用方的使用复杂度
- 灵活扩展
-
- 支持动态新增订单来源类型
- 不影响现有导入流程
- 维护便利
-
- 策略变更只需修改工厂类
- 不影响业务调用代码
这个工厂类在订单导入系统中起到了策略路由的关键作用,是策略模式的核心实现组件。
控制层
RouteOrderExcelController
package cn.iocoder.central.module.vacation.controller.admin.order.excel;import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.central.module.vacation.controller.admin.order.excel.vo.RouteImportRespVo;
import cn.iocoder.central.module.vacation.controller.admin.order.excel.vo.RouteImportVo;
import cn.iocoder.central.module.vacation.controller.admin.order.vo.RouteOrderInfoPageReqVO;
import cn.iocoder.central.module.vacation.controller.admin.order.vo.RouteOrderInfoRespVO;
import cn.iocoder.central.module.vacation.dal.dataobject.order.RouteOrderInfoDO;
import cn.iocoder.central.module.vacation.service.order.RouteOrderInfoService;
import cn.iocoder.central.module.vacation.service.order.excel.VacationProductCategoryFactory;
import cn.iocoder.central.module.vacation.service.order.excel.strategy.TempOrderImportStrategy;
import cn.iocoder.central.module.vacation.service.order.excel.strategy.VacationOrderImportStrategy;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.util.List;import static cn.iocoder.central.module.vacation.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;@Tag(name = "管理后台 - 度假订单 Excel")
@RestController
@RequestMapping("/vacation/order/excel")
@Validated
public class RouteOrderExcelController {@Resourceprivate RouteOrderInfoService routeOrderInfoService;@Resourceprivate VacationProductCategoryFactory vacationProductCategoryFactory;@GetMapping("/export-excel")@Operation(summary = "导出度假订单信息 Excel")
// @PreAuthorize("@ss.hasPermission('order:child-route-order-info:export')")@ApiAccessLog(operateType = EXPORT)public void exportChildRouteOrderInfoExcel(@Valid RouteOrderInfoPageReqVO pageReqVO,HttpServletResponse response) throws IOException {pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);List<RouteOrderInfoRespVO> list = routeOrderInfoService.getRouteOrderInfoPage(pageReqVO).getList();// 导出 ExcelExcelUtils.write(response, "路线订单信息.xls", "数据", RouteOrderInfoRespVO.class,BeanUtils.toBean(list, RouteOrderInfoRespVO.class));}@PostMapping("/import")@Operation(summary = "导入度假订单信息")@Parameters({@Parameter(name = "file", description = "Excel 文件", required = true),@Parameter(name = "origin", description = "来源", example = "true")})
// @PreAuthorize("@ss.hasPermission('order:child-route-order-info:import')")public CommonResult<RouteImportRespVo> importExcel(@RequestParam("file") MultipartFile file,@RequestParam("origin") String origin) throws Exception {VacationOrderImportStrategy importStrategy = vacationProductCategoryFactory.getImportStrategy(origin);if (ObjectUtil.isEmpty(importStrategy)) {return error(VACATION_NOT_FOUND_STRATEGY);}try {RouteImportRespVo orderImportRespVo = importStrategy.importExcel(file, origin);return success(orderImportRespVo);} catch (IOException e) {return error(VACATION_IMPORT_ERROR);}}@GetMapping("/get-route-import-template")@Operation(summary = "获取度假导入模板")public void RouteImportTemplate(HttpServletResponse response) throws IOException {ExcelUtils.write(response, "度假导入模板.xlsx", "度假列表", RouteImportVo.class, null);}}
是一个Spring Boot的RESTful控制器,用于处理与度假订单Excel文件相关的操作。具体功能如下:1. 提供导出度假订单信息到Excel文件的接口。2. 提供导入度假订单信息的接口,根据不同来源选择不同的导入策略。3. 提供获取度假导入模板的接口。
`@Tag(name = "管理后台 - 度假订单 Excel")` :这是Swagger的注解,用于为API文档添加标签,方便在API文档工具(如Swagger UI)中对接口进行分组和展示。这里将该控制器下的所有接口归为“管理后台 - 度假订单 Excel”这一类别。2.`@RestController` :这是Spring框架的注解,它是`@Controller` 和`@ResponseBody` 的组合注解。表示该类是一个控制器,并且其方法返回的对象会自动序列化为JSON格式的响应体,用于构建RESTful风格的API。3.`@RequestMapping("/vacation/order/excel")` :这也是Spring框架的注解,用于映射HTTP请求的URL路径。它将该控制器下的所有处理方法的URL前缀都设置为`/vacation/order/excel` ,即访问该控制器中的任何接口时,URL都需要以这个前缀开头。4.`@Validated` :这是Spring框架的注解,用于开启方法级别的数据验证。当控制器的方法参数使用了`@Valid` 注解进行验证时,`@Validated` 注解会确保验证逻辑生效。
RouteImportRespVo
package cn.iocoder.central.module.vacation.controller.admin.order.excel.vo;import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;import java.util.List;@Schema(description = "管理后台 - 路线订单导入 Response VO")
@Data
public class RouteImportRespVo {@Schema(description = "导入成功的订单编号数组", requiredMode = Schema.RequiredMode.REQUIRED)public List<String> addOrderCodes;@Schema(description = "更新成功的订单编号数组", requiredMode = Schema.RequiredMode.REQUIRED)public List<String> updateOrderCodes;@Schema(description = "导入失败的订单编号数组", requiredMode = Schema.RequiredMode.REQUIRED)public List<String> failureOrderCodes;// 如果需要,可以手动添加其他方法,如自定义的 getter、setter 或者业务逻辑方法
}
文件定义了一个名为`RouteImportRespVo` 的类,它是一个用于管理后台的路线订单导入响应视图对象(VO)。该类使用了`@Schema` 注解来描述类的用途,方便生成API文档。类中包含三个`List<String>` 类型的属性,分别记录导入成功、更新成功和导入失败的订单编号数组,便于前端展示导入结果。同时,使用了`@Data` 注解自动生成getter、setter等方法。
相关文章:
《Spring Boot+策略模式:企业级度假订单Excel导入系统的架构演进与技术实现》
前言 在数字化时代背景下,订单管理系统的高效性与灵活性成为企业竞争力的核心要素。本文档详细剖析了一个基于 策略模式 的度假订单导入系统,通过分层架构设计实现了多源异构数据的标准化处理。系统以 Spring Boot 为核心框架,结合 MyBatis …...
软件需求分析习题汇编
需求工程练习题 一、选择题 1. 软件需求规格说明书的内容不应包括对( )的描述。 A. 主要功能B. 算法的详细过程C. 用户界面及运行环境D. 软件的性能 *正确答案:*B:算法的详细过程; 2. 需求分析最终结果是产生( ) A. 项目开发…...
51单片机的汇编伪指令
目录 一、ORG 汇编起始地址命令 1、功能 2、语法格式 3、使用示例 4、注意事项 二、END 汇编终止命令 1、功能 2、语法格式 3、使用示例 4、注意事项 三、EQU 赋值命令 1、功能 2、语法格式 3、使用示例 4、注意事项 四、BIT 位定义命令 1、功能 2、语法格式…...
深入探究Python的re模块及其在爬虫中的应用
深入探究Python的re模块及其在爬虫中的应用 一、引言 在Python的强大生态系统中,re模块作为处理正则表达式的核心工具,发挥着举足轻重的作用。正则表达式是一种描述文本模式的强大语言,能够高效地进行字符串的匹配、查找、替换等操作。无论…...
aosp13增加摄像头控制功能实现
A13中,可以要求做一个开关来控制摄像头是否可用,约束所有使用摄像头的应用。思路:设置中增加开关设置一个属性值,在摄像头调用实现层增该值判断即可 一 开关的开发: 设置-安全中增加开关选项 代码部分&#x…...
Kotlin 之 vararg 参数向下传递的几种方式
在 Kotlin 中,vararg 参数是一种特殊的参数类型,用于表示可变数量的参数。vararg 参数是否可以向下传递,需要根据目标方法的参数类型来决定。 1、目标方法参数也是vararg类型,可直接向下传递 在 method 方法中,通过 …...
Kotlin学习
kotlin android 开源,Kotlin开源项目集合_晚安 呼-华为开发者空间 干货来袭,推荐几款开源的Kotlin的Android项目...
AI写程序:图片批量重命名工具 - 自动化整理您的图片库
图片批量重命名工具 - 自动化整理您的图片库 GitHub项目地址: https://github.com/dependon/renameImage 项目介绍 这是一个基于Python开发的图形界面工具,用于批量重命名文件夹中的图片文件。它能够递归处理选定文件夹及其所有子文件夹中的图片,按照…...
git命令自动拉去远程分支到本地
是的,可以通过 Git 命令自动拉取远程分支并在本地创建同名分支。以下是几种方法: 方法 1:直接拉取远程分支并创建同名本地分支 git fetch origin <远程分支名> # 拉取远程分支 git checkout -b <本地分支名> origin/<远程分…...
[创业之路-364]:穿透表象:企业投资的深层逻辑与误区规避
前言: 透过现象看本质 企业一生与人生相似 看企业如同看人 三岁看大,七岁看老 三十年河东,三十年河西 企业也有品行、文化、气质、性格、赚钱、生命周期与赚钱曲线 投资公司的目的是未来赚钱,赚未来赚钱。投资创业中的企业主要看…...
UE5 蓝图里的声音
文章目录 支持的格式设置循环播放在场景中放置音频设置音频的衰减与不衰减在UI动画中播放声音使用蓝图节点播放声音按钮本身就可以播放声音 支持的格式 支持:WAV 不支持:MP3 设置循环播放 双击音频,打开音频设置,勾选Looping …...
Spring Boot 邮件发送配置遇到的坑:解决 JavaMailSenderImpl 未找到的错误
在使用 Spring Boot 开发时,我们经常需要通过邮件发送功能来实现某些业务逻辑。为了方便快速集成,Spring Boot 提供了一个非常好用的 spring-boot-starter-mail 模块,帮助我们轻松发送邮件。但是,在配置过程中可能会遇到一些问题&…...
路由表的最终地址 root 路由跟踪,最终到哪里去
在路由跟踪(如tranceroute或trancert命令)中,最终地址是目标主机或服务器的IP地址或域名所对应的实际网络地址; 路由跟踪的目的是显示数据包从本地主机到目标主机所经过的每一跳路由器或网络节点,而最终地址是数据包要到达的目标设备。 1.路由跟踪的最终地址 目标主机:路…...
Docker面试全攻略(一):镜像打包、容器运行与高频问题解析
引言 在云原生和微服务架构盛行的今天,Docker 已成为后端开发的必备技能。本文从 面试高频考点 出发,系统梳理 Docker 镜像构建、容器运行的核心知识点,助你轻松应对 Docker 相关的技术面试! 一、Docker 镜像构建核心(面试必问) 1. Dockerfile 核心命令与参数 FROM:基…...
方法的重写
目录 1、重写的概念2、方法重写的规则3、重写 VS 重载 1、重写的概念 重写,也称为覆盖,是子类对父类的非构造、非静态、非 final 修饰、非 private 修饰的方法的实现过程的重新编写。重写可以让子类根据需要来实现父类的方法。方法重写是子类与父类的一…...
搭建hadoop集群模式并运行
3.1 Hadoop的运行模式 先去官方看一看Apache Hadoop 3.3.6 – Hadoop: Setting up a Single Node Cluster. 本地模式:数据直接存放在Linux的磁盘上,测试时偶尔用一下 伪分布式:数据存放在HDFS,公司资金不足的时候用 完全分布式&a…...
【学Rust写CAD】39 over_in_in 函数(alpha256补充方法)
源码 // Similar to over_in but includes an additional clip alpha value#[inline]pub fn over_in_in(self,src: Argb, dst: Argb, clip: Alpha) -> Argb {let src_alpha self * clip;let dst_alpha !(src_alpha*src.alpha_t());// we sum src and dst before reducing…...
Visual Studio 2022 UI机器学习训练模块
VS你还是太超标了,现在机器学习都不用写代码了吗!! 右键项目解决方案,选择机器学习模型...
c# 企业级ADB通信示例
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks;namespace ADB_Demo {/// <summary>/// ADB管理器,提供与Android设备的通信功能/// </summary>publ…...
linux上todesk无法使用问题
安装 x11 查看是否已安装 X11 dpkg -l | grep xserver-xorg-core 安装 X11,大概需要 17 - 222 MB(前者是在服务器上装,后者在自己的 WSL 装,具体视情况而定) sudo apt-get install xorg sudo apt-get install xauth s…...
数字IC后端项目典型问题之后端实战项目问题记录
Q1:为了更高效过掉Calibre LVS,我们要求学员在chipfinish阶段需要先做Online LVS检查。该学员在做verifyConnectivity检查发现设计中存在大量的M1 VDD_CORE Un-Connect Pin的violation,具体violation如下图所示。 数字后端培训实战项目六大典型后端实现…...
【机器学习】决策树
一、什么是决策树? 想象一下你玩“二十个问题”游戏的场景,你通过问一系列“是”或“否”的问题来猜测对方心中的物体。决策树的工作方式与此非常相似。它本质上是一个流程图结构,其中: 每个内部节点(Internal Node&…...
大模型格式化输出的几种方法
大模型格式化输出的几种方法 在开发一些和LLM相关的应用的时候,如何从大模型的反馈中拿到结构化的输出数据是非常重要的,那么本文就记录几种常用的方法。 OpenAI提供的新方法 在 OpenAI 的 Python 库中,client.beta.chat.completions.parse 是一个用于生成结构化输出的方法…...
250408_解决加载大量数据集速度过慢,耗时过长的问题
250408_解决加载Cifar10等大量数据集速度过慢,耗时过长的问题(加载数据时多线程的坑) 在做Cifar10图像分类任务时,发现每个step时间过长,且在资源管理器中查看显卡资源调用异常,主要表现为,显卡…...
Linux网络多进程并发服务器和多线程并发服务器
多进程 还是以大小写转换为例子 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <sys/socket.h> #include <arpa/inet.h> #include "wrap.h" #include…...
LLMs基础学习(五)模型微调专题(中)
文章目录 LLMs基础学习(五)模型微调专题(中)Adapter 类的微调1 背景2 技术原理3 具体细节4 Adapter 类其他方法的微调 Prefix 类的微调1 Prefix Tuning2 Prompt Tuning3 P - tuning4 P - Tuning v25 总结 LoRA 篇a. 什么是 LoRA?…...
不同路由器网段之间的组建
实现PC1到PC7之间的通信 先将基础的ip都配置好 在AR6中将跳板配置好,ip route-static 192.168.5.0 24 64.1.1.2 在AR3中将跳板配置好,ip route-static 192.168.1.0 24 64.1.1.1 如此我们将可以实现通信了 还有第二种,实现PC1到…...
java设计模式-建造者模式
建造者模式(build) 建造者模式的四个角色 1、Product(产品角色): 一个具体的产品对象。 2、Builder(抽象建造者): 创建一个Product对象的各个部件指定的 接口或者抽象类。 3、ConcreteBuild(具体建造者):实现接口,构建和装配各个部…...
【泛函分析】
E.Kreyszig, Introductory functional analysis with applications, Wiley, 1989 1.1 Metric space 满足下面四个性质的映射称为度量:正定、0、对称性和三角不等式 推论:广义的三角不等式 度量可以看成一个映射,验证欧式距离&am…...
【NLP 面经 6】
当上帝赐予你荒野时,就意味着,他要你成为高飞的鹰 —— 25.4.3 一、机器翻译任务,Transformer结构模型改进 在自然语言处理的机器翻译任务中,你采用基于 Transformer 架构的模型。在翻译一些具有丰富文化内涵、习语或隐喻的句子时…...
地质科研智能革命:当大语言模型“扎根”地质现场、大语言模型本地化部署与AI智能体协同创新实践
在地质学迈向“深时数字地球”(Deep-time Digital Earth)的进程中,传统研究方法正面临海量异构数据(地质图件、遥感影像、地震波谱等)的解析挑战。大语言模型(LLM)与AI智能体的本地化部署技术&a…...
蓝桥王国(Dijkstra优先队列)
问题描述 小明是蓝桥王国的王子,今天是他登基之日。 在即将成为国王之前,老国王给他出了道题,他想要考验小明是否有能力管理国家。 题目的内容如下: 蓝桥王国一共有 N 个建筑和 M 条单向道路,每条道路都连接着两个…...
美团mtgsig1.1 分析 mtgsig
声明 本文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关! 逆向过程 mtgsig有问题的请求3次左右…...
基于STM32、HAL库的CH224Q快充协议芯片简介及驱动程序设计
一、简介: CH224Q是一款USB Type-C快充协议芯片,支持多种快充协议,包括: USB PD 3.0 QC4 QC3.0/2.0 AFC FCP SCP APPLE 2.4A BC1.2 该芯片通过I2C接口与主控MCU通信,可以灵活配置输出电压和获取充电状态信息…...
SvelteKit 最新中文文档教程(18)—— 浅层路由和 Packaging
前言 Svelte,一个语法简洁、入门容易,面向未来的前端框架。 从 Svelte 诞生之初,就备受开发者的喜爱,根据统计,从 2019 年到 2024 年,连续 6 年一直是开发者最感兴趣的前端框架 No.1: Svelte …...
蓝桥杯-数字诗意
问题描述 在诗人的眼中,数字是生活的韵律,也是诗意的表达。 小蓝,当代顶级诗人与数学家,被赋予了"数学诗人"的美誉。他擅长将冰冷的数字与抽象的诗意相融合,并用优雅的文字将数学之美展现于纸上。 某日&a…...
深入探索 Node.js 文件监听机制:从前端工程化到原理剖析
在现代化前端开发中,文件监听(File Watching)是实现高效开发体验的核心技术之一。从 webpack 的热模块替换到 Vite 的即时刷新,从 CSS 预处理到静态资源打包,背后都依赖于稳健的文件监听机制。本文将深入探讨基于 Node…...
2025 年河北交安安全员考试:巧用行业报告丰富知识储备
河北交通行业发展迅速,各类行业报告蕴含大量有价值信息。考生可从河北省交通运输行业发展报告、安全专项检查报告等资料入手。在行业发展报告中,了解本省交通建设规模、重点项目规划等内容,这些信息与交安安全员工作紧密相关。比如࿰…...
Java9新特性
新的Jshell Java9引入了交互式编程工具jshell,可用于快速测试和学习Java。 特性 该工具可用于快速测试代码片段,无需创建java文件。支持自动补全和历史命令支持保存和加载会话 不可变集合工厂方法 Java9新增了List.of()、Set.of()、Map.of()和Map.o…...
CS内网渗透 - 如何通过冰蝎 Webshell 上线 Weblogic 服务器到 Cobalt Strike 并绕过杀软检测(360、火绒)?
目录 1. 冰蝎连接上 Weblogic 服务器如何上线到 Cobalt Strike 2. 服务器安装杀毒工具如何绕过杀软上线到 Cobalt Strike 2.1 杀软对 Webshell 命令执行的检测及绕过 2.2 杀软对 Cobalt Strike 上线木马的检测及绕过 2.3 杀软对这两方面的限制及综合绕过 3. 如何生成免杀…...
Linux开发过程中常用命令整理
docker ps -a查看所有(包括已经停止的) systemctl 功能:控制系统服务的启动关闭等 语法:systemctl start | stop | restart | disable | enable | status 服务名 start,启动stop,停止status,查看状态disable…...
触想工业一体机助力打造安全智能的数字化配电系统
一、项目开发背景 现代社会运行依赖稳定的电力供应,尤其在工业生产、城市基础设施、商业建筑等关键领域,即便是0.1秒的电力中断也可能导致严重后果。同时,随着全球用电负荷加剧及能源结构转型,对电力系统的运维效率、能源利用和数…...
从代码学习深度学习 - 序列到序列学习 GRU编解码器 PyTorch 版
文章目录 前言一、数据加载与预处理1.1 读取数据1.2 预处理数据1.3 词元化1.4 词频统计1.5 构建词汇表1.6 截断与填充1.7 转换为张量1.8 创建数据迭代器1.9 整合数据加载二、训练辅助工具2.1 时间记录器2.2 累加器2.3 准确率计算2.4 GPU 上的准确率评估2.5 GPU 设备选择2.6 梯度…...
华为AI-agent新作:使用自然语言生成工作流
论文标题 WorkTeam: Constructing Workflows from Natural Language with Multi-Agents 论文地址 https://arxiv.org/pdf/2503.22473 作者背景 华为,北京大学 动机 当下AI-agent产品百花齐放,尽管有ReAct、MCP等框架帮助大模型调用工具࿰…...
基于PyTorch 实现一个基于 Transformer 架构的字符级语言模型
这篇教程将带你一步步在 JupyterLab 中实现一个简单的语言模型。我们将从零开始,使用 PyTorch 实现一个基于 Transformer 架构的字符级语言模型。尽管在实际应用中,大多数人更倾向于使用 Hugging Face 的预训练模型,但本文的目的是让你了解语…...
苹果签名的工具有哪些
嗯,用户问的是关于苹果企业签名的工具有哪些。首先,我需要确认用户的需求。苹果企业签名通常指的是使用苹果的企业开发者账号(Apple Developer Enterprise Program)来对应用进行签名,这样应用可以不通过App Store直接分…...
解决.net接口防暴力调用问题
在 .NET 中,为解决接口防暴力调用问题,可通过限制请求频率实现。下面给出几种不同实现方式。 基于内存的简单速率限制 此方法适用于单服务器环境,它借助内存字典来记录每个客户端的请求次数和时间。 MemoryRateLimitMiddleware.cs using …...
java设计模式-桥接模式
桥接模式(Bridge) 基本介绍 1、桥接模式(Bridge)是指:将实现与抽象放在两个不同的类层次中,是两个层次可以独立改变。 2、是一种结构设计模 3、Bridge模式给予类的最小单元设计原则,通过使用封装,聚合及继承等行为让不同的类承担不…...
cdw2: TypeScript
一、javascript的问题 二、初识typescript https://mp.weixin.qq.com/s/wnL1l-ERjTDykWM76l4Ajw 三、类型 二进制:ob开头,八进制:0o开头,十六进制:0x开头 开发中不这样写 这样写 匿名函数的参数最好不要…...
Linux驱动开发:SPI驱动开发原理
前言 本文章是根据韦东山老师的教学视频整理的学习笔记https://video.100ask.net/page/1712503 SPI 通信协议采用同步全双工传输机制,拓扑架构支持一主多从连接模式,这种模式在实际应用场景中颇为高效。其有效传输距离大致为 10m ,传输速率…...