基于Spring Boot+Vue的博客系统 15——实现文章搜索功能(分词搜索)
需求在输入框输入一串带有关键词的字符串,后台可以将字符串分成若干个关键词,然后从数据库中查询出带有关键词的文章,在页面上显示,并且显示的时候关键词为红色后端实现一开始分词搜素功能使用的是ElasticSearch来实现的,最后发现只用使用一款分词工具就可以实现相同的功能,使用ElasticSearch简直是是大材小用,这里分词工具选用的是HanLP。使用HanLPHanLP是一系列模型...
废弃说明:
这个专栏的文章本意是记录笔者第一次搭建博客的过程,文章里里有很多地方的写法都不太恰当,现在已经废弃,关于SpringBoot + Vue 博客系列,笔者重新写了这个系列的文章,不敢说写的好,但是至少思路更加清晰,还在看SpringBoot + Vue 博客系列文章的朋友可以移步:https://blog.csdn.net/li3455277925/category_10341110.html,文章中有错误的地方或者大家有什么意见或建议都可以评论或者私信交流。
需求
在输入框输入一串带有关键词的字符串,后台可以将字符串分成若干个关键词,然后从数据库中查询出带有关键词的文章,在页面上显示,并且显示的时候关键词为红色
后端实现
一开始分词搜素功能使用的是ElasticSearch
来实现的,最后发现只用使用一款分词工具就可以实现相同的功能,使用ElasticSearch
简直是是大材小用,这里分词工具选用的是HanLP
。
使用HanLP
HanLP是一系列模型与算法组成的NLP工具包,由大快搜索主导并完全开源,目标是普及自然语言处理在生产环境中的应用。HanLP具备功能完善、性能高效、架构清晰、语料时新、可自定义的特点。
HanLP官网:http://hanlp.com/
- 引入依赖
<dependency>
<groupId>com.hankcs</groupId>
<artifactId>hanlp</artifactId>
<version>portable-1.7.4</version>
</dependency>
- 在
ArticleRepository
里面添加按照正则表达式查询的方法
注意这里如果使用SQL语句的话,就要将
nativeQuery
属性设为true
,第二个参数Pageable
为分页信息
package com.qianyucc.blog.repository;
import com.qianyucc.blog.model.entity.*;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.repository.*;
import org.springframework.data.repository.query.*;
import java.util.*;
/**
* @author lijing
* @date 2019-10-11 10:39
* @description 访问数据库中文章
*/
public interface ArticleRepository extends JpaRepository<ArticleDO, Long>, JpaSpecificationExecutor<ArticleDO> {
// 正则匹配
@Query(value = "select * from article where title regexp :regex",nativeQuery = true)
Page<ArticleDO> findByTitleWithRegex(@Param("regex") String regex, Pageable pageable);
}
- 在
ArticleService
中添加按照查询字符串查询的方法
/**
* 根据关键词查询文章
*
* @param queryString
* @return
*/
public PageInfoVO<SimpleArticleVO> findArticlesByQueryString(String queryString, Integer pageNumber) {
// 容错
pageNumber = pageNumber < 1 ? 0 : pageNumber - 1;
// 使用HanLP分词
List<Term> termList = StandardTokenizer.segment(queryString);
// 拼接正则字符串
StringBuffer sb = new StringBuffer();
for (int i = 0; i < termList.size(); i++) {
String word = termList.get(i).word;
if (i != termList.size() - 1) {
sb.append(word + "|");
} else {
sb.append(word);
}
}
String regex = sb.toString();
sb.insert(0, ".*(");
sb.append(").*");
// 利用正则查找,这里的函数实现是使用SQL语句查询的所以在Sort里面要使用gmt_update而不能使用gmtUpdate
Pageable pageable = new PageRequest(pageNumber, PAGE_SIZE, new Sort(Sort.Direction.DESC, "gmt_update"));
Page<ArticleDO> page = articleRepository.findByTitleWithRegex(sb.toString(), pageable);
List<ArticleDO> articleDOS = page.getContent();
// 将标题中关键字替换为红色
articleDOS.forEach(article -> {
String title = article.getTitle();
// 利用正则替换
String newTitle = title.replaceAll(regex, "<font style='color:red;'>$0</font>");
article.setTitle(newTitle);
});
PageInfoVO<SimpleArticleVO> pageInfoVO = new PageInfoVO<>();
pageInfoVO.setTotalCount(page.getTotalElements());
pageInfoVO.setCurrentPage(pageNumber + 1);
pageInfoVO.setTotalPages(page.getTotalPages());
pageInfoVO.setData(ArticleUtil.jpaDosToSimpleArticleVOs(articleDOS));
return pageInfoVO;
}
注意这里的
Sort
对象的第二个参数不能为gmtUpdate
,因为这里我们使用的是SQL语句查询,数据库中并没有gmtUpdate
字段,而是gmt_update
字段,所以这里应该改为gmt_update
,下图为使用gmtUpdate
时出现的错误。
- 编写Controller
@GetMapping("/getArticlesByQueryString")
public PageInfoVO<SimpleArticleVO> getArticlesByQueryString(
@RequestParam(name = "queryString") String queryString,
@RequestParam(name = "pageNumber", required = false, defaultValue = "1") Integer pageNumber) {
PageInfoVO<SimpleArticleVO> pageInfoVO = articleService.findArticlesByQueryString(queryString, pageNumber);
return pageInfoVO;
}
正则替换
在上面的ArticleService
类中使用了正则替换对文章标题进行操作,代码如下:
String newTitle = title.replaceAll(regex, "<font style='color:red;'>$0</font>");
这句代码实现的功能是将标题中的所有关键词替换为带有红色样式的关键词,下面主要解释一下java
中的replaceAll()
函数的具体使用方法
- 首先说一下普通的正则替换,比如将下面字符串中的
我们
替换为**
,我们可以这样写:
public class TestString {
public static void main(String[] args) {
String s1 = "我们都是好孩子,他们绝不会在代码里下毒";
String s2 = s1.replaceAll("我们", "**");
System.out.println(s2);
}
}
运行结果如下:
- 如果我们想要替换
我们
或者他们
为**
,可以这样实现:
public class TestString {
public static void main(String[] args) {
String s1 = "我们都是好孩子,他们绝不会在代码里下毒";
String s2 = s1.replaceAll("我们|他们", "**");
System.out.println(s2);
}
}
运行结果如下:
- 假如我们替换的的时候需要用到匹配到的字符串,例如我们想把
我们
或者他们
作为关键词加粗,在关键词两边分别加上**
,就可以用如下代码实现:
public class TestString {
public static void main(String[] args) {
String s1 = "我们都是好孩子,他们绝不会在代码里下毒";
String s2 = s1.replaceAll("(我|他)(们)", "**$0**");
System.out.println(s2);
}
}
运行结果:
这里的$0
含义如下图所示,$1
为第一个括号里匹配到的内容,$2
为第二个括号里匹配到的内容,$0
为整体匹配到的内容
前端实现
- 在
/src/request/api/url.js
中添加根据含有关键字的字符串查询的URL
const getArticlesByQueryStringUrl = baseUrl + 'api/comm/article/getArticlesByQueryString';
- 在
/src/request/api/article.js
里面封装根据含有关键字字符串查询的方法
getArticlesByQueryString(queryString, pageNumber, callback) {
axios
.get(url.getArticlesByQueryStringUrl, {
params: {
queryString: queryString,
pageNumber: pageNumber
}
})
.then(callback)
.catch(err => {
console.log("getArticlesByQueryString Error");
});
},
getArticles(callback) {
let pageInfo = store.state.articles;
if (pageInfo.condition) {
switch (pageInfo.condition) {
case 'all':
this.getPageArticles(pageInfo.currentPage, callback);
break;
case 'tag':
// 根据tag查询
break;
case 'category':
// 根据分类查询
break;
case 'queryString':
this.getArticlesByQueryString(pageInfo.queryString, pageInfo.currentPage, callback);
break;
}
}
}
- 在
navBar.vue
中定义点击搜索键之后的回调函数search()
和点击博客名时的回调函数toIndex()
methods: {
...mapMutations([
"setIsLogin",
"setPageInfo",
"setQueryString",
"setCurrentPage",
"setCondition"
]),
// 退出登录
exit() {
window.localStorage.removeItem("token");
this.setIsLogin(false);
},
search() {
if (this.queryString != null && this.queryString != "") {
this.setCondition({
condition: "queryString",
info: this.queryString
});
this.setCurrentPage(1);
this.$api.article.getArticles(resp => {
this.setPageInfo(resp.data);
});
}
},
toIndex() {
this.queryString = "";
this.setCondition({
condition: "all"
});
this.setCurrentPage(1);
this.$api.article.getArticles(resp => {
this.setPageInfo(resp.data);
});
router.push("/");
}
}
- 在指定元素上绑定回调函数,这里注意不要将
b-button
的属性设置为submit
,否则会提交请求并刷新页面
需要注意的是:在
articles.vue
中,渲染标题时应该用v-html
才能显示关键字为红色的效果
运行项目效果如下
更多推荐
所有评论(0)