当前位置: 首页 > article >正文

【从0做项目】Java搜索引擎(7) web模块

阿华代码,不是逆风,就是我疯

你们的点赞收藏是我前进最大的动力!!

希望本文内容能够帮助到你!!

目录

文章导读

零:项目结果展示

一:后端web模块

1:思路

2:设计

3:注意点

(1)设置响应头格式

(2)方法返回类型

(3)实例化DocSearch

二:前端代码

 1:head标签

 2:body标签

(1)div标签

(2)style标签

(3)script标签

三:前端显示优化&后端联动

1:实现前端搜索关键字标红

(1)实现逻辑

(2)正则表达式

2:后端代码

3:呈现效果


文章导读

阿华将发布项目复盘系列的文章,旨在:

1:手把手细致带大家从0到1做一个完整的项目,保证每2~3行代码都有详细的注解

2:通过文字+画图的方式,对项目进行整个复盘,更好的理解以及优化项目

3:总结自己的优缺点,扎实java相关技术栈,增强文档编写能力

零:项目结果展示

项目目前已经上线,小伙伴们可以进行使用!!!

Java 文档搜索

简述:在我的搜索引擎网站,用户进行关键字搜索,就可以查询到与这个关键字相关的java在线文档,(包含标题,关键字附近的简述,url),用户点击标题,即可跳转到相关在线文档,适用于JDK17版本。

一:后端web模块

1:思路

提供一个web接口,最终以网页的形式,把我们的程序呈现给用户~~

前端(HTML+CSS+JS)+ 后端(Java,Script、Spring)

约定前后端通信接口,

需要明确的描述出,服务器能够接收什么样的请求,返回什么样的响应~~

2:设计

这里我们只需要实现一个搜索接口即可~~!!

3:注意点

(1)设置响应头格式

这里我们还是使用Jackson库(Jackson我滴神)中ObjectMapper类来实现json和Java对象之间的转换~~,在返回的ContentType中我们需要设置一下 produces= “application/json;charset=utf-8”

(2)方法返回类型

这里我们把多个Result封装为集合的形式进行返回

(3)实例化DocSearch

我们用到DocSearch类中的search方法所以需要对类进行实例化

@RestController
@RequestMapping("/docSearch")
@Slf4j
public class DocSearcherController{
    private static DocSearcher docSearcher = new DocSearcher();//这里实例化对象后,直接就把构造好的索引加载到内存当中了。(DocSearcher中的构造方法)
    private ObjectMapper objectMapper = new ObjectMapper();
    @RequestMapping(value = "/searcher" , produces = "application/json;charset=utf-8")
    @ResponseBody
    public String search(@RequestParam("query") String query) throws JsonProcessingException {
        log.info("后端接收到参数query:{}",query);
        List<Result> results = docSearcher.search(query);
        return objectMapper.writeValueAsString(results);
    }
}

二:前端代码

注:博主是后端选手,前端代码这里学的比较浅,通过多方面的帮助,以及阿华的修改查验,完成了前端页面的个性化简单制作,这里我只对我们js代码中的ajax请求进行讲解,大家可以根据自己的审美进行前端页面的制作!!

js源代码不会整的可以在阿华博文中搜索jquery,手把手教你

 1:head标签

<!doctype html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Java 文档搜索</title>
</head>

 2:body标签

(1)div标签

<!-- 通过 .container 来表示整个页面的元素容器 -->
    <div class="container">
        <!-- 搜索框+搜索按钮 -->
        <div class="header">
            <input type="text">
            <button id="search-btn">搜索</button>
        </div>

        <!-- 显示搜索结果 -->
        <div class="result">
            <!-- 每一条item表示一个结果 -->
            <!-- <div class="item">
                <a href="#">我是标题</a>
                <div class="desc">我是一段描述嘿嘿嘿,落魄谷中寒风吹,春秋蝉鸣少年归,荡魂山处石人泪,定仙游走魔向北</div>
                <div class="url">https://blog.csdn.net/qq_42257666/article/details/105701914</div>
            </div>

            <div class="item">
                <a href="#">我是标题</a>
                <div class="desc">我是一段描述嘿嘿嘿,落魄谷中寒风吹,春秋蝉鸣少年归,荡魂山处石人泪,定仙游走魔向北</div>
                <div class="url">https://blog.csdn.net/qq_42257666/article/details/105701914</div>
            </div> -->

        </div>
    </div>

