• 通过动态包含和Ajax机制抽取Web应用的公共页面


    在Java Web应用开发中,经常遇到的一种情况是,许多的页面中都包含着“公共页面”,这部分动态页面的特征是:访问量大,会带来较大的性能压力。功能设计上会动态地改变自身的元素。比如在登录前和登录后所展示的页面有所不同,比如以下代码:

     1 <div class="col-md-3" style="padding-top:20px">
     2                     <ol class="list-inline">
     3                     <%-- 根据Session中的loginUser是否为空, 来判断展示的内容 --%>
     4                       <c:if test="${empty loginUser}">                    
     5                         <li><a href="${pageContext.request.contextPath}/UserServlet?method=loginUI">登录</a></li>
     6                         <li><a href="${pageContext.request.contextPath}/UserServlet?method=registUI">注册</a></li>
     7                       </c:if>
     8                         
     9                       <c:if test="${not empty loginUser}">
    10                         <li>欢迎${loginUser.username}</li>
    11                         <li><a href="${pageContext.request.contextPath}/UserServlet?method=logOut">退出</a></li>
    12                         <li><a href="${pageContext.request.contextPath}/jsp/cart.jsp">购物车</a></li>
    13                         <li><a href="${pageContext.request.contextPath}/jsp/order_list.jsp">我的订单</a></li>
    14                       </c:if>    
    15                         
    16                     </ol>
    17                 </div>

    这是一段前端JSP代码,实现的是根据服务器处理登录功能后,session对象中的loginUser值是否为空,来判断是否登录完成,从而决定显示哪一段的标签内容。

    事实上,因为这是一段顶层页面的公共菜单栏,从而在成百上千的网页中都包括这段代码。如果每个页面都要更改这是不可想象的。

    解决的方法是通过动态包含机制来解决。

    相关的Java开发技巧可见:

    Java Servlet开发的轻量级MVC框架最佳实践

    以用户注册功能模块为例浅谈MVC架构下的JavaWeb开发流程

    静态包含和动态包含

    以JSP为例说明页面的静态包含和动态包含

    JSP中有两种包含:

    静态包含:<%@include file="被包含页面"%>

    动态包含:<jsp:include page="被包含页面"flush="true">。下面以一个例子来说明如何使用包含。

    实例
    项目文件树:

    header.jsp文件中内容:

    1 <html>
    2 <head>
    3 <meta http-equiv="Content-Type" content="text/html; charset=GB18030">
    4 <title>Insert title here</title>
    5 </head>
    6 <body>
    7 <h1>This is header</</h1>

    content.jsp文件中内容

     1 <table border="1">
     2 <tr>
     3 <td>col1</td>
     4 <td>col2</td>
     5 </tr>
     6 <tr>
     7 <td>col1</td>
     8 <td>col2</td>
     9 </tr>
    10 </table>

    footer.jsp文件中内容:

    1 <hr>
    2 copyright: 1999-2010
    3 </body>
    4 </html>

    静态包含:
    index.jsp文件中内容:

    1 <%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
    2 <%@ include file="/header.jsp" %>
    3 <%@ include file="/content.jsp" %>
    4 <%@ include file="/footer.jsp" %>

    页面显示结果:

    被编译成的java文件:

    动态包含

    index.jsp文件中内容:

    1 <%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
    2 <jsp:include page="/header.jsp"></jsp:include>
    3 <jsp:include page="/content.jsp"></jsp:include>
    4 <jsp:include page="/footer.jsp"></jsp:include>

    页面显示结果:

    被编译成的java文件:

    这个例子说明,使用静态包含和动态包含最终的执行结果相同,但是实现过程不同,很明显编译成的java文件数目不同。

    静态和动态包含的区别与联系

    注:下文将包含有其它文件的jsp文件称为主体文件,比如上文中的index.jsp文件.将被包含的文件称为包含文件,比如上文中的header.jsp文件.

    1. <%@ include file="" %>是指令元素。<jsp:include page=""/>是行为元素
    2. 最终编译成java文件的数目不同。(从上面的例子可以看出)
      • 静态包含在转换成为java文件的时候将包含文件的内容“复制”到主体文件,然后作为一个整体编译。最终编译为一个java文件。
      • 动态包含是各个jsp文件分别转换,分别编译。最终编程成多个java文件。
    3. 执行时间不同
      • 静态包含发生在:JSP编译为java文件阶段。
      • 动态包含发生在:执行class文件阶段。动态加入。
    4. 静态包含在两个文件中不能有相同的变量,动态包含允许。
      • 由于静态包含相当于将包含文件内容直接复制到主体文件中,如果出现相同的变量,就会出现覆盖等问题,导致文件出错。而动态包含相当于调用不同的jsp,变量所在的空间不同,自然不会出现覆盖等现象。
    5. 无论是动态包含还是静态包含,其request对象都是相同的。也就是同一个request对象。
      • 静态包含最终编译成一个java文件,有一个request对象很好理解。而动态包含最终编译成多个jsp文件,为何会使用一个request对象呢?其实这些jsp组合的过程是一个请求转发的过程,自然也使用同一个request对象了。

    静态包含和动态包含的使用
    简单总结一下,就一句话:被包含的页面是静态页面就用静态包含,是动态页面就用动态包含。(当然不是很绝对,但是这样用没有错)

    Ajax动态获取公共页面元素的JSON格式数据

    公共页面,除了经常作为Header或Footer被多个页面引入外,更主要的是动态获取后台数据库Category数据作为菜单选项元素。在经典MVC架构中,这对应着一个Service和Dao服务如下:

    Servlet层

    1             CategoryService CategoryService=new CategoryServiceImp();
    2             List<Category> list = CategoryService.getAllCats();
    3             req.setAttribute("CatList", list);
    4             return "/jsp/info.jsp";

    Service层

    1     CategoryDao CategoryDao=new CategoryDaoImp();
    2     return CategoryDao.getAllCats();        

    Dao层

    1      String sql="select * from category";
    2         QueryRunner qr=new QueryRunner(JDBCUtils.getDataSource());
    3         return qr.query(sql, new BeanListHandler<Category>(Category.class));

    但如果有成百上千的页面都需要用到这个公共页面,那就要在成百上千的交互中添加这段Servlet代码,这样的话代价很高。

    实践中主要是利用Ajax和Json格式来实现这样的菜单功能。

    基于JQuery的Ajax功能代码实现如下:

     1 $(function(){
     2     //向服务端CategoryServlet__>gteAllCats发起ajax请求,服务端经过处理,
     3     //将所有分类信息以JSON格式的数据返回,获取到返回的所有分类绑定在页面的显示分类区域
     4     var url="/ServletStoreDemo/CategoryServlet";
     5     var obj={"method":"findAllCats"};
     6     $.post(url,obj,function(data){
     7         //alert(data);
     8     
     9         //获取到服务端响应会的数据,经过观察data中存放的是一个JSON格式数组,遍历数组,动态的显示分类区域代码    
    10         $.each(data,function(i,obj){
    11             var li="<li><a href='#'>"+obj.cname+"</a></li>";
    12             $("#myUL").append(li);
    13         });
    14         
    15     },"json");
    16     
    17 });

    同时在CategoryServlet中,将数据库返回的数据,包装成JSON格式返回到客户端浏览器

    1 jsonStr=JSONArray.fromObject(list).toString();
    2 //将全部分类信息响应到客户端
    3 //告诉浏览器本次响应的数据是JSON格式的字符串
    4 resp.setContentType("application/json;charset=utf-8");
    5 resp.getWriter().print(jsonStr);

    原理解析

    1. 页面加载后,Ajax会向服务端CategoryServlet发起请求,触发getAllCats方法,服务端会处理该方法。

    2. 服务端查询数据库,将所有分类信息以JSON格式的数据返回。前端获取到返回的所有分类,通过使用匿名函数,绑定分类数据到页面的显示分类区域。

    3. 对获取的JSON格式数组进行遍历数组,动态的展示分类区域代码。

    通过使用Redis缓存,可以大幅提高首页访问的性能,在以后的博文中将介绍其原理。
     
  • 相关阅读:
    Python练手例子(3)
    Python练手例子(2)
    Python练手例子(1)
    Python学习之旅(三十八)
    《剑指offer》— JavaScript(24)二叉树中和为某一值的路径
    《剑指offer》— JavaScript(23)二叉搜索树的后序遍历序列
    《剑指offer》— JavaScript(22)从上往下打印二叉树
    《剑指offer》— JavaScript(21)栈的压入、弹出序列
    《剑指offer》— JavaScript(20)包含min函数的栈
    《剑指offer》— JavaScript(19)顺时针打印矩阵
  • 原文地址:https://www.cnblogs.com/leoliu168/p/9988425.html
Copyright © 2020-2023  润新知