概览
最近做了一个chatgpt对接项目,通过让用户关注公众号实现登录并使用chatgpt对话。因为在用户使用过程中,为了安全和成本考虑,需要对用户的访问次数以及用户提问信息进行控制,因此写了一个拦截功能,该功能基于工厂+策略模式实现。
涉及对象
LogicStrategy 拦截注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogicStrategy {
DefaultLogicFactory.LogicModel logicMode();
}
ILogicFilter 定义行为的接口
/**
* 规则过滤接口
*/
public interface ILogicFilter {
RuleLogicEntity<ChatProcessAggregate> filter(ChatProcessAggregate chatProcessAggregate) throws Exception;
}
DefaultLogicFactory 工厂对象
/**
* 规则工厂
*/
@Service
public class DefaultLogicFactory {
//记录所有的拦截逻辑对象
public Map<String, ILogicFilter> logicFilterMap = new ConcurrentHashMap<>();
//构造函数入参为接口类型,在项目启动的时候spring会自动扫描项目里的所有符合对象
public DefaultLogicFactory(List<ILogicFilter> logicFilters) {
logicFilters.forEach(logic ->{
LogicStrategy strategy = AnnotationUtils.findAnnotation(logic.getClass(), LogicStrategy.class);
if(Objects.nonNull(strategy)){
logicFilterMap.put(strategy.logicMode().getCode(),logic);
}
});
}
public Map<String,ILogicFilter> openLogicFilter(){
return logicFilterMap;
}
}
AccessLimitFilter 访问次数限制逻辑对象
在这里仅用拦截次数举例,如果想扩展更多拦截逻辑也很方便,仅需要编写新的拦截逻辑的类并且在类上加上@LogicStrategy注解即可
@Component
@LogicStrategy(logicMode = DefaultLogicFactory.LogicModel.ACCESS_LIMIT)
public class AccessLimitFilter implements ILogicFilter {
@Value("${app.config.limit-count:10}")
private Integer limitCount;
@Value("${app.config.white-list}")
private String whiteListStr;
@Resource
private Cache<String,Integer> visitCache;
@Override
public RuleLogicEntity<ChatProcessAggregate> filter(ChatProcessAggregate chatProcessAggregate) throws Exception {
//白名单用户直接放行
if(chatProcessAggregate.isWhiteList(whiteListStr)){
return RuleLogicEntity.<ChatProcessAggregate>builder()
.type(LogicCheckTypeVO.SUCCESS)
.data(chatProcessAggregate)
.build();
}
final String openid = chatProcessAggregate.getOpenid();
//访问次数判断
int visitCount = visitCache.get(openid,()->0);
if(visitCount < limitCount){
visitCache.put(openid,visitCount+1);
return RuleLogicEntity.<ChatProcessAggregate>builder()
.type(LogicCheckTypeVO.SUCCESS)
.data(chatProcessAggregate)
.build();
}
return RuleLogicEntity.<ChatProcessAggregate>builder()
.info("您今日的免费" + limitCount + "次,已耗尽。")
.type(LogicCheckTypeVO.REFUSE)
.data(chatProcessAggregate)
.build();
}
}
在代码里调用
//规则过滤
@Resource
private DefaultLogicFactory logicFactory;
/**
*
* @param chatProcessAggregate
* @param logics 想要只想的拦截器编码
* @return
* @throws Exception
*/
@Override
protected RuleLogicEntity<ChatProcessAggregate> doCheckLogic(ChatProcessAggregate chatProcessAggregate, String... logics) throws Exception {
//获取项目中所有拦截器
Map<String, ILogicFilter> logicFilterMap = logicFactory.openLogicFilter();
RuleLogicEntity<ChatProcessAggregate> entity = null;
for (String code : logics) {
final ILogicFilter iLogicFilter = logicFilterMap.get(code);
if(Objects.nonNull(iLogicFilter)){
//目标拦截器存在则执行拦截逻辑
entity = iLogicFilter.filter(chatProcessAggregate);
if(!LogicCheckTypeVO.SUCCESS.equals(entity.getType())) return entity;
}
}
return entity != null ? entity :
RuleLogicEntity.<ChatProcessAggregate>builder()
.type(LogicCheckTypeVO.SUCCESS)
.data(chatProcessAggregate)
.build();
}
采用工厂模式后,就可以将每个拦截的逻辑独立写成一个一个的类对象,各司其职,在调用时也仅需要获取到工厂对象后,按需根据传入的编码执行拦截逻辑。使代码具有更高的通用性,提高代码编写质量。