0、团队课程设计
1、主要使用的技术
- HTML/CSS
- Bootstrap5
- javascript/jQuery/jQuery-UI
- JSP
2、前期调查与设计
搜索引擎主要分为两个界面,主界面和搜索结果界面
主界面
从图看出,主界面的组成有
- logo
- 搜索框
- 搜索按钮
- 搜索提示
logo
采用居中设计,在输入框的正上方
搜索框&搜索按钮
整体是一个表单,搜索框可使用Bootstrap5的form-control类,搜索按钮可采用Bootstrap5的按钮样式
表单以GET请求方式请求到搜索结果界面
搜索提示
内部使用js实现,通过发送AJAX请求给后台获取对应的推荐数据,在进行展示。到时候应用jQuery发送AJAX请求和jQuery-UI中的autocompletion插件即可
搜索结果界面
顶部
底部
分析图中的元素构成
- 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表单部分
<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的获取搜索结果部分
<%
/**
* 接受表单请求, 分页请求,日期选择请求,
* 未来将封装至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的搜索结果输出部分
<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获取搜索建议
@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插件的使用
//参考实例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的数据
分页跳转功能
$("#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的样式,才可以达到自己的预期效果,还要注意回调函数的两个参数