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

小熊家政帮day22-day23 订单系统优化(订单状态机、练习分库分表、索引、订单缓存)

目录

  • 1 状态机
    • 1.1 状态机介绍
      • 1.1.1 当前存在的问题
      • 1.1.2 使用状态机解决问题
    • 1.2 实现订单状态机
      • 1.2.1 编写订单状态机
        • 1.2.1.1 依赖引入
        • 1.2.1.2 订单状态枚举类
        • 1.2.1.3 状态变更事件枚举类
        • 1.2.1.4 定义订单快照类
        • 1.2.1.5 定义事件变更动作类
        • 1.2.1.5 定义订单状态机类
        • 1.2.1.6 状态机表设计
      • 1.2.2 测试订单状态机
        • 加载订单状态机
        • 测试启动状态机
      • 1.2.3 使用订单状态机
        • 下单时启动状态机
        • 支付成功使用状态机
        • 测试

1 状态机

1.1 状态机介绍

1.1.1 当前存在的问题

在预约下单模块设计订单状态共有7种,如下图:
在这里插入图片描述
目前我们使用了待支付、派单中两种状态,在代码中我们发现存在对订单状态进行硬编码的情况,但是随着开发的深入这种代码会越来越多,比如在实现对订单进行关闭时代码会写成如下的形式:

1//运营人员在订单完成时取消订单//执行此场景下的业务逻辑//更新订单状态为派单中update(id,已关闭)
)
if(订单状态==服务中){//运营人员在服务中时取消订单//执行此场景下的业务逻辑//更新订单状态为已关闭update(id,已关闭)
)
...

以上代码存在问题如下:
在业务代码中对订单状态进行硬编码如果有一天更改了业务逻辑就需要更改代码,不方便进行系统扩展和维护。
另外对订单状态的管理是散落在很多地方不方便对订单状态进行统一管理和维护。

1.1.2 使用状态机解决问题

针对以上问题如何解决呢?
我们可以使用状态机对订单状态进行统一管理。

什么是状态机?
上图在UML中叫状态图(又叫状态机图),UML是软件开发中的一种建模语言,用来辅助进行软件设计,常用的如:类图、对象、状态图、序列图等,注意状态机图并不是状态机,状态机是一种数学模型,应用在自动化控制、计算机科学、通信等很多领域,简单理解状态机就是对状态进行统一管理的数学模型。
我们画的状态图是状态机在计算机科学中的应用方法,还有状态机设计模式也是状态机在软件领域的应用方法。
状态机设计模式是状态机在软件中的应用,状态机设计模式描述了一个对象在内部状态发生变化时如何改变其行为,将状态之间的变更定义为事件,将事件暴露出去,通过执行状态变更事件去更改状态,这是状态机设计模式的核心内容。

理解状态机设计模式需要理解四个要素:现态、事件、动作、次态。

1、现态:是指当前所处的状态。
2、事件:当一个条件被满足,状态会由现态变为新的状态,事件发生会触发一个动作,或者执行一次状态的迁移。
3、动作:发生事件执行的动作,动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
4、次态:条件满足后要迁往的新状态。

我们拿待支付状态到派单中状态举例:
在这里插入图片描述
现态:订单当前处于待支付状态那么现态为待支付。
事件:用户支付成功为事件,支付成功是条件,当条件满足进行状态迁移。
动作:将订单状态由待支付更改为派单中。
次态:派单中。

使用状态机优化代码:
使用状态机之后对代码进行以下优化。
支付成功更改订单状态的代码优化如下:

if(支付状态==支付成功){//调用状态机执行支付成功事件orderStateMachine.changeStatus(id,支付成功事件);
}

订单取消的代码优化如下:

orderStateMachine.changeStatus(id,订单完成时取消订单事件);

我们发现使用状态机的代码并没有对订单状态进行硬编码,只是指定了订单id和事件名称,执行changeStatus方法后自动更改订单的状态。

1.2 实现订单状态机

1.2.1 编写订单状态机

1.2.1.1 依赖引入

