描述
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。
使用
最近在做ChatGPT项目时,用到了这么个设计模式,用户发送消息,先进行敏感词过滤,再判断是否IP限制,再判断是否有额度,最后进行消息回答。
类图
接口
package org.xiaobai.ai.handler.emitter;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import org.xiaobai.ai.api.domain.request.ChatProcessRequest;
/**
* ResponseBodyEmitter 链路
* 责任链模式实现
*/
public interface ResponseEmitterChain {
/**
* 处理请求
*
* @param request 请求对象
* @param emitter 响应对象
*/
void doChain(ChatProcessRequest request, ResponseBodyEmitter emitter);
/**
* 获取下一个处理器
*
* @return 下一个处理器
*/
ResponseEmitterChain getNext();
/**
* 设置下一个处理器
*
* @param next 下一个处理器
*/
void setNext(ResponseEmitterChain next);
/**
* 获取前一个处理器
*
* @return 前一个处理器
*/
ResponseEmitterChain getPrev();
/**
* 设置前一个处理器
*
* @param prev 前一个处理器
*/
void setPrev(ResponseEmitterChain prev);
}
抽象类
package org.xiaobai.ai.handler.emitter;
/**
* 抽象的响应 Emitter 链路实现类,实现了 ResponseEmitterChain 接口
*/
public abstract class AbstractResponseEmitterChain implements ResponseEmitterChain {
/**
* 下一个链路节点
*/
private ResponseEmitterChain next;
/**
* 上一个链路节点
*/
private ResponseEmitterChain prev;
@Override
public ResponseEmitterChain getNext() {
return next;
}
@Override
public void setNext(ResponseEmitterChain next) {
// 设置下一个节点,并将当前节点设置为下一个节点的上一个节点
this.next = next;
next.setPrev(this);
}
@Override
public ResponseEmitterChain getPrev() {
return prev;
}
@Override
public void setPrev(ResponseEmitterChain prev) {
this.prev = prev;
}
}
实现类
只拿ip过滤例子
package org.xiaobai.ai.handler.emitter;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import org.xiaobai.ai.api.domain.request.ChatProcessRequest;
import org.xiaobai.ai.api.domain.vo.ChatReplyMessageVO;
import org.xiaobai.ai.handler.RateLimiterHandler;
import org.xiaobai.core.utils.ObjectMapperUtil;
import org.xiaobai.core.utils.WebUtil;
import java.io.IOException;
/**
* Ip 限流处理
*/
@AllArgsConstructor
public class IpRateLimiterEmitterChain extends AbstractResponseEmitterChain {
@Override
public void doChain(ChatProcessRequest request, ResponseBodyEmitter emitter) {
try {
String ip = WebUtil.getIp();
// 根据ip判断是够可放行
Pair<Boolean, String> limitPair = RateLimiterHandler.allowRequest(ip);
if (limitPair.getKey()) {
if (getNext() != null) {
getNext().doChain(request, emitter);
}
} else {
ChatReplyMessageVO chatReplyMessageVO = ChatReplyMessageVO.onEmitterChainException(request);
chatReplyMessageVO.setText(StrUtil.format("当前访问人数过多,请等到 {} 后再尝试下", limitPair.getValue()));
emitter.send(ObjectMapperUtil.toJson(chatReplyMessageVO));
emitter.complete();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
使用
@Override
public ResponseBodyEmitter sendMessage(ChatProcessRequest chatProcessRequest) {
// 超时时间设置 3 分钟
ResponseBodyEmitter emitter = new ResponseBodyEmitter(3 * 60 * 1000L);
emitter.onCompletion(() -> log.debug("请求参数:{},Front-end closed the emitter connection.", ObjectMapperUtil.toJson(chatProcessRequest)));
emitter.onTimeout(() -> log.error("请求参数:{},Back-end closed the emitter connection.", ObjectMapperUtil.toJson(chatProcessRequest)));
// 构建 emitter 处理链路
ResponseEmitterChain ipRateLimiterEmitterChain = new IpRateLimiterEmitterChain();
ResponseEmitterChain sensitiveWordEmitterChain = new SensitiveWordEmitterChain();
ResponseEmitterChain chatLimiterEmitterChain = new ChatLimiterEmitterChain();
sensitiveWordEmitterChain.setNext(new ChatMessageEmitterChain());
ipRateLimiterEmitterChain.setNext(sensitiveWordEmitterChain);
chatLimiterEmitterChain.setNext(ipRateLimiterEmitterChain);
chatLimiterEmitterChain.doChain(chatProcessRequest, emitter);
return emitter;
}
评论区