JavaServer Page它不是Servlet

前言

      Servlet有两个缺点是无法克服的:首先,写在Servlet中的所有HTML标签必须包含Java字符串,这使得处理HTTP响应报文的工作十分繁琐;第二,所有的文本和HTML标记是硬编码,导致即使是表现层的微小变化,如改变背景颜色,也需要重新编译。
      JavaServer Pages(JSP)解决了上述两个问题。同时,JSP不会取代Servlet,相反,它们具有互补性。现代的Java Web应用会同时使用Servlet和JSP页面。

1.JSP概述

      JSP页面本质上是一个Servlet。然而,用JSP页面开发比使用Servlet更容易,主要有两个原因。首先,不必编译JSP页面;其次,JSP页面时一个已.jsp为扩展名的文本文件,可以使用任何文本编辑器来编写它们。JSP页面在JSP容器中运行,一个Servlet容器通常也是JSP容器。例如,Tomcat就是一个Servlet/JSP容器。
      当一个JSP页面第一次被请求时,Servlet/JSP容器主要做以下两件事情:
      (1)转换JSP页面到JSP页面实现类,该实现类是一个实现javax.servlet.jsp.JspPage接口或子接口javax.servlet.jsp.HttpJspPage的Java类。JspPage是javax.servlet.Servlet的子接口,这使得每一个JSP页面都是一个Servlet。该实现类的类名由Servlet/JSP容器生成。如果出现转换错误,则相关错误信息将被发送到客户端。
      (2)如果转换成功,Servlet/JSP容器随后编译该Servlet类,并装载和实例化该类,像其他正常的Servlet一样执行生命周期操作。
      对于同一个JSP页面的后续请求,Servlet/JSP容器会先检查JSP页面是否被修改过。如果是,则该JSP页面会被重新翻译、编译并执行。如果不是,则执行已经在内存中的JSP Servlet。这样一来,一个JSP页面的第一次调用的实际花费总比后来的花费多,因为它涉及翻译和编译。为了解决这个问题,可以执行下列动作之一:

  • 配置应用程序,使所有的JSP页面在应用程序启动时被调用(实际上也可视为翻译和编译),而不是在第一次请求时调用。
  • 预编译JSP页面,并将其部署为Servlet。

      JSP页面可以包含模板数据和语法元素。这里,语法元素是一些具有特殊意义的JSP转换符。例如,“<%”是一个元素,因为它表示在JSP页面中的Java代码块的开始。“%>”也是一个元素,因为它是Java代码块的结束符。除去语法元素外的一切是模板数据。模板数据会原样发送给浏览器。例如,JSP页面中的HTML标记和文字都是模板数据。
      下图所示代码为welcome.jsp的JSP页面。它是发送一个客户问候的简单页面。注意,同Servlet相比,JSP页面时如何更简单地完成同样的事情的。
在这里插入图片描述
      一个JSP页面不同于一个Servlet的另一方面是是,前者不需要添加注解或在部署描述符中配置映射URL。在应用程序目录中的每一个JSP页面可以直接在浏览器中输入路径页面访问。下图给出了该应用程序的目录结构。
在这里插入图片描述
      应用程序的结构非常简单,由一个WEB-INF目录和welcome.jsp页面构成。可以通过URL访问welcome.jsp页面:

http://localhost:8080/JSPtest_war_exploded/welcome.jsp

在这里插入图片描述
      说明:添加新的JSP页面后,无须重启Tomcat。
      下图展示了如何在JSP页面中使用Java代码来生成动态页面。显示了今天的日期。
在这里插入图片描述
在这里插入图片描述
      请注意两件事情。首先,Java代码可以出现在JSP页面中的任何位置,并通过“<%”和“%>”包括起来。其次,可以使用page指令的import属性导入在JSP页面中使用的Java类型,如果没有导入的类型,必须在代码中写Java类的全路径名称。

2.注释

      在浏览器中为JSP页面添加注释是一个良好的习惯。JSP支持两种不同的注释格式:
(1)JSP注释。该注释记录页面中做了什么。
(2)HTML/XHTML注释。这些注释将会发送到浏览器上。
      JSP注释以“<%–”开始,以“–%>”结束。下面是一个例子:

<%-- retrieve products to display --%>

JSP注释不会被发送到浏览器端,也不会被嵌套。
HTML/XHTML注释语法如下:

<!-- [comments here] -->

一个HTML/XHTML注释不会被容器处理,会发原样发送给浏览器。HTML/XHTML注释的一个用途是用来确定JSP页面本身。

3.隐式对象

      Servlet容器会传递几个对象给它运行的Servlet。例如,可以通过Servlet的service方法拿到HttpServletRequest和HttpServletResponse对象,以及可以通过init方法访问到ServletConfig对象。此外,可以通过调用HttpServletRequest对象的getSession方法访问到HttpSession对象。
      在JSP中,可以通过使用隐式对象来访问上述对象。下标所示为JSP隐式对象(九大内置对象)。
在这里插入图片描述
      以request对象为例,该隐式对象代表Servlet/JSP容器传递给Servlet服务方法的HttpServletRequest对象。可以将request理解为一个指向HttpServletRequest对象的引用变量。下面的代码示例,从HttpServletRequest对象中返回username参数值:

<%
  String username=request.getParameter("userName"); 
