Mongodb:业务应用(1)

环境搭建参考: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中的数据成功添加

下一篇:Mongodb:业务应用(2)_Success___的博客-CSDN博客

相关推荐
r i c k1 小时前
数据库系统学习笔记
数据库·笔记·学习
野犬寒鸦1 小时前
从零起步学习JVM || 第一章:类加载器与双亲委派机制模型详解
java·jvm·数据库·后端·学习
IvorySQL2 小时前
PostgreSQL 分区表的 ALTER TABLE 语句执行机制解析
数据库·postgresql·开源
·云扬·2 小时前
MySQL 8.0 Redo Log 归档与禁用实战指南
android·数据库·mysql
IT邦德2 小时前
Oracle 26ai DataGuard 搭建(RAC到单机)
数据库·oracle
惊讶的猫3 小时前
redis分片集群
数据库·redis·缓存·分片集群·海量数据存储·高并发写
不爱缺氧i3 小时前
完全卸载MariaDB
数据库·mariadb
纤纡.3 小时前
Linux中SQL 从基础到进阶:五大分类详解与表结构操作(ALTER/DROP)全攻略
linux·数据库·sql
jiunian_cn3 小时前
【Redis】渐进式遍历
数据库·redis·缓存
橙露3 小时前
Spring Boot 核心原理:自动配置机制与自定义 Starter 开发
java·数据库·spring boot