环境搭建参考:mongodb:环境搭建_Success___的博客-CSDN博客
需求:
在文章搜索服务中实现保存搜索记录到mongdb
并在搜索时查询出mongdb保存的数据
1、安装mongodb依赖
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
</dependency>
2、创建数据库对应实体类
package com.heima.model.common.search;
import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* APP用户搜索信息表
* </p>
* @author itheima
*/
@Data
@Document("ap_user_search")
public class ApUserSearch implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private String id;
/**
* 用户ID
*/
private Integer userId;
/**
* 搜索词
*/
private String keyword;
/**
* 创建时间
*/
private Date createdTime;
}
3、配置nacos
spring:
data:
mongodb:
host: 192.168.200.130
port: 27017
database: leadnews-history
实现保存
1、在搜索服务的service层新增搜索历史保存方法insert
package com.heima.search.service;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.search.UserSearchDto;
import java.io.IOException;
public interface ArticleSearchService {
/*文章搜索*/
ResponseResult search(UserSearchDto dto) throws IOException;
/**
* 保存用户搜索历史记录
* @param keyword
* @param userId
*/
void insert(String keyword,Integer userId);
}
2、实现类
package com.heima.search.service.impl;
import com.heima.model.common.search.ApUserSearch;
import com.heima.search.service.ArticleSearchService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
@Service
@Slf4j
public class ArticleSearchServiceImpl implements ArticleSearchService {
@Autowired
MongoTemplate mongoTemplate;
/**
* 保存用户搜索历史记录
* @param keyword
* @param userId
*/
@Override
@Async
public void insert(String keyword, Integer userId) {
/*查询当前用户搜索的关键字*/
//构造查询条件
Query query = Query.query(Criteria.where("userid").is(userId)
.and("keyword").is(keyword));
//执行mongodb库的查询
ApUserSearch userSearch = mongoTemplate.findOne(query, ApUserSearch.class);
/*存在则更新创建时间重新保存*/
if(userSearch != null) {
userSearch.setCreatedTime(new Date());
mongoTemplate.save(userSearch);
return;
}
/*不存在,判断当前搜索记录数量是否超过10条*/
userSearch = new ApUserSearch();
userSearch.setUserId(userId);
userSearch.setKeyword(keyword);
userSearch.setCreatedTime(new Date());
//构造搜索条件
Query query1 = Query.query(Criteria.where("userId")
.is(userId));
query1.with(Sort.by(Sort.Direction.DESC,"createdTime"));
//执行查询
List<ApUserSearch> list = mongoTemplate.find(query1, ApUserSearch.class);
//判断list
if(list == null || list.size() < 10){
mongoTemplate.save(userSearch);
}else {
//获取mongodb中最后一条数据就
ApUserSearch apUserSearch = list.get(list.size() - 1);
//findAndReplace:根据查询条件替换库中的数据
mongoTemplate.findAndReplace(
Query.query(Criteria.where("id")
.is(apUserSearch.getId())),
userSearch);
}
}
}
3、在文章搜索方法search中异步调用上面实现的保存记录方法
注意:异步调用的方法需要在方法上加@Async 注解,并在工程启动类加入@EnableAsynczh注解开启异步
@Async是 Spring 框架提供的注解,用于将方法标记为异步执行的方法。它的作用是告诉 Spring 框架在调用被注解的方法时,将其放入线程池中异步执行,而不是阻塞等待方法的完成。
service层完整代码如下
package com.heima.search.service.impl;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson.JSON;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.common.search.ApUserSearch;
import com.heima.model.common.search.UserSearchDto;
import com.heima.model.common.user.ApUser;
import com.heima.search.service.ArticleSearchService;
import com.heima.utils.thread.AppThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Service
@Slf4j
public class ArticleSearchServiceImpl implements ArticleSearchService {
@Autowired
RestHighLevelClient restHighLevelClient;
@Autowired
MongoTemplate mongoTemplate;
/*文章搜索*/
@Override
public ResponseResult search(UserSearchDto dto) throws IOException {
//参数校验
//1.检查参数
if(dto == null || StringUtils.isBlank(dto.getSearchWords())){
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
ApUser user = AppThreadLocalUtil.getUser();
//异步调用 保存搜索记录
if(user != null && dto.getFromIndex() == 0){
insert(dto.getSearchWords(), user.getId());
}
//2.设置查询条件
SearchRequest searchRequest = new SearchRequest("app_info_article");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//布尔查询
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//关键字的分词之后查询
QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery(dto.getSearchWords()).field("title").field("content").defaultOperator(Operator.OR);
boolQueryBuilder.must(queryStringQueryBuilder);
//查询小于mindate的数据
// RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("publishTime").lt(dto.getMinBehotTime().getTime());
// boolQueryBuilder.filter(rangeQueryBuilder);
//分页查询
searchSourceBuilder.from(0);
searchSourceBuilder.size(dto.getPageSize());
//按照发布时间倒序查询
searchSourceBuilder.sort("publishTime", SortOrder.DESC);
//设置高亮 title
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.preTags("<font style='color: red; font-size: inherit;'>");
highlightBuilder.postTags("</font>");
searchSourceBuilder.highlighter(highlightBuilder);
searchSourceBuilder.query(boolQueryBuilder);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//3.结果封装返回
List<Map> list = new ArrayList<>();
SearchHit[] hits = searchResponse.getHits().getHits();
for (SearchHit hit : hits) {
String json = hit.getSourceAsString();
Map map = JSON.parseObject(json, Map.class);
//处理高亮
if(hit.getHighlightFields() != null && hit.getHighlightFields().size() > 0){
Text[] titles = hit.getHighlightFields().get("title").getFragments();
String title = org.apache.commons.lang.StringUtils.join(titles);
//高亮标题
map.put("h_title",title);
}else {
//原始标题
map.put("h_title",map.get("title"));
}
list.add(map);
}
return ResponseResult.okResult(list);
}
/**
* 保存用户搜索历史记录
* @param keyword
* @param userId
*/
@Override
@Async
public void insert(String keyword, Integer userId) {
/*查询当前用户搜索的关键字*/
//构造查询条件
Query query = Query.query(Criteria.where("userid").is(userId)
.and("keyword").is(keyword));
//执行mongodb库的查询
ApUserSearch userSearch = mongoTemplate.findOne(query, ApUserSearch.class);
/*存在则更新创建时间重新保存*/
if(userSearch != null) {
userSearch.setCreatedTime(new Date());
mongoTemplate.save(userSearch);
return;
}
/*不存在,判断当前搜索记录数量是否超过10条*/
userSearch = new ApUserSearch();
userSearch.setUserId(userId);
userSearch.setKeyword(keyword);
userSearch.setCreatedTime(new Date());
//构造搜索条件
Query query1 = Query.query(Criteria.where("userId")
.is(userId));
query1.with(Sort.by(Sort.Direction.DESC,"createdTime"));
//执行查询
List<ApUserSearch> list = mongoTemplate.find(query1, ApUserSearch.class);
//判断list
if(list == null || list.size() < 10){
mongoTemplate.save(userSearch);
}else {
//获取mongodb中最后一条数据就
ApUserSearch apUserSearch = list.get(list.size() - 1);
//findAndReplace:根据查询条件替换库中的数据
mongoTemplate.findAndReplace(
Query.query(Criteria.where("id")
.is(apUserSearch.getId())),
userSearch);
}
}
}
4、测试
前端输入搜索内容
查看数据库mongdb中的数据成功添加