现在,我们的时钟显示了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。

<Chapter 2>2-2-2-1.介绍JSPs,JSTL,和EL(Introducing JSPs, JSTL, and EL)的更多相关文章

  1. 零元学Expression Blend 4 &ndash; Chapter 43 如何指定Childwindow PopUp位置

    原文:零元学Expression Blend 4 – Chapter 43 如何指定Childwindow PopUp位置 有网友询问我有关Childwindow是否能指定弹出位置? 其实只要透过小小 ...

  2. 用纯JS做俄罗斯方块 - 简要思路介绍(1)

    大家都知道俄罗斯方块是一款大众化的游戏了,我很小的时候就玩过,今年已经25岁了,可以说俄罗斯方块确实是历史悠久,做俄罗斯方块是我上个星期开始的想法.也许是由于自己从来没有写过这种东西吧,所以有生疏.代 ...

  3. Spark中常用工具类Utils的简明介绍

    <深入理解Spark:核心思想与源码分析>一书前言的内容请看链接<深入理解SPARK:核心思想与源码分析>一书正式出版上市 <深入理解Spark:核心思想与源码分析> ...

  4. WPF入门教程系列六——布局介绍与Canvas(一)

    从这篇文章开始是对WPF中的界面如何布局做一个较简单的介绍,大家都知道:UI是做好一个软件很重要的因素,如果没有一个漂亮的UI,功能做的再好也无法吸引很多用户使用,而且没有漂亮的界面,那么普通用户会感 ...

  5. EL表达式介绍

    EL 全名为Expression Language EL 语法很简单,它最大的特点就是使用上很方便.接下来介绍EL主要的语法结构: ${sessionScope.user.sex} 所有EL都是以${ ...

  6. 第四节 数据格式化和ModelAttribute注解的介绍

    从来都不坦荡,情绪都写在脸上:不开心的时候,不爱说话,笑也勉强. 课堂笔记,如果这么写,不仅仅是手速,还要有语速, 这样不太适合! --胖先生 关于数据传递: 客户端传递数据到服务端: 1.使用普通的 ...

  7. Vue.js介绍

    http://www.cnblogs.com/keepfool/p/5619070.html Vue.js介绍 Vue.js是当下很火的一个JavaScript MVVM库,它是以数据驱动和组件化的思 ...

  8. APP自动化框架LazyAndroid使用手册(3)--核心API介绍

    作者:黄书力 概述 在前一篇博文中,简要介绍了一款安卓UI自动化测试框架LazyAndroid (http://blog.csdn.net/kaka1121/article/details/53204 ...

  9. Wpf 之Canvas介绍

    从这篇文章开始是对WPF中的界面如何布局做一个较简单的介绍,大家都知道:UI是做好一个软件很重要的因素,如果没有一个漂亮的UI,功能做的再好也无法吸引很多用户使用,而且没有漂亮的界面,那么普通用户会感 ...

随机推荐

  1. 在PowerDesigner中设计物理模型3——视图、存储过程和函数

    原文:在PowerDesigner中设计物理模型3--视图.存储过程和函数 视图 在SQL Server中视图定义了一个SQL查询,一个查询中可以查询一个表也可以查询多个表,在PD中定义视图与在SQL ...

  2. 纯后台生成highcharts图片有哪些方法?

    比如说,领导抛给你一个需求,把一些数据做成图表,每天通过邮件发送,让领导能在邮件中就看到图片,你会有什么思路呢?本人使用的是phantomjs这个神器,它的内核是WebKit引擎,不提供图形界面,只能 ...

  3. asp.net Twilio

    Imports System.Net Imports System.Text Imports Twilio Public Class clsTwilioSMS Public Shared Functi ...

  4. Linux命令之chmod 及+s 参数(临时以所有者权限执行)

    转自: http://blog.csdn.net/shaobingj126/article/details/7031221 chmod用于改变文件或目录的访问权限.用户用它控制文件或目录的访问权限.该 ...

  5. Windows 7下配置JDK环境变量和Java环境变量配置

    下面来介绍一下Java环境变量配置,是在Windows 7下配置JDK环境变量. 方法/步骤  1 安装JDK,安装过程中可以自定义安装目录等信息,例如我们选择安装目录为:C:\Program Fil ...

  6. shell/bash 让vi/vim显示空格,及tab字符

    shell/bash 让vi/vim显示空格,及tab字符 Vim 可以用高亮显示空格和TAB.文件中有 TAB 键的时候,你是看不见的.要把它显示出来::set listTAB 键显示为 ^I,   ...

  7. Android开发性能优化大总结

    1.  采用硬件加速,在androidmanifest.xml中application添加android:hardwareAccelerated="true".不过这个需要在and ...

  8. Qt之自定义界面(窗体缩放-跨平台终极版)

    简述 通过上一节内容,我们实现了窗体的缩放,功能很不错,但是很遗憾-不支持跨平台!如果对于多平台来说,这是一个硬伤,所以,我们急需要一个能够支持跨平台的实现方案. 在网上看到过很多不同的实现方式,多多 ...

  9. POJ 1577 Falling Leaves

    题意:给出一些字符串,从上到下的建树,输出其前序遍历 像前面那一题一样,先建树,然后再递归前序遍历 不过想像上一题那样用数组建树,建树和上题一样的办法,可是应该怎么输出前序遍历呢= = 还是看的题解= ...

  10. C#计算程序执行速度

    long t1 = DateTime.Now.Ticks; //执行程序,例如处理100个文件 long t2 = DateTime.Now.Ticks; Response.Write("执 ...