(2)style标签

<style>
        /*去除浏览器默认样式*/
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        /* 指定页面高度 */
        html,
        body {
            height: 100%;
            background-image: url(image/light.jpg);
            /* 不平铺 */
            background-repeat: no-repeat;
            /* 设置背景图位置 */
            background-position: center center;
            /* 背景图大小 */
            background-size: cover;
        }

        /* 对内容实现版心效果 */
        .container {
            width: 1200px;
            height: 100%;
            /* 水平居中 */
            margin: 0 auto;
            /* 背景色和透明度 */
            background-color: rgba(255, 255, 255, 0.6);
            /* 圆角 */
            border-radius: 10px;
            /* 内边距 */
            padding: 20px;

            /* 页面滚动 */
            overflow: auto;

        }


        /* 对内容样式进行设置 */
        .header{
            width: 100%;
            height: 50px;

            /* 框+按钮弹性设置 */
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .header>input{
            width: 1050px;
            height:50px;

            /* 输入框中字体大小,高度,左边距 */
            font-size: 22px;
            line-height: 50px;
            padding-left: 10px;

            border-radius: 10px;
        }

        .header>button{
            width: 100px;
            height: 50px;

            /* 按钮颜色、字体大小、高度 */
            background-color:rgb(42, 107, 205) ;
            color: antiquewhite;
            font-size: 22px;
            line-height: 50px;

            /* 圆角 */
            border-radius: 10px;
            border: none;
        }
        
        .header>button:active{
            background-color: gray;
        }

        /* 给搜索结果数字统计css一下 */
        .result .count{
            color: gray;
            margin-top: 10px;
        }


        .item{
            width: 100%;
            /* 元素顶部外边距,把每一条item间隔开来 */
            margin-top: 20px;
        }

        .item a{
            /* 块级元素 */
            display: inline;
            height: 40px;
            /* 字体大小高度粗度 */
            font-size: 20px;
            line-height: 40px;
            font-weight: 700;

            color:rgb(42, 107, 205);
        }

        .item .desc{
            font-size: 18px;
        }

        .item .url{
            font-size: 18px;
            color: rgb(0,128,0);
        }

        /* 把后端设置的i标签中的内容加红 */
        .item .desc i {
            color: red; 
            /* 去斜体 */
            font-style: normal;
        }
    </style>

(3)script标签

<script src="js/jquery.js"></script>

思路:

第一步:前端返回的list集合中有好多个Result对象

第二步:我们遍历,对每一个Result进行处理

这里逻辑比较简单,大家边看代码边看注释会比较好理解一点!

<script>
        // js核心代码
        let button = document.querySelector("#search-btn");
        button.onclick = function(){
            //获取输入框的内容
            let input = document.querySelector(".header input");
            let query = input.value;
            console.log("query:" + query);
            $.ajax({
                type: "GET",
                url: "docSearch/searcher?query=" + query,
                success: function(data , status){
                    buildResult(data);
                }
            });
        }
        
        function buildResult(data){
            // 把data中每一个元素,把每一个元素都构建成一个div.item,再加入到div.result中
            let result = document.querySelector('.result');
            //每次搜索把前一次的结果清空
            result.innerHTML = '';

            //显示搜索的结果个数
            let countDiv = document.createElement('div');
            countDiv.innerHTML = '当前找到' + data.length + '个结果';
            countDiv.classNamee = 'count';
            result.appendChild(countDiv);

            for(var item of data){
                let itemDiv = document.createElement('div');
                itemDiv.className = 'item';

                //构造一个标题
                let title = document.createElement('a');
                title.href = item.url;
                title.innerHTML = item.title;
                title.target = '_blank';
                itemDiv.appendChild(title);

                //构造描述
                let desc = document.createElement('div');
                desc.className = 'desc';
                desc.innerHTML = item.desc;
                itemDiv.appendChild(desc);

                //构造url
                let url = document.createElement('div');
                url.className = 'url';
                url.innerHTML = item.url;
                itemDiv.appendChild(url);

                result.appendChild(itemDiv);
            }
        }
    </script>

三:前端显示优化&后端联动

1:实现前端搜索关键字标红

【从0做项目】Java搜索引擎(5)-CSDN博客

这篇文章介绍了正文的一个处理逻辑

(1)实现逻辑

①我们修改后端代码,生成搜索结果的时候,把其中包含查询词的部分,加上一个标记,例如:给这部分加<i>标签,这样前端就可以进行处理了

②前端针对这个<i>标签设置样式,我是给标红了!!(写的时候华也红温了)


(2)正则表达式

依然是掏出我们的正则表达式

2:后端代码

第一步:对正文进行处理,转小写,把标点和空格全部替换成空格,这样单词与单词之间就以空格分隔开来

第二步:遍历搜索词句的分词,在正文中锁定位置(只要找到一个就break)

第三步:截取一定长度正文,这里不做过多描述,之前有详细介绍

第四步:在正文中把所有term关键字给替换成

举个例子:

单词1 空格 word 空格 单词2 空格 ——》     

"空格"+word+"空格"     ——>     <i>word<i/>

"(?i)"这是一个正则表达式的修饰符,表示忽略大小写,可以理解成,在匹配过程中,不区分字母的大小写。

    private String GenDesc(String content , List<Term> terms){
        //遍历分词结果,看哪个
        int firstPos = -1;
        for(Term term : terms){
            String word = term.getName();
//            firstPos = content.toLowerCase().indexOf(" " + word + " ");//避免包含关系 例:查array  结果查到ArrayList
            //使用正则表达式,indexOf不支持正则,我们曲线救国!!
            content = content.toLowerCase().replaceAll("\\b" + word + "\\b" , " " + word + " ");//匹配标点符号和空格,全部替换成空格
            firstPos = content.indexOf(" " + word + " ");//女少
            if(firstPos >= 0){
                break;//找到了位置,可能这个content中会包含多个term,我们只取第一个
            }
        }
        //用户输入的词,在正文中没有出现,虽然有点扯,但还是处理一下这种情况
        if(firstPos == -1){
            if(content.length() > 160){
                return content.substring(0,160) + "...";
            }
            return content;//我去测试了一下,还真有这种情况离谱!说明查的词在标题中出现了,但是正文没出现666,这里也要对正文的长度做一下判断
        }
        //截取一部分正文
        String desc = "";
        int descBeg = firstPos < 60 ? 0 : firstPos - 60;
        if(descBeg + 160 > content.length()){
            desc = content.substring(descBeg);
        }else {
            desc = content.substring(descBeg , descBeg + 160) + "...";
        }
        for(Term term : terms){
            String word = term.getName();
            desc = desc.replaceAll("(?i) " + word + " " , "<i> " + word + "</i> ");//正则忽略大小写全字段匹配,那头单词和尾单词呢?
        }
        return desc;
    }

3:呈现效果


http://www.kler.cn/a/553853.html

相关文章:

  • Git入门与进阶:详细使用指南
  • linux环境-nginx通过nginx_upstream_check_module模块,配置服务自动检测-日志自动分割
  • 点击unity资源文件自动展开左侧的文件路径
  • Github 2025-02-16 php开源项目日报 Top10
  • 解析跨域:原理、解决方案与实践指南
  • JDK 8+新特性(Stream API、Optional、模块化等)
  • Nacos学习(一)——基本介绍、安装与负载均衡策略
  • Ubuntu:20.04更新cmake到更高版本
  • Linux 文件与目录命令学习记录
  • 基于Flask的去哪儿网海南旅游攻略数据分析系统的设计与实现
  • vue-awesome-swiper 露出下一张图片部分+自定义按钮滑动到上一个/下一个slide
  • DeepSeek + Mermaid编辑器——常规绘图
  • Flutter开发如何高效布局
  • SpringBoot中自动装配机制的原理
  • ubuntu 多版本python冲突时设置临时环境
  • 重新出发的LLM本地部署——DeepSeek加持下的Ollama+OpenWebUI快速部署
  • 三、数据治理应用开发整体架构
  • 蓝桥杯 Day6 贪心
  • (前端基础)CSS(一)
  • 【练习】【滑动窗口】力扣热题100 3. 无重复字符的最长子串