@cxm-2016
2016-12-28T08:33:25.000000Z
字数 12304
阅读 3557
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 htmlPUBLIC "-//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? = nullvar `var`: String? = nullprivate var context: PageContext? = nullprivate var parent: Tag? = nulloverride 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? = nullvar `var`: String? = nullvar regex: String? = nullprivate var parent: JspTag? = nullprivate var context: JspContext? = nullprivate var body: JspFragment? = nulloverride fun setParent(parent: JspTag) {this.parent = parent}override fun getParent() = parentoverride 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? = nullvar regex: String? = nullvar result = falseoverride fun doTag() {val res = regex!!.toRegex().matches(item!!)result = resjspBody.invoke(null)}}class TrueTag : SimpleTagSupport() {override fun doTag() {if (parent != null) {val result = (parent as MatchTag).resultif (result) {jspBody.invoke(null)}}}}class FalseTag : SimpleTagSupport() {override fun doTag() {if (parent != null) {val result = (parent as MatchTag).resultif (!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()