本项目基于状态机设计模式开发了状态机组件,代码在jzo2o-framework中,如果在订单管理服务中实现订单状态机需要添加状态机的依赖。
在jzo2o-orders-base工程的pom.xml中添加状态机组件的依赖

<dependency><groupId>com.jzo2o</groupId><artifactId>jzo2o-statemachine</artifactId><version>1.0-SNAPSHOT</version>
</dependency>
1.2.1.2 订单状态枚举类

阅读订单状态枚举类,它实现了StatusDefine 状态接口,不论是现态还是次态都需要实现状态接口。
定义每个枚举需要注意见名知意,比如:NO_PAY(0, “待支付”, “NO_PAY”)表示待支付状态。
订单状态枚举类如下:

@Getter
@AllArgsConstructor
public enum OrderStatusEnum implements StatusDefine {NO_PAY(0, "待支付", "NO_PAY"),DISPATCHING(100, "派单中", "DISPATCHING"),NO_SERVE(200, "待服务", "NO_SERVE"),SERVING(300, "服务中", "SERVING"),FINISHED(500, "已完成", "FINISHED"),CANCELED(600, "已取消", "CANCELED"),CLOSED(700, "已关闭", "CLOSED");private final Integer status;private final String desc;private final String code;/*** 根据状态值获得对应枚举** @param status 状态* @return 状态对应枚举*/public static OrderStatusEnum codeOf(Integer status) {for (OrderStatusEnum orderStatusEnum : values()) {if (orderStatusEnum.status.equals(status)) {return orderStatusEnum;}}return null;}
}
1.2.1.3 状态变更事件枚举类

所有状态之间存在的变更都需要定义状态变更事件,它实现了StatusChangeEvent 状态变更事件接口,事件对应状态机四要素的事件
代码如下,重点看PAYED:
PAYED(OrderStatusEnum.NO_PAY, OrderStatusEnum.DISPATCHING, “支付成功”, “payed”)表示由NO_PAY(未支付)状态变化为DISPATCHING(派单中)状态,事件名称为“支付成功”(payed)。

