需求背景
需
求
:
根
据
各
种
规
则
过
滤
数
据
,
筛
选
出
满
足
条
件
的
数
据
\color{red} 需求:根据各种规则过滤数据,筛选出满足条件的数据
需求:根据各种规则过滤数据,筛选出满足条件的数据
要求:
1. 支持各种规则动态组合
2. 尽量灵活搭配,不要指定某种情景下的过滤器
代码下载
职责链模式
开发设计
- 定义规则过滤器顶级接口
package com.dgut.edu.com.filterproject.filterchain.filter;
/**
* FileName: Filter
* Author:
* Date: 2021/6/22 19:09
* Description: 过滤器接口
*/
public interface RuleFilter<T> {
/**
* 口径过滤逻辑
* @param entity
* @return true表示可以执行下一个过滤器,false终止过滤
*/
boolean filter(T entity)throws Exception;
/**
* 获取器的名称
* @return
*/
String name();
}
1.1 具体实现类
package com.dgut.edu.com.filterproject.filterchain.filter.impl;
import com.dgut.edu.com.filterproject.entity.PriceCompareResult;
import com.dgut.edu.com.filterproject.filterchain.filter.RuleFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @description: 跟价口径中,商品属性过滤器,过滤掉不满足条件的数据
* @author: hongbin.zheng
* @create: 2021-06-28 14:39
**/
@Slf4j
@Component
public class MerchandiseRuleFilter implements RuleFilter<PriceCompareResult> {
private static final String MERCHANDISE_RULE_FILTER_NAME = "商品属性过滤器";
/**
* 1. 商品名称包含套装
*
* @param entity
* @return
* @throws Exception
*/
@Override
public boolean filter(PriceCompareResult entity) throws Exception {
// 1. 过滤内网无货商品、过滤分货、过滤库存、过滤下架商品状态
if (entity == null) {
return true;
}
if (entity.getGoodsName().contains("套装")) {
return true;
}
return false;
}
@Override
public String name() {
return "merchandiseRuleFilter";
}
}
package com.dgut.edu.com.filterproject.filterchain.filter.impl;
import com.dgut.edu.com.filterproject.entity.PriceCompareResult;
import com.dgut.edu.com.filterproject.filterchain.filter.RuleFilter;
import com.dgut.edu.com.filterproject.utils.RuleFilterUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @description: 专场过滤器
* @author: hongbin.zheng
* @create: 2021-06-28 17:24
**/
@Slf4j
@Component
public class SalesNoRuleFilter implements RuleFilter<PriceCompareResult> {
private static final String SALES_NAME_RULE_FILTER_NAME = "商品专场过滤器";
/**
* 2. 专场包含:专场包含VIP 和 LUX (顺序先后无关系了)
*
* @param entity
* @return
* @throws Exception
*/
@Override
public boolean filter(PriceCompareResult entity) throws Exception {
// 1 专场包含VIP 和 LUX (顺序先后无关系了)
if (RuleFilterUtils.containsWord(entity.getSalesName(), RuleFilterUtils.VIP) &&
RuleFilterUtils.containsWord(entity.getSalesName(), RuleFilterUtils.LUX)) {
return true;
}
return false;
}
@Override
public String name() {
return "salesNoRuleFilter";
}
}
2、BusinessHandler
package com.dgut.edu.com.filterproject.filterchain.handler;
/**
* FileName: Handler
* Author:
* Date: 2021/6/22 19:12
* Description: 业务处理接口
*/
public interface BusinessHandler<T> {
/**
* 处理方法
* @param entity
*/
void handler(T entity);
}
3、FilterChainConfig 过滤器配置
package com.dgut.edu.com.filterproject.filterchain;
import lombok.Data;
import java.util.List;
/**
* FileName: FilterChainConfig
* Author: shangjie.tang
* Date: 2021/6/22 20:08
* Description: 解析配置
*/
@Data
public class FilterChainConfig {
private String name;
private String handler;
private Boolean enable;
private List<String> filterList;
}
4、 FilterChainFactory 过滤链创建工厂
package com.dgut.edu.com.filterproject.filterchain;
import com.dgut.edu.com.filterproject.filterchain.filter.RuleFilter;
import com.dgut.edu.com.filterproject.filterchain.handler.BusinessHandler;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.Optional;
/**
* FileName: FilterChainF
* Author: shangjie.tang
* Date: 2021/6/22 20:06
* Description: 根据配置,创建过滤链的工厂
*/
@Service
@Slf4j
public class FilterChainFactory {
@Autowired
private ApplicationContext context;
private Map<String, RuleFilter> filterMap;
private Map<String, BusinessHandler> handlerMap;
@PostConstruct
private void init(){
filterMap = Maps.newHashMap();
handlerMap = Maps.newHashMap();
Map<String, RuleFilter> filterBeanMap = context.getBeansOfType(RuleFilter.class);
for (Map.Entry<String, RuleFilter> entry : filterBeanMap.entrySet()) {
filterMap.put(entry.getValue().name(),entry.getValue());
}
Map<String, BusinessHandler> handlerBeanMap = context.getBeansOfType(BusinessHandler.class);
for (Map.Entry<String, BusinessHandler> entry : handlerBeanMap.entrySet()) {
handlerMap.put(entry.getKey(),entry.getValue());
}
}
public <T> FilterChain<T> createChains(FilterChainConfig config,Class<T> tClass){
FilterChain<T> chain = new FilterChain<T>(config.getName(),handlerMap.get(config.getHandler()), Optional.ofNullable(config.getEnable()).orElse(true));
for (String filterBeanName : config.getFilterList()) {
RuleFilter<T> filter = filterMap.get(filterBeanName);
if(filter!=null){
chain.addFilter(filter);
}
}
log.info("创建过滤链成功");
return chain;
}
}
5、过滤链 FilterChain
package com.dgut.edu.com.filterproject.filterchain;
import com.dgut.edu.com.filterproject.filterchain.filter.RuleFilter;
import com.dgut.edu.com.filterproject.filterchain.handler.BusinessHandler;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
/**
* FileName: BaseFilterChain
* Author: shangjie.tang
* Date: 2021/6/22 19:11
* Description: 过滤链
*/
@Slf4j
public class FilterChain<T> {
private String name;
private BusinessHandler<T> businessHandler;
private List<RuleFilter<T>> chain;
private boolean enable;
public FilterChain(String name, BusinessHandler<T> businessHandler, boolean enable) {
this.name = name;
this.businessHandler = businessHandler;
this.enable = enable;
this.chain = new ArrayList<>();
}
public void addFilter(RuleFilter<T> ruleFilter) {
this.chain.add(ruleFilter);
}
/**
* 开始进行过滤
*
* @param entity
* @return 通过返回原样, 不通过返回null
* @throws Exception
*/
public T process(T entity) throws Exception {
if (enable && chain.size() != 0) {
for (RuleFilter<T> ruleFilter : chain) {
if (ruleFilter.filter(entity)) {
log.info("FilterChain_process-filter","没有通过该过滤器");
return null;
}
}
//能达到这步的,都是符合业务的数据,执行业务操作
if (businessHandler != null) {
businessHandler.handler(entity);
}
} else {
log.info("FilterChain_process-filterChain_name","过滤链没有启用");
}
return entity;
}
public String getName() {
return name;
}
}
6、读取配置 CfgCenterUtil
package com.dgut.edu.com.filterproject.service;
public class CfgCenterUtil {
public static String getValue(String CfgName, String other) {
return "[\n" +
"\t{\n" +
"\t\t\"name\":\"过滤链\",\n" +
"\t\t\"handler\":\"\",\n" +
"\t\t\"filterList\":[\"merchandiseRuleFilter\", \"salesNoRuleFilter\"]\n" +
"\t}\n" +
"\t\n" +
"]";
}
}
7、包装服务层
package com.dgut.edu.com.filterproject.service;
import com.alibaba.fastjson.JSONArray;
import com.dgut.edu.com.filterproject.entity.PriceCompareResult;
import com.dgut.edu.com.filterproject.filterchain.FilterChain;
import com.dgut.edu.com.filterproject.filterchain.FilterChainConfig;
import com.dgut.edu.com.filterproject.filterchain.FilterChainFactory;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Service
@Slf4j
public class PcResultFilterService {
@Autowired
private FilterChainFactory filterChainFactory;
/**
* 老配置的md5
*/
private String oldConfigMd5;
/**
* 生成的过滤链
*/
private List<FilterChain<PriceCompareResult>> filterChains = new ArrayList<>();
/**
* 批量进行过滤
*
* @param priceCompareResultList
* @return
*/
public List<PriceCompareResult> batchExecute(List<PriceCompareResult> priceCompareResultList) {
return priceCompareResultList.stream().filter(priceCompareResult -> execute(priceCompareResult) != null ? true : false).collect(Collectors.toList());
}
/**
* 单个进行过滤
*
* @param result
* @return
*/
public PriceCompareResult execute(PriceCompareResult result) {
checkChains();
for (FilterChain<PriceCompareResult> filterChain : filterChains) {
try {
return filterChain.process(result);
} catch (Exception e) {
log.error("PcResultFilterAdmin_execute-filterChain", "执行失败");
}
}
return result;
}
/**
* 查看配置有没有更新,有就重新创建
*/
private void checkChains() {
try {
String filterChainConfig = CfgCenterUtil.getValue("PC_RESULT_FILTER_CHAIN", "");
if (StringUtils.isEmpty(filterChainConfig)) {
log.info("checkChains-filterChainConfig", "配置为空");
return;
}
String newConfigMd5 = DigestUtils.md5DigestAsHex(filterChainConfig.getBytes());
if (!newConfigMd5.equals(oldConfigMd5)) {
List<FilterChainConfig> configs = JSONArray.parseArray(filterChainConfig, FilterChainConfig.class);
List<FilterChain<PriceCompareResult>> list = Lists.newArrayListWithCapacity(configs.size());
for (FilterChainConfig config : configs) {
FilterChain<PriceCompareResult> chain = filterChainFactory.createChains(config, PriceCompareResult.class);
list.add(chain);
}
oldConfigMd5 = newConfigMd5;
filterChains.clear();
filterChains = list;
}
} catch (Exception e) {
log.error("PcResultFilterAdmin_checkChains-新增或更新过滤链失败", e);
}
}
}
8、 测试代码
package com.dgut.edu.com.filterproject;
import com.dgut.edu.com.filterproject.entity.PriceCompareResult;
import com.dgut.edu.com.filterproject.service.PcResultFilterService;
import com.google.common.collect.Lists;
import org.junit.Assert;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class FilterprojectApplicationTests {
@Autowired
private PcResultFilterService pcResultFilterService;
@Test
void contextLoads() {
List<PriceCompareResult> priceCompareResultLists = getPriceCompareResultLists();
List<PriceCompareResult> priceCompareResults = pcResultFilterService.batchExecute(priceCompareResultLists);
Assert.assertEquals(1, priceCompareResults.size());
}
private List<PriceCompareResult> getPriceCompareResultLists() {
List<PriceCompareResult> results = Lists.newArrayList();
PriceCompareResult priceCompareResult1 = getPriceCompareResult();
results.add(priceCompareResult1);
PriceCompareResult priceCompareResult2 = getPriceCompareResult();
priceCompareResult2.setSalesName("专场包含VIP和LUX");
results.add(priceCompareResult2);
PriceCompareResult priceCompareResult3= getPriceCompareResult();
priceCompareResult3.setGoodsName("专场套装");
results.add(priceCompareResult3);
return results;
}
private PriceCompareResult getPriceCompareResult() {
PriceCompareResult entity = new PriceCompareResult();
entity.setGoodsName("商品名称");
entity.setMerchandiseNo(10086L);
entity.setSalesName("专场名称VIP LUP");
entity.setSalesNo(123456L);
return entity;
}
}
测试结果
最后效果,输入三条数据
只有一条满足,返回满足的一条,其他两天直接过滤
总结
知 道 的 越 多 , 不 知 道 的 越 多 , 希 望 对 你 有 帮 助 ! \color{red}知道的越多,不知道的越多,希望对你有帮助! 知道的越多,不知道的越多,希望对你有帮助!