基于ElasticsearchRepository进行简单封装

  • 封装用到的2个自定义类
  • repository层
  • service层
  • service实现类
  • 使用时注意

封装用到的2个自定义类

public class PageQuery implements Serializable {private static final long serialVersionUID = 7172912761241281958L;/*** 当前页*/private Integer page = 0;/*** 条目数*/private Integer size = 20;/*** 关键字*/@ApiModelProperty(value = "搜索关键字")private String keyword;/** 排序字段 */@ApiModelProperty(value = "排序字段")private String sortField;/** 排序方法 */@ApiModelProperty(value = "排序方式 asc,desc")private String sortWay;public Integer getPage() {return page;}public void setPage(Integer page) {this.page = page;}public Integer getSize() {return size;}public void setSize(Integer size) {this.size = size;}public String getKeyword() {return keyword;}public void setKeyword(String keyword) {this.keyword = keyword;}public String getSortField() {return sortField;}public void setSortField(String sortField) {this.sortField = sortField;}public String getSortWay() {return sortWay;}public void setSortWay(String sortWay) {this.sortWay = sortWay;}

import org.elasticsearch.search.sort.SortOrder;import java.io.Serializable;public class SortParam implements Serializable {private static final long serialVersionUID = -379151600753725891L;/** 排序字段 */private String fieldName;/** 排序方式 */private SortOrder order;public String getFieldName() {return fieldName;}public void setFieldName(String fieldName) {this.fieldName = fieldName;}public SortOrder getOrder() {return order;}public void setOrder(SortOrder order) {this.order = order;}
}

repository层

直接继承org.springframework.data.elasticsearch.repository.ElasticsearchRepository<T, ID>即可

public interface XxxRepository extends org.springframework.data.elasticsearch.repository.ElasticsearchRepository<Xxx, String>{}

service层

import cn.venny.base.beans.PageQuery;
import cn.venny.base.beans.SortParam;
import cn.venny.base.utils.CollectionUtils;
import cn.venny.base.utils.StringUtils;import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.lang.Nullable;import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;public interface IEsBaseService<T, ID> {/** 属性缓存 */Map<Class<?>, List<Field>> FIELD_CACHE = new ConcurrentHashMap<>();/*** 获取实体class类型* @return 实体clazz类型*/default Class<T> getEntityClass() {return (Class<T>) (((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);}/*** 获取实体所有属性(排除序列号属性)* @return 属性集合*/default List<Field> getEntityAllField() {Class<T> entityClass = getEntityClass();if (FIELD_CACHE.get(entityClass) != null) {return FIELD_CACHE.get(entityClass);}Field[] currentFields = entityClass.getDeclaredFields();Class<? super T> superclass = entityClass.getSuperclass();List<Field> supperFields = new ArrayList<>();// 可能有多层继承while (!superclass.equals(Object.class)) {Field[] declaredFields = superclass.getDeclaredFields();Collections.addAll(supperFields, declaredFields);superclass = superclass.getSuperclass();}// 排除序列化字段List<Field> fieldList = Arrays.stream(currentFields).filter(f -> !"serialVersionUID".equalsIgnoreCase(f.getName())).distinct().collect(Collectors.toList());// 父类字段List<Field> superFieldList = supperFields.stream().filter(f -> !"serialVersionUID".equalsIgnoreCase(f.getName())).distinct().collect(Collectors.toList());if (CollectionUtils.notEmpty(superFieldList)) {fieldList.addAll(superFieldList);}FIELD_CACHE.put(entityClass, fieldList);return fieldList;}/*** 页面返回字段* @return 实体所有字段名称数组*/default String[] returnFields() {List<Field> fieldList = getEntityAllField();String[] fields = new String[fieldList.size()];for (int i = 0; i < fieldList.size(); i++) {fields[i] = fieldList.get(i).getName();}return fields;}/*** 排序字段、排序方式设置* 默认按照创建时间倒叙排列* @param query 查询参数* @param <Q>   查询参数实体*/default <Q extends PageQuery> List<SortParam> sortFields(Q query) {if (StringUtils.isEmpty(query.getSortField()) || StringUtils.isEmpty(query.getSortWay())) {return null;}SortParam sp = new SortParam();sp.setFieldName(query.getSortField());sp.setOrder(SortOrder.valueOf(query.getSortWay().toUpperCase()));return CollectionUtils.singleList(sp);}/*** 构建过滤条件*/default <Q extends PageQuery> void buildFilterCondition(BoolQueryBuilder filter, Q queryParam) {// eg:// 带分词匹配// filter.must(QueryBuilders.matchQuery("xxx", query.getXxxx()));// 不分词匹配// filter.must(QueryBuilders.termQuery("xxx", query.getXxx()));// 范围匹配// filter.must(QueryBuilders.rangeQuery("createTime").gte(query.getCreateTime() + " 00:00:00"));}<S extends T> S save(S entity);<S extends T> Iterable<S> saveAll(Iterable<S> entities);Optional<T> findById(ID id);boolean existsById(ID id);Collection<T> findAll();Collection<T> findAllById(Collection<ID> ids);long count();void deleteById(ID id);void delete(T entity);void deleteAllById(Iterable<? extends ID> ids);void deleteAll(Collection<? extends T> entities);void deleteAll();Iterable<T> findAll(Sort sort);Page<T> findAll(Pageable pageable);/*** 模糊搜索* @param entity   请求实体* @param fields   查询字段名称* @param pageable 分页对象* @return 分页参数*/Page<T> searchSimilar(T entity, @Nullable String[] fields, Pageable pageable);/*** 分页查询(自定义)* @param query 请求参数* @param <Q>   请求参数类型* @return 分页数据*/<Q extends PageQuery> Page<T> search(Q query);/*** 分页查询(自定义)* @param query 请求参数* @param <Q>   请求参数类型* @return 数据总数*/<Q extends PageQuery> Long count(Q query);/*** 分页查询(自定义)* @param query 请求参数* @param <Q>   请求参数类型* @return 数据总数*/<Q extends PageQuery> List<T> list(Q query);/*** 分页查询(自定义)* @param query      请求参数* @param <Q>        请求参数类型* @param columnName 返回列名* @return 数据总数*/<Q extends PageQuery> List<T> list(Q query, String... columnName);/*** 根据ID保存或者更新* @param entity 请求实体* @param <S>    实体类型*/<S extends T> void update(S entity);/*** 根据ID保存或者更新* @param entity 请求实体* @param <S>    实体类型*/<S extends T> void updateAndFlush(S entity);/*** 批量保存或者更新* @param entities 请求实体集合* @param <S>      实体类型*/<S extends T> void update(Collection<S> entities);/*** 批量保存或者更新* @param entities 请求实体集合* @param <S>      实体类型*/<S extends T> void updateAndFlush(Collection<S> entities);/*** 批量保存或者更新* @param entities 请求实体集合* @param <S>      实体类型*/<S extends T> void saveOrUpdate(Collection<S> entities);

service实现类

import xx.xx.xx.PageQuery;
import xx.xx.xx.SortParam;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.Id;
import org.springframework.data.domain.*;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.query.BulkOptions;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.UpdateQuery;import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;public abstract class EsBaseServiceImpl<T, ID, M extends org.springframework.data.elasticsearch.repository.ElasticsearchRepository<T, ID>>  implements IEsBaseService<T, ID> {@Autowired(required = false)public M repository;@Autowiredpublic ElasticsearchRestTemplate elasticsearchRestTemplate;@Overridepublic <S extends T> S save(S entity) {return repository.save(entity);}@Overridepublic <S extends T> Iterable<S> saveAll(Iterable<S> entities) {return repository.saveAll(entities);}@Overridepublic Optional<T> findById(ID id) {return repository.findById(id);}@Overridepublic boolean existsById(ID id) {return repository.existsById(id);}@Overridepublic Collection<T> findAll() {return list(new PageQuery());}@Overridepublic Collection<T> findAllById(Collection<ID> ids) {return (Collection<T>) repository.findAllById(ids);}@Overridepublic long count() {return repository.count();}@Overridepublic void deleteById(ID id) {repository.deleteById(id);}@Overridepublic void delete(T entity) {final List<Field> fields = getEntityAllField();AtomicInteger num = new AtomicInteger();// 构建过滤条件BoolQueryBuilder filter = buildFilterBoolQueryBuilder(fields, entity, num);if (num.intValue() < 1) {return;}// 构建查询条件NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();queryBuilder.withFilter(filter);// 执行删除elasticsearchRestTemplate.delete(queryBuilder.build(), getEntityClass());}@Overridepublic void deleteAllById(Iterable<? extends ID> ids) {repository.deleteAllById(ids);}@Overridepublic void deleteAll(Collection<? extends T> entities) {if (CollectionUtils.isEmpty(entities)) {return;}entities.forEach(this::delete);}@Overridepublic void deleteAll() {repository.deleteAll();}@Overridepublic Iterable<T> findAll(Sort sort) {return repository.findAll(sort);}@Overridepublic Page<T> findAll(Pageable pageable) {return repository.findAll(pageable);}@Overridepublic Page<T> searchSimilar(T entity, String[] fields, Pageable pageable) {return repository.searchSimilar(entity, fields, pageable);}@Overridepublic <Q extends PageQuery> Page<T> search(Q query) {Long total = count(query);SearchHits<T> searchHits = commonSearch(query, true);if (searchHits.getTotalHits() > 0) {List<T> searchProductList = searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList());return new PageImpl<>(searchProductList, PageRequest.of(query.getPage(), query.getSize()), total);}return new PageImpl<T>(new ArrayList<>(), PageRequest.of(query.getPage(), query.getSize()), total);}@Overridepublic <Q extends PageQuery> Long count(Q query) {return commonSearch(query, false).getTotalHits();}@Overridepublic <Q extends PageQuery> List<T> list(Q query) {SearchHits<T> searchHits = commonSearch(query, false);if (searchHits.getTotalHits() > 0) {return searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList());}return null;}@Overridepublic <Q extends PageQuery> List<T> list(Q query, String... columnName) {SearchHits<T> searchHits = commonSearch(query, false, columnName);if (searchHits.getTotalHits() > 0) {return searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList());}return null;}@Overridepublic <S extends T> void update(S entity) {commonUpdate(CollectionUtils.singleList(entity), false);}@Overridepublic <S extends T> void updateAndFlush(S entity) {commonUpdate(CollectionUtils.singleList(entity), true);}@Overridepublic <S extends T> void update(Collection<S> entities) {commonUpdate(entities, false);}@Overridepublic <S extends T> void updateAndFlush(Collection<S> entities) {commonUpdate(entities, true);}@Overridepublic <S extends T> void saveOrUpdate(Collection<S> entities) {Map<ID, Map<String, Object>> tempMap = idTempMap(entities);if (tempMap == null) {return;}List<ID> ids = new ArrayList<>(tempMap.keySet());Collection<T> records = findAllById(ids);if (CollectionUtils.isEmpty(records)) {saveAll(entities);return;}List<T> save = new CopyOnWriteArrayList<>();List<T> update = new CopyOnWriteArrayList<>();records.forEach(entity -> {Field[] declaredFields = entity.getClass().getDeclaredFields();for (Field field : declaredFields) {if (!field.isAnnotationPresent(Id.class)) {continue;}ID id = (ID) doGetFieldValue(field, entity);Map<String, Object> map = tempMap.get(id);if (map == null) {// savesave.add(entity);} else {// updateupdate.add(entity);}}});if (CollectionUtils.notEmpty(save)) {saveAll(save);}if (CollectionUtils.notEmpty(update)) {commonUpdate(update, true);}}/*** 通用更新* @param entities 请求实体* @param flush    是否立即刷新* @param <S>      请求实体类型*/private <S extends T> void commonUpdate(Collection<S> entities, Boolean flush) {Map<ID, Map<String, Object>> tempMap = idTempMap(entities);if (tempMap == null) {return;}List<UpdateQuery> queries = new CopyOnWriteArrayList<>();tempMap.forEach((id, params) -> {UpdateQuery build = UpdateQuery.builder(String.valueOf(id)).withDocument(Document.from(params)).build();queries.add(build);});if (flush) {// 立刻刷新,损害性能elasticsearchRestTemplate.bulkUpdate(queries,BulkOptions.builder().withRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE).build(),elasticsearchRestTemplate.getIndexCoordinatesFor(getEntityClass()));} else {// 不执行立刻刷新,损害性能elasticsearchRestTemplate.bulkUpdate(queries, getEntityClass());}}private <S extends T> Map<ID, Map<String, Object>> idTempMap(Collection<S> entities) {if (CollectionUtils.isEmpty(entities)) {return null;}final List<Field> fields = getEntityAllField();Map<ID, Map<String, Object>> tempMap = new ConcurrentHashMap<>();entities.forEach(entity -> buildIdMapParams(fields, entity, tempMap));if (CollectionUtils.isEmpty(tempMap)) {return null;}return tempMap;}private <S extends T> void buildIdMapParams(List<Field> fields, S entity, Map<ID, Map<String, Object>> tempMap) {// 用来存放参数Map<String, Object> params = new LinkedHashMap<>();for (Field field : fields) {Object o = doGetFieldValue(field, entity);if (o == null) {continue;}params.put(field.getName(), o);if (field.isAnnotationPresent(Id.class)) {// 主键IDtempMap.put((ID) o, params);}}}private BoolQueryBuilder buildFilterBoolQueryBuilder(List<Field> fields, T entity, AtomicInteger num) {// 查询构建器BoolQueryBuilder filter = QueryBuilders.boolQuery();for (Field field : fields) {Object obj = doGetFieldValue(field, entity);if (obj == null) {continue;}// 计数器统计数量+1num.incrementAndGet();filter.must(QueryBuilders.termQuery(field.getName(), obj));}return filter;}/*** 获取属性值* @param field  field对象* @param entity 实体类* @return 属性值*/private Object doGetFieldValue(Field field, T entity) {field.setAccessible(true);// 一般属性Object o = null;try {o = field.get(entity);} catch (IllegalAccessException e) {log.error("获取属性异常", e);}return o;}/*** 通用查询* @param query 查询条件* @param <Q>   查询条件类型* @param page  是否需要分页* @return es响应对象*/private <Q extends PageQuery> SearchHits<T> commonSearch(Q query, boolean page, String... columnName) {// 构建查询条件NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();// 查询构建器BoolQueryBuilder builder = QueryBuilders.boolQuery();// 构建过滤条件buildFilterCondition(builder, query);queryBuilder.withQuery(builder);List<SortParam> sorts = sortFields(query);if (CollectionUtils.notEmpty(sorts)) {for (SortParam sort : sorts) {queryBuilder.withSort(SortBuilders.fieldSort(sort.getFieldName()).order(sort.getOrder()));}}// 分页条件if (page) {queryBuilder.withPageable(PageRequest.of(query.getPage(), query.getSize()));}NativeSearchQuery nativeSearchQuery = queryBuilder.build();// 页面返回字段设置if (columnName != null && columnName.length > 0) {nativeSearchQuery.addFields(columnName);} else {nativeSearchQuery.addFields(returnFields());}// 使用ElasticsearchRestTemplate进行复杂查询return elasticsearchRestTemplate.search(nativeSearchQuery, this.getEntityClass());}
}

以上用到的工具类,StringUtils、CollectionUtils是自定义的工具类,具体实现很简单,继承spring对应的工具类,添加常用方法,例如:notEmpty()-->调用spring的isEmpty()方法再取反

使用时注意

  • 查询用到的构造条件需要重写
  /*** 构建过滤条件*/public <Q extends PageQuery> void buildFilterCondition(BoolQueryBuilder filter, Q queryParam) {// 强转为实际请求对象XxxQuery query = (XxxQuery)queryParam;// 根据实际参数构造查询条件// eg:// 带分词匹配// filter.must(QueryBuilders.matchQuery("xxx", query.getXxx()));// 不分词匹配// filter.must(QueryBuilders.termQuery("xxx", query.getXxx()));// 范围匹配// filter.must(QueryBuilders.rangeQuery("createTime").gte(query.getCreateTime() + " 00:00:00"));}

基于ElasticsearchRepository进行简单封装实现非空更新,saveOrUpdate[笔记]相关推荐

  1. nodejs操作sqlserver数据_nodejs基于mssql模块连接sqlserver数据库的简单封装操作示例...

    本文实例讲述了nodejs基于mssql模块连接sqlserver数据库的简单封装操作.分享给大家供大家参考,具体如下: 注意:开启sqlserver服务器允许远程连接的步骤,自行百度,很多经验,no ...

  2. swoole mysql 协程_swoole-orm: 基于swoole的mysql协程连接池,简单封装。实现多个协程间共用同一个协程客户端。参考thinkphp-orm...

    swoole-orm 基于swoole的mysql协程连接池,简单封装. 实现多个协程间共用同一个协程客户端 感谢完善 [1]:nowbe -> 新增数据返回insert_id 版本 v0.0. ...

  3. nodejs操作sqlserver数据_实例分析nodejs基于mssql模块连接sqlserver数据库的简单封装操作...

    本文主要介绍了nodejs基于mssql模块连接sqlserver数据库的简单封装操作,结合实例形式分析了nodejs中mssql模块的安装与操作sqlserver数据库相关使用技巧,需要的朋友可以参 ...

  4. SpringBoot基于AOP实现自定义非空验证的注解

    为了避免对大量参数进行过多的非空校验,我们可以自定义一个非空验证的注解,因为spring自带的@RequestParam并不能对参数进行非空 准备工作 首先需要创建一个spring boot项目,并引 ...

  5. 记录一次生产发布事件——(简单的非空验证也能引发大问题)

    事件经过 下午四点,发布生产g环境(生产环境m为正式环境,g为内测环境).这时测试有人提出"服务器忙".听到这里我赶紧翻了翻内测日志,发现了最熟悉的老朋友--未将对象引用设置到对象 ...

  6. 还在用if(obj!=null)做非空判断?带你快速上手Optional实战性理解!

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 1.前言 相信不少小伙伴已经被java的NPE(Null ...

  7. 表单提交时submit验证非空return false没用_开发这样一个复杂的表单你需要用多久...

    表单在中后台开发的时,是最多也是最另人头疼的,多级联动,繁杂的验证,动态解析等可算是苦不堪言.所以出现了无数的表单解决方案,像Uform, formily, NoForm等等一大堆用来解决中后台开发表 ...

  8. java 多态判断非空_收藏Java 面试题全梳理

    脚本之家 你与百万开发者在一起 来源 | Java建设者(ID:javajianshe) 作者 |cxuan 如若转载请联系原公众号 Java 基础篇 Java 有哪些特点 并发性的:你可以在其中执行 ...

  9. orika 映射非空字段_Orika:将JAXB对象映射到业务/域对象

    orika 映射非空字段 这篇文章着眼于使用Orika将JAXB对象映射到业务域对象. 本月初, 我使用基于反射的Dozer讨论 了相同的映射用例 . 在本文中,我假设需要映射相同的示例类,但是它们将 ...

最新文章

  1. qt获取当前系统音量值_Qt编写自定义控件50-迷你仪表盘
  2. Linux下简单的邮件服务器搭建
  3. AlphaZero进化论:从零开始,制霸所有棋类游戏
  4. 修改Ubuntu和XP双系统时的默认启动系统
  5. 使用python数据分析的研究意义_大数据分析语言Python的价值和意义
  6. 【LOJ】 #2540. 「PKUWC2018」随机算法
  7. jquery中怎么删除ul中的整个li包括节点
  8. 思考:那么些大学生仅凭个人好恶来判断,缺乏是非观
  9. 楼天成夺Facebook黑客杯季军,已被Facebook录用得到美国绿卡
  10. 黑鲨5系列游戏手机通过3C认证:支持120W超级快充
  11. jQuery keyup事件
  12. mysql-基本操作
  13. 如何在S函数中对变量或者输入信号进行求导
  14. 今年秋季 MacBook Pro 将迎来六大变化
  15. 读《诗经·邶风·击鼓》有感-间歇博客
  16. HEVC视频扩展解决方法
  17. excel shell合成_1分钟拆解:「如何将10多个工作表sheet,合并成一张?」
  18. K8S在centeros中的部署
  19. Androidnbsp;LinearLayout与Relat…
  20. Above the MedianDueling GPSs

热门文章

  1. 罗塞塔石碑1141问题
  2. 《如师通语言学习软件(罗塞塔石碑)》(Rosetta Stone) v3.4.5 英语/日语/法语/德语/韩语/俄语/西班牙语/意大利语/阿拉伯语/葡萄牙语/汉语 [云端免安装版]
  3. 201903-2二十四点[20201213封笔题目]没写呢
  4. 不朽凡人 第五百二十章 有脾气冲我来
  5. TinyXML2 学习
  6. 正则应用(用户名输入框)
  7. HDU-2094(产生冠军)
  8. 大数据必学Java基础(五):第一段程序
  9. 《计算机网络(谢希仁6版)》学习笔记(word导入)[待补全]
  10. JS对象中添加新的属性及修改字段名