- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
ps:【文章由来】 公司项目中所用的合同签章处理流程,本人基于责任链上使用策略模式进行优化.
执行的流程如下:
整个结构类似于递归调用。每个节点中依赖上一个节点的输入以及下一个节点的输出,在中间过程可以实现每个节点的自定义操作,比较灵活.
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 .
设置注解的运行周期(有效范围),一般是运行时有效, 。
设置该注解的数据类型, 。
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 后进入责任链流程。 到此,整个策略+责任链+组合的优化方式结束了.
问题: 责任链中的顺序是怎么保证的? 相信认真看完的你能在文章或者 代码中 找到答案.
最后此篇关于【进阶玩法】策略+责任链+组合实现合同签章的文章就讲到这里了,如果你想了解更多关于【进阶玩法】策略+责任链+组合实现合同签章的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
作者:小林coding 计算机八股文网站:https://xiaolincoding.com 大家好,我是小林。 今天跟大家聊聊,常见的缓存更新策略。 Cache Aside(旁路缓存)策略; Rea
我使用 git 多年,最近为了一个项目改用 mercurial。在过去的 6 个月里,我已经学会了如何通过命令行很好地使用 Mercurial。 这可能是我的想象,但在我看来,mercurial 在
这个问题适合任何熟悉的人 Node.js express Passport 带有 Passport 的 JWT 身份验证(JSON Web token ) Facebook OAuth2.0 或谷歌
在 Coq 中,当试图证明记录的相等性时,是否有一种策略可以将其分解为所有字段的相等性?例如, Record R := {x:nat;y:nat}. Variables a b c d : nat.
我正在处理的项目目前只有一个 Bootstrap 文件,用于初始化应用程序中的所有 javascript 对象。类似于下面的代码 if(document.getElementById('nav'))
我正在考虑使用 OpenLDAP 在首次登录时添加密码到期和强制更改密码。 似乎使用 ppolicy 覆盖来实现这一点。 当我在 ppolicy.schema 中看到这个时,我开始使用 ppolicy
这基本上是我昨天问的一个问题的重新陈述,因为我得到的一个答案似乎没有理解我的问题,所以我一定是不清楚。我的错。 因为 WPF 依赖于 DirectX,所以它对卡和驱动程序的内部非常敏感。我有一个案例,
我是单点登录(SSO)概念的新手。我开始知道 SAML 请求和响应是实现 SSO 流程的最佳方式。然后我开始阅读有关 SAML2.0 的信息。我来了一个术语 NameIdPolicy 在 saml1.
关闭。这个问题需要更多 focused .它目前不接受答案。 想改进这个问题?更新问题,使其仅关注一个问题 editing this post . 5年前关闭。 Improve this questi
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 9 年前。 Improv
在 Azure 上创建新的 SQL 数据库时,它将“计算+存储”选项设置为“2 vCore + 32GB 数据最大大小”作为默认配置,但我不想使用 vCore,我可以更改它。但问题是,是否可以通过策略
我希望创建一项策略,防止在未启用身份验证的情况下创建应用服务(仅审核它们是不够的)。 以下策略可以正确识别未启用身份验证的现有资源: { "mode": "All", "policyRule"
我正在尝试从现有 AuditIfNotExists 策略创建 DeployIfNotExists 策略。部署时不会出错,但会错误提示“没有相关资源与策略定义中的效果详细信息匹配”。当评估政策时。当我将
我正在尝试从现有 AuditIfNotExists 策略创建 DeployIfNotExists 策略。部署时不会出错,但会错误提示“没有相关资源与策略定义中的效果详细信息匹配”。当评估政策时。当我将
我正在使用 wunderground 的 json api 来查询我网站上的天气状况。 api 为我提供了一个包含所有必要数据的漂亮 json 对象,但我每天只能进行多次调用。存储这些数据的首选方式是
我有一个名为可视化数据结构的项目。我有这样的 OOP 设计。 Class VisualDataStructures extends JFrame Class ControlPanel extends
这个问题在这里已经有了答案: 关闭 14 年前。 副本: Use javascript to inject script references as needed? Javascript 没有任何指
Android 应用程序遇到了一些 ANR 问题,因此我实现了 StrictMode 策略。以前从未使用过这个,所以希望有人可以帮助解释以下内容: 为什么日志显示 2 个看似相似的违规行为,除了前 4
我目前正在尝试解决一个问题。假设我们在路上行驶,我们知道路上有 10 家酒店。每家酒店都有 0 到 6 星。我的问题是:找到选择星级酒店的最佳解决方案。唯一的问题是:您不能回头去参观您已经决定不去的酒
我正在将我的应用程序迁移到 MVP。从这个 konmik 中获得了有关静态演示者模式的提示 这是我的简要 MVP 策略。为简洁起见,删除了大部分样板和 MVP 监听器。这个策略帮助我改变了方向,证明了
我是一名优秀的程序员,十分优秀!