@Getter
@AllArgsConstructor
public enum OrderStatusChangeEventEnum implements StatusChangeEvent {PAYED(OrderStatusEnum.NO_PAY, OrderStatusEnum.DISPATCHING, "支付成功", "payed"),DISPATCH(OrderStatusEnum.DISPATCHING, OrderStatusEnum.NO_SERVE, "接单/抢单成功", "dispatch"),START_SERVE(OrderStatusEnum.NO_SERVE, OrderStatusEnum.SERVING, "开始服务", "start_serve"),COMPLETE_SERVE(OrderStatusEnum.SERVING, OrderStatusEnum.FINISHED, "完成服务", "complete_serve"),
//    EVALUATE(OrderStatusEnum.NO_EVALUATION, OrderStatusEnum.FINISHED, "评价完成", "evaluate"),CANCEL(OrderStatusEnum.NO_PAY, OrderStatusEnum.CANCELED, "取消订单", "cancel"),SERVE_PROVIDER_CANCEL(OrderStatusEnum.NO_SERVE, OrderStatusEnum.DISPATCHING, "服务人员/机构取消订单", "serve_provider_cancel"),CLOSE_DISPATCHING_ORDER(OrderStatusEnum.DISPATCHING, OrderStatusEnum.CLOSED, "派单中订单关闭", "close_dispatching_order"),CLOSE_NO_SERVE_ORDER(OrderStatusEnum.NO_SERVE, OrderStatusEnum.CLOSED, "待服务订单关闭", "close_no_serve_order"),CLOSE_SERVING_ORDER(OrderStatusEnum.SERVING, OrderStatusEnum.CLOSED, "服务中订单关闭", "close_serving_order"),
//    CLOSE_NO_EVALUATION_ORDER(OrderStatusEnum.NO_EVALUATION, OrderStatusEnum.CLOSED, "待评价订单关闭", "close_no_evaluation_order"),CLOSE_FINISHED_ORDER(OrderStatusEnum.FINISHED, OrderStatusEnum.CLOSED, "已完成订单关闭", "close_finished_order");/*** 源状态*/private final OrderStatusEnum sourceStatus;/*** 目标状态*/private final OrderStatusEnum targetStatus;/*** 描述*/private final String desc;/*** 代码*/private final String code;
}
1.2.1.4 定义订单快照类
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OrderSnapshotDTO extends StateMachineSnapshot {/*** 订单id*/private Long id;/*** 订单所属人*/private Long userId;/*** 服务类型id*/private Long serveTypeId;/*** 服务类型名称*/private String serveTypeName;/*** 服务项id*/private Long serveItemId;/*** 服务项名称*/private String serveItemName;/*** 服务项图片*/private String serveItemImg;/*** 服务单位*/private Integer unit;/*** 服务id*/private Long serveId;/*** 订单状态,0:待支付,100:派单中,200:待服务,300:服务中,500:订单完成,600:订单取消,700已关闭*/private Integer ordersStatus;/*** 支付状态,2:待支付,4:支付成功*/private Integer payStatus;/*** 退款,0:发起退款,1:退款中,2:退款成功  3:退款失败*/private Integer refundStatus;/*** 单价*/private BigDecimal price;/*** 购买数量*/private Integer purNum;/*** 订单总金额*/private BigDecimal totalAmount;/*** 实际支付金额*/private BigDecimal realPayAmount;/*** 优惠金额*/private BigDecimal discountAmount;/*** 城市编码*/private String cityCode;/*** 服务详细地址*/private String serveAddress;/*** 联系人手机号*/private String contactsPhone;/*** 联系人姓名*/private String contactsName;/*** 服务开始时间*/private LocalDateTime serveStartTime;/*** 经度*/private String lon;/*** 纬度*/private String lat;/*** 支付时间*/private LocalDateTime payTime;/*** 评价时间*/private LocalDateTime evaluationTime;/*** 订单创建时间*/private LocalDateTime createTime;/*** 订单更新时间*/private LocalDateTime updateTime;/*** 支付服务交易单号*/private Long tradingOrderNo;/*** 支付服务退款单号*/private Long refundNo;/*** 支付渠道【支付宝、微信、现金、免单挂账】*/private String tradingChannel;/*** 三方流水,微信支付订单号或支付宝订单号*/private String thirdOrderId;/*** 退款三方流水,微信支付订单号或支付宝订单号*/private String thirdRefundOrderId;/*** 取消人id*/private Long cancellerId;/*** 取消人名称*/private String cancelerName;/*** 取消人类型*/private Integer cancellerType;/*** 取消时间*/private LocalDateTime cancelTime;/*** 取消原因*/private String cancelReason;/*** 实际服务完成时间*/private LocalDateTime realServeEndTime;/*** 评价状态*/private Integer evaluationStatus;@Overridepublic String getSnapshotId() {return String.valueOf(id);}@Overridepublic Integer getSnapshotStatus() {return ordersStatus;}@Overridepublic void setSnapshotId(String snapshotId) {this.id = Long.parseLong(snapshotId);}@Overridepublic void setSnapshotStatus(Integer snapshotStatus) {this.ordersStatus = snapshotStatus;}}
1.2.1.5 定义事件变更动作类
/*** 支付成功执行的动作*/
@Slf4j
@Component("order_payed")
public class OrderPayedHandler implements StatusChangeHandler<OrderSnapshotDTO> {@Resourceprivate IOrdersCommonService ordersService;/*** 订单支付处理逻辑** @param bizId   业务id* @param bizSnapshot 快照*/@Overridepublic void handler(String bizId, StatusChangeEvent statusChangeEventEnum, OrderSnapshotDTO bizSnapshot) {log.info("支付成功事件处理逻辑开始,订单号:{}", bizId);}
}
1.2.1.5 定义订单状态机类

AbstractStateMachine状态机抽象类是状态机的核心类,是具体的状态机要继承的抽象类,比如我们实现订单状态机就需要继承AbstractStateMachine抽象类。
在这里插入图片描述

