@cxm-2016
2016-12-28T16:33:25.000000Z
字数 12304
阅读 3000
Web
版本:1
作者:陈小默
声明:禁止商业,禁止转载
可用的标准动作元素如下:
语法 | 描述 |
---|---|
jsp:include | 在页面被请求的时候引入一个文件。 |
jsp:useBean | 寻找或者实例化一个JavaBean。 |
jsp:setProperty | 设置JavaBean的属性。 |
jsp:getProperty | 输出某个JavaBean的属性。 |
jsp:forward | 把请求转到一个新的页面。 |
jsp:plugin | 根据浏览器类型为Java插件生成OBJECT或EMBED标记。 |
jsp:element | 定义动态XML元素 |
jsp:attribute | 设置动态定义的XML元素属性。 |
jsp:body | 设置动态定义的XML元素内容。 |
jsp:text | 在JSP页面和文档中使用写入文本的模板 |
所有的动作要素都有两个属性:id属性和scope属性。
page
, request
, session
, 和 application
。<jsp:include>
动作元素用来包含静态和动态的文件。该动作把指定文件插入正在生成的页面。语法格式如下:
<jsp:include page="相对 URL 地址" flush="true" />
前面已经介绍过include指令,它是在JSP文件被转换成Servlet的时候引入文件,而这里的jsp:include动作不同,插入文件的时间是在页面被请求的时候。
以下是include动作相关的属性列表。
属性 | 描述 |
---|---|
page | 包含在页面中的相对URL地址。 |
flush | 布尔属性,定义在包含资源前是否刷新缓存区。 |
实例
以下我们定义了两个文件 date.jsp 和 main.jsp,代码如下所示:
date.jsp文件代码:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<p>
今天的日期是: <%= (new java.util.Date()).toLocaleString()%>
</p>
main.jsp文件代码:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<h2>include 动作实例</h2>
<jsp:include page="date.jsp" flush="true" />
</body>
</html>
现在将以上两个文件放在服务器的根目录下,访问main.jsp文件。显示结果如下:
include 动作实例
今天的日期是: 2016-6-25 14:08:17
jsp:useBean 动作用来加载一个将在JSP页面中使用的JavaBean。
这个功能非常有用,因为它使得我们可以发挥 Java 组件复用的优势。
jsp:useBean动作最简单的语法为:
<jsp:useBean id="name" class="package.class" />
在类载入后,我们既可以通过 jsp:setProperty 和 jsp:getProperty 动作来修改和检索bean的属性。
以下是useBean动作相关的属性列表。
属性 | 描述 |
---|---|
class | 指定Bean的完整包名。 |
type | 指定将引用该对象变量的类型。 |
beanName | 通过 java.beans.Beans 的 instantiate() 方法指定Bean的名字。 |
<jsp:useBean id="currentDate"
class="java.util.Date"/>
上述代码在被翻译成Servlet的时候是这个样子的
java.util.Date currentDate = null;
synchronized (_jsp_page_context) {
currentDate = (Date)_jsp_page_context.getAttribute("currentDate",PageContext.PAGE_SCOPE);
if(currentDate == null){
currentDate = new java.util.Date();
_jsp_page_context.("currentDate", currentDate, PageContext.PAGE_SCOPE)
}
}
jsp:setProperty用来设置已经实例化的Bean对象的属性,有两种用法。首先,你可以在jsp:useBean元素的外面(后面)使用jsp:setProperty,如下所示:
<jsp:useBean id="myName" ... />
...
<jsp:setProperty name="myName" property="someProperty" .../>
此时,不管jsp:useBean是找到了一个现有的Bean,还是新创建了一个Bean实例,jsp:setProperty都会执行。第二种用法是把jsp:setProperty放入jsp:useBean元素的内部,如下所示:
<jsp:useBean id="myName" ... >
...
<jsp:setProperty name="myName" property="someProperty" .../>
</jsp:useBean>
此时,jsp:setProperty只有在新建Bean实例时才会执行,如果是使用现有实例则不执行jsp:setProperty。
jsp:setProperty动作有下面四个属性,如下表:
属性 | 描述 |
---|---|
name | name属性是必需的。它表示要设置属性的是哪个Bean。 |
property | property属性是必需的。它表示要设置哪个属性。有一个特殊用法:如果property的值是"*",表示所有名字和Bean属性名字匹配的请求参数都将被传递给相应的属性set方法。 |
value | value 属性是可选的。该属性用来指定Bean属性的值。字符串数据会在目标类中通过标准的valueOf方法自动转换成数字、boolean、Boolean、 byte、Byte、char、Character。例如,boolean和Boolean类型的属性值(比如"true")通过 Boolean.valueOf转换,int和Integer类型的属性值(比如"42")通过Integer.valueOf转换。value和param不能同时使用,但可以使用其中任意一个。 |
param | param 是可选的。它指定用哪个请求参数作为Bean属性的值。如果当前请求没有参数,则什么事情也不做,系统不会把null传递给Bean属性的set方法。因此,你可以让Bean自己提供默认属性值,只有当请求参数明确指定了新值时才修改默认属性值。 |
jsp:getProperty动作提取指定Bean属性的值,转换成字符串,然后输出。语法格式如下:
<jsp:useBean id="myName" ... />
...
<jsp:getProperty name="myName" property="someProperty" .../>
下表是与getProperty相关联的属性:
属性 | 描述 |
---|---|
name | 要检索的Bean属性名称。Bean必须已定义。 |
property | 表示要提取Bean属性的值 |
实例
以下实例我们使用了Bean:
package com.runoob.main;
public class TestBean {
private String message = "菜鸟教程";
public String getMessage() {
return(message);
}
public void setMessage(String message) {
this.message = message;
}
}
编译完成后会在当前目录下生成一个 TestBean.class 文件, 将该文件拷贝至当前 JSP 项目的 WebContent/WEB-INF/classes/com/runoob/main 下( com/runoob/main 包路径,没有需要手动创建)。
下面是一个很简单的例子,它的功能是装载一个Bean,然后设置/读取它的message属性。
现在让我们在main.jsp文件中调用该Bean:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<h2>Jsp 使用 JavaBean 实例</h2>
<jsp:useBean id="test" class="com.runoob.main.TestBean" />
<jsp:setProperty name="test"
property="message"
value="菜鸟教程..." />
<p>输出信息....</p>
<jsp:getProperty name="test" property="message" />
</body>
</html>
jsp:forward动作把请求转到另外的页面。jsp:forward标记只有一个属性page。语法格式如下所示:
<jsp:forward page="相对 URL 地址" />
以下是forward相关联的属性:
属性 | 描述 |
---|---|
page | page属性包含的是一个相对URL。page的值既可以直接给出,也可以在请求的时候动态计算,可以是一个JSP页面或者一个 Java Servlet. |
实例
以下实例我们使用了两个文件,分别是: date.jsp 和 main.jsp。
date.jsp 文件代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<p>
今天的日期是: <%= (new java.util.Date()).toLocaleString()%>
</p>
main.jsp文件代码:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<h2>forward 动作实例</h2>
<jsp:forward page="date.jsp" />
</body>
</html>
现在将以上两个文件放在服务器的根目录下,访问main.jsp文件。显示结果如下:
今天的日期是: 2016-6-25 14:37:25
jsp:plugin动作用来根据浏览器的类型,插入通过Java插件 运行Java Applet所必需的OBJECT或EMBED元素。
如果需要的插件不存在,它会下载插件,然后执行Java组件。 Java组件可以是一个applet或一个JavaBean。
plugin动作有多个对应HTML元素的属性用于格式化Java 组件。param元素可用于向Applet 或 Bean 传递参数。
以下是使用plugin 动作元素的典型实例:
<jsp:plugin type="applet" codebase="dirname" code="MyApplet.class"
width="60" height="80">
<jsp:param name="fontcolor" value="red" />
<jsp:param name="background" value="black" />
<jsp:fallback>
Unable to initialize Java Plugin
</jsp:fallback>
</jsp:plugin>
如果你有兴趣可以尝试使用applet来测试jsp:plugin动作元素,元素是一个新元素,在组件出现故障的错误是发送给用户错误信息。
<jsp:element>
、 <jsp:attribute>
、 <jsp:body>
动作元素动态定义XML元素。动态是非常重要的,这就意味着XML元素在编译时是动态生成的而非静态。
以下实例动态定义了XML元素:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<jsp:element name="xmlElement">
<jsp:attribute name="xmlElementAttr">
属性值
</jsp:attribute>
<jsp:body>
XML 元素的主体
</jsp:body>
</jsp:element>
</body>
</html>
<jsp:text>
动作元素允许在JSP页面和文档中使用写入文本的模板,语法格式如下:
<jsp:text>模板数据</jsp:text>
以上文本模板不能包含其他元素,只能只能包含文本和EL表达式(注:EL表达式将在后续章节中介绍)。请注意,在XML文件中,您不能使用表达式如 ${whatever > 0}
,因为>
符号是非法的。 你可以使用 ${whatever gt 0}
表达式或者嵌入在一个CDATA部分的值。
<jsp:text><![CDATA[<br>]]></jsp:text>
如果你需要在 XHTML 中声明 DOCTYPE,必须使用到<jsp:text>
动作元素,实例如下:
<jsp:text><![CDATA[<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"DTD/xhtml1-strict.dtd">]]>
</jsp:text>
<head><title>jsp:text action</title></head>
<body>
<books><book><jsp:text>
Welcome to JSP Programming
</jsp:text></book></books>
</body>
</html>
你可以对以上实例尝试使用及不使用该动作元素执行结果的区别。
class TraditionalTag : Tag {
override fun setParent(t: Tag?) {
TODO()
// 如果当前标签有福标签,则此方法会传入该标签的父标签
}
override fun getParent(): Tag? {
TODO()
}
override fun doStartTag(): Int {
TODO()
//执行到开始标签时调用的方法,返回值指定标签体是否执行
// SKIP_BODY 跳过标签体
// EVAL_BODY_INCLUDE 执行标签体
}
override fun setPageContext(pc: PageContext) {
TODO()
// 传入当前JSP页面的PageContext对象
}
override fun release() {
TODO()
// 表示标签资源被释放,通常在其被容器移除时(服务器shutdown时)调用。
}
override fun doEndTag(): Int {
TODO()
//执行到结束标签时调用,返回值指定标签结束后剩下的页面内容是否执行
// SKIP_PAGE 不执行剩下的内容
// EVAL_PAGE 执行页面剩下的内容
}
}
那么假如我们需要实现一个能够将字符串转换为大写的功能,比如下面这样:
<t:toUpper item="hello world" var="s">
${s}
</t:toUpper>
那么我们要去实现这个标签,注意:我们在标签中声明了两个属性item
和var
,那么一定要在标签对象中提供属性的getter和setter方法(Kotlin直接声明可读写的属性即可)。
class TraditionalTag : Tag {
var item: String? = null
var `var`: String? = null
private var context: PageContext? = null
private var parent: Tag? = null
override fun setParent(parent: Tag?) {
this.parent = parent
}
override fun getParent(): Tag? {
return parent
}
override fun doStartTag(): Int {
val upper = item!!.toUpperCase()
context!!.setAttribute(`var`, upper)
return Tag.EVAL_BODY_INCLUDE
}
override fun setPageContext(context: PageContext) {
this.context = context
}
override fun release() {
}
override fun doEndTag(): Int {
context!!.removeAttribute(`var`)
return Tag.EVAL_PAGE
}
}
然后创建一个tld文件
<taglib xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
version="2.1">
<tlib-version>1.0</tlib-version>
<short-name>tag</short-name>
<uri>http://cccxm.github.com/tag</uri>
<!-- Invoke 'Generate' action to add tags or functions -->
<tag>
<name>toUpper</name>
<tag-class>com.github.cccxm.tag.TraditionalTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>item</name>
<type>java.lang.String</type>
<required>yes</required>
</attribute>
<attribute>
<name>var</name>
<type>java.lang.String</type>
<required>yes</required>
</attribute>
</tag>
</taglib>
tld文件中有四种标签体(body-content)类型 :empty、JSP、scriptless、tagdependent
在简单标签(SampleTag)中标签体body-content的值只允许是empty
、scriptless
、tagdependent
,不允许设置成JSP
,如果设置成JSP就会出现异常。
body-content的值如果设置成empty
,那么就表示该标签没有标签体,如果是设置成scriptless
,那么表示该标签是有标签体的,但是标签体中的内容不可以是<%java代码%>
在传统标签中标签体body-content的值允许是empty
、JSP
、scriptless
、tagdependent
,body-content
的值如果是设置成JSP
,那么表示该标签是有标签体的,并且标签体的内容可以是任意的,包括java代码,如果是设置成scriptless
,那么表示该标签是有标签体的,但是标签体的内容不能是java代码
<%@ taglib uri="http://cccxm.github.com/tag" prefix="t" %>
在每一次被访问的使用调用setPageContext
->setParent
->doStartTag
->doEndTag
当服务器关闭时调用release
使用最基本的TAG接口实现的话,功能太少,如果我们需要使用更多一点的功能,可以使用SimpleTag接口。
简单自定义标签的特点是每次解析过程都会创建一个处理类对象,而不是像传统TAG标签那样只在第一次被解析时创建对象之后永驻内存。当解析完成之后解析对象自动销毁。
当web容器开始执行标签时,会调用如下方法完成标签的初始化:
class StringTag : SimpleTag {
override fun setParent(parent: JspTag?) {
TODO() //TODO
}
override fun getParent(): JspTag? {
TODO() //TODO
}
override fun setJspBody(jspBody: JspFragment?) {
TODO() //TODO
// 获取到的标签体
}
override fun setJspContext(pc: JspContext?) {
TODO() //TODO
}
override fun doTag() {
TODO() //TODO
//业务实现方法
}
}
接下来我们实现一个简单的分割字符串的标签
class StringTag : SimpleTag {
var item: String? = null
var `var`: String? = null
var regex: String? = null
private var parent: JspTag? = null
private var context: JspContext? = null
private var body: JspFragment? = null
override fun setParent(parent: JspTag) {
this.parent = parent
}
override fun getParent() = parent
override fun setJspBody(jspBody: JspFragment?) {
this.body = jspBody
}
override fun setJspContext(context: JspContext) {
this.context = context
}
override fun doTag() {
val items = item!!.split(regex!!.toRegex())
for (i in items) {
context!!.setAttribute(`var`, i)
body!!.invoke(null)
}
}
}
如果我们需要修改标签体的话,则需要指定标签体内容的输出流
val writer = StringWriter()
jspBody.invoke(writer)
//处理writer以修改标签体
jspContext.out.write(writer.toString())
然后再配置tld文件
<tag>
<name>forToken</name>
<tag-class>com.github.cccxm.tag.StringTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>item</name>
<type>java.lang.String</type>
<required>yes</required>
</attribute>
<attribute>
<name>regex</name>
<type>java.lang.String</type>
<required>yes</required>
</attribute>
<attribute>
<name>var</name>
<type>java.lang.String</type>
<required>yes</required>
</attribute>
</tag>
然后我们就可以使用forEach的方式输出分割后的字符串了。
<t:forToken item="a1b2c3d4e" regex="[0-9]" var="s">
${s}<br>
</t:forToken>
上面的接口比TAG接口要方便的多,可是除了doTag其他的方法我们一般都不会做额外的操作,那么为什么不把他们抽取出来呢?
于是,SimpleTagSupport类就诞生了。接下来我们使用简化了的自定义标签实现一个验证字符串的标签。
class MatchTag : SimpleTagSupport() {
var item: String? = null
var regex: String? = null
var result = false
override fun doTag() {
val res = regex!!.toRegex().matches(item!!)
result = res
jspBody.invoke(null)
}
}
class TrueTag : SimpleTagSupport() {
override fun doTag() {
if (parent != null) {
val result = (parent as MatchTag).result
if (result) {
jspBody.invoke(null)
}
}
}
}
class FalseTag : SimpleTagSupport() {
override fun doTag() {
if (parent != null) {
val result = (parent as MatchTag).result
if (!result) {
jspBody.invoke(null)
}
}
}
}
<tag>
<name>match</name>
<tag-class>com.github.cccxm.tag.MatchTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>item</name>
<type>java.lang.String</type>
<required>yes</required>
</attribute>
<attribute>
<name>regex</name>
<type>java.lang.String</type>
<required>yes</required>
</attribute>
</tag>
<tag>
<name>true</name>
<tag-class>com.github.cccxm.tag.TrueTag</tag-class>
<body-content>scriptless</body-content>
</tag>
<tag>
<name>false</name>
<tag-class>com.github.cccxm.tag.FalseTag</tag-class>
<body-content>scriptless</body-content>
</tag>
<t:match item="13012345678" regex="1[0-9]{10}">
<t:true>是手机号</t:true>
<t:false>不是手机号</t:false>
</t:match>
在普通的TAG中,我们通过返回值来决定是否跳过剩余页面,那么在简单标签实现时使用方式是抛出异常
throw SkipPageException()