jsp机制基础

时间:2023-03-08 22:11:14
jsp机制基础

JSP

jsp机制基础

和Servlet技术一样,JSP也是SUN公司定义的一种开发动态web资源的技术,属于JavaEE技术之一。JSP实际上就是Servlet,它们在一起又称JSP/Servlet规范。

Servlet:写Java代码。在做HTML页面的输出时不方便(开发效率很低)

JSP:HTML+Java

1、JSP的原理及生命周期

当某个jsp页面第一次被请求时,会被Tomcat服务器的JSP引擎部分翻译成一个Servlet (☆),然后按照servlet的调用方式进行调用,过程如下:

jsp机制基础

jsp机制基础

当一个jsp页面被翻译成Servlet后,后面的过程,包括生命周期都和Servlet是类似的。所以说JSP就是Servlet,理解了JSP页面中的各个组成部分是如何被翻译成Servlet的,就掌握了JSP。学习JSP的过程中,应时常翻阅JSP对应的Servlet源码。

2、demo1_jsp.java类

上一小节中的demo1.jsp在访问时会被翻译成demo1_jsp.java,该类称为jsp的实现类(关于Tomcat中该类怎么命名不多说)。

demo1_jsp类继承自org.apache.jasper.runtime.HttpJspBase抽象类,该类除了继承HttpServlet类外,还实现了javax.servlet.jsp.HttpJspPage接口,在HttpJspPage接口中声明了一个_jspService()方法,它对应着jsp页面,绕晕了的看下图所示:

jsp机制基础

demo1.jsp中的几乎各种组成部分都能在demo1_jsp.java的_jspService()方法中找到(☆)。

3、JSP页面的组成部分

一个JSP页面可能会包含如下几个部分:JSP模板元素、Java脚本、JSP指令、JSP标签等等,这些部分都会被翻译到生成的Servlet中。

JSP模板元素即JSP页面中的HTML内容,翻译时直接放在out.write()方法中输出。

4、JSP中的JAVA脚本

1)JSP脚本片断:<% Java代码 %>

① JSP脚本片断中只能出现java代码,不能出现其它模板元素。JSP引擎在翻译JSP页面时,会将JSP脚本片断中的Java代码将被原封不动地放到Servlet的_jspService()方法中。

② 在一个JSP页面中可以有多个脚本片断,在两个或多个脚本片断之间可以嵌入文本、HTML标记和其他JSP元素。

③ 单个脚本片断中的Java语句可以是不完整的,但是,多个脚本片断组合后的结果必须是完整的Java语句。

<ul>

<%

for(int i = 0;i < 5; i ++){

%>

<li>第<%=i %></li>

<%

}

%>

</ul>

2)JSP脚本表达式:<%=Java变量或表达式 %>

JSP脚本表达式用于将程序数据输出到客户端。JSP引擎在翻译脚本表达式时,会在相应位置用out.print(…) 将表达式的值输给客户端(变量或表达式后面不能有分号!)。

3)JSP声明:<%! Java代码 %>

① JSP页面中编写的所有代码,默认会翻译到servlet的_jspService() 方法中,而JSP声明中的Java代码被翻译到_jspService方法的外面,所以JSP声明可用于定义JSP页面转换成的Servlet程序的成员变量和方法、静态代码块。

② JSP中九大隐式对象的作用范围仅限于_jspService()方法中,所以在JSP声明中不能使用这些隐式对象。

4)JSP注释:<%-- 注释信息 --%>

JSP引擎在将JSP页面翻译成Servlet程序时,忽略JSP页面中被注释的内容。

正规开发的JSP中应尽量避免出现Java脚本(可用标签封装)。

5、JSP指令

JSP指令是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分。在JSP 2.0规范*定义了三大指令(page、include、taglib)。

基本语法格式:<%@ 指令 属性=”值” …… %>,如果一个指令有多个属性,这多个属性可以写在一个指令中,也可以分开写。

1)page指令:<%@ page …… %>,有以下常用属性:

