指示元素
JSP指示元素主要是为了表示容器将 JSP 转译为 Servlet 源代码时所必须遵守的信息。
语法为:<%@ 指示类型 [属性="值"]* %>
,指示元素可以有多对的属性/值
JSP 常用的三种指示类型为:page
、include
、taglib
page
: 告知容器如何转译当前的JSP网页include
: 告知容器将别的JSP页面包括进来进行转译taglib
: 告知容器如何转译这个页面的标签库
1 | <%import="java.util.Date" %> |
1
:告知容器转译时要包括import
属性中的值的包,即 Servlet 要有import java.uutil.Date;
,如果有多个包要包含,可以用逗号分割开:... import="java.util.Date, java.util.io*, ..."
2
:contenType
属性对应转译后的response.setContentType("...")
,pageEncoding
告诉容器这个网页的编码
include
类型的范例:
1 | <!-- includeDemo.jsp --> |
1 | <!--header.jspf--> |
1 | <!--foot,jspf--> |
includeDemo.jsp 第一次执行时会将上面两个文件的内容包括起来,然后进行转译,所以最终会生成一个Servlet,这是一种静态的包括方式。<jsp:include>
标签是运行时动态包括别的网页执行流程进行响应的方式,会各自生成独立的 Servlet。
同时也可以看到,包含的两个文件的后缀名是 .jspf,.jspf 文件通常是通过include伪指令包含在.jsp文件中的文件。’f’代表’fragment’,因为这些文件本身可能并不是完整的JSP,而是JSP的片段。类似这样的后缀名还有一个 .jspx。
同样,关于一些JSP的设置也可以在 web.xml 中更改,例如网页编码、内容类型等等
1 | <web-app ...> |
也可以声明指定的JSP文件的开头和结尾所要包括的网页
1 | ... |
在编写JSP网页时,换行字符不会忽略,所以最后产生的换行字符也会输出,如果要忽略,可以在 web.xml 中的<jsp-property-group>标签中加上
<trim-directive-whitespaces>true</...>
声明、Scriptlet 与表达式元素
JSP 中可以使用 声明、Scriptlet 元素和表达式来指定转译后 Servlet 类中包括的类成员、方法声明和语句。
声明元素的语法:<@! 类成员声明或方法声明 %>
Scriptlet 的语法:<% Java 语句 %>
在 JSP 中的编写的 HTML,都会变成 out 语句所输出的内容,而 Scriptlet 出现的顺序在转译为 Servlet 后,会按顺序出现在 _jsoService()
中。
表达式元素的语法:<%= Java表达式 %>
表达式的运算结果将直接输出为网页的一部分,但表达式语句不能加上分号,因为在转译后,表达式语句的表达式会转译为 out 对象输出时的指定内容。
由于<%
和%>
在 JSP 中用来作为一些元素的开头和结尾,所以如果要在 JSP 网页中输出这两个符号要换成其他字符:<%
–> <%
,%>
–> %>
或%\>
(HTML输出&
用&
)。
一个网页通过适当的规划、切割业务逻辑与呈现逻辑,JSP 网页可以通过标准标签、EL 或 JSTL 自定义标签等消除网页上的 Scriptlet。
注释元素
使用 <%-- JSP注释 --%>
,写出网页注释会输出到网页上。
隐式对象
| 隐式对象 | 说明 |
| :———- | ———————————————————— |
| out | 转译后对应
JspWriter
对象,其内部关联一个 PrintWriter
对象 || request | 转译后对应
HttpServletRequest
对象 || response | 转译后对应
HttpServletResponse
对象 || config | 转译后对应
ServletConfig
对象 || applicaton | 转译后对应
ServletContext
对象 || session | 转译后对应
HttpSession
对象 || pageContext | 转译后对应
pageContext
对象,提供了 JSP 页面资源的封装,可设置页面范围属性 || exception | 转译后对应
Throwable
对象 ,代表其他 JSP 页面抛出的异常对象,只会出现于 JSP 错误页面 || page | 转译后对应
this
|隐式对象只能在<%
和%>
或<%=
和%>
之间使用。隐式对象转译后是_jspService()
中的局部变量。
JspWriter
主要模拟了 BufferedWriter
与 PrintWriter
的功能,内部也是用 PrntWriter
来输出,但 JspWriter
具有缓冲区功能,使用 print()
和 println()
响应输出时,如果 JSP 页面没有缓冲或清楚缓冲时,才会直接创建 printWriter()
对象进行输出。
page
指示元素的 buffer
属性来设置缓冲区的大小,默认是8kb,autoFlush
属性决定缓冲区已满后的行为,默认值是 true
,表示慢了就清除,如果设置为 false
,要自行调用 JspWriter
的 flush()
方法来清除,否则调用 println()
会抛出 IOException
异常。
所有的隐式对象都可以通过 pageContext
的 getXXX()
方法来取得,pageContext
也可以设置页面范围属性,类似 Servlet 中的几个对象,可以使用 setAttribute()
、getAttribute()
、removeAttribute()
来设置。页面范围属性的作用范围仅仅局限于同一页面中。
pageContext
提供了单一的 API 来设置四种范围属性:
1 | getAttribute(String name, int scope); |
scope 的取值所代表的范围:
pageContext.PAGE_SCOPE
: 页面pageContext.REQUEST_SCOPE
: 请求pageContext.SESSION_SCOPE
: 会话pageContext.APPLICATION_SCOPE
: 应用程序范围
如果不知道属性范围的名称,可以用 pageContext
的 findAttribute()
方法依序从页面、请求、会话、应用程序范围中寻找,先找到就返回。
错误处理
JSP 发生错误按时段分为三种:
- JSP 转换为 Servlet 源代码
- Servlet 源代码编译时
- Servlet 载入容器进行服务但发生运行时错误时
可以自定义运行时异常发生时的处理页面,需要用 page
指示元素,设置 errorPage
属性来指定错误处理的页面。
1 | <%--add.jsp--%> |
1 | <%--error.jsp--%> |
exception
对象是 JSP 的隐式对象,只有 isErrorPage
设置为 true
的页面才可以使用这个对象。如果没有处理,会由容器默认处理,直接显示异常信息和堆栈跟踪信息。
1 | <web-app ...> |
标准标签
JSP 规范中提供了一些标准标签,所有容器都支持,可协助编写 JSP 是减少 Scriptlet 的使用,所有的标签都以 jsp: 为前缀。
<jsp:include>、<jsp:forward>标签
<jsp:include>
和 <jsp:forward>
标签在转译后,底层是取得 RequestDispatcher
对象,并执行对应的 forward()
方法和 include()
方法。
1 | <jsp:include page="add.jsp"> |
<jsp:param>
指定了动态包括 add.jsp 时需要给页面的请求参数。
<jsp:userBean>、<jsp:setProperty>与<jsp:getProperty>
JavaBean 元件具有的条件:
必须实现
java.io.Serializable
接口没有公开的类变量
具有无参数的构造器
具有公开的设值(setXXX)和取值(getXXX)方法
<jsp:userBean>、<jsp:setProperty>与<jsp:getProperty> 这三个标准标签就是搭配 JavaBean 元件的。
1 | <jsp:useBean id="user" class="User"/> |
1.用来取得或创建 JavaBean
id
指定 JavaBean 的实例名,之后可使用这个指定的名称设值和取值。
class
属性指定要实例化哪个类。
还有一个属性 scope
(默认为 page
范围)指定先查找设定的属性范围是否有名为id
指定值的 JavaBean 的属性存在,如果找到就直接使用,没有找到就会新建新的对象。
type
属性,指定声明 JavaBean 的类型,可以是一个抽象类、也可以是一个接口。但如果只设置了 type 而没有 class , 如果指定范围内找不到对象会抛出异常。
2.设置 JavaBean 的属性值
name
指定要使用哪个名称来使用 JavaBean 实例,property
表示要设置的 JavaBean 属性,这两个属性在这个标签中必需的。
value
和 param
两个属性可选,找到 JavaBean 后,如果指定了 value
元素,会将value的值转换为合适的基本类型赋值给指定的 JavaBean 属性。有 param
属性的话会将指定的参数的值转化会合适的基本类型赋给 JavaBean 属性。
如果value
和 param
都省略,可以用 JSP 的自省机制判断是否有 property
值相同的请求参数,有的话就赋给 JavaBean。
最有弹性的写法是示例代码第二行所示,标签中只有必要元素,property
值设为 *
,代表将请求参数名称和 JavaBean 属性名交给自省机制自动匹配。自省机制可以自动转换基本类型。
有两种很容易混淆的写法:
1 | <jsp:useBean id="user" class="User"/> |
这种写法无论如何都会使用设值。
1 | <jsp:useBean id="user" class="User"> |
这种只有找不到 JavaBean 对象的时候,才会新建对象并设置值。
<jsp:getProperty>
只有一种使用方法:<jsp:getProperty name="JavaBean 对象实例名", property="JavaBean 对象属性名">
,然后用 pageContext
的 findAttribute()
依次查找。
表达式语言(EL)
JSP 中一些简单的属性、请求参数、标头和 Cookie 等信息可以用 EL 来处理,更加简便。
EL 是使用 ${
与 }
来包括要处理的表达式。EL 处理了null
值的情况,对 null
值直接以空字符串显示,运算时不会因此发生错误而抛出异常。
由于某些时候网页使用了模板等有类似EL表达式的语法存在,可以设置 JSP 网页是否使用 EL.
web.xml 中修改
1
2
3
4
5
6
7
8
9<web-app ...>
...
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<el-ignored>true</el-ignored>
</jsp-property-group>
</jsp-config>
</web-app>page
指示元素的属性isELIgnored
(default:false
)
如果在 page
中设置了属性,以 page
中的设置为主。
隐式对象
EL 中,可以用 EL 隐式对象指定范围来存取属性。如果不指定属性的范围,以 page、request、session、application 的顺序依次查找。
EL 中有11个隐式对象,只有 pageContext
隐式对象对应 PageContext
,其他都对应 Map
类型
pageContext
PageContext 本身是 JavaBean 对象,所以只要是 getXXX() 方法,就可以使用
${pageContext.xxx}
来取得。也可以使用点运算符连续存取对象。属性范围相关隐式对象
表示作用范围,
pageScope
,requestScope
,sessionScope
,applicationScope
分别可以取得使用对应 JSP 隐式对象的setAttribute()
方法所设置的属性对象。请求参数相关隐式对象:
param
和paramValues
${param.user}
想当于<%= request.getParameter("user")%>
paramValues
相当于request.getParameterValues()
,因为返回的可能是多个值,可以用 [] 运算符指定取得的是那个元素。标头相关隐式对象:
header
和headersValues
,${header["User-Agent"]}
<-->reqest.getHeader("User-Agent")
-->Cookie 隐式对象:
cookie
用来取得用户 Cookie 设置值。
初始参数隐式对象:
initParam
可以取得 web.xml 中设置的ServletContext
初始参数
取得元素的方式
可以用 . 和 [] 来取得属性中的元素:
- . 运算符:左边可以是 JavaBean 或 Map 对象(Map 建议用 [] 运算符)
- [] 运算符:左边可以是 JavaBean 属性,Map,数组或 List 对象
[] 在指定索引是使用双引号,就是作为键名或索引来使用,不加双引号会先尝试运算。
运算符
- 算数运算符:+, -, *(mod), /(div), %(mod), ? :
- 逻辑运算符:and, or, not
- 关系运算符:<(lt), >(gt), <=(le), >=(ge), ==(eq), !=(ne)
自定义函数
第一步:编写类,公开类,且调用的方法是公开且为静态方法
第二步:编写 TLD(标签程序描述)文件(xml文件,以 .tld 为后缀),告诉容器如何将类中的方法作为 EL 函数
第三步:将文件放在 WEB-INF 文件夹下或 JAR 文件中