0、团队项目博客

1、主要使用的技术

  • HTML/CSS
  • Bootstrap5
  • javascript/jQuery/jQuery-UI
  • JSP

2、前期调查与设计

搜索引擎主要分为两个界面,主界面和搜索结果界面

主界面

搜索主界面

从图看出,主界面的组成有

  • logo
  • 搜索框
  • 搜索按钮
  • 搜索提示

采用居中设计,在输入框的正上方

搜索框&搜索按钮

整体是一个表单,搜索框可使用Bootstrap5的form-control类,搜索按钮可采用Bootstrap5的按钮样式

表单以GET请求方式请求到搜索结果界面

搜索提示

内部使用js实现,通过发送AJAX请求给后台获取对应的推荐数据,在进行展示。到时候应用jQuery发送AJAX请求和jQuery-UI中的autocompletion插件即可

搜索结果界面

顶部

搜索结果界面

底部

image-20230110230825633

分析图中的元素构成

  • logo
  • 搜索框&搜索按钮
  • 搜索结果数量
  • 选择时间的工具
  • 一块搜索结果,包含
    • 标题
    • 文章内容
    • 结果链接
  • 分页导航栏

排版分析

logo&搜索框&搜索按钮

在Bootstrap5中,可以将他们放在一个container-fluid的容器中,通过Bootstrap5的网格系统,row&col来实现响应式网页

其中表单的组成为搜索框&搜索按钮,提交GET请求给自己让自己处理

搜素结果&选择时间的工具

他们也可以放在一个container中,通过Bootstrap5的网格系统来实现响应式网页。

在该项目的设计中,我将选择时间的工具简化成一个下拉菜单,通过选择相应的选项来实现按时间范围查找功能

如图所示:

时间选择

搜索结果

首先他们也在一个container中,然后将他们放进一个div,这个div中有a、div.content、a。将对应的样式设计好后,通过jsp循环输出即可

分页导航栏

分页导航栏是动态的,而且这种东西网上肯定有人写过了,果不其然,jqPaginator就能满足我们的需求,只需要简单的创建一个无序列表就能实现,样式的话我们可以采用Bootstrap5的样式,也算可以了

3、设计思路

项目目前采用的是Bootstrap5的框架,由于此次时间有限就采取默认风格,通过学习一些简单的Bootstrap5可以稍微跳过一些CSS的学习,而且更容易创建响应式界面。

基本思路:将元素的组合划分为一个个独立的container或container-fluid,在使用Bootstrap5的样式进行调整即可

4、代码实现

经过3的分析,可以知道大致需要index.html、search.jsp这两个主要文件,和一些处理前端数据的Servlet

index.html的form表单部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="container mb-5 mt-5">
<form action="search.jsp" method="get">
<div class="row">
<div class="col-lg-3"></div>
<div class="input-group mx-auto col">
<label for="searchInput"></label>
<input type="search"
id="searchInput"
class="form-control search-input"
placeholder="Enter content"
name="inputText">
<button type="submit" class="btn btn-primary">搜索一下</button>
</div>
<div class="col-lg-3"></div>
</div>
</form>
</div>

form标签中,action为请求资源路径,method为请求方式;搜索按钮的类型一定要是submit才能提交表单

search.jsp的获取搜索结果部分

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
<%
/**
* 接受表单请求, 分页请求,日期选择请求,
* 未来将封装至servlet 返回json,通过setAttribute
*/
request.setCharacterEncoding("utf-8");
String inputText = request.getParameter("inputText");
String page1 = request.getParameter("page");
String beginDate = request.getParameter("beginDate");
String endDate = request.getParameter("endDate");

// 给currentPage, beginDate, endDate初始值
if(page1 == null) {
page1 = "1";
}
int currentPage = Integer.parseInt(page1);

// 去后台搜索结果
Search search = new EsSearch();
List<ResultEntry> searchResult = new ArrayList<>();
if(inputText != null) {
if(beginDate == null && endDate == null) {
searchResult = search.search(inputText, currentPage);
} else if (endDate == null) {
searchResult = search.search(inputText, currentPage, beginDate);
}
}
long searchCount = search.getSearchCount();

