【从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;
}