• ElasticSerach+MongoDB:实现文章检索历史功能


    实现目标:

    • 展示用户的搜索记录10条,按照搜索关键词的时间倒序
    • 可以删除搜索记录
    • 保存历史记录,保存10条,多余的则删除最久的历史记录

    image.png

    数据库的选择:

    用户的搜索记录,需要给每一个用户都保存一份,数据量较大,要求加载速度快,通常这样的数据存储到mongodb更合适,不建议直接存储到关系型数据库中。与redis对比,MongoDB是结构化数据,而redis中只有keyValue。

    实现思路:

    image.png

    实现

    保存

    1. 创建实体类

    ```java @Data @Document("apusersearch") // mongoDB的映射注解 public class ApUserSearch implements Serializable { private static final long serialVersionUID = 1L;

    private Integer userId; private String keyword; private Date createdTime; } ```

    2. 保存userSearch

    ```java @Autowired private MongoTemplate mongoTemplate;

    // keyword从dto中获取,userId从线程中获取 @Override public void insert(String keyword, Integer userId){ // 1. 查询当前用户的搜索关键词 Query query = Query.query(Criteria .where("userId").is(userId) .and("keyword").is(keyword)); ApUserSearch apUserSearch = ApUsermongoTemplate.findOne(query, ApUserSearch.class); // 2. 存在,更新创建时间 if(apUserSearch != null) { apUserSerach.setCreatedTime(new Date()); mongoTemplate.save(apUserSearch); return; } // 3. 不存在,判断当前历史总是是否超过10 apUserSearch = new ApUserSearch(); apUserSearch.setUserId(userId); apUserSearch.setKeyWord(keyword); apUserSearch.setCreatedTime(new Date()); // 重新排序 Query query1 = Query.query(Criteria .where("userId").is(userId); query1.with(Sort.by(Sort.Direction.DESC, "createdTime")); List list = mongoTemplate.find(query1, ApUserSearch.class); // 保存历史记录,保存10条,多余的则删除最久的历史记录 if(list == null || list.size() < 10){ mongoTemplate.save(apUserSearch); }else{ ApUserSearch lastInfo = apUserSearchList.get(apUserSearchList.size() - 1); // 替换 mongoTemplate.findAndReplace( Query.query(Criteria.where("id").is(lastInfo.getId()) , apUserSearch); }

    } ```

    3. 获取当前的用户

    拦截器类,继承Ordered,GlobalFilter,其中重写filter方法,获取到了用户信息,存储到了header中,再重置请求

    java @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { //1.获取request和response对象 ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse response = exchange.getResponse(); }

    实现一个工具类AppThreadLocalUtil在utils的Service服务中,用于获取用户 ```java public class AppThreadLocalUtil {

    1. private final static ThreadLocal WM_USER_THREAD_LOCAL = new ThreadLocal<>();
    2. //存入线程中
    3. public static void setUser(ApUser apUser){
    4. WM_USER_THREAD_LOCAL.set(apUser);
    5. }
    6. //从线程中获取
    7. public static ApUser getUser(){
    8. return WM_USER_THREAD_LOCAL.get();
    9. }
    10. //清理
    11. public static void clear(){
    12. WM_USER_THREAD_LOCAL.remove();
    13. }

    } ``` 实现拦截器

    ```java public class AppTokenInterceptor implements HandlerInterceptor { // 把用户解析放在线程中 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String userId = request.getHeader("userId"); if(userId != null){ //存入到当前线程中 ApUser apUser = new ApUser(); apUser.setId(Integer.valueOf(userId)); AppThreadLocalUtil.setUser(apUser);

    1. }
    2. return true;
    3. }
    4. // 清理线程
    5. @Override
    6. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    7. AppThreadLocalUtil.clear();
    8. }

    } ``` 在config中的WebMvcConfig中配置

    java @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AppTokenInterceptor()).addPathPatterns("/**"); } }

    4. 最后在ArticleSerachServiceImple中的search函数中添加

    java ApUser user = AppThreadLocalUtil.getUser(); if(user != null && dto.getFromIndex() == 0){ // 首页 // 异步调用 保存搜索记录 apUserSearchService.insert(dto.getSearchWords(), user.getId()); }

    查询

    java List apUserSearches = mongoTemplate.find(Query.query(Criteria.where("userId").is(user.getId())).with(Sort.by(Sort.Direction.DESC, "createdTime")), ApUserSearch.class);

    删除

    ```java //1.检查参数 if(dto.getId() == null){ return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID); }

    //2.判断是否登录 ApUser user = AppThreadLocalUtil.getUser(); if(user == null){ return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN); }

    //3.删除 mongoTemplate.remove(Query.query(Criteria.where("userId").is(user.getId()).and("id").is(dto.getId())),ApUserSearch.class); return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS); ```

  • 相关阅读:
    Linux(基于Centos7)(四)
    SQL Server登录及建库相关操作
    火爆全网的“羊了个羊”,疯狂圈钱2400多万,背后隐藏着什么?
    servlet中doGet方法无法读取body中的数据
    Spark-RDD知识点
    Android应用内组件通讯之EventBus源码分析之post流程(三)
    Linux应用基础——串口应用编程
    国标视频云服务EasyGBS国标视频平台迁移服务器后无法启动的问题解决方法
    java毕业设计火车订票管理系统mybatis+源码+调试部署+系统+数据库+lw
    小程序中实现付款功能
  • 原文地址:https://blog.csdn.net/Dream__Y/article/details/132978446