springboo项目用自定义框架来完成elasticsearch7.14.0最新版的增删改。同时在mybatis-plus中集成elasticsearch,完成一系列自动化操作。

elasticsearch7.14.0最新版的操作集合,以及对elasticsearch和mybatis-plus整合。

前言

  • 就算不用这个框架,用这个来魔改一下也挺不错哦🤪
  • 该框架是在springboot中对elasticsearch的方法进行包装。同时整合mybatis-plus和elasticsearch(利用mybatis-plus的拦截器来完成自动增删改)
  • 不用在给每个类配置一个独一无二的增删改操作了。且能够自动的实现elasticsearch的增删改操作,以及自动创建index。还有es的搜索功能、支持高亮显示、must匹配和should匹配、list列表分页获取数据。
  • 版本使用:
    • elasticsearch 7.14.0 最新版本
    • springboot 2.4.1
  • 自定义的yml配置
smart-es:
  client-config:
    hostname: # 服务器ip
    port: 9200
    scheme: http
    username: # es给你生成的用户名
    password: # es给你生成的密码
  service-config:
    pre-tags: <span class="highlight">
    post-tags: </span>
    pkg: cn.omisheep.spook.entity # 实体类包名

1. 自动创建索引

如下,有三个注解,分别是@Index@IndexId@IndexField

@Data
@Index
@TableName("article")
@Accessors(chain = true)
public class Article {
   

    @TableId(value = "id", type = IdType.AUTO)
    @IndexId
    private Integer id;

    @IndexField(isSearch = false)
    private String userAvatar;

    @IndexField
    private String type; 
    @IndexField
    private String tags; 

    @IndexField
    private String title;
    @IndexField(searchAnalyzer = "ik_smart")
    private String content;
    @IndexField(isSearch = false)
    private String firstPicture;
    @IndexField
    private String description;

    @IndexField
    private Integer views; // 浏览量
    @IndexField
    @TableField(value = "`like`")
    private Integer like; // 浏览量

    @IndexField
    private Date createTime;

}
  • @Index

该注解用于实体类上面,被注解标记的实体类在springboot运行时会自动判断你的服务器有没有对应的索引,如果没有会创建,有的话会update,稍后说。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Index {
   
String value() default ""; // 索引名
}
  • @IndexId

    该注解用于属性上,被该注解标记的实体类在创建index时或者数据自动增删改时会将其当作es的id,什么类型无所谓,类型会自动转成string。

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IndexId {
   
}
  • @IndxField

    该注解用于属性上,被该注解标记的实体类顾名思义就是index里面的属性。可以自定义搜索方式分词方式指定类型指定名称,基础类型可以不写,其他的,比如String类型可以有text或者keyword。默认text。

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IndexField {
   
String value() default ""; // 字段名,默认为属性名

String type() default ""; // 字段类型,如text等,可以不设置,会默认根据java类型来转换

String analyzer() default "ik_max_word"; // 在类型为text时生效

String searchAnalyzer() default "ik_max_word"; // 在类型为text时生效

/**
* 默认为true参与搜索。
* false时不参与搜索,只作为内容传递,但在指定should和must搜索下仍然能被搜索
*/
boolean isSearch() default true;
}

2. 增删改统一方法

​ 如下,比如在ElasticSearchService类中,使用

@Autowired
private ArticleMapper articleMapper;

@Autowired
private ElasticSearchService elasticSearchService;

public int releaseArticle(Article article, User user) {
   
    article.setUserId(user.getId()).setUserAvatar(user.getAvatar());
    int insert = articleMapper.insert(article);
    elasticSearchService.insert(article);
    // elasticSearchService.update(article);
    return insert;
}

众所周知,因为mybatis的特性,当你插入一个数据时,如果你想这个id由数据库生成,然后在你插入返还id给你,你得重写从对象里面取出来,比如:

articleMapper.insert(article);

int id = article.getId();

看上面,只需要一行代码就能实现插入。使用逻辑和mybatis-plus基本一致

