文章目录
- 定义策略接口
- 定义es/mysql两种搜索模式的业务类实现上面的接口
- 定义一个枚举类
- 定义一个策略上下文(重点)
- 调用1
- 调用2
- 原理
可以按照以下形式利用策略模式实现mysql/es搜索,qq/微信/gitee登录,上传本地/oss/minio等多种模式进行选择
原理和另外一篇文章基本一样设计模式——使用spring自动注入实现工厂模式参考
定义策略接口
public interface SearchStrategy {
/**
* 搜索文章
*
* @param keywords 关键字
* @return {@link List< ArticleSearchVO >} 文章列表
*/
List<ArticleSearchVO> searchArticle(String keywords);
}
定义es/mysql两种搜索模式的业务类实现上面的接口
es:注意加上注解@Service(“elasticsearchStrategyImpl”)
@Service("elasticsearchStrategyImpl")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class EsSearchStrategyImpl implements SearchStrategy {
@Override
public List<ArticleSearchVO> searchArticle(String keywords) {
System.out.println("使用elasticsearch搜索==========================》"+keywords);
return null;
}
}
mysql:注意加上注解@Service(“mysqlStrategyImpl”)
@Service("mysqlStrategyImpl")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class MysqlSearchStrategyImpl implements SearchStrategy {
@Override
public List<ArticleSearchVO> searchArticle(String keywords){
System.out.println("使用mysql搜索=================================》"+keywords);
return null;
}
}
定义一个枚举类
注意:枚举对象定义的搜索策略中的字符串"mysqlStrategyImpl"和"elasticsearchStrategyImpl"要与前面用@Service注入spring的bean名称一样
public enum SearchModelEnum {
/**
* mysql搜索
*/
MYSQL(0, "mysql搜索", "mysqlStrategyImpl"),
/**
* elasticsearch搜索
*/
ELASTICSEARCH(1, "elasticsearch搜索", "elasticsearchStrategyImpl");
//创建构造函数
SearchModelEnum(int code, String desc, String strategy) {
this.type = code;
this.desc = desc;
this.strategy = strategy;
}
/**
* 搜索方式
*/
private final Integer type;
/**
* 描述
*/
private final String desc;
/**
* 策略
*/
private final String strategy;
public Integer getType() {
return type;
}
public String getDesc() {
return desc;
}
public String getStrategy() {
return strategy;
}
/**
* 获取策略
*
* @param type 模式
* @return {@link String} 搜索策略
*/
public static String getStrategy(int type) {
for (SearchModelEnum value : SearchModelEnum.values()) {
if (value.getType() == (type)) {
return value.getStrategy();
}
}
return null;
}
}
定义一个策略上下文(重点)
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class SearchStrategyContext {
//重点spring会自动注入map里的实现类,因此searchStrategyMap.get(searchMode)能获取到值
private final Map<String, SearchStrategy> searchStrategyMap;
/**
* 执行搜索策略
*
* @param keywords 关键字
* @return {@link List< ArticleSearchVO >} 搜索文章
*/
public List<ArticleSearchVO> executeSearchStrategy(String searchMode, String keywords) {
return searchStrategyMap.get(searchMode).searchArticle(keywords);
}
}
调用1
这里searchModel=0,使用mysql搜索,业务searchModel的值应该从表中或者,这样可以动态修改搜索模式。
@RestController
@RequestMapping("search")
public class MyBatisPlusApplication {
@Autowired
private SearchStrategyContext searchStrategyContext;
@GetMapping
public void serach(String keywords){
//搜索模式【0:SQL搜索 、1:全文检索】 可建立一张配置表查询来获取searchModel
int searchModel=0;
String strategy = SearchModelEnum.getStrategy(searchModel);
List<ArticleSearchVO> articleSearchVOS = searchStrategyContext.executeSearchStrategy(strategy, keywords);
}
调用2
修改searchModel=1,使用es搜索
原理
核心在于SearchStrategyContext类当中定义的private final Map<String, SearchStrategy> searchStrategyMap;
可以看看到,我们并没有往该该map当中复制,可是依旧可以获取到里面对应的搜索实现类"elasticsearchStrategyImpl"和"mysqlStrategyImpl"调用其中的search方法。原因如下Spring会自动将SearchStrategy接口的实现类注入到这个Map中(前提是实现类得是交给Spring 容器管理的),这个Map的key为bean id,可以用@Component(value = “xxx”)的方式设置,如果直接用默认的方式的话,就是首字母小写。value值则为对应的策略实现类)