1、主要使用的技术
- HTML/CSS
- Bootstrap5
- javascript/jQuery/jQuery-UI
- JSP
2、前期调查与设计
搜索引擎主要分为两个界面,主界面和搜索结果界面
主界面

从图看出,主界面的组成有
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
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
| <%
request.setCharacterEncoding("utf-8"); String inputText = request.getParameter("inputText"); String page1 = request.getParameter("page"); String beginDate = request.getParameter("beginDate"); String endDate = request.getParameter("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>"); 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
| $(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"); 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