① import:告知JSP引擎,导入哪些包。JSP引擎会在生成的Servlet中默认导入javax.servlet.*、javax.servlet.http.*、javax.servlet.jsp.*。如:

<%@ page import="java.util.*,java.sql.*" %> 等价于:

<%@ page import="java.sql.*" %>   <%@ page import="java.util.*" %>

② session:告知引擎是否在_jspService()代码中产生session对象,默认值true。

③ errorPage:告知引擎,如果当前页面出现了异常,应该转发到哪个页面上(“/”代表当前应用)。开发中一般会直接在web.xml中配置全局错误页面(两种写法):

<error-page>

<exception-type>java.lang.Exception</exception-type>

<location>/common/error.jsp</location>

</error-page>

<error-page>

<error-code>404</error-code>

<location>/common/404.jsp</location>

</error-page>

④ isErrorPage:告知引擎是否在_jspService()代码中产生exception对象,默认为false。利用该对象可以捕获页面中的异常,打印异常的详细信息。

⑤ contentType:☆ 告知引擎响应正文的MIME类型,在Servlet中被翻译成response.setContentType(xxx)。

⑥ pageEncoding:☆ 告知引擎,翻译JSP时(从磁盘上读JSP文件)所用的码表,同时还会设置响应正文的MIME类型。pageEncoding的默认值为“ISO-8859-1”。

如:pageEncoding=”UTF-8”相当于告知了引擎用UTF-8读jsp,并在servlet中response.setContentType(“text/html;charset=UTF-8”)

⑦ isELIgnored:告知引擎,是否忽略EL表达式。默认值是false,不忽略。

2)include指令:<%@ include file=”/demo2.jsp” %>,file属性以“/”开头代表当前应用。

3)taglib:<%@ taglib uri=”” prefix=”” %>,导入外部标签库,uri表示外部标签库的uri地址,好比名称空间,prefix相当于一个别名。

6、JSP标签

JSP标签也称之为Jsp Action(JSP动作)元素,它用于在jsp页面中提供业务逻辑功能,避免在jsp页面中直接编写java代码,造成jsp页面难以维护。

1)转发:

<jsp:forward page=”/demo2.jsp”>

<jsp:param name=”from” value=”demo1” />

</jsp:forward>

2)包含:

<jsp:include page=”/demo2.jsp” >

<jsp:param name=”from” value=”demo1” />

</jsp:include>

注意:

① JSP转发和包含标签实际上是对RequestDispatcher的两个方法(forward和include)的改写,且都可以包含<jsp:param>子标签,<jsp:param>中的name-value会以参数的形式加在page后。

② 动态包含和静态包含:除了include指令为静态包含,其余的全是动态包含,它们的区别如下图:

jsp机制基础

了解了上图后,对静态包含和动态包含的各种区别就很容易理解了,实际开发中,能用静态包含就不用动态包含!

3)JavaBean相关

JSP中提供了三个关于JavaBean组件的内置标签,分别为:

① <jsp:useBean>标签:

语法:<jsp:useBean id="beanName" class="package.class" scope="xxx"/>

属性:id属性用于指定JavaBean实例对象的引用名称和其存储在域范围中的名称,class属性用于指定JavaBean的完整类名,scope的取值为page、request、session、application四个中的一个,默认值为page属性。

作用:在指定的域范围内查找指定的JavaBean对象:

A. 如果存在则直接返回该JavaBean对象的引用。

B. 如果不存在则实例化一个新的JavaBean对象并将它以指定的名称存储到指定的域范围中。

② <jsp:setProperty>标签:

语法1:<jsp:setProperty name="beanName" property=”propertyName” value=”xxx” />

语法2:<jsp:setProperty name=”beanName” property=”propertyName | *” param=”xxx” />

属性:name指定JavaBean实例对象的引用名称,对应id属性;property 指定JavaBean的属性名,指定param时用请求参数设置JavaBean的属性。

③ <jsp:getProperty>标签:

语法:<jsp:getProperty name="beanName" property="propertyName" />

使用案例,注意事项都写在注释中了,直接看即可:

<jsp:useBean id="p" class="org.flyne.domain.Person" scope="page" />

<!-- 一定要注意value的写法:基本类型和字符串类型直接写,其他类型用表达式 -->

<jsp:setProperty name="p" property="name" value="Flyne" />

<jsp:setProperty name="p" property="age" value="24" />

<jsp:setProperty name="p" property="regTime" value="<%=new Date() %>" />

name: <jsp:getProperty name="p" property="name"/><br />

age: <jsp:getProperty name="p" property="age"/><br />

regTime: <jsp:getProperty name="p" property="regTime"/><br />

另外还可以使用请求参数设置JavaBean的属性:

<jsp:setProperty name="p" property="name" param="name"/>

<!-- 当JavaBean的属性名同请求参数名一致时还可以使用通配符 -->

<jsp:setProperty name="p" property="*" />

7、九大隐含对象和四大域对象(☆)

在_jspService方法的开始部分定义了9大对象(exception对象需自行开启,通过isErrorPage指定),在JSP页面中可以直接使用这9大对象。

隐含对象名称

类型

备注

request

javax.servlet.http.HttpServletRequest

response

javax.servlet.http.HttpResponse

session

javax.servlet.http.HttpSession

page指令有开关:session

application

javax.servlet.ServletContext

config

javax.servlet.ServletConfig

page

javax.servlet.http.HttpServlet

当前jsp对应Servlet的实例引用

exception

java.lang.Throwable

page指令有开关:isErrorPage

out

javax.servlet.jsp.JspWriter

相当于带缓存功能的PrintWriter

pageContext

javax.servlet.jsp.PageContext

很重要(☆)

其中pageContext、request、session、application被称为四大域对象,又称属性范围,在实际开发中被用于存放数据(核心是把握其生命周期):

pageContext

页面范围:存储的数据仅本页有效,开发中不用它来存储数据

request

请求范围:一次请求范围内均有效,经常用

session

会话范围:多次请求可共享数据,但不同的客户端不能共享,经常用

application

应用范围:开发中尽量少用,用时要做同步处理

8、PageContext抽象类

1)利用PageContext可以获取其他8个JSP隐含对象。

使用场景:试想有这样一个函数,需要同时用到上述9个隐含对象(有点极端),设置9个参数?错,只需传入pageContext对象,再利用pageContext对象的getRequest()、getResponse()、getSession()、getServletContext()等方法获取其余8个对象。(自定义标签时会用到)

2)操作其他3个域对象中的属性:

① void setAttribute(String name, Object value, int scope)

Object getAttribute(String name, int scope)

void removeAttribute(String name, int scope)

scope参数可取如下常量值:PAGE_SCOPE(页面范围)、REQUEST_SCOPE(请求范围)、SESSION_SCOPE(会话范围)、APPLICATION_SCOPE(应用范围)。

② Object findAttribute(String name) 依次在四个范围中查找指定名称的属性:pageContext --> request --> session --> application。

3)提供转发和包含的简易方法(forward、include)

9、其他问题

1)JSP中的异常处理技巧

① 运行时异常:如1 / 0的运算,此时需查看与JSP文件对应的的Servlet的源码。

② 出现语法错误时,一般IDE会报错,在浏览器中也可以看到错误的详细信息,此时直接定位到JSP文件中查看就行。

2)使用page指令解决JSP中文乱码(☆)

出现中文乱码问题主要还是因为读和写所用的码表不一致造成的:

JSP开发人员可以采用各种字符集编码来编写JSP源文件(如UTF-8、GBK),JSP引擎将JSP源文件翻译成的Servlet源文件默认采用ISO8859-1编码,因此,JSP引擎将JSP源文件翻译成Servlet源文件时,需要进行字符编码转换,通过pageEncoding属性指定,两者需要保持一致。

3)JSP最佳实践

由于Servlet和JSP各自的特点,在长期的软件实践中,人们逐渐把servlet作为web应用中的控制器组件来使用,而把JSP技术作为数据显示模板来使用。

本文来源于:http://www.flyne.org/article/502