@Component
public class OrderStateMachine extends AbstractStateMachine<OrderSnapshotDTO> {protected OrderStateMachine(StateMachinePersister stateMachinePersister, BizSnapshotService bizSnapshotService, RedisTemplate redisTemplate) {super(stateMachinePersister, bizSnapshotService, redisTemplate);}/*** 指定状态机的名称* @return*/@Overrideprotected String getName() {return "order";}/*** * @param bizSnapshot*/@Overrideprotected void postProcessor(OrderSnapshotDTO bizSnapshot) {}/*** 指定订单的初始状态* @return*/@Overrideprotected StatusDefine getInitState() {return OrderStatusEnum.NO_PAY;}
}
1.2.1.6 状态机表设计

状态机使用MySQL对状态进行持久化,涉及到如下表:
状态机持久化表:
每个订单对应状态机表中的一条记录。
state_machine_name :针对订单的状态机起个名称叫order,针对服务单的状态机可以起个名称为serve。
biz_id:存储订单id
state:记录该订单的当前状态

create table `jzo2o-orders`.state_persister
(id                 bigint auto_increment comment '主键'constraint `PRIMARY`primary key,state_machine_name varchar(255)                       null comment '状态机名称',biz_id             varchar(255)                       null comment '业务id',state              varchar(255)                       null comment '状态',create_time        datetime default CURRENT_TIMESTAMP null comment '创建时间',update_time        datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间',constraint 唯一索引unique (state_machine_name, biz_id)
)

状态机快照表:
一个订单在快照表有多条记录,每变一个状态会记录该状态下的快照信息(即订单相关的详细信息)便于查询订单变化的历史记录。
state_machine_name :同上
biz_id :同上
db_shard_id:暂时用不到
state:对应快照的状态
biz_data:快照信息(json格式),用在订单状态机就是记录订单相关的信息。

create table `jzo2o-orders`.biz_snapshot
(id                 bigint auto_increment comment '主键'constraint `PRIMARY`primary key,state_machine_name varchar(50)                        null comment '状态机名称',biz_id             varchar(50)                        null comment '业务id',db_shard_id        bigint                             null comment '分库键',state              varchar(50)                        null comment '状态代码',biz_data           varchar(5000)                      null comment '业务数据',create_time        datetime default CURRENT_TIMESTAMP not null comment '创建时间',update_time        datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间'
)

1.2.2 测试订单状态机

加载订单状态机

在base工程进行导入状态机

@Configuration
@ComponentScan({"com.jzo2o.orders.base.service","com.jzo2o.orders.base.handler"})
@MapperScan("com.jzo2o.orders.base.mapper")
@Import({OrderStateMachine.class})
@EnableConfigurationProperties({DispatchProperties.class, ExecutorProperties.class})
public class AutoImportConfiguration {
}
测试启动状态机

调用OrderStateMachine的start()方法启动一个订单的状态机,启动状态机表示订单用状态机管理状态,启动状态机后会设置订单的初始状态。
观察state_persister表有一条10100号订单的状态持久化记录,每条订单对应state_persister表的一条记录。
观察biz_snapshot表有一条10100号订单的快照信息,一条订单在biz_snapshot表对应多个条记录,每次订单状态变更都会产生一个快照

