- 封装用到的2个自定义类
- repository层
- service层
- service实现类
- 使用时注意
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
public interface XxxRepository extends org.springframework.data.elasticsearch.repository.ElasticsearchRepositoryservice层{ }
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 IEsbaseServiceservice实现类{ Map , List > FIELD_CACHE = new ConcurrentHashMap<>(); default Class getEntityClass() { return (Class ) (((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]); } default List getEntityAllField() { Class entityClass = getEntityClass(); if (FIELD_CACHE.get(entityClass) != null) { return FIELD_CACHE.get(entityClass); } Field[] currentFields = entityClass.getDeclaredFields(); Class super T> superclass = entityClass.getSuperclass(); List supperFields = new ArrayList<>(); // 可能有多层继承 while (!superclass.equals(Object.class)) { Field[] declaredFields = superclass.getDeclaredFields(); Collections.addAll(supperFields, declaredFields); superclass = superclass.getSuperclass(); } // 排除序列化字段 List fieldList = Arrays.stream(currentFields).filter(f -> !"serialVersionUID".equalsIgnoreCase(f.getName())).distinct().collect(Collectors.toList()); // 父类字段 List 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; } default String[] returnFields() { List fieldList = getEntityAllField(); String[] fields = new String[fieldList.size()]; for (int i = 0; i < fieldList.size(); i++) { fields[i] = fieldList.get(i).getName(); } return fields; } default ListsortFields(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 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 save(S entity);IterablesaveAll(Iterableentities); OptionalfindById(ID id); boolean existsById(ID id); Collection findAll(); Collection findAllById(Collection 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 findAll(Sort sort); Page findAll(Pageable pageable); Page searchSimilar(T entity, @Nullable String[] fields, Pageable pageable); Pagesearch(Q query); Long count(Q query);Listlist(Q query); Listlist(Q query, String... columnName); void update(S entity);void updateAndFlush(S entity);void update(Collectionentities);void updateAndFlush(Collectionentities);void saveOrUpdate(Collectionentities);
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> implements IEsbaseService { @Autowired(required = false) public M repository; @Autowired public ElasticsearchRestTemplate elasticsearchRestTemplate; @Override public S save(S entity) { return repository.save(entity); } @Override publicIterablesaveAll(Iterableentities) { return repository.saveAll(entities); } @Override public OptionalfindById(ID id) { return repository.findById(id); } @Override public boolean existsById(ID id) { return repository.existsById(id); } @Override public Collection findAll() { return list(new PageQuery()); } @Override public Collection findAllById(Collection ids) { return (Collection ) repository.findAllById(ids); } @Override public long count() { return repository.count(); } @Override public void deleteById(ID id) { repository.deleteById(id); } @Override public void delete(T entity) { final List 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()); } @Override public void deleteAllById(Iterable extends ID> ids) { repository.deleteAllById(ids); } @Override public void deleteAll(Collection extends T> entities) { if (CollectionUtils.isEmpty(entities)) { return; } entities.forEach(this::delete); } @Override public void deleteAll() { repository.deleteAll(); } @Override public Iterable findAll(Sort sort) { return repository.findAll(sort); } @Override public Page findAll(Pageable pageable) { return repository.findAll(pageable); } @Override public Page searchSimilar(T entity, String[] fields, Pageable pageable) { return repository.searchSimilar(entity, fields, pageable); } @Override public Pagesearch(Q query) { Long total = count(query); SearchHits searchHits = commonSearch(query, true); if (searchHits.getTotalHits() > 0) { List searchProductList = searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList()); return new PageImpl<>(searchProductList, PageRequest.of(query.getPage(), query.getSize()), total); } return new PageImpl (new ArrayList<>(), PageRequest.of(query.getPage(), query.getSize()), total); } @Override public Long count(Q query) { return commonSearch(query, false).getTotalHits(); } @Override publicListlist(Q query) { SearchHits searchHits = commonSearch(query, false); if (searchHits.getTotalHits() > 0) { return searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList()); } return null; } @Override public Listlist(Q query, String... columnName) { SearchHits searchHits = commonSearch(query, false, columnName); if (searchHits.getTotalHits() > 0) { return searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList()); } return null; } @Override public void update(S entity) { commonUpdate(CollectionUtils.singleList(entity), false); } @Override publicvoid updateAndFlush(S entity) { commonUpdate(CollectionUtils.singleList(entity), true); } @Override publicvoid update(Collectionentities) { commonUpdate(entities, false); } @Override publicvoid updateAndFlush(Collectionentities) { commonUpdate(entities, true); } @Override publicvoid saveOrUpdate(Collectionentities) { Map> tempMap = idTempMap(entities); if (tempMap == null) { return; } List ids = new ArrayList<>(tempMap.keySet()); Collection records = findAllById(ids); if (CollectionUtils.isEmpty(records)) { saveAll(entities); return; } List save = new CopyOnWriteArrayList<>(); List 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 map = tempMap.get(id); if (map == null) { // save save.add(entity); } else { // update update.add(entity); } } }); if (CollectionUtils.notEmpty(save)) { saveAll(save); } if (CollectionUtils.notEmpty(update)) { commonUpdate(update, true); } } private void commonUpdate(Collectionentities, Boolean flush) { Map> tempMap = idTempMap(entities); if (tempMap == null) { return; } List 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 Map> idTempMap(Collection entities) { if (CollectionUtils.isEmpty(entities)) { return null; } final Listfields = getEntityAllField(); Map > tempMap = new ConcurrentHashMap<>(); entities.forEach(entity -> buildIdMapParams(fields, entity, tempMap)); if (CollectionUtils.isEmpty(tempMap)) { return null; } return tempMap; } private void buildIdMapParams(Listfields, S entity, Map > tempMap) { // 用来存放参数 Map 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)) { // 主键ID tempMap.put((ID) o, params); } } } private BoolQueryBuilder buildFilterBoolQueryBuilder(List fields, T entity, AtomicInteger num) { // 查询构建器 BoolQueryBuilder filter = QueryBuilders.boolQuery(); for (Field field : fields) { Object obj = doGetFieldValue(field, entity); if (obj == null) { continue; } // 计数器统计数量+1 num.incrementAndGet(); filter.must(QueryBuilders.termQuery(field.getName(), obj)); } return filter; } 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; } private SearchHitscommonSearch(Q query, boolean page, String... columnName) { // 构建查询条件 NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); // 查询构建器 BoolQueryBuilder builder = QueryBuilders.boolQuery(); // 构建过滤条件 buildFilterCondition(builder, query); queryBuilder.withQuery(builder); List 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 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[笔记] 基于ElasticsearchRepository进行简单封装实现非空更新,saveOrUpdate[笔记]](http://www.mshxw.com/aiimages/31/591430.png)
