小熊家政帮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);}
测试

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1451812.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

明天二战六级

明天二战六级&#xff0c;各位程序员们&#xff0c;加油

HTML静态网页成品作业(HTML+CSS)—— 明星吴磊介绍网页(5个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有5个页面。 二、作品演示 三、代…

最新Sublime Text软件安装包分享(汉化版本)

Sublime Text 是一款广受欢迎的跨平台文本编辑器&#xff0c;专为代码、标记和散文编辑而设计。它以其简洁的用户界面、强大的功能和高性能而著称&#xff0c;深受开发者和写作者的喜爱。 一、下载地址 链接&#xff1a;https://pan.baidu.com/s/1kErSkvc7WnML7fljQZlcOg?pwdk…

EasyGBS服务器和终端配置

服务器配置 修改easygbs.ini sip/host为本机IP&#xff0c;否则终端能登录&#xff0c;无法视频。 [sip] host192.168.3.190 终端用于登录的用户名和密码 default_usertest default_passwordtest1234 default_guest_userguest default_guest_passwordtest1234终端配置 关…

2024 年最新基于 LLOneBot NT 框架搭建 QQ 机器人详细教程(更新中)

LLOneBot 概述 llonebot&#xff08;LLOneBot&#xff09;是一个与OneBot&#xff08;也称为CQHTTP&#xff09;协议兼容的机器人框架&#xff0c;它允许开发者使用不同的编程语言&#xff08;如Python、Go、JavaScript等&#xff09;编写机器人应用&#xff0c;并与各种支持 …

(done) 什么是 perplexity 困惑度?

参考&#xff1a;https://www.youtube.com/watch?vB_2bntDYano 困惑度 perplexity 是一种用来衡量语言模型性能的度量&#xff0c;类似于交叉熵。 困惑度越低越好&#xff0c;越低说明一个模型越好。 一个典型的公式在下面&#xff1a;

WordPress如何删除内存中的缓存?

今天boke112百科将某篇文章修改分类和内容更新后&#xff0c;发现文章底部的相关文章显示的内容跟文章分类、标签毫无关系&#xff0c;还是显示原来的旧内容。后来查看YIA主题相关文章的代码&#xff0c;才发现相关文章的数据保存到内存中的&#xff0c;而且是永不过期&#xf…

Windows 11 中安装 Docker Desktop 并安装镜像

本该主要介绍在 Windows 11 中安装 Docker Desktop 时的一些准备工作&#xff0c;以及该如何下载和安装&#xff0c;然后分别使用管理界面和 Docker 命令安装两个镜像。 一、准备工作 在 Windows 11 中安装 Docker Desktop 前&#xff0c;需要做一些准备。打开 【Windows 功能…

深入解析Prometheus:强大的开源监控与告警系统

目录 引言 一、运维监控平台的设计思路 &#xff08;一&#xff09;设计思路 1.数据收集模块 2.数据提取模块 3.监控告警模块 &#xff08;二&#xff09;监控平台层级 二、Prometheus简介 &#xff08;一&#xff09;基本介绍 &#xff08;二&#xff09;核心特征 …

c++/c输出double问题

这个我大抵能理解&#xff0c;%d是int嘛。 这是为啥&#xff1f; 这样又好了&#xff1f; 这我也能理解 这也可以 这也对&#xff1f; &#xff08;我知道我呢个函数为什么不对了&#xff0c;我的函数写的是int(&#xff09;) 附&#xff1a;保留几位小数&#xff1a; %.2f

五、特征缩放和多项式回归

目录 一、为什么要使用特征缩放(Feature Scaling) 1.首先来看预测房价的例子 2.特征缩放前后效果对比 二、特征缩放方法 1.统一除以范围最大值 2.均值归一化(Mean Normalization) 3.Z-score标准化(Z-score Normalization) 4.一些可以接受/不接受的缩放范围 三、如何识别…

填表统计预约打卡表单系统(FastAdmin+ThinkPHP+UniApp)

填表统计预约打卡表单系统&#xff1a;一键搞定你的预约与打卡需求​ 填表统计预约打卡表单系统是一款基于FastAdminThinkPHPUniApp开发的一款集信息填表、预约报名&#xff0c;签到打卡、活动通知、报名投票、班级统计等功能的自定义表单统计小程序。 &#x1f4dd; 一、引言…

SpringBoot集成mqtt上下线提醒功能设计

目录 1.首先安装emqx&#xff0c;去官网下载emqx压缩包&#xff0c;并且解压。 2.使用emqx start 命令启动emqx后台管理 3.下载mqttx调试工具&#xff0c;使用mqttx调试mqtt连接。下载地址:MQTTX下载-MQTTX官方版下载,下载完成直接打开&#xff0c;便可进行mqtt连接调试 4.…

Commons-Collections篇-CC4链分析

前言 因为 CommonsCollections4 除 4.0 的其他版本去掉了 InvokerTransformer 继承 Serializable&#xff0c;导致该方法无法序列化。 同时 CommonsCollections 4的版本 TransformingComparator 继承了 Serializable接口&#xff0c;而CommonsCollections 3里是没有的&#xf…

仿element-ui 实现自己组件库 <3>

目录 input 组件封装 v-model用在组件上 显示和隐藏密码 封装switch组件 实现转换的功能 设置checkbox input 组件封装 首先input组件的基本框架和样式&#xff1a; <div class"miao-input"><input class"miao-input_inner" > </div…

秋招突击——6/14——复习{(树形DP)树的最长路径}——新作{非递归求二叉树的深度、重复区间合并}

文章目录 引言复习树形DP——树的最长路径 新作使用dfs非递归计算二叉树的深度多个区间合并删除问题实现思路实现代码参考思路 总结 引言 这两天可能有点波动&#xff0c;但是算法题还是尽量保证复习和新作一块弄&#xff0c;数量上可能有所差别。 复习 树形DP——树的最长路…

Visual Studio Code 的安装教程和配置C语言环境插件推荐

目录 1.vscode简介2.下载安装vs code3.VSCode基础配置VSCode界面简介VSCode设置中文界面VSCode个性化设置VSCode常用设置基本编辑快捷键VSCode常用快捷键 4.下载安装MinGW5.设置vscode里的环境6.插件推荐7.vscode官方文档 1.vscode简介 VSCode是微软出的一款轻量级编辑器&…

WordPress实时搜索插件Ajax Search Lite,轻松替代默认搜索功能

WordPress自带的默认搜索功能是跳转到搜索结果页&#xff0c;如果你想要实时搜索功能&#xff0c;特别是在问答中心显示搜索功能&#xff0c;那么建议使用这个WordPress实时搜索插件Ajax Search Lite&#xff0c;它可以在文章、页面、自定义类型文章中搜索标题、内容、摘要、自…

八爪鱼现金流-022-mybatis插件加密和国密SM4算法

背景&#xff1a; 用户的金额数据&#xff0c;不希望被别人看到。 业务场景分析&#xff1a; 用户在页面上添加金额数据 -----> 服务器内存&#xff08;加密、解密&#xff09; -----> 存储数据库 调研及结果&#xff1a; 使用mybatis的拦截器插件&#xff0c;进行数…

LeetCode | 168.Excel表列名称

这道题一开始以为是简单的进制转换问题&#xff0c;用的以往的思路&#xff0c;对于一般性的进制转换题目&#xff0c;只需要不断地对 columnNumber 进行 % 运算取得最后一位&#xff0c;然后对 columnNumber 进行 / 运算&#xff0c;将已经取得的位数去掉&#xff0c;直到 col…