filter应用案例四:页面静态化
1 说明
你到“当当”搜索Java分类图书时,“当当”会去查询数据库!每天都有很多人去搜索“Java分类”的图书,每次都去访问数据库,这会有性能上的缺失!如果是在访问静态页面(html)那么就会快的多了!静态页面本身就比动态页面快很多倍,而且动态页面总是要去数据库查询,这会更加降低速度!
页面静态化是把动态页面生成的html保存到服务器的文件上,然后再有相同请求时,不再去执行动态页面,而是直接给用户响应上次已经生成的静态页面。而且静态页面还有助与搜索引擎找到你!
2 查看图书分类
我们先来写一个小例子,用来查看不同分类的图书。然后我们再去思考如何让动态页面静态化的问题。
1 <body> 2 <a href="<c:url value='/BookServlet'/>">全部图书</a><br/> 3 <a href="<c:url value='/BookServlet?category=1'/>">JavaSE分类</a><br/> 4 <a href="<c:url value='/BookServlet?category=2'/>">JavaEE分类</a><br/> 5 <a href="<c:url value='/BookServlet?category=3'/>">Java框架分类</a><br/> 6 </body>
1 public class BookServlet extends BaseServlet { 2 private BookDao bookDao = new BookDao(); 3 4 public String findAll(HttpServletRequest request, HttpServletResponse response) 5 throws ServletException, IOException { 6 request.setAttribute("bookList", bookDao.findAll()); 7 return "/show.jsp"; 8 } 9 10 public String findByCategory(HttpServletRequest request, HttpServletResponse response) 11 throws ServletException, IOException { 12 String value = request.getParameter("category"); 13 int category = Integer.parseInt(value); 14 request.setAttribute("bookList", bookDao.findByCategory(category)); 15 return "/show.jsp"; 16 } 17 }
1 <table border="1" align="center" width="50%"> 2 <tr> 3 <th>图书名称</th> 4 <th>图书单价</th> 5 <th>图书分类</th> 6 </tr> 7 8 <c:forEach items="${bookList }" var="book"> 9 <tr> 10 <td>${book.bname }</td> 11 <td>${book.price }</td> 12 <td> 13 <c:choose> 14 <c:when test="${book.category eq 1}"><p style="color:red;">JavaSE分类</p></c:when> 15 <c:when test="${book.category eq 2}"><p style="color:blue;">JavaEE分类</p></c:when> 16 <c:when test="${book.category eq 3}"><p style="color:green;">Java框架分类</p></c:when> 17 </c:choose> 18 </td> 19 </tr> 20 </c:forEach> 21 </table>
3 分析
我们的目标是在用户第一次访问页面时生成静态页面,然后让请求重定向到静态页面上去。当用户再次访问时,直接重定向到静态页面上去。
我们需要为不同的请求生成静态页面,例如用户访问BookServlet?category=1时,我们要生成静态页面,当用户访问BookServlet?category=2时,也要生成静态页面。即不同的参数生成不同的静态页面!
1 public class StaticResponse extends HttpServletResponseWrapper { 2 private PrintWriter pw; 3 4 /** 5 * String path:html文件路径! 6 */ 7 public StaticResponse(HttpServletResponse response, String path) 8 throws FileNotFoundException, UnsupportedEncodingException { 9 super(response); 10 11 // 创建一个与html文件路径在一起的流对象 12 pw = new PrintWriter(path, "utf-8"); 13 } 14 15 public PrintWriter getWriter() { 16 // 返回一个与html绑定在一起的printWriter对象 17 // jsp会使用它进行输出,这样数据都输出到html文件了。 18 return pw; 19 } 20 }
1 public class StaticFilter implements Filter { 2 private FilterConfig config; 3 public void destroy() {} 4 public void init(FilterConfig fConfig) throws ServletException { 5 this.config = fConfig; 6 } 7 8 public void doFilter(ServletRequest request, 9 ServletResponse response, FilterChain chain) 10 throws IOException, ServletException { 11 HttpServletRequest req = (HttpServletRequest) request; 12 HttpServletResponse res = (HttpServletResponse) response; 13 /* 14 * 1. 第一次访问时,查找请求对应的html页面是否存在,如果存在重定向到html 15 * 2. 如果不存在,放行!把servlet访问数据库后,输出给客户端的数据保存到一个html文件中 16 * 再重定向到html 17 */ 18 /* 19 * 一、获取category参数! 20 * category有四种可能: 21 * * null --> null.html 22 * * 1 --> 1.html 23 * * 2 --> 2.html 24 * * 3 --> 3.html 25 * 26 * html页面的保存路径, htmls目录下 27 * 28 * 判断对应的html文件是否存在,如果存在,直接重定向! 29 */ 30 String category = request.getParameter("category"); 31 String htmlPage = category + ".html";//得到对应的文件名称 32 String htmlPath = config.getServletContext().getRealPath("/htmls");//得到文件的存放目录 33 File destFile = new File(htmlPath, htmlPage); 34 35 if(destFile.exists()) {//如果文件存在 36 // 重定向到这个文件 37 res.sendRedirect(req.getContextPath() + "/htmls/" + htmlPage); 38 return; 39 } 40 41 /* 42 * 二、如果html文件不存在,我们要生成html 43 * 1. 放行,show.jsp会做出很多的输出,我们要让它别再输出给客户端,而是输出到我们指定的一个html文件中 44 * 完成: 45 * * 调包response,让它的getWriter()与一个html文件绑定,那么show.jsp的输出就到了html文件中 46 */ 47 StaticResponse sr = new StaticResponse(res, destFile.getAbsolutePath()); 48 chain.doFilter(request, sr);//放行,即生成了html文件 49 50 // 这时页面已经存在,重定向到html文件 51 res.sendRedirect(req.getContextPath() + "/htmls/" + htmlPage); 52 } 53 }