前置内容
- 把握战略形式
- 把握职责链形式
- 把握类承继、接口的完结
- 把握参数的传递与设置
- GitHub地址
ps:【文章由来】 公司项目中所用的合同签章处理流程,本人根据职责链上运用战略形式进行优化。
签章的处理流程
- 合同文本初始化
- 合同文本生成
- 签章挡板是否敞开
- 合同签章发送mq
- 合同签章流水更新
- 合同上传文件服务器
- 签章途径挑选
- 签章途径的实际调用
履行的流程如下:
整个结构类似于递归调用。每个节点中依靠上一个节点的输入以及下一个节点的输出,在中心进程能够完结每个节点的自界说操作,比较灵敏。
流程完结
GitHub地址
项目结构
DesignPatterns
└── src
└── main
└── java
└── com.xbhog.chainresponsibility
├── annotations
│ └── ContractSign
├── channel
│ ├── ContractSignChannelImpl.java
│ └── ContractSignChannel
├── Config
│ └── SignConfig
├── Enum
│ └── ContractSignEnum
├── impl
│ ├── ContractSignCompactInitImpl.java
│ ├── ContractSignGenerateImpl.java
│ ├── ContractSignMockImpl.java
│ ├── ContractSignMqImpl.java
│ ├── ContractSignSaveUploadImpl.java
│ ├── ContractSignSerialImpl.java
│ └── ContractSignTradeImpl.java
├── inter
│ ├── Call
│ ├── Chain
│ ├── Interceptor
│ └── Processor
├── pojo
│ ├── ContractRequest.java
│ └── ContractResponse.java
├── ContractCall
├── ContractChain
└── ContractSignProcessor.java
项目类图
职责链+组合形式代码完结
工程结构
DesignPatterns
└── src
└── main
└── java
└── com.xbhog.chainresponsibility
├── channel
│ ├── ContractSignChannelImpl.java
│ └── ContractSignChannel
├── impl
│ ├── ContractSignCompactInitImpl.java
│ ├── ContractSignGenerateImpl.java
│ ├── ContractSignMockImpl.java
│ ├── ContractSignMqImpl.java
│ ├── ContractSignSaveUploadImpl.java
│ ├── ContractSignSerialImpl.java
│ └── ContractSignTradeImpl.java
├── inter
│ ├── Call
│ ├── Chain
│ ├── Interceptor
│ └── Processor
├── pojo
│ ├── ContractRequest.java
│ └── ContractResponse.java
├── ContractCall
├── ContractChain
└── ContractSignProcessor.java
职责链中的目标界说
//恳求
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ContractRequest {
private String name;
private String age;
private String status;
}
//呼应
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ContractResponse {
private String status;
private String mas;
}
界说流程中的恳求及呼应类,便利处理每个职责链的恳求、回来信息。
职责链处理流程
/**
* @author xbhog
* @describe: 职责链+组合完结合同签章
* @date 2023/7/11
*/
@Slf4j
@Component
public class ContractSignProcessor <T extends ContractRequest> implements Processor<T, ContractResponse> {
@Resource(name = "contractSignCompactInitImpl")
private Interceptor<T,ContractResponse> contractCompactInitImpl;
......
public ContractSignProcessor() {
}
@Override
public ContractResponse process(T paramter) {
//获取一切的监听器
List<Interceptor<T,ContractResponse>> interceptorList = new ArrayList<>();
interceptorList.add(contractCompactInitImpl);
......
//开端签章
log.info("签章开端");
return new ContractCall(paramter,interceptorList).exectue();
}
}
合同签章办法的主流程调用接口(进口) ,该类中注入一切的节点完结类(如contractCompactInitImpl
),经过编排完结职责链流程。 在初始化节点之前,进行节点的封装以及数据恳求的处理。例:contractCompactInitImpl
-合同数据初始化节点
/**
* @author xbhog
* @describe: 合同数据恳求、节点的实例化及办法履行
* @date 2023/7/11
*/
public class ContractCall<T extends ContractRequest> implements Call<T, ContractResponse> {
private final T originalRequest;
private final List<Interceptor<T,ContractRequest>> interceptorList;
public ContractCall(T originalRequest, List<Interceptor<T, ContractRequest>> interceptorList) {
this.originalRequest = originalRequest;
this.interceptorList = interceptorList;
}
@Override
public T request() {
return this.originalRequest;
}
@Override
public ContractResponse exectue() {
//实例化流程节点
ContractChain<T> chain = new ContractChain(0,this.originalRequest,this.interceptorList);
return chain.proceed(this.originalRequest);
}
}
获取节点中的恳求参数,实例化当时职责链节点(contractCompactInitImpl
),在履行节点中的proceed
办法来获取当时节点的参数以及获取节点的信息。
/**
* @author xbhog
* @describe: 合同节点
* @date 2023/7/11
*/
@Slf4j
public class ContractChain<T extends ContractRequest> implements Chain<T, ContractResponse> {
private final Integer index;
private final T request;
private final List<Interceptor<T,ContractResponse>> interceptors;
public ContractChain(Integer index, T request, List<Interceptor<T, ContractResponse>> interceptors) {
this.index = index;
this.request = request;
this.interceptors = interceptors;
}
@Override
public T request() {
return this.request;
}
@Override
public ContractResponse proceed(T request) {
//操控节点流程
if(this.index >= this.interceptors.size()){
throw new IllegalArgumentException("index越界");
}
//下一个节点参数设置
Chain<T,ContractResponse> nextChain = new ContractChain(this.index + 1, request, this.interceptors);
//获取节点信息
Interceptor<T, ContractResponse> interceptor = this.interceptors.get(this.index);
Class<? extends Interceptor> aClass = interceptor.getClass();
log.info("当时节点:{}",aClass.getSimpleName());
ContractResponse response = interceptor.process(nextChain);
if(Objects.isNull(response)){
throw new NullPointerException("intercetor"+interceptor+"return null");
}
return response;
}
}
到此合同签章的架构流程已经确定,后续只需填充Interceptor
具体的完结类即可。 在代码中ContractResponse response = interceptor.process(nextChain);
来履行合同初始化节点的具体操作。
/**
* @author xbhog
* @describe: 合同文本初始化
* @date 2023/7/12
*/
@Slf4j
@Component
public class ContractSignCompactInitImpl<T extends ContractRequest> implements Interceptor<T, ContractResponse> {
public ContractSignCompactInitImpl() {
}
@Override
public ContractResponse process(Chain<T,ContractResponse> chain) {
log.info("=============履行合同文本初始化拦截器开端");
//获取处理的恳求参数
T request = chain.request();
request.setStatus("1");
log.info("=============履行合同文本初始化拦截器完毕");
//进入下一个职责链节点
ContractResponse response = chain.proceed(request);
if(Objects.isNull(response)){
log.error("回来值的为空");
response = ContractResponse.builder().status("fail").mas("处理失败").build();
}
//其他处理
return response;
}
}
测试验证
@SpringBootTest
class SPringBootTestApplicationTests {
@Autowired
@Qualifier("contractSignProcessor")
private Processor<ContractRequest,ContractResponse> contractSignProcessor;
@Test
void contextLoads() {
ContractRequest contractRequest = new ContractRequest();
contractRequest.setName("xbhog");
contractRequest.setAge("12");
ContractResponse process = contractSignProcessor.process(contractRequest);
System.out.println(process);
}
}
在这里只需要调用合同签章进口的办法即可进入合同签章的流程。
2023-07-16 13:25:13.063 INFO 26892 --- [ main] c.e.s.c.ContractSignProcessor : 签章开端
2023-07-16 13:25:13.067 INFO 26892 --- [ main] c.e.s.chainresponsibility.ContractChain : 当时节点:ContractSignCompactInitImpl
2023-07-16 13:25:13.068 INFO 26892 --- [ main] c.e.s.c.i.ContractSignCompactInitImpl : =============履行合同文本初始化拦截器开端
2023-07-16 13:25:13.069 INFO 26892 --- [ main] c.e.s.c.i.ContractSignCompactInitImpl : =============履行合同文本初始化拦截器完毕
2023-07-16 13:25:13.069 INFO 26892 --- [ main] c.e.s.chainresponsibility.ContractChain : 当时节点:ContractSignGenerateImpl
2023-07-16 13:25:13.069 INFO 26892 --- [ main] c.e.s.c.impl.ContractSignGenerateImpl : =============履行合同文本生成拦截器开端
2023-07-16 13:25:13.069 INFO 26892 --- [ main] c.e.s.c.impl.ContractSignGenerateImpl : =============履行合同文本生成拦截器完毕
2023-07-16 13:25:13.069 INFO 26892 --- [ main] c.e.s.chainresponsibility.ContractChain : 当时节点:ContractSignMockImpl
2023-07-16 13:25:13.069 INFO 26892 --- [ main] c.e.s.c.impl.ContractSignMockImpl : =============履行签章挡板拦截器开端
2023-07-16 13:25:13.069 INFO 26892 --- [ main] c.e.s.c.impl.ContractSignMockImpl : =============履行签章挡板拦截器完毕
2023-07-16 13:25:13.069 INFO 26892 --- [ main] c.e.s.chainresponsibility.ContractChain : 当时节点:ContractSignMqImpl
2023-07-16 13:25:13.069 INFO 26892 --- [ main] c.e.s.c.impl.ContractSignMqImpl : =============履行合同签章完结发送mq拦截器开端
2023-07-16 13:25:13.069 INFO 26892 --- [ main] c.e.s.chainresponsibility.ContractChain : 当时节点:ContractSignSerialImpl
2023-07-16 13:25:13.069 INFO 26892 --- [ main] c.e.s.c.impl.ContractSignSerialImpl : =============履行合同签章流水处理拦截器开端
2023-07-16 13:25:13.069 INFO 26892 --- [ main] c.e.s.chainresponsibility.ContractChain : 当时节点:ContractSignSaveUploadImpl
2023-07-16 13:25:13.069 INFO 26892 --- [ main] c.e.s.c.impl.ContractSignSaveUploadImpl : =============履行合同签章完结上传服务器拦截器开端
2023-07-16 13:25:13.069 INFO 26892 --- [ main] c.e.s.chainresponsibility.ContractChain : 当时节点:ContractSignTradeImpl
2023-07-16 13:25:13.069 INFO 26892 --- [ main] c.e.s.c.impl.ContractSignTradeImpl : =============履行签章途径实际调用拦截器开端
2023-07-16 13:25:13.069 INFO 26892 --- [ main] c.e.s.c.channel.ContractSignChannelImpl : 签章处理开端
2023-07-16 13:25:13.070 INFO 26892 --- [ main] c.e.s.c.impl.ContractSignSaveUploadImpl : 开端上传服务器
2023-07-16 13:25:13.070 INFO 26892 --- [ main] c.e.s.c.impl.ContractSignSaveUploadImpl : .............
2023-07-16 13:25:13.070 INFO 26892 --- [ main] c.e.s.c.impl.ContractSignSaveUploadImpl : 上传服务器完结
2023-07-16 13:25:13.070 INFO 26892 --- [ main] c.e.s.c.impl.ContractSignSaveUploadImpl : =============履行合同签章完结上传服务器拦截器完毕
2023-07-16 13:25:13.070 INFO 26892 --- [ main] c.e.s.c.impl.ContractSignSerialImpl : =============履行合同签章流水处理拦截器完毕
2023-07-16 13:25:13.070 INFO 26892 --- [ main] c.e.s.c.impl.ContractSignMqImpl : 发送MQ给下流处理数据
2023-07-16 13:25:13.070 INFO 26892 --- [ main] c.e.s.c.impl.ContractSignMqImpl : =============履行合同签章完结发送mq拦截器完毕
ContractResponse(status=success, mas=处理成功)
战略+职责链+组合代码完结
以下是完整的合同签章进口完结类:
/**
* @author xbhog
* @describe: 职责链+组合完结合同签章
* @date 2023/7/11
*/
@Slf4j
@Component
public class ContractSignProcessor <T extends ContractRequest> implements Processor<T, ContractResponse> {
@Resource(name = "contractSignCompactInitImpl")
private Interceptor<T,ContractResponse> contractCompactInitImpl;
@Resource(name = "contractSignGenerateImpl")
private Interceptor<T,ContractResponse> contractGenerateImpl;
@Resource(name = "contractSignMockImpl")
private Interceptor<T,ContractResponse> contractSignMockImpl;
@Resource(name = "contractSignMqImpl")
private Interceptor<T,ContractResponse> contractSignMqImpl;
@Resource(name = "contractSignSaveUploadImpl")
private Interceptor<T,ContractResponse> contractSignSaveUploadImpl;
@Resource(name = "contractSignSerialImpl")
private Interceptor<T,ContractResponse> contractSignSerialImpl;
@Resource(name = "contractSignTradeImpl")
private Interceptor<T,ContractResponse> ContractSignTradeImpl;
public ContractSignProcessor() {
}
@Override
public ContractResponse process(T paramter) {
//获取一切的监听器
List<Interceptor<T,ContractResponse>> interceptorList = new ArrayList<>();
interceptorList.add(contractCompactInitImpl);
interceptorList.add(contractGenerateImpl);
interceptorList.add(contractSignMockImpl);
interceptorList.add(contractSignMqImpl);
interceptorList.add(contractSignSerialImpl);
interceptorList.add(contractSignSaveUploadImpl);
interceptorList.add(ContractSignTradeImpl);
//开端签章
log.info("签章开端");
return new ContractCall(paramter,interceptorList).exectue();
}
}
能够看到,现在的合同签章的处理流程需要的节点数已经7个了,后续如果新增节点或许削减节点都需要对该类进行手动的处理;比方:削减一个节点的流程。
- 删去节点完结的注入
- 删去
list
中的bean完结类
为便利后续的拓展(懒是社会进步的加速器,不是),在职责链,组合的基础上经过战略形式来修改bean的注入方法。 完整的项目结构和项目类图就是作者文章开端放的,可回来查看。 在榜首部分的基础上添加的功用点如下
- 新增签章注解
- 新增签章节点枚举
- 新增签章装备类
签章注解完结
package com.example.springboottest.chainresponsibility.annotations;
import com.example.springboottest.chainresponsibility.Enum.ContractSignEnum;
import java.lang.annotation.*;
/**
* @author xbhog
* @describe:
* @date 2023/7/15
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ContractSign {
ContractSignEnum.SignChannel SIGN_CHANNEL();
}
设置注解润饰目标的范围,主要是对bean的一个注入,所以类型挑选type
,
- TYPE: 用于描绘类、接口(包括注解类型) 或enum声明
设置注解的运行周期(有用范围),一般是运行时有用,
- RUNTIME:在运行时有用 (大部分注解的挑选)
设置该注解的数据类型,
- ENUM:枚举类型,便利统一处理
枚举完结
package com.xbhog.chainresponsibility.Enum;
/**
* @author xbhog
* @describe:
* @date 2023/7/15
*/
public class ContractSignEnum {
public enum SignChannel {
SIGN_INIT(1, "合同文本初始化"),
SIGN_GENERATE(2, "合同文本生成"),
SIGN_MOCK(3, "签章挡板"),
SIGN_MQ(4, "合同签章完结发送MQ"),
SIGN_TABLE(5, "合同签章表处理"),
SIGN_UPLOAD(6, "合同签章完结上传服务器"),
SIGN_TRADE(7, "签章途径实际调用");
private Integer code;
private String info;
SignChannel(Integer code, String info) {
this.code = code;
this.info = info;
}
......
}
}
对合同签章中的流程节点进行统一的装备。
签章装备类
在项目发动的时分,经过注解东西类AnnotationUtils
扫描一切被ContractSign注解
润饰的类,将这些类经过Map进行存储,便利后续的调用。
public class SignConfig {
@Resource
protected List<Interceptor> contractSignList;
protected static final Map<Integer,Interceptor> CONTRACT_SIGN_MAP = new ConcurrentHashMap<>();
@PostConstruct
public void init(){
contractSignList.forEach(interceptor -> {
//查找这个接口的完结类上有没有ContractSign注解
ContractSign sign = AnnotationUtils.findAnnotation(interceptor.getClass(), ContractSign.class);
if(!Objects.isNull(sign)){
CONTRACT_SIGN_MAP.put(sign.SIGN_CHANNEL().getCode(),interceptor);
}
});
}
}
到此,简化了Bean的注入方法。
签章注解运用
以合同文本初始化ContractSignCompactInitImpl
来说。
/**
* @author xbhog
* @describe: 合同文本初始化
* @date 2023/7/12
*/
@Slf4j
@ContractSign(SIGN_CHANNEL = ContractSignEnum.SignChannel.SIGN_INIT)
@Component
public class ContractSignCompactInitImpl<T extends ContractRequest> implements Interceptor<T, ContractResponse> {
public ContractSignCompactInitImpl() {
}
@Override
public ContractResponse process(Chain<T,ContractResponse> chain) {
log.info("=============履行合同文本初始化拦截器开端");
//获取处理的恳求参数
T request = chain.request();
request.setStatus("1");
log.info("=============履行合同文本初始化拦截器完毕");
//进入下一个职责链节点
ContractResponse response = chain.proceed(request);
if(Objects.isNull(response)){
log.error("回来值的为空");
response = ContractResponse.builder().status("fail").mas("处理失败").build();
}
//其他处理
return response;
}
}
在该完结类上绑定了枚举@ContractSign(SIGN_CHANNEL = ContractSignEnum.SignChannel.SIGN_INIT)
. 在合同签章进口类( **ContractSignProcessor**
)中的改变如下:
@Slf4j
@Component
public class ContractSignProcessor <T extends ContractRequest> extends SignConfig implements Processor<T, ContractResponse> {
public ContractSignProcessor() {
}
@Override
public ContractResponse process(T paramter) {
//获取一切的监听器
List<Interceptor<T,ContractResponse>> interceptorList = new ArrayList<>();
//获取排序后的成果,确保职责链的次序,hashmap中key如果是数字的话,经过hashcode编码后是有序的
for(Integer key : CONTRACT_SIGN_MAP.keySet()){
interceptorList.add(CONTRACT_SIGN_MAP.get(key));
}
//开端签章
log.info("签章开端");
return new ContractCall(paramter,interceptorList).exectue();
}
}
经过承继合同签章装备类(SignConfig
),来获取Map
,遍历Map添加到list
后进入职责链流程。 到此,整个战略+职责链+组合的优化方法完毕了。
问题: 职责链中的次序是怎样确保的? 信任认真看完的你能在文章或许代码中找到答案。