%>

这个没啥好说的,向后台的ES请求资源

search.jsp的搜索结果输出部分

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
<div class="container">
<div class="result">
<%
for(ResultEntry resultEntry : searchResult) {
out.println("<div class=\"col col-lg-7 mt-3\">");
out.println("<a class=\"address\" href="+resultEntry.getUrl()+" target=\"_blank\">"+resultEntry.getTitle()+"</a>");
// 获取content需要输出的区间
int front = resultEntry.getText().indexOf("<span");
int tail = resultEntry.getText().lastIndexOf("span>");
front -= 10; tail += 25;
if(front < 0) {
front = 0;
}
if(tail > resultEntry.getText().length() - 1) {
tail = resultEntry.getText().length() - 1;
do {
if(!"\"".equals(resultEntry.getText().charAt(tail))) {
tail++;
break;
}
tail--;
}while (tail > 0);
}
String content = resultEntry.getText().substring(front, tail);
out.println("<div class=\"content\">"+content+"</div>");
out.println("<a href="+resultEntry.getUrl()+" style=\"font-size: small; color: gray\">"+resultEntry.getUrl()+"</a>");
out.println("</div>");
}
%>
</div>
</div>

将搜索结果放进一个循环,输出对应的样式即可

其中对content的摘要后面可优化到Servlet里,前端就不会有这么复杂的逻辑处理

SearchSuggest.java获取搜索建议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@WebServlet("/SearchSuggest")
public class SearchSuggest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
request.setCharacterEncoding("utf-8");
String input = request.getParameter("input");
if(input != null) {
Search search = new EsSearch();
List<String> searchSuggest = search.getSearchSuggest(input);
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println(JSON.toJSONString(searchSuggest));
out.close();
search.close();
}
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
this.doGet(request, response);
}
}

这个就是获取请求返回对应的JSON字符串,采用了alibaba的fastjson

my-js.js中的jQuery-UI的autocompletion插件的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//参考实例2——https://www.runoob.com/jqueryui/api-autocomplete.html#option-source
$(function () {
$(".search-input").autocomplete({
source: function( request, response ) {
var input = $(".search-input").val();
var source = "";
$.ajax({
type : "get",
url : "SearchSuggest",
datatype : "json",
data: {"input": input},
async : false,
error : function() {
console.error("Load recommand data failed!");
},
success : function(data) {
source = data;
}
});
response(JSON.parse(decodeURI(source)));
}
})
})

autocompletion的回调函数中,response就是响应autocompletion的source的数据

分页跳转功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$("#my-pagination").jqPaginator({
totalPages: <%=searchCount/10+1%>,
visiblePages: 10,
currentPage: <%=currentPage%>,
first: '<li class="first page-item"><a class="page-link" href="javascript:;">首页</a></li>',
prev: '<li class="prev page-item"><a class="page-link" href="javascript:;">上一页</a></li>',
next: '<li class="next page-item"><a class="page-link" href="javascript:;">下一页</a></li>',
last: '<li class="last page-item"><a class="page-link" href="javascript:;">末页</a></li>',
page: '<li class="page page-item"><a class="page-link" href="javascript:;">{{page}}</a></li>',
onPageChange: function (num, type) {
$('#my-pagination-text').html('当前第' + num + '页');
if("change" == type) { // 换页触发的
let inputText = getQueryVariable("inputText");
let beginDate = getQueryVariable("beginDate");
// console.log("search.jsp?inputText="+inputText+"&page="+num);
if(beginDate != "") {
window.location.href = "search.jsp?inputText="+inputText+"&page="+num+"&beginDate="+beginDate;
} else {
window.location.href = "search.jsp?inputText="+inputText+"&page="+num;
}
}
}
});

使用插件时注意引用Bootstrap5的样式,才可以达到自己的预期效果,还要注意回调函数的两个参数

5、参考链接

w3c-从无到有

菜鸟教程你值得拥有

jQuery