0%

实现搜索词补全功能

百度搜索栏下方的提示效果如下:
在这里插入图片描述
实现路线:

  • ajax异步请求
  • trie树数据结构

trie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package songsong.host.food.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

class Node {
public Map<String, Node> nexts; // 子节点
public int end;

public Node() {
this.nexts = new HashMap<String, Node>();
this.end = 0;
}
}

public class Trie {
private Node root;
private List<String> list;

public Trie(){
root = new Node();
list = new ArrayList<String>();
}

public void insert(String word) {
if (word == null)
return;
Node node = root;
for (int i = 0; i < word.length(); i++) {
String str = "" + word.charAt(i);
if (node.nexts.get(str) == null)
node.nexts.put(str, new Node());
node = node.nexts.get(str);
}
node.end = 1;
}

public boolean startWith(String preWord) {
Node node = root;
for (int i = 0; i < preWord.length(); i++) {
String str = "" + preWord.charAt(i);
if (node.nexts.get(str) == null)
return false;
node = node.nexts.get(str);
}
return true;
}

public List<String> getData(String preword) {
list.clear();
if (!startWith(preword))
return null;
else {
StringBuilder str = new StringBuilder("");
str.append(preword);
Node node = root;
for (int i = 0; i < preword.length(); i++)
node = node.nexts.get("" + preword.charAt(i));
dfs(node, str);
}
return list;
}

private void dfs(Node root, StringBuilder str) {
if (root.end == 1) {
list.add(str.toString());
if (root.nexts.size() == 0)
return;
}
Node node = root;
for (String s : node.nexts.keySet()) {
str.append(s);
dfs(node.nexts.get(s), str);
str.delete(str.length() - 1, str.length());
}
}


// public static void main(String[] args) {
// System.out.println("ok");
// Trie test = new Trie();
// test.insert("what");
// test.insert("what do you do");
// test.insert("what is your name");
// test.insert("宫保鸡丁");
// test.insert("烧烤");
// test.insert("鱼香肉丝");
// test.insert("红烧鸡");
// test.insert("红焖鸡");
// System.out.println("输入a");
// System.out.println(test.getData("a"));
// System.out.println(test.startWith("a"));
//
// }
}

有了这就好说了,启动浏览器的时候,直接从数据库的search表里把关键字拿出来构建trie树,当然可以将关键字进行排序等处理,拿热搜等等。ajax异步请求,搜索栏发生变化,补全提示词实时变化。

请求数据

1
2
3
4
5
6
7
8
9
10
//实现打开浏览器就加载热搜,并构建trie树
@RequestMapping("/search")
public void search(HttpServletResponse response){
//查询前X的热搜:
List<Search> searcheList=commonService.selectAllSearch(100);
//构建trie树
for (int i = 0;i<searcheList.size();i++) {
test.insert(searcheList.get(i).getWords());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
//给前端写回json数据
private void writeBack(HttpServletResponse response,Object o){
//解决:拒绝引用
String json = JSON.toJSONString(o, SerializerFeature.DisableCircularReferenceDetect);
response.setCharacterEncoding("utf-8");
response.setContentType("application/json; charset=utf-8");
try {
response.getWriter().print(json);
} catch (IOException e) {
e.printStackTrace();
}
}
1
2
3
4
5
6
7
/补全提示
@RequestMapping("/search/{word}")
public void search(HttpServletResponse response,@PathVariable("word") String word){
//查询联想词
List<String> words = test.getData(word);
writeBack(response,words);
}

search.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
$(function(){
$.ajax({
url : "/common/search/",
type : 'get',
dataType : 'json',
success : function(data) {
alert("构建trie成功!")
}
})
});

$(function(){
$('#keyword').blur(function() {
setTimeout(function() { //进行延时处理,时间单位为千分之一秒
clearContent();
}, 500)
}).focus(function(){
if($(this).val() != ''){
getMoreContents();
}
});
//激活新加进来的元素点击事件
$('body').on("click", "#content_table_body tr", function () {
var td = $(this).find("td");
var data = td.eq(0).text();
$("#keyword").val(data.toString());
})
})

function getMoreContents() {
setLocation();
var content = $("#keyword").val();
if (content == "") {
return;
}
submit(content);
}

//清空数据
function clearContent() {
$("#popdiv").attr("style","display: none");
}


function setLocation() {
//关联信息的显示位置
var content = document.getElementById("keyword");
var width = content.offsetWidth;//输入框的宽度
$("#popdiv").attr("style","position:absolute;z-index: 9999");

document.getElementById("content_table").style.width = width + "px";
}

function submit(word) {
$.ajax({
url : "/common/search/"+word,
type : 'get',
dataType : 'json',
success : function(data) {
$("#content_table_body").html("");
$.each(data, function (i, item) {
$("#content_table_body").append(searchTable(item));
});
}
})
}

function searchTable(item){
var tr = '<tr><td>'
+ item
+'</td></tr>';
return tr;
}

部分html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
<script type="text/javascript" th:src="@{/js/jquery-3.2.1.min.js}"></script>
<script type="text/javascript" th:src="@{/js/bootstrap.min.js}"></script>
<script type="text/javascript" th:src="@{/js/search.js}"></script>
<div class="col-lg-5 col-md-8 col-sm-5 m-auto" id="search">
<form action="/common/search/s" method="post" class="input-group input-group-lg mt-3">
<!--onblur="keywordBlur()" onfocus="getMoreContents()"-->
<input type="text" autocomplete='off' class="form-control input-lg" id="keyword" name="keyword" onkeyup="getMoreContents()" placeholder="请输入..." />
<button type="submit" class="btn btn-primary">搜 索</button>
</form>
<div id="popdiv" class="bg-light text-dark">
<table id="content_table" class="table table-hover bg-secondary text-white">
<tbody id="content_table_body">

</tbody>
</table>
</div>
</div>

效果

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

------------- Thank you for reading -------------

Title - Artist
0:00