%>

      pageContext用于javax.servlet.jsp.PageContext。它提供了有用的上下文信息,并通过其自说明的方法类访问各种Servlet相关对象,如getRequest、getResponse、getServletContext、getServletConfig和getSession。当然,这些方法在脚本中不是非常有用的,因为可以更直接地通过隐式对象来访问request、response、session和application。
      此外,PageContext中提供了另一组有趣的方法:用于获取和设置属性的方法,即getAttribute方法和setAttribute方法。属性值可被存储在4个范围之一:页面、请求、会话和应用程序。页面范围是是最小范围,这里存储的属性只在同一个JSP页面可用。请求范围是指当前的ServletRequest中。会话范围是指当前的HttpSession中。应用程序范围指应用的ServletContext中。
pageContext的setAttribute方法签名如下:

public abstract void setAttribute(java.lang.String name,java.lang.Object value,int scope)

      其中,scope的取值范围为PageContext对象的最终静态int值:PAGE_SCOPE、REQUEST_SCOPE、SESSION_SCOPE和APPLICATION_SCOPE。
      若要保存一个属性到页面范围,可以直接使用setAttribute重载方法:

public abstract void setAttribute(java.lang.String name,java.lang.Object value)

      如下脚本将一个属性保存到ServletRequest中:

<%
pageContext.setAttribute("product",product,PageContext.REQUEST_SCOPE);
%>
同样效果的代码如下:
<%
request.setAttribute("product",product);
%>

      隐式对象out引用了一个javax.servlet.jsp.JspWriter对象,这类似于你在调用HttpServletResponse的getWriter方法时得到java.io.PrintWriter。可以通过调用它的print方法将消息发送到浏览器。例如:

out.println("Welcome");

      下图中的implicitObjects.jsp页面展示了部分隐式对象的使用。
在这里插入图片描述
在这里插入图片描述

4.指令

      指令是JSP语法元素的第一种类型。它们指示JSP转换器如何翻译JSP页面为Servlet。page和include指令尤为重要。
(1)page指令
      page指令的语法如下:

<%@ page attribute1="value1" attribute2="value2"...%>

      @和page间的空格不是必须的,attribute1、attribute2等式page指令的属性。如下是几个比较常用的page指令属性列表:

  • import:定义一个或多个本页面中被导入和使用的java类型。例如:import="java.util.List"将导入List接口。可以使用通配符“*”来引入整个包。可以通过在两个类型间加入“,”分隔符来导入多个类型,如import=“java.util.ArrayList,java.util.Calendar”。此外,JSP默认导入如下包:java.lang、javax.servlet、javax.servlet.http、javax.servlet.jsp。
  • session:值为True,本页面会加入会话管理;值为False则相反。
  • errorPage:定义当时出错是用来处理错误的页面。
  • isErrorPage:标识本页面是一个错误处理页面。
  • contentType:定义本页面隐式对象response的内容类型,默认是text/html。
  • pageEncoding:定义本页面的字符编码,默认是ISO-8859-1。

(2)include指令
      可以使用include指令将其他文件中的内容包含到当前JSP页面。一个页面中可以有多个include指令。若存在一个内容会在多个不同页面中使用或一个页面不同位置使用的场景,则将该内容模块化到一个include文件非常有用。
      include指令的语法如下:

<%@ include file="url" %>

      其中,@和include间的空格不是必须的,URL为被包含文件的相对路径,若URL以一个斜杆(/)开始,则该URL为文件在服务器上的绝对路径,否则为当前JSP页面的相对路径。

5.脚本元素

      一个脚本程序是一个Java代码块,以<%符号开始,以%>符号结束。以下图所示的scriptletTest.jsp页面为例。
在这里插入图片描述
在这里插入图片描述
      在上述页面中有两个脚本程序,需要注意的是定义在一个脚本程序中的变量可以被其后续的脚本程序使用。
      脚本程序第一行代码可以紧接<%标记,最后一行代码也可以紧接%>标记,不过,这会降低代码的可读性。
(1)表达式
      每个表达式都会被JSP容器执行,并使用隐式对象out的打印方法输出结果。表达式一“<%=”开始,并以“%>”结束。举例如下:

Today is<%=java.util.Calendar.getInstance().getTime()%>

      注意,表达式无须分号结尾。
      JSP容易首先执行java.util.Calendar.getInstance().getTime(),并将计算结果传递给out.print(),这与如下脚本程序的效果一样:

Today is
<%
  out.print(java.util.Calendar.getInstance().getTime());
%>

(2)声明
      可以声明能在JSP页面中使用的变量和方法。声明以“<%!”开始,并“%>”结束。例如下图的declarationTest.jsp页面展示了一个JSP页面,该页面声明了一个名为getTodayDate的方法。
在这里插入图片描述
在这里插入图片描述
      在JSP页面中,一个声明可以出现在任何地方,并且一个页面可以有多个声明。

6.错误处理

      JSP提供了很好的错误处理能力。除了在Java代码中可以使用try语句,还可以指定一个特殊页面。当应用页面遇到未捕获的异常时,用户将看到一个精心设计的网页解释发生了什么,而不是一个用户无法理解的错误信息。
      请使用page指令的isErrorPage属性(属性值必须为True)来标识一个JSP页面是错误页面,下图errorHandler.jsp展示了一个错误处理程序。
在这里插入图片描述在这里插入图片描述
      其它需要防止未捕获的异常的页面使用page指令的errorPage属性来指向错误处理页面,例如,下图的buggy.jsp页面
在这里插入图片描述在这里插入图片描述
      运行的buggy.jsp页面会抛出一个异常。不过,我们不会看到由Servlet/JSP容器生成错误消息。相反,会看到errorHandler.jsp页面的内容。

7.小结

      JSP是构建在Java Web应用程序上的第二种技术,是Servlet技术的补充,而不是取代Servlet技术。一个精心设计的Java Web应用程序会同时使用Servlet和JSP。

猜你喜欢

转载自blog.csdn.net/Achenming1314/article/details/105952361