第3章〓JSP视图 JSP与静态网页HTML对应,表示Jakarta服务器页面。需要注意的是,它不是指运行在Web服务器的页面,而是在服务器端定义页面的样式,然后由Servlet容器解析成HTML后,回应给客户端浏览器显示。 Jakarta EE 10中包含的JSP版本是3.1。 参见hello.jsp的代码,看一下JSP的页面组成,其基本组成就是Java代码+HTML+JS。 <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <% String msg = (String)request.getAttribute("msg"); %> <!DOCTYPE html> <html> <head> <meta charset="ISO-8859-1"> <title>hello</title> <script type="text/javascript"></script> </head> <body> <%=msg%> </body> </html> 3.1JSP与Servlet的关系 视频讲解 所有JSP页面的默认父类是org.apache.jasper.runtime.HttpJspBase,而HttpJspBase又继承了HttpServlet,因此所有JSP页面的本质就是Servlet。它与自定义Servlet一样,由Servlet容器统一管理。 public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {…} JSP容器就是Servlet容器,它提供了JSP的生命期管理、JSP运行期支持和Servlet组件管理。HTTP请求通过JSP容器发送给JSP页面,JSP容器管理JSP页面生命期,二次访问JSP分为如下几个阶段(见图31和图32)。 图31第一次访问JSP 图32第二次访问JSP (1) 翻译阶段: JSP容器校验JSP页面、标签文件、Java脚本等语法拼写,然后把JSP页面自动翻译成Java代码,如hello.jsp就会翻译成hello_jsp.java。翻译后的文件保存在Tomcat的work文件夹下(\work\Catalina\localhost\Hello\org\apache\jsp\main\hello_jsp.java),翻译后的代码如下: public final class hello_jsp extends org.apache.jasper.runtime.HttpJspBase implements org.apache.jasper.runtime.JspSourceDependent, org.apache.jasper.runtime.JspSourceImports {…} (2) 编译阶段: JSP容器把翻译好的Java文件,自动编译成class文件,如hello_jsp.java编译成hello_jsp.class。JSP页面的翻译与编译处理,在第一次访问JSP页面时进行。如果项目运行期间JSP页面没有变化,则第二次访问JSP页面无须再次翻译和编译。 (3) 执行阶段: JSP容器调用编译好的JSP组件,完成创建、初始化、服务、释放等操作,JSP组件的生命期管理与前面讲的Servlet生命期管理一致。JSP的运行结果为HTML,即返回给客户端浏览器的是HTML文本信息(见图33)。 图33JSP输出HTML 3.2JSP指令 3.2.1Page指令 每个JSP页面的头部必须使用Page指令声明当前页面特性。 Page指令定义了一系列依赖于JSP容器交互的属性信息(见表31)。 视频讲解 表31Page指令属性 属性描述 language指定当前页面使用的服务器脚本语言 <%@ page language="java" %> contentType设置HTTP的 ContentType 响应头,指明将发送到客户程序的文档的 MIME 类型 <%@ page contentType="text/html" %> pageEncoding设置当前JSP页面的编码格式 <%@ page pageEncoding="utf-8" %> import指明服务器脚本中使用的类所在包,与业务类中的import含义相同,如 <%@ page import="java.util.*, com.icss.biz.*" %> 默认情况下,servlet 导入 java.lang.*、jakarta.servlet.*、jakarta.servlet.jsp.*、jakarta.servlet.http.*等包 buffer设置 out 变量(类型为JspWriter )使用的缓冲区大小 <%@ page buffer="none" %> <%@ pagebuffer="16Kb" %> autoFlush用来控制当缓冲区充满之后,是应该自动清空输出缓冲区(默认),还是在缓冲区溢出后抛出一个异常 <%@ pageautoFlush ="false" %> errorPageerrorPage 属性用来指定一个 JSP 页面,由该页面来处理当前页面中抛出但未被捕获的任何异常 <%@ page errorPage="/oops.jsp" %> isErrorPage表示当前页是否可以作为其他 JSP 页面的错误页面 <%@ page isErrorPage="false" %> ...其他不常用属性 例如: <%@ page language="java" import="com.icss.biz.*,com.icss.util.*" contentType="text/html"pageEncoding="utf-8" %> 3.2.2taglib指令 taglib简称标签库,是一套Java EE已经定义好的标签库,根据需要引用即可。如果Java EE标签库不能满足你的需要,也可以根据业务定义自己的标签库。 JSTL即JSP标准标签库,具体使用见第5章。 例如: <%@ taglib uri="jakarta.tags.sql" prefix="sql"%> <%@ taglib uri="jakarta.tags.core" prefix="c"%> <%@ taglib uri="jakarta.tags.fmt" prefix="fmt"%> 3.2.3include指令 include指令用于在当前JSP页面中替换文本或代码数据。include指令的作用与<jsp:include>元素的作用基本一致。 例如: <%@ include file="../public/head.html" %> 等效于 <jsp:include page="../public/head.jsp"></jsp:include> 如果include文件发生了变化,JSP容器可以接到变化通知,然后会重写编译变化的JSP文件。JSP文件允许在项目运行期间动态修改JSP文件,修改后Tomcat无须重新启动。 注意: include指令与<jsp:include>元素中都要使用相对路径,不要使用绝对路径。 include指令与<jsp:include>元素的区别见表32。 表32include指令与<jsp:include>元素对比 语法嵌 入 内 容对象描述 <%@include file=... %>相对file的路径静态JSP容器解析嵌入内容 <jsp:include page= />相对page的路径静态或动态内容不被提前解析,在Servlet运行期动态嵌入 视频讲解 3.3JSP中的Java元素 用一对<%%>包裹的内容,不属于HTML和JavaScript数据,可以统称为服务器Java元素信息。这些元素分别为: 指令: <%@ 指令 %>,见3.2节。 服务端注释: <% …%>,注释后的内容JSP容器不做处理。 Java表达式输出: <% =Java表达式 %>,在JSP中输出表达式结果,如 <%=msg %> <%= (new java.util.Date()).toLocaleString() %> Java脚本: <% Java代码 %>,如同在Servlet中编写代码一样。 Java声明: <% !Java方法或变量 %>,这种模式尽量不要使用,JSP的定位是视图,业务方法应该抽取到服务层。 3.3.1Java脚本与表达式 Java脚本元素(<% Java代码 %>)与Java表达式元素(<% =Java表达式 %>)经常协同操作,即在Java脚本中进行动态计算,在Java表达式中输出运算结果。 示例31 动态获取Web站点绝对路径,并在<img >中使用绝对路径显示图片信息。 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName() +":"+request.getServerPort()+path+"/"; %> <!DOCTYPE html> <html> <head> <meta charset="ISO-8859-1"> <title>Insert title here</title> </head> <body> <img src="<%=basePath%>main/flex.png"> </body> </html> 示例32 在Java脚本中进行简单计算,并在JSP页面中输出计算结果。 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8" %> <html> <head><title>计算圆的面积</title></head> <body> <% double r = 5; double PAI = 3.1415926; double area = PAI*r*r; %> 圆的周长为 <%=r%><br> 圆的面积为 <%= area %> </body> </html> 3.3.2Java声明 Java声明元素: <%!Java方法或变量 %> 可以声明变量或方法,在JSP的页面范围均可调用声明的变量或方法。 声明信息不会在当前输出流中产生任何输出。 声明在JSP页面初始化时被初始化,在其他声明、Java脚本、Java表达式中都有效。 示例33 示例中声明了一个整数变量i, 这个变量在page页面范围内全局有效。 <%! int i=0; %> <!DOCTYPE html> <html> <head> <title>hello</title> </head> <body> i= <%= i=i+5 %> </body> </html> 示例34 <%@ page language="java" contentType="text/html" pageEncoding="utf-8" import="java.util.*,java.text.*"%> <%! public String today(Date date){ SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd"); return sd.format(date); } %> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <%=today(new Date()) %> </body> </html> 3.3.3JSP中使用注释 1. HTML与XML中的注释 在HTML和XML中的注释语法是: <!-- comments … --> 使用这种注释,注释信息会随着response输出流与JSP其他信息一起输出到客户端。在JSP中也支持这种注释的使用。 示例35 <body> <!-- 显示打招呼信息 --> <%=msg%> </body> 在注释中,使用Java脚本、表达式、声明等,JSP容器仍然会处理,语法如下: <!-- 注释信息 <%= 表达式 %> 其他注释 … --> 示例36 <%@ page language="java" import="com.icss.biz.*,com.icss.util.*" contentType="text/html"pageEncoding="utf-8" %> <% String msg = (String)request.getAttribute("msg"); String uname = request.getParameter("uname"); %> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>hello</title> </head> <body> <!-- 显示<%=uname%>打招呼信息--> <%=msg%> </body> </html> 2. JSP中的注释 在JSP页面中设计了专门的元素用于注释,这种注释与HTML注释的区别: 注释内容不会被response输出流写到客户端。 JSP注释语法如下: <%--注释信息 --%> 用Java脚本可以替换上面的JSP注释: <% /**注释信息 … **/ %> 示例37 <body> <!-- 显示<%=uname%>打招呼信息--> <%-- 显示<%=uname%>打招呼信息--%> <% /** 显示打招呼信息 … **/ %> <%=msg%> </body> 视频讲解 3.4JSP的9个内置对象 JSP页面中可以使用9个内置对象,分别为request、response、session、application、out、pageContext、config、page、exception(见表33)。 表33JSP内置对象 内 置 对 象Java类型描述 requestjakarta.servlet.http.HttpServletRequest接收HTTP请求数据 responsejakarta.servlet.http.HttpServletResponse回应HTTP请求 sessionjakarta.servlet.http.HttpSession会话对象 applicationjakarta.servlet.ServletContext 存储全局数据 outjakarta.servlet.jsp.JspWriter输出文本 pageContextjakarta.servlet.jsp.PageContext当前页面的上下文对象 pagejava.lang.Objectpage = this,表示当前页面对象 configjakarta.servlet.ServletConfig用于读取初始化配置参数 exceptionjava.lang.Throwable在<%@ page isErrorPage="true"%>的页面中才能使用,用于输出异常信息 注: 本节只重点演示几个常用内置对象的使用,其他内容请参考JSP 3.1规范。 JSP内置对象在页面翻译阶段,会转换成相应的Java类型。这些对象的创建与释放,都是由JSP容器自动管理,开发人员无须关注。 3.4.1request与response对象 request对象是jakarta.servlet.http.HttpServletRequest接口的实例,参见2.5节ServletRequest接口。它是JSP中使用次数最多的内置对象,常用于获取Web站点名称、站点端口号、主机名、HTTP请求信息、分发器等。 response对象是jakarta.servlet.http.HttpServletResponse接口的实例,参见2.6节ServletResponse接口。response对象在JSP页面应用并不多,主要应用于Servlet中。 示例38 获取Hello项目的站点名。 <% out.println("path="+request.getContextPath()); out.println("path2=" + application.getContextPath()); %> 输出结果: path=/Hello,path2=/Hello。 总结 参见HttpServletRequest和ServletContext的API,分别调用 request.getContextPath()和application.getContextPath()可以获得当前站点名称。 示例39 获得Web站点绝对地址。 <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName() +":"+request.getServerPort()+path+"/"; %> <body> <img src="<%=basePath%>pic/flex.png"> </body> 总结 request对象是HTTP请求的封装,根据HTTP请求,可以动态解析当前站点的站点名称、IP、主机名、端口、HTTP方法名、HTTP参数、HTTP的头信息、HTTP的ContentType等很多信息。 示例310 默认主页设置。 (1) 在Hello项目的WebContent根下新建index.jsp。 (2) 在web.xml中配置项目启动时的欢迎页。 <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> (3) 默认页index.jsp不显示任何信息,转向真正的主页main.jsp。 <%@ page language="java" contentType="text/html;" pageEncoding="GBK"%> <% request.getRequestDispatcher("/main/main.jsp").forward(request, response); %> (4) 浏览器访问http://localhost:8080/Hello/,会自动转到主页main.jsp。 总结 默认主页的设置,在Jakarta Web项目很常见,如上代码使用request对象获取了RequestDispatcher对象,然后调用分发器的forward()方法实现了服务器端页面的跳转。 3.4.2pageContext对象 视频讲解 pageContext(jakarta.servlet.jsp.PageContext)对象继承JspContext类,给JSP组件在Servlet环境下运行提供了上下文环境支持。 通过pageContext可以获取访问当前页面的其他JSP内置对象: request对象、response对象、session对象、application对象、config对象、out对象、exception对象、page对象。 public abstract jakarta.servlet.ServletRequest getRequest() 返回request对象。 public abstract jakarta.servlet.ServletResponse getResponse() 返回response对象。 public abstract jakarta.servlet.http.HttpSession getSession() 返回session对象。 public abstract jakarta.servlet.ServletContext getServletContext() 返回application对象。 public abstract jakarta.servlet.ServletConfig getServletConfig() 返回config对象。 public abstract java.lang.Exception getException() 返回exception对象。 public abstract java.lang.Object getPage() 返回page对象。 示例311 修改索引页index.jsp,实现页面转向。 <%@ page language="java" contentType="text/html" pageEncoding="gbk"%> <% pageContext.forward("/main/main.jsp"); %> 示例312 在EL表达式或Java表达式中获取绝对路径。 <body> <img src="${pageContext.request.contextPath}/pic/flex.png"> 等效于 <img src="<%=request.getContextPath()%>/pic/flex.png"> </body> 3.4.3session与application对象 session和application对象的使用详细介绍见第6章。 3.5<jsp:>标准动作 在JSP页面中使用<jsp:>开头的XML元素,统称JSP标准动作(Action)。 JSP标准动作有<jsp:useBean>、<jsp:setProperty>、<jsp:getProperty>、<jsp:include>、<jsp:forward>、<jsp:param>、<jsp:plugin>、<jsp:params>、<jsp:fallback>、<jsp:attribute>、<jsp:body>、<jsp:invoke>、<jsp:doBody>、<jsp:element>、<jsp:text>、<jsp:output>、<jsp:root>、<jsp:declaration>、<jsp:scriptlet>、<jsp:expression>等,下面着重介绍常用的几个标准动作,其他内容参见JSP 3.1规范。 视频讲解 3.5.1<jsp:useBean> <jsp:useBean>的作用如下: 用ID值在指定的scope范围查找指定类型的Java对象。 如果对象存在,直接返回对象引用,否则实例一个新对象。 在Java脚本中声明一个ID值的变量,指向找到的对象。 简化的基本语法如下: <jsp:useBeanid="变量名" scope="page|request|session|application" class="包名.类名"/> 示例313 (1) 在com.icss.entity下定义实体类User。 public class User { private String uname; private String pwd; private int role; private double score; public User() { } public User(String uname) { this.uname = uname; } } (2) 在JSP页面使用<jsp:useBean>创建bean对象。 注意User必须有一个无参构造器,否则调用时报错。 <body> <jsp:useBean id="myUser" class="com.icss.entity.User"/> <jsp:setProperty name="myUser" property="score" value="85"/> ${myUser.score+3} </body> 输出结果: 88.0。 JavaBean有如下特点: 不能是非静态内部类。 必须拥有一个无参的构造器或者@Inject注解的构造器。 示例314 修改示例313的代码,首先在Java脚本中创建User对象,然后存储于request域对象中。<jsp:useBean>必须指明查找范围是request,否则默认从page中查找。 <body> <% User user = new User("tom"); user.setScore(85); request.setAttribute("myUser", user); %> <jsp:useBean id="myUser" class="com.icss.entity.User" scope="request"/> ${myUser.score+3} </body> 输出结果: 88.0。 如果没有设置scope="request",从page中找不到myUser,输出结果为3.0。 视频讲解 3.5.2<jsp:setProperty>与<jsp:getProperty> <jsp:setProperty>设置bean对象的属性值,简化的基本语法如下。 <jsp:setPropertyname="bean的名字" property="bean的属性名" value="属性值" param="请求参数名" /> value用于给属性直接赋值,param从请求中提取参数值给属性赋值,value与param不能同时使用。 <jsp:getProperty>为读取bean对象的属性值,简化的基本语法如下: <jsp:getPropertyname="name" property="propertyName"/> 注意: <jsp:getProperty>没有scope属性,它调用pageContext的 findAttribute()方法进行范围查找,即按照page、request、session、application的顺序查找。如果未找到指定名称的bean对象,则抛出异常。 示例315 (1) 在page域中查找myUser,没找到就实例化一个User对象。 (2) 设置myUser对象的属性score=85。 (3) 读取名字为myUser的bean对象,并在页面输出。 <body> <jsp:useBean id="myUser" class="com.icss.entity.User"/> <jsp:setProperty name="myUser" property="score" value="85"/> <jsp:getProperty name="myUser" property="score"/> </body> 输出结果: 85.0。 3.5.3<jsp:include> 在JSP当前页面,嵌入静态或动态资源(必须是当前Web应用的资源,不能是外部资源)。 嵌入资源时,应该使用相对路径,这会被翻译成基于当前context的绝对路径。 <jsp:include>在JSP页面翻译后,在Servlet运行过程动态导入资源。<jsp:include>属性见表34。 表34<jsp:include>属性 属性名描述 page嵌入URL资源的相对路径 flush可选属性,boolean值,如果flush为真,缓冲区马上刷新。默认值是false <jsp:include>与<c:import>功能相似,区别见5.2.4节中<c:import>部分内容。 <jsp:include>的基本语法如下: <jsp:includepage=" 相对路径指向嵌入页面"flush="true|false"/> 示例316 在当前JSP页面动态嵌入一个共享的头文件。 <body> <jsp:include page="/main/head.jsp"></jsp:include> </body> 3.5.4<jsp:forward> <jsp:forward>与RequestDispatcher的forward()方法功能一致,就是在Web应用运行期,分发请求到当前Web应用的静态资源、JSP页面或Servlet类。 基本语法如下: <jsp:forwardpage="相对路径" /> 示例317 从项目索引页index.jsp转向主页。 <body> <jsp:forward page="/main/main.jsp"></jsp:forward> </body> 3.6本章习题 (1) ()可在JSP页面出现该指令的位置处静态插入一个文件。 A. page指令标签B. page指令的import属性 C. include指令标签D. include动作标签 (2) 在JSP中,使用<jsp:useBean>动作可以将JavaBean嵌入JSP页面,对JavaBean的访问范围不能是()。 A. page B. request C. response D. application (3) Page指令的作用是()。 A. 用来定义整个JSP页面的一些属性和这些属性的值 B. 用来在JSP页面内某处嵌入一个文件 C. 使该JSP页面动态包含一个文件 D. 指示JSP页面加载Java plugin (4) 关于include指令,下面表述错误的是()。 A. include指令用于把资源文件嵌入当前页面中 B. include指令可以嵌入动态页面和静态页面 C. file属性是目标资源的路径和文件名 D. file属性可以使用相对路径,也可以使用绝对路径 (5) 下列关于<jsp:useBean>说法,错误的是()。 A. <jsp:useBean>用于定位或实例化一个JavaBeans组件 B. <jsp:useBean>首先会试图定位一个Bean实例,如果这个Bean不存在,那么<jsp:useBean>就会从一个class或模板中进行实例化 C. <jsp:useBean>元素的主体通常包含有<jsp:setProperty>元素,用于设置Bean的属性值 D. 如果这个Bean已经存在,<jsp:useBean>能够定位它,那么主体中的内容将不会起作用 (6) 下面关于jsp:setProperty说法,错误的是()。 A. jsp:setProperty用来设置已经实例化的Bean对象的属性 B. name属性表示要设置属性的是哪个Bean C. property属性表示要设置哪个属性 D. Param指定用哪个请求参数作为Bean属性的值 E. value属性用来指定Bean属性的值,value和Param参数可以同时使用 (7) 下面对out对象的说法,错误的是()。 A. out对象用于输出字符型数据 B. out对象的作用域范围是application C. out.newLine()方法用来输出一个换行符 D. out.close()方法用来关闭输出流 (8) 下面关于request对象的说法,错误的是()。 A. request对象是ServletRequest的一个实例 B. 当客户端请求一个JSP网页时,JSP引擎会将客户端的请求信息包装在一个request对象中 C. 在Servlet中用request.setAttribute()存储的数据,在JSP页面只能用request.getAttribute()读取 D. request.getParameter()方法返回指定参数的值 (9) 在JSP文件中加载动态页面可以用()。 A. <%@ include file="fileName" %>指令 B. <jsp:include>动作 C. page指令 D. <jsp:forward>动作 E. taglib指令 (10) 当要在JSP页面中使用自定义标签时,下面错误的是()。 A. 在tld文件中定义标签 B. 创建一个标签处理器 C. 在JSP页面中使用page指令,引入这个标签的标签库 D. 在JSP页面中使用taglib指令,引入这个标签的标签库 (11) 对于预定义<%! 声明 %>的说法,错误的是()。 A. 一次可声明多个变量和方法,只要以“;”结尾就行 B. 一个声明仅在一个页面中有效 C. 声明的变量将作为局部变量使用 D. 声明信息不会在当前输出流中产生任何输出 (12) 在JSP中使用<jsp:getProperty>标记时,不会出现的属性是()。 A. name B. value C. property D. scope (13) 在JSP中调用JavaBean时,不会用到的标记是()。 A. <jsp:Javabean>B. <jsp:useBean> C. <jsp:setProperty> D. <jsp:getProperty> (14) 在JSP中如果要导入 java.io.*包,应该使用()指令。 A. pageB. taglib C. include D. forward (15) 如果当前JSP页面出现异常,需要转到一个异常页,设置page 指令的()属性。 A. ExceptionB. isErrorPageC. error D. errorPage (16) JSP中的隐式注释为()。 A. // 注释内容 B. <!注释内容> C. <%注释内容%> D. /* 注释内容 */ (17) 下列()指令定义在JSP编译时包含所需要的资源。 A. includeB. page C. taglib D. forward (18) 重定向应该使用()方法。 A. response.sendRedirect("login.jsp") B. request.sendRedirect("login.jsp") C. <jsp :forward page= "login.jsp"/> D. <forward page= "login.jsp"/> (19) <jsp:useBean>声明对象的默认有效范围为()。 A. pageB. sessionC. application D. request (20) 某JSP程序中声明使用javaBean的语句如下: <jsp:useBean id="user" class="mypackage.User" scope="page"/> 要取出该javaBean的loginName属性值,以下语句正确的是()。 A. <jsp:getProperty name="user" property="loginName"/> B. <jsp:getProperty id="user" property="loginName" /> C. <%=user.getLoginName()%> D. <%=user.getProperty("loginName")%> (21) 以下()选项不属于浏览器的功能。 A. 发送HTTP请求,并接收HTTP响应 B. 解析并展现JSP代码样式 C. 解析并运行JavaScript代码 D. 解析并展现HTML代码样式 (22) 以下()选项不属于Web服务器的功能。 A. 接收HTTP请求,并回应HTTPB. 动态编译JSP代码 C. 运行并展示JSP页面 D. 管理Servlet和JSP组件生命期 (23) 下面()选项属于解释型语言。 A. HTMLB. JSPC. JavaD. JavaScript