• <Chapter 2>2-2-2-1.介绍JSPs,JSTL,和EL(Introducing JSPs, JSTL, and EL)


    现在,我们的时钟显示了UTC时区的时间。我们希望我们的应用可以让用户自定义时区,并且为将来的访问记住用户的偏好。为了做到这一点,我们使用Google帐户来识别哪个用户正在使用这个应用。

    在我们深入了解之前(Before we go any further),我们应当介绍一种保持HTML和我们的servlet代码相分离的方法。这允许我们分别维护应用的外观和业务逻辑(business logic),业务逻辑代码实现了我们应用的主要目标,使得我们的逻辑易于测试,应用的外观易于改变。典型的是,你将会使用模板系统以文件形式来定义应用的外观,文件包括THML,CSS,JavaScrpt以及用于放动态数据的保留空白。在Java中很多好的模板系统可供选择,比如Apache Velocity。

    对于这个例子,我们使用Java Servlet Pages,或JSPs。JSPs是J2EE的标准部分,它意味着你不需要安装任何其他的东西就可以使用它们。一个JSP包含文本(HTML)、定义这页逻辑的Java代码的混合。JSP编译为一个servlet(The JSP compiles to a servlet),就像我们已经定义的ClockServlet,它等同于写HTML部分和评价Java部分(that's equivalent to writing out the HTML portions,and evaluating the Java portions)。在某种意义上,JSPs仅仅是写servlet代码的另一种方式。

    JSPs经常被批评为太强大了。因为从一个JSP中可以获得整个Java语言,所以存在这样的风险:业务逻辑可能会写到模板中,而你不再进行有效的分离。为了缓和这点,JSP规范的后续版本包含了新的方法来描述模板逻辑,这就有意地使得没有整个Java代码强大:Java Servlet Templating Language(JSTL)和JSP Expression Language(EL)。我们为这个例子,以及在本书的其他需要模板化输出的地方,使用这些特性。

    编辑ClockServlet.java成类似例2-12。

    例2-12.显示Google帐户和链接的ClockServlet.java代码

    package clock;
    
    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.SimpleTimeZone;
    import javax.servlet.RequestDispatcher;
    import javax.servlet.ServletException;
    import javax.servlet.http.*;
    
    import com.google.appengine.api.users.User;
    import com.google.appengine.api.users.UserService;
    import com.google.appengine.api.users.UserServiceFactory;
    
    @SuppressWarnings("serial")
    public class ClockServlet extends HttpServlet{
        public void doGet(HttpServletRequest req,HttpServletResponse resp)
                   throws IOException,ServletException{
                 SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
                 fmt.setTimeZone(new SimpleTimeZone(0,""));
    
                 UserService userService = UserServiceFactory.getUserService();
                 User user = userService.getCurrentUser();
                 String loginUrl = userService.createLoginURL("/");
                 String logoutUrl = userService.createLogoutURL("/");
    
                 req.setAttribute("user",user);
                 req.setAttribute("loginUrl",loginUrl);
                 req.setAttribute("logoutUrl",logoutUrl);
                 req.setAttribute("currentTime",fmt.format(new Date()));      
    
                 resp.setContentType("text/html");
    
                 RequestDispatcher jsp = req.getRequestDispatcher("/WEB-INF/home.jsp");
                 jsp.forward(req,resp);
            }
    }

    接下来,在你的项目的war/WEB-INF/目录创建一个新的文件叫做home.jsp,并添加类似例2-13的内容。

    例2-13.显示Google帐户和链接的ClockServlet.java代码

    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <html>
      <head>
        <title>The Time Is ...</title>
      </head>
      <body>
        <c:choose>
          <c:when test="${user != null}">
            <p>
               Welcome,${user.email}!
               You can <a href="${logoutUrl}">sign out</a>.
            </p>
          </c:when>
         <c:otherwise>
             <p>
                Welcome!
                <a href="${loginUrl}">Sign in or register</a> to customize.
             </p>
         </c:otherwise>
        </c:choose>
         <p>The time is:${currentTime}</p>
        </body>
    </html> 

    使用Eclipse,你可以让开发服务器在你编辑代码时一直运行。当你保存对代码做的变更时,Eclipse会编译类,并且如果它编译成功的话,Eclipse会将新的类注入已经运行的服务器中。在大多数情况下,你可以简单地在浏览器中重载页面,它将会使用新的代码。

    如果你不使用Eclipse,通过键入Crl-C来使开发服务器宕机。再次编译你的项目,然后重启这个服务器。

    在你的浏览中重载新版本的时钟应用。新的页面类似于在前面的图2-5中的Python例子。

    下面是我们将要说明的在本书中的关于JSPs、JSTL、EL的内容。

    ・记住home.jsp代表一个servlet。在这个情况下,希望某些属性被设置在它的上下文中。ClockServlet通过在HttpServletRequest对象的setAttribute()方法设置属性来调用home.jsp。然后转发这个请求和响应到home.jsp servlet。

    ・转发是发生在home.jsp servlet的RequestDispatcher中。在这个情况下,我们将home.jsp放在/WEB-INF/目录下,因此servlet容器不会将它映射到URL。如果JSP位于/WEB-INF/的外面,对于那个路径(来自WAR的根目录)的URL会映射到JSP servlet,并且servlet容器会直接调用它(假设没有显式URL模式匹配这个URL)。

    ・请求实例的getRequestDispatcher()方法拿到JSP的路径并且返回它的RequestDispatcher。确保路径以正斜杠开始。

    ・为了调用JSP,ClockServlet调用RequestDispatcher的forward()方法,把HttpServletRequest和HttpServletResponse对象作为参数。forward()方法可能抛出ServletException;在这个例子中,我们仅仅在doGet()中增加了throws语句。

    ・一个JSP包含文本(HTML)和特别格式化的指令。这个例子包含一个指令,<@ taglib ...%>,它会加载JSTL标签库。你可能还看到了<%...%>,它包含成为servlet某部分的Java代码,以及<%=...%>,它包含Java表达式,它的字符串形式被打印到页面。

    ・<c:choose>...</c:choose>、<c:when>...</c:when>、<c:otherwise>...</c:otherwise>是JSTL标签的例子。这些由来自第一行的taglib导入命令导入的/jsp/jstl/core标签库。c:是和导入命令的库相关的前缀。这儿,当用户登录时,<c:choose>结构提交<c:when>块,否则提交<c:otherwise>块。

    ・${user != null}是EL表达式的例子。一个EL表达式可以出现在文档的文本中,就是它的值被提交到的文本位置,JSTL标签属性中,就是它的值被标签使用的位置。表达式${logoutUrl}表达ClockServlet设置的logoutUrl属性的String值。${user.email}是访问一个值得JavaBean属性的例子:这个值等价于调用User对象值得getEmail()方法。${user!=null}展示一个EL表达式如何使用简单操作符的,在这个情况下生成一个被<c:when test="...">使用的boolen值。

    对于本书,我们将坚持用JSPs,JSTL,和EL的简单特性,并且不提供额外的解释。更多关于这些J2EE特性的解释,参看Brian Basham等的Head First Servlet and JSP(O'Reilly)。

    ※当使用请求dispatchers时,当URL模式/*映射到你的部署解释器中的一个servlet时要注意。显式的URL映射会复写默认的JSP路径映射,并且当决定这个路径的servlet时,请求dispatcher会honor it。如果你有一个可能匹配JSP路径的/*URL映射,你必须有一个显式的JSP URL映射在部署解释器中复写它:

    <servlet>
        <servlet-name>home-jsp</servlet-name>
        <jsp-file>/WEB-INF/home.jsp</jsp-file>
      </servlet>
      <servlet-mapping>
        <servlet-name>home-jsp</servlet-name>
        <url-pattern>/WEB-INF/home.jsp</url-pattern>
      </servlet-mapping>
      <servlet>
        <servlet-name>clock</servlet-name>
        <servlet-class>clock.ClockServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>clock</servlet-name>
        <url-pattern>/*</url-pattern>
      </servlet-mapping>

    注意在/WEB-INF/的一个映射依旧是隐藏的(from clients)。对于/WEB-INF/home.jsp的请求会返回一个404没有找到错误,并且不会调用JSP servlet。

  • 相关阅读:
    题解——[[SHOI2010]最小生成树]
    7.12周总结
    还有5个月就NOIP2019了,我干了什么
    【CQOI2018】破解D-H协议
    【SHOI2006】仙人掌
    【HNOI/AHOI2018】道路
    2019.11纪中集训 宋新波老师和曹天佑学长的勉励
    纪中集训2019.11.05
    【2019.10.25 OI-Killer的模拟赛】3.鸡数
    【华东师附国庆模拟赛】Day2 1.矩阵
  • 原文地址:https://www.cnblogs.com/niaomingjian/p/4805283.html
Copyright © 2020-2023  润新知