当然,你可以不写,借助mybatis-plus给你的拦截器,你可以在所有mapper调用insert方法之后去拦截她,然后在拦截器中写上这个方法。因为所有的类使用都是一个模样elasticSearchService.insert(object);

  • 拦截器如下
@Slf4j
@Intercepts(@Signature(type = Executor.class, method = "update", args = {
   MappedStatement.class,
        Object.class}))
public class ESAop implements Interceptor {
   

    @Autowired
    private ElasticSearchService elasticSearchService;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
   
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        Object proceed = invocation.proceed(); // 这个就是mapper的方法执行
        fun(mappedStatement.getId(), invocation.getArgs()[1]);
        return proceed;
    }

    public Object plugin(Object o) {
   
        return Plugin.wrap(o, this);
    }

    public void setProperties(Properties properties) {
   
    }

    @SneakyThrows
    private void fun(String method, Object parameter) {
   
        int i = method.lastIndexOf(".");
        String className = method.substring(0, i);
        String methodName = method.substring(i + 1);

        ParameterizedType parameterizedType =
                (ParameterizedType) Class.forName(className)
                        .getGenericInterfaces()[0];

        Class<?> clz = (Class<?>) parameterizedType.getActualTypeArguments()[0];
        if (!elasticSearchService.isIndex(clz)) {
   
            return;
        }

        switch (methodName) {
    // 在这里添加自定义方法,如果不熟悉,可以打个断点
            case "insert": {
   
                if (clz == parameter.getClass()) {
   
                    elasticSearchService.insert(parameter);
                }
                break;
            }
            case "updateById":
                Object o = ((MapperMethod.ParamMap) parameter).get("param1");
                if (clz == o.getClass()) {
   
                    elasticSearchService.insert(parameter);
                }
                elasticSearchService.insert(o);
                break;
            case "deleteById": {
   
                elasticSearchService.delete(clz.getName(), parameter + "");
                break;
            }
        }
    }
}

自定义的mapper方法需要拦截,你需要动动你的小手自己加上去。。。

  • 再来看看insert这个方法。其他方法大同小异
/**
 * 请在save之后调用此方法,否则获得不到id,这样在插入到es服务器中,id是随机的。
 */
@SneakyThrows
public <E> int insert(E o) {
   
    log.info(" elastic service insert {}", o);
    Meta meta = new Meta(o);

    IndexRequest request = new IndexRequest(meta.getIndexName())
            .id(meta.getIndexId())
            .timeout("3s")
            .source(meta.getSource());
    return client.index(request, RequestOptions.DEFAULT).status().getStatus();
}

很明显。参数是不是固定的。所以可以实现插入任意的实体类。这个service有点长,在最后贴出来。

Meta meta = new Meta(o); // 这一行代码就是根据之前的一些注解来包装成一个对象。

还有一些其他的如update delete啥的放在最后了,或者去gitee上下载下来。https://gitee.com/iozxc/smart-es

3. 搜索查询

搜索就不看service的代码了。直接看controller如何调用的

@RestController
@RequestMapping
@Slf4j
public class SearchController {
   

    @Autowired
    private ElasticSearchService elasticSearchService;

    @GetMapping(value = {
   "/search", "/s"}) 
    public Result search(@RequestParam(value = "kw", required = false) String keyword,
                         @RequestParam(required = false) Integer pageNo,
                         @RequestParam(required = false) Integer pageSize,
                         @RequestParam(required = false) String type,
                         @RequestParam(required = false) String index,
                         @RequestParam(required = false) String must,
                         @RequestParam(required = false) String should,
                         @RequestParam(value = "highlight", required = false, defaultValue = "true") Boolean isHighlight) {
   
        if (keyword == null) {
   
            return new Result(ResultCode.SUCCESS);
        }
        HashMap<String, List<Object>> search = elasticSearchService.search(keyword, pageNo, pageSize, type, index, must, should, isHighlight);
        return new Result(ResultCode.SUCCESS, search);
    }


    @GetMapping(value = {
   "/list", "/l"})
    public Result list(@RequestParam(value = "i", required = false) String index,
                       @RequestParam(required = false) Integer pageNo,
              
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值