EL的不足,由JSTL来加强 -> 自定义标签来实现。
1:自定义标签也是类。
2:让用户在JSP页面使用,不引用Java代码的情况下,调用Java代码。
package cn.tag;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;
public class DateTag implements Tag {
/**
* 为了在其他的方法中使用pageContext
*
*/
private PageContext pageContext;
/**
* 当在页面上使用了这个标签,当jsp在运行时,会先调用此方法 <br>
* 将pageContext传递到DataTag类中类
*/
@Override
public void setPageContext(PageContext pc) {
this.pageContext = pc;
}
/**
* 当这个标签开始时,即容器来调用以下的方法 <c:out> 标签的body部分 </c:out>
*/
@Override
public int doStartTag() throws JspException {
// 输出当前时间,到页面上去
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str = sdf.format(new Date());
// 输出如果要输出,获取JspWriter就可以了
JspWriter out = pageContext.getOut();
try {
out.print("当前时间是:" + str);
} catch (Exception e) {
e.printStackTrace();
}
/*
* 返回值是有固定值的 这个的返回值,决定了这个标签后面的body部分如何执行 <br>Tag.EVAL_BODY_INCLUDE
* 执行body部分 SKIP_BODY:不执行body部分不显示
*/
return SKIP_BODY;
}
/**
* 当执行标签结束的时</c:out>时执行以下的代码 <br>
* 返回的值是: SKIP_PAGE : 页面的后面的部分,不执行不显<br>
* EVAL_PAGE : 执行页面的 后面的部分
*/
@Override
public int doEndTag() throws JspException {
return EVAL_PAGE;
}
<?xml version="1.0" encoding="UTF-8" ?>
<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">
</taglib>
以下是开发完成的完整的配置:
<?xml version="1.0" encoding="UTF-8" ?>
<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>ql</short-name>
<!-- 声明标签的引用方式标识符号 -->
<uri>/ql.com</uri>
<!-- 声明自己的标签 -->
<tag>
<!-- 声明标签的名称 -->
<name>date</name>
<!-- 声明标签的服务类 -->
<tag-class>cn.tag.DateTag</tag-class>
<!-- 声明body的内容是什么 -->
<body-content>empty</body-content>
</tag>
</taglib>
<%@ taglib uri="/ql.com" prefix="ql" %>
使用:
<ql:date/>
public class Date2Tag extends TagSupport {
@Override
public int doStartTag() throws JspException {
String str = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(new Date());
JspWriter out = pageContext.getOut();
try {
out.print("当前的时间为:" + str);
} catch (Exception e) {
}
return SKIP_BODY;
}
}
配置:
<tag>
<name>myDate2</name>
<tag-class>cn.tag.Date2Tag</tag-class>
<body-content>empty</body-content>
</tag>
以下是使用:
<ql:myDate2/>
功能:
让程序员在页面上像是使用HTML标签一样,使用Java代码。
防止重复提交:
以下的情况下,可能会发生重复提交:
1:刷新页面。
2:服务或是网络比较慢。
如何防止重复提交:
使用Session
在JSP页面上,生成一个UUID放放到Session中去。
同时在JSP页面上,和验证码一样,自动的提交这个UUID.
后台代码,从提交信息中,和Session中获取这个UUID的值比较。
自定义标签:
public class TokenTag extends TagSupport {
@Override
public int doStartTag() throws JspException {
String uuid = UUID.randomUUID().toString().replace("-", "");
pageContext.getSession().setAttribute("token", uuid);
// 向页面上输出
JspWriter out = pageContext.getOut();
try {
String html = "<input type='hidden' value='" + uuid + "' name='token'/>";
out.print(html);
} catch (Exception e) {
e.printStackTrace();
}
return SKIP_BODY;
}
}
配置:
<tag>
<name>token</name>
<tag-class>cn.tag.TokenTag</tag-class>
<body-content>empty</body-content>
</tag>
JSP 可以包含任意的JSP代码
在doStartTag中返回的是skip_body,则有内容也不显示。
Eval_body_include则显示,执行body部分内容
Empty : 则不能包含任意的内容
Skip_page : 页面的后面的部分不显示
Eval_page : 则页面的后面的部分显示。
<c:out value=”...”/> c前缀 ,out标签功能 value = “...” 属性。
让标签接收属性:
思想:
1:在标签类里面声明setXxx方法用于接收属性的值。
2:在*.tld的配置文件中,声明这个标签类有xxx属性。
3:在JSP页面上,使用标签时,设置属性的值。
修改时间:
<ql:date2 name=”张三”/> - = > 你好张三,当前时间是:...
<!-- 声明属性 -->
<attribute>
<name>name</name>
<required>true</required>
<!-- runtime expression value是否接收运行时间 表达 式的值,即${..} -->
<rtexprvalue>true</rtexprvalue>
<type>java.lang.String</type>
</attribute>
<ql:myDate2 name="Jack"/>
<ql:myDate2 name="${param.name}"/>
<c:forEach items=”${map | list | set | String[] | Ob ject[] | int[] | double[] | .. }” var=”name”>
${name} - > EL - > 表示:pageContext.findAttribute(“name”);从四个域对象中找
</c:forEach>
多一个方法 :
package cn.tag;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
public class ForTag extends TagSupport {
// 声明一个可以遍历的对象
private Iterator<Object> it;
public void setItems(Object obj) {
if (obj instanceof Collection) {// List/Set
it = ((Collection) obj).iterator();
} else if (obj instanceof Map) {
it = ((Map) obj).entrySet().iterator();
} else if (obj.getClass().isArray()) {
// 获取数组的长度
int len = Array.getLength(obj);
List<Object> list = new ArrayList<Object>();
for (int i = 0; i < len; i++) {
Object val = Array.get(obj, i);
list.add(val);
}
it = list.iterator();
} else {
throw new RuntimeException("不接收的类型" + obj.getClass());
}
}
private String var;
public void setVar(String var) {
this.var = var;
}
@Override
public int doStartTag() throws JspException {
if (it.hasNext()) {
// 获取这什个值
pageContext.setAttribute(var, it.next());
return EVAL_BODY_INCLUDE;
} else {
return SKIP_BODY;
}
}
@Override
public int doEndTag() throws JspException {
pageContext.removeAttribute(var);
return EVAL_PAGE;
}
@Override
public int doAfterBody() throws JspException {
if (it.hasNext()) {
// 获取这什个值
pageContext.setAttribute(var, it.next());
return EVAL_BODY_AGAIN;
} else {
return SKIP_BODY;
}
}
}
<tag>
<name>for</name>
<tag-class>cn.tag.ForTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>items</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.Object</type>
</attribute>
<attribute>
<name>var</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
<type>java.lang.String</type>
</attribute>
a
public class HelloTag extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
String str = new Date().toLocaleString();
JspWriter out = getJspContext().getOut();
out.print("你好当前时间是:" + str);
}
}
<tag>
<name>hello</name>
<tag-class>cn.tag.HelloTag</tag-class>
<body-content>empty</body-content>
</tag>
接收属性,就是声明
setXxx,修改tld文件,在页面上传递
private String name;
public void setName(String name) {
this.name = name;
}
<tag>
<name>hello</name>
<tag-class>cn.tag.HelloTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>name</name>
<required>yes</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.String</type>
</attribute>
</tag>