一、引入jar包
<!--阿里状态机jar-->
<dependency>
<groupId>com.alibaba.cola</groupId>
<artifactId>cola-component-statemachine</artifactId>
<version>4.3.2</version>
</dependency>
二、引入流转类型枚举
package com.lx.designPattern.statepattern.statemachine.enums;
/**
* 流转类型枚举
* @author lwp
* @date 2023-07-06 14:56:27
* @version 1.0
*/
public enum TransitionTypeEnum {
/**
* 内部流转
*/
INTERNAL,
/**
* 外部流转
*/
EXTERNAL,
/**
* 多状态外部流转
*/
EXTERNALS;
}
三、引入事件枚举
package com.lx.designPattern.statepattern.statemachine.enums;
/**
* 履约状态事件枚举
*
* @author lwp
* @version 1.0
* @date 2023-07-06 13:40:11
*/
public enum FulfillmentStatusEventEnum {
/**
* 开始租赁非标商品履约
*/
BEGIN_RENT_NON_STANDARD_GOODS_FULFILLMENT,
/**
* 完成资源匹配
*/
MATCH_RESOURCE,
/**
* 完成租赁交付
*/
COMPLETE_RENT_DELIVER,
/**
* 重置履约计划
*/
RESET_FULFILLMENT,
/**
* 取消履约单
*/
CANCEL_FULFILLMENT,
/**
* 创建售车交付履约单
*/
CREATE_SALE_DELIVER_FULFILLMENT,
/**
* 完成服务执行中
*/
COMPLETE_SERVICE_FULFILLMENT,
/**
* 非灰度履约单交付
*/
NON_GRAY_DELIVER,
/**
* 欢乐租备车
*/
HAPPY_RENT_PLAN_CAR,
/**
* 开始替换车履约
*/
START_REPLACE_DELIVER_FULFILLMENT,
/**
* 开始常规租赁退车履约
*/
START_RENT_BACK_CAR_FULFILLMENT,
/**
* 完成替换车车退车
*/
COMPLETE_REPLACE_BACK_CAR_FULFILLMENT,
/**
* 完成租赁退车
*/
COMPLETE_RENT_BACK_CAR_FULFILLMENT,
/**
* 取消履约 (新的)
*/
CANCEL_FULFILLMENT_2ND,
/**
* 完成服务履约
*/
COMPLETE_VEHICLE_SERVICE,
/**
* 渠道商履约
*/
CHANNEL_FULFILLMENT,
;
}
四、引入流转状态枚举
package com.lx.designPattern.statepattern.statemachine.enums;
import com.lx.exception.BusinessException;
import java.util.Objects;
/**
* 履约单状态枚举
* @author lwp
* @date 2023/1/5 9:16
* @version 1.0
*/
public enum FulfillmentStatusEnum {
/**
* 初始状态
*/
INITIAL(0, "初始状态"),
/**
* 待匹配
*/
WAIT_MATCH(2, "待匹配"),
/**
* 进行中
*/
IN_PROGRESS(3, "进行中"),
/**
* 已完成
*/
COMPLETED(4, "已完成"),
/**
* 已取消
*/
CANCELED(5, "已取消"),
;
private Integer status;
private String desc;
FulfillmentStatusEnum(Integer status, String desc) {
this.status = status;
this.desc = desc;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public static FulfillmentStatusEnum getByStatus(Integer status) {
for (FulfillmentStatusEnum fulfillmentStatusEnum : FulfillmentStatusEnum.values()) {
if (Objects.equals(status, fulfillmentStatusEnum.getStatus())) {
return fulfillmentStatusEnum;
}
}
throw new BusinessException("未找到履约状态枚举");
}
}
?1.需要处理的业务参数类
package com.lx.designPattern.statepattern.statemachine.dto;
import lombok.Data;
/**
* 履约单dto
* @author lwp
* @date 2023-07-25 16:22:04
* @version 1.0
*/
@Data
public class FulfillmentBillDTO {
/**
* 交易订单
*/
private A a;
/**
* 履约主单
*/
private B b;
/**
* 车辆履约子单
*/
private C c;
}
五、准备状态机
package com.lx.designPattern.statepattern.statemachine;
import com.alibaba.cola.statemachine.StateMachine;
import com.alibaba.cola.statemachine.builder.StateMachineBuilder;
import com.alibaba.cola.statemachine.builder.StateMachineBuilderFactory;
import com.lx.designPattern.statepattern.statemachine.statustransition.FulfillmentStatusTransition;
import com.lx.designPattern.statepattern.statemachine.dto.FulfillmentBillDTO;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEnum;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEventEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.List;
/**
* 履约状态机
*
* @author lwp
* @version 1.0
* @date 2023-07-27 10:31:27
*/
@Slf4j
@Lazy
@Component
public class FulfillmentStatusStateMachine {
/**
* 状态机ID
*/
private static final String MACHINE_ID = "FulfillmentStatusStateMachine";
/**
* 状态机
*/
private StateMachine<FulfillmentStatusEnum, FulfillmentStatusEventEnum, FulfillmentBillDTO> stateMachine;
@Autowired
private List<FulfillmentStatusTransition> fulfillmentStatusTransitions;
/* ******************************* 履约单状态流转 *****************************/
/**
* 初始化
*/
@PostConstruct
public void init() {
// 创建状态机
StateMachineBuilder<FulfillmentStatusEnum, FulfillmentStatusEventEnum, FulfillmentBillDTO> stateMachineBuilder
= StateMachineBuilderFactory.create();
// 添加没有命中配置规则时的回调
stateMachineBuilder.setFailCallback(this::stateMachineFailCallback);
// 初始化transition
initTransition(stateMachineBuilder);
stateMachine = stateMachineBuilder.build(MACHINE_ID);
}
/**
* 触发流转
*/
public FulfillmentStatusEnum fireEvent(FulfillmentStatusEnum status,
FulfillmentStatusEventEnum event,
FulfillmentBillDTO fulfillmentBill) {
FulfillmentStatusEnum resultStatus = stateMachine.fireEvent(status, event, fulfillmentBill);
// 如果结果状态和源状态相同,代表流转失败
if (resultStatus == status) {
log.warn("履约单{}状态流转失败, from:{}, to:{}, event:{}",
fulfillmentBill.getMainFulfillmentBill().getFulfillmentCode(),
status.getStatus(),
resultStatus.getDesc(),
event);
} else {
log.info("履约单{}状态流转, from:{}, to:{}, event:{}",
fulfillmentBill.getMainFulfillmentBill().getFulfillmentCode(),
status.getStatus(),
resultStatus.getDesc(),
event);
}
return resultStatus;
}
/**
* 没有命中配置规则时的回调
*/
private void stateMachineFailCallback(FulfillmentStatusEnum status,
FulfillmentStatusEventEnum event,
FulfillmentBillDTO fulfillmentBill) {
log.error("履约单{}状态流转失败: 未找到匹配的流转规则, from:{}, event:{}",
fulfillmentBill.getMainFulfillmentBill().getId(),
status.getDesc(),
event);
}
/**
* 初始化transition
*/
private void initTransition(StateMachineBuilder<FulfillmentStatusEnum, FulfillmentStatusEventEnum,
FulfillmentBillDTO> builder) {
fulfillmentStatusTransitions.forEach(transition -> {
switch (transition.getTransitionType()) {
case INTERNAL:
if (transition.getWithin().isPresent()) {
builder.internalTransition()
.within(transition.getWithin().get())
.on(transition.getEvent())
.when(transition.getCondition())
.perform(transition.getAction());
} else {
log.error("初始化履约单内部状态流转错误: 缺少within参数");
throw new IllegalArgumentException("履约状态状态机初始化失败");
}
break;
case EXTERNAL:
if (transition.getFrom().isPresent() && transition.getTo().isPresent()) {
builder.externalTransition()
.from(transition.getFrom().get())
.to(transition.getTo().get())
.on(transition.getEvent())
.when(transition.getCondition())
.perform(transition.getAction());
} else {
log.error("初始化履约单外部状态流转错误: 缺少from或to参数");
throw new IllegalArgumentException("履约状态状态机初始化失败");
}
break;
case EXTERNALS:
if (transition.getFromAmong().isPresent() && transition.getTo().isPresent()) {
builder.externalTransitions()
.fromAmong(transition.getFromAmong().get())
.to(transition.getTo().get())
.on(transition.getEvent())
.when(transition.getCondition())
.perform(transition.getAction());
} else {
log.error("初始化履约单多状态外部状态流转错误: 缺少fromAmong或to参数");
throw new IllegalArgumentException("履约状态状态机初始化失败");
}
break;
default:
log.error("不支持的流转类型:{}", transition.getTransitionType());
}
});
}
}
六、准备流转接口
package com.lx.designPattern.statepattern.statemachine.statustransition;
import com.alibaba.cola.statemachine.Action;
import com.alibaba.cola.statemachine.Condition;
import com.lx.designPattern.statepattern.statemachine.dto.FulfillmentBillDTO;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEnum;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEventEnum;
import com.lx.designPattern.statepattern.statemachine.enums.TransitionTypeEnum;
import java.util.Optional;
/**
* 履约单状态流转
* @author lwp
* @date 2023-07-06 15:08:18
* @version 1.0
*/
public interface FulfillmentStatusTransition {
/**
* 获取类转类型
* @return 流转类型
*/
TransitionTypeEnum getTransitionType();
/**
* 获取within参数(内部流转必需)
* @return within
*/
default Optional<FulfillmentStatusEnum> getWithin() {
return Optional.empty();
}
/**
* 获取from参数(外部流转必需)
* @return from
*/
default Optional<FulfillmentStatusEnum> getFrom() {
return Optional.empty();
}
/**
* 获取fromAmong参数(多状态外部流转必需)
* @return fromAmong
*/
default Optional<FulfillmentStatusEnum[]> getFromAmong() {
return Optional.empty();
}
/**
* 获取to参数(外部流转和多状态外部流转必需)
* @return to
*/
default Optional<FulfillmentStatusEnum> getTo() {
return Optional.empty();
};
/**
* 获取event
* @return on参数
*/
FulfillmentStatusEventEnum getEvent();
/**
* 获取condition
* @return when
*/
Condition<FulfillmentBillDTO> getCondition();
/**
* 获取action
* @return preform
*/
Action<FulfillmentStatusEnum, FulfillmentStatusEventEnum, FulfillmentBillDTO> getAction();
}
七、实现流转接口和定义流转规则
package com.lx.designPattern.statepattern.statemachine.statustransition;
import com.alibaba.cola.statemachine.Action;
import com.alibaba.cola.statemachine.Condition;
import com.lx.designPattern.statepattern.statemachine.dto.FulfillmentBillDTO;
import com.lx.designPattern.statepattern.statemachine.dto.MainFulfillmentBill;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEnum;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEventEnum;
import com.lx.designPattern.statepattern.statemachine.enums.TransitionTypeEnum;
import org.springframework.stereotype.Component;
import java.util.Optional;
/**
* 完成履约状态流转
* @author lwp
* @date 2023-07-12 10:30:32
* @version 1.0
*/
@Component
public class CompleteFulfillmentTransition implements FulfillmentStatusTransition {
//@Autowired
//private FulfillmentBillDaoService fulfillmentBillDaoService;
@Override
public TransitionTypeEnum getTransitionType() {
return TransitionTypeEnum.EXTERNAL;
}
@Override
public Optional<FulfillmentStatusEnum> getFrom() {
return Optional.of(FulfillmentStatusEnum.IN_PROGRESS);
}
@Override
public Optional<FulfillmentStatusEnum> getTo() {
return Optional.of(FulfillmentStatusEnum.COMPLETED);
}
@Override
public FulfillmentStatusEventEnum getEvent() {
return FulfillmentStatusEventEnum.COMPLETE_RENT_DELIVER;
}
@Override
public Condition<FulfillmentBillDTO> getCondition() {
return (fulfillmentBillDTO -> true);
}
@Override
public Action<FulfillmentStatusEnum, FulfillmentStatusEventEnum, FulfillmentBillDTO> getAction() {
return (srcState, tarState, event, fulfillmentBillDTO) -> {
// 修改履约单状态
MainFulfillmentBill updateMainBill = new MainFulfillmentBill();
updateMainBill.setId(fulfillmentBillDTO.getMainFulfillmentBill().getId());
updateMainBill.setStatus(tarState.getStatus());
//fulfillmentBillDaoService.updateMainBillById(updateMainBill);
System.out.println("状态改为完成了");
};
}
}
八、准备测试类测试
package com.lx.designPattern;
import com.lx.designPattern.statepattern.statemachine.FulfillmentStatusStateMachine;
import com.lx.designPattern.statepattern.statemachine.business.InsuranceStatusChangeServiceImpl;
import com.lx.designPattern.statepattern.statemachine.dto.FulfillmentBillDTO;
import com.lx.designPattern.statepattern.statemachine.dto.MainFulfillmentBill;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEnum;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEventEnum;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @Desc 阿里状态机测试类
* @author lwp
* @version 1.0
* @date 2024-01-13 22:16:22
*/
@RunWith(SpringRunner.class)
@SpringBootTest(properties = "dev")
public class StateMachineTest {
@Autowired
private FulfillmentStatusStateMachine fulfillmentStatusStateMachine;
@Test
public void handStatusChangeComplete() {
FulfillmentBillDTO billDTO = new FulfillmentBillDTO();
MainFulfillmentBill mainFulfillmentBill = new MainFulfillmentBill();
mainFulfillmentBill.setFulfillmentCode("LY001");
mainFulfillmentBill.setStatus(1);
billDTO.setMainFulfillmentBill(mainFulfillmentBill);
fulfillmentStatusStateMachine.fireEvent(FulfillmentStatusEnum.getByStatus(3),
FulfillmentStatusEventEnum.COMPLETE_RENT_DELIVER,billDTO);
}
}
?九、测试效果如下图