@SpringBootTest
@Slf4j
public class OrderStateMachineTest {@Resourceprivate OrderStateMachine orderStateMachine;@Testpublic void test_start() {//启动状态机String start = orderStateMachine.start("10100");log.info("返回初始状态:{}", start);}@Testpublic void test_changeStatus() {//状态变更orderStateMachine.changeStatus("10100", OrderStatusChangeEventEnum.PAYED);}}

根据状态变更事件定义可知,执行测试方法后1010订单的状态由NO_PAY(待支付)变更为DISPATCHING(派单中)。

1.2.3 使用订单状态机

目标:
下单时使用状态机
在支付成功时使用状态机

下单时启动状态机

下单后创建一个新订单,使用状态机的启动方法表示用状态机对该订单的状态开始进行管理。

@Transactional(rollbackFor = Exception.class)
public void add(Orders orders) {boolean save = this.save(orders);if (!save) {throw new DbRuntimeException("下单失败");}//构建快照对象OrderSnapshotDTO orderSnapshotDTO = BeanUtil.toBean(baseMapper.selectById(orders.getId()), OrderSnapshotDTO.class);//状态机启动orderStateMachine.start(null,String.valueOf(orders.getId()),orderSnapshotDTO);
}
支付成功使用状态机
  1. 定义状态变更动作类
    在动作类中更新订单的状态,在动作类中更新订单的状态要比在多处业务代码中对订单状态硬编码要强的多,因为可以在动作类中统一对订单状态进行管理。
    除了更新订单状态以外还需要填充订单快照的相关信息,这里主要是支付相关的信息,包括:支付状态、支付时间、支付服务的交易单号、第三方支付的交易单号等。
    @Resourceprivate IOrdersCommonService ordersService;/*** 订单支付处理逻辑** @param bizId   业务id* @param bizSnapshot 快照*/@Overridepublic void handler(String bizId, StatusChangeEvent statusChangeEventEnum, OrderSnapshotDTO bizSnapshot) {log.info("支付成功事件处理逻辑开始,订单号:{}", bizId);//统一对订单状态进行更新 未支付变为派单中OrderUpdateStatusDTO orderUpdateStatusDTO = new OrderUpdateStatusDTO();orderUpdateStatusDTO.setId(bizSnapshot.getId());orderUpdateStatusDTO.setOriginStatus(OrderStatusEnum.NO_PAY.getStatus());orderUpdateStatusDTO.setTargetStatus(OrderStatusEnum.DISPATCHING.getStatus());orderUpdateStatusDTO.setPayStatus(OrderPayStatusEnum.PAY_SUCCESS.getStatus());orderUpdateStatusDTO.setTradingOrderNo(bizSnapshot.getTradingOrderNo());orderUpdateStatusDTO.setTransactionId(bizSnapshot.getThirdOrderId());orderUpdateStatusDTO.setPayTime(bizSnapshot.getPayTime());orderUpdateStatusDTO.setTradingChannel(bizSnapshot.getTradingChannel());Integer res = ordersService.updateStatus(orderUpdateStatusDTO);if(res < 1){throw new CommonException("订单号为"+bizId+"的支付事件处理失败");}}
  1. 在支付成功方法中使用状态机
    使用状态机执行支付成功状态变更。
    /*** 支付成功, 更新数据库的订单表及其他信息** @param tradeStatusMsg 交易状态消息*/@Override@Transactional(rollbackFor = Exception.class)public void paySuccess(TradeStatusMsg tradeStatusMsg){/*        boolean update = lambdaUpdate().eq(Orders::getId, tradeStatusMsg.getProductOrderNo()).eq(Orders::getOrdersStatus,0) //订单状态只能由待支付 才可以变为派单中.set(Orders::getPayStatus, OrderPayStatusEnum.PAY_SUCCESS.getStatus()).set(Orders::getTransactionId, tradeStatusMsg.getTransactionId()).set(Orders::getOrdersStatus, OrderStatusEnum.DISPATCHING.getStatus()) //订单状态变为派单中.set(Orders::getPayTime, LocalDateTime.now()).update();if(!update){throw new CommonException("支付成功,更新"+tradeStatusMsg.getProductOrderNo()+"订单状态为派单中失败");}*///使用状态机将待支付状态变为派单中OrderSnapshotDTO orderSnapshotDTO = OrderSnapshotDTO.builder().payTime(LocalDateTime.now()).tradingOrderNo(tradeStatusMsg.getTradingOrderNo()).tradingChannel(tradeStatusMsg.getTradingChannel()).thirdOrderId(tradeStatusMsg.getTransactionId()).build();orderStateMachine.changeStatus(null,tradeStatusMsg.getProductAppId().toString(), OrderStatusChangeEventEnum.PAYED,orderSnapshotDTO);}
测试

在这里插入图片描述
在这里插入图片描述
测试成功

相关文章:

小熊家政帮day22-day23 订单系统优化(订单状态机、练习分库分表、索引、订单缓存)

目录 1 状态机1.1 状态机介绍1.1.1 当前存在的问题1.1.2 使用状态机解决问题 1.2 实现订单状态机1.2.1 编写订单状态机1.2.1.1 依赖引入1.2.1.2 订单状态枚举类1.2.1.3 状态变更事件枚举类1.2.1.4 定义订单快照类1.2.1.5 定义事件变更动作类1.2.1.5 定义订单状态机类1.2.1.6 状…...

LeetCode 1731, 151, 148

目录 1731. 每位经理的下属员工数量题目链接表要求知识点思路代码 151. 反转字符串中的单词题目链接标签思路代码 148. 排序链表题目链接标签Collections.sort()思路代码 归并排序思路代码 1731. 每位经理的下属员工数量 题目链接 1731. 每位经理的下属员工数量 表 表Emplo…...

Codeforces Round 953 (Div. 2)(A~D题解)

这次比赛是我最顺利的一次比赛&#xff0c;也是成功在中途打进前1500&#xff0c;写完第三道题的时候也是保持在1600左右&#xff0c;但是后面就啥都不会了&#xff0c;还吃了点罚时&#xff0c;虽说如此也算是看到进步了&#xff0c;D题学长说很简单&#xff0c;但是我当时分析…...

晶圆切割机(晶圆划片机)为晶圆加工重要设备 我国市场国产化进程不断加快

晶圆切割机&#xff08;晶圆划片机&#xff09;为晶圆加工重要设备 我国市场国产化进程不断加快 晶圆切割机又称晶圆划片机&#xff0c;指能将晶圆切割成芯片的机器设备。晶圆切割机需具备切割精度高、切割速度快、操作便捷、稳定性好等特点&#xff0c;在半导体制造领域应用广…...

39、基于深度学习的(拼音)字符识别(matlab)

1、原理及流程 深度学习中常用的字符识别方法包括卷积神经网络&#xff08;CNN&#xff09;和循环神经网络&#xff08;RNN&#xff09;。 数据准备&#xff1a;首先需要准备包含字符的数据集&#xff0c;通常是手写字符、印刷字符或者印刷字体数据集。 数据预处理&#xff1…...

CCF 矩阵重塑

第一题&#xff1a;矩阵重塑&#xff08;一&#xff09; 本题有两种思路 第一种 &#xff08;不确定是否正确 但是100分&#xff09; #include<iostream> using namespace std; int main(){int n,m,p,q,i,j;cin>>n>>m>>p>>q;int a[n][m];for(i…...

Aigtek高压放大器在柔性爬行机器人驱动性能研究中的应用

实验名称&#xff1a;柔性爬行机器人的材料测试 研究方向&#xff1a;介电弹性体的最小能量结构是一种利用DE材料的电致变形与柔性框架形变相结合设计的新型柔性驱动器&#xff0c;所谓最小能量是指驱动器在平衡状态时整个系统的能量最小&#xff0c;当系统在外界的电压刺激下就…...

Postman下发流表至Opendaylight

目录 任务目的 任务内容 实验原理 实验环境 实验过程 1、打开ODL控制器 2、网页端打开ODL控制页面 3、创建拓扑 4、Postman中查看交换机的信息 5、L2层流表下发 6、L3层流表下发 7、L4层流表下发 任务目的 1、掌握OpenFlow流表相关知识&#xff0c;理解SDN网络中L…...

C语言王国——数组的旋转(轮转数组)三种解法

目录 一、题目 二、分析 2.1 暴力求解法 2.2 找规律 2.3 追求时间效率&#xff0c;以空间换时间 三、结论 一、题目 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出…...

MySQL中CAST和CONVERT函数都用于数据类型转换

在 MySQL 中&#xff0c;CAST() 和 CONVERT() 函数都用于数据类型转换。虽然这两个函数在大多数情况下可以互换使用&#xff0c;但它们之间还是有一些细微的差别。 官方文档地址 https://dev.mysql.com/doc/refman/8.4/en/cast-functions.html#function_cast CAST() 函数 C…...

速盾:cdn影响seo吗?

CDN (Content Delivery Network) 是一个分布式网络架构&#xff0c;用于在全球范围内加速网站内容的传输和分发。它通过将网站的静态资源&#xff08;例如图片、CSS、JavaScript 文件等&#xff09;存储在多个服务器上&#xff0c;使用户可以从最接近他们位置的服务器上获取这些…...

期末算法复习

0-1背包问题&#xff08;动态规划&#xff09; 例题 算法思想&#xff1a; 动态规划的核心思想是将原问题拆分成若干个子问题&#xff0c;并利用已解决的子问题的解来求解更大规模的问题。 主要是状态转移方程和状态 算法描述&#xff1a; 初始化一个二维数组dp&#xff0…...

可穿戴设备:苹果“吃老底”、华为“忙复苏”、小米“再扩容”

配图来自Canva可画 随着产品功能的创新&#xff0c;可穿戴设备不再被简单地视为手机的延伸&#xff0c;而是被当成一种独立的、具有独特功能和优势的产品&#xff0c;受到了越来越多人的青睐。 一方面&#xff0c;技术的进步使得可穿戴设备在功能、性能和使用体验上得到显著提…...

AI数据分析:集中度分析和离散度分析

在deepseek中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个Python脚本编写的任务&#xff0c;具体步骤如下&#xff1a; 读取Excel表格&#xff1a;"F:\AI自媒体内容\AI行业数据分析\toolify月榜\toolify2023年-2024年月排行榜汇总数据.xlsx&qu…...

redis的分布式session和本地的session有啥区别

在web应用开发中&#xff0c;Session用于在多个请求之间存储用户数据。传统上&#xff0c;Session存储在服务器的内存中&#xff0c;即本地Session。然而&#xff0c;随着应用规模和复杂度的增加&#xff0c;特别是在分布式环境中&#xff0c;本地Session会遇到一些问题。这时&…...

SSH概念、用途、详细使用方法

还是大剑师兰特&#xff1a;曾是美国某知名大学计算机专业研究生&#xff0c;现为航空航海领域高级前端工程师&#xff1b;CSDN知名博主&#xff0c;GIS领域优质创作者&#xff0c;深耕openlayers、leaflet、mapbox、cesium&#xff0c;canvas&#xff0c;webgl&#xff0c;ech…...

关于电脑文件的规划思考

概述 设置C、D、E、F 四个盘 C盘&#xff1a;系统数据使用&#xff0c;操作系统、其他软件需要用到的系统性资源 D盘&#xff1a;应用软件区 的使用&#xff0c;数据库、navacat、idea、visual studio、浏览器、向日葵、虚拟机…… E盘&#xff1a;工作区&#xff1a;公司资料…...

DVWA - Brute Force

DVWA - Brute Force 等级&#xff1a;low ​ 直接上bp弱口令爆破&#xff0c;设置变量&#xff0c;攻击类型最后一个&#xff0c;payload为用户名、密码简单列表 ​ 直接run&#xff0c;长度排序下&#xff0c;不一样的就是正确的用户名和密码 ​ 另解&#xff1a; 看一下…...

安卓手机文件找回方法汇总,3个技巧,不再焦虑

我们用手机来储存各种重要的信息和文件&#xff0c;无论是珍贵的照片、重要的文档还是喜爱的音乐&#xff0c;用来记录和分享生活中的每一个瞬间。但如果不小心删除了这些文件&#xff0c;我们可能会面临数据丢失的风险&#xff0c;进而产生焦虑和不安。本文将为您揭秘手机文件…...

{}初始化

文章目录 ()初始化的问题易混淆弱检查 {}初始化{}初始化是c11推荐的初始化&#xff0c;解决了上述的问题 ()则被用于强制类型转换 ()初始化的问题 易混淆 string s();不能确定是函数定义还是对象定义 弱检查 int a(3.14);3.14 可以通过 int 定义 {}初始化 {}初始化是c11推…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…...

微服务通信安全:深入解析mTLS的原理与实践

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言&#xff1a;微服务时代的通信安全挑战 随着云原生和微服务架构的普及&#xff0c;服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...

在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南

在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...

边缘计算网关提升水产养殖尾水处理的远程运维效率

一、项目背景 随着水产养殖行业的快速发展&#xff0c;养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下&#xff0c;而且难以实现精准监控和管理。为了提升尾水处理的效果和效率&#xff0c;同时降低人力成本&#xff0c;某大型水产养殖企业决定…...