关于JSTL和EL的使用不再特别记录,需要时单独查看。
此处记录JSP的实用功能--自定义Tag
如果实现自定义Tag不需要处理Body的内容,只需继承SimpleTagSupport或者TagSupport类。
以SimpleTagSupport为例。实现一个可以通过角色控制显示的Button
public class AuthorizationButton extends SimpleTagSupport {
private String role;
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
@Override
public void doTag() throws IOException {
JspContext context = getJspContext();
JspWriter writer = context.getOut();
String displayType = role.equals("admin") ? "block" : "none";
writer.println("<button type='button' class='btn btn-default' style='display:" + displayType + ";'>确认</button>");
}
}
在doTag方法中,根据属性role的内容,决定输出的button的display类型。
属性的定义在标签注册时标明。
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<description>Simple Tag Examples</description>
<tlib-version>1.0</tlib-version>
<short-name>myTag</short-name>
<uri>http://example.com/tag</uri>
<tag>
<description>authorization button</description>
<name>authButton</name>
<tag-class>com.sample.servlet.AuthorizationButton</tag-class>
<body-content>empty</body-content>
<attribute>
<name>role</name>
<required>true</required>
</attribute>
</tag>
</taglib>
name 标签名称
tag-class 标签处理的Java类
attribute 定义标签属性
uri 资源标识符
bodycontent
参考文章:http://blog.csdn.net/aaa1117a8w5s6d/article/details/8157212
body-content的值有下面4种:
<xsd:enumeration value="tagdependent"/>
<xsd:enumeration value="JSP"/>
<xsd:enumeration value="empty"/>
<xsd:enumeration value="scriptless"/>
tagdependent:标签体内容直接被写入BodyContent,由自定义标签类来进行处理,而不被JSP容器解释,
如下:
<test:myList>
select name,age from users
</test:myList>
JSP:接受所有JSP语法,如定制的或内部的tag、scripts、静态HTML、脚本元素、JSP指令和动作。如:
<my:test>
<%=request.getProtocol()%> // ②
</my:test>
具体可参考后面附源码。
empty:空标记,即起始标记和结束标记之间没有内容。
下面几种写法都是有效的,
<test:mytag />
<test:mytag uname="Tom" />
<test:mytag></test:mytag>
scriptless:接受文本、EL和JSP动作。
定义之后,就可以在JSP中引用该Tag
语法:<%@taglib uri="http://example.com/tag" prefix="cus"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@taglib uri="http://example.com/tag" prefix="cus"%>
<%@include file="./common/include.jsp"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>CustomizeTag</title>
</head>
<body>
<div class="container">
<div class="row" style="margin-top:10px">
<div class="col-md-1">
<cus:authButton role="admin"></cus:authButton>
<cus:authButton role="visitor"></cus:authButton>
</div>
</div>
</div>
</body>
</html>
当Role为admin时,生成的Button会被显示
如果需要处理Body的内容,则应该继承BodyTagSupport
TagSupport与BodyTagSupport的区别参考:(找到的文章都是转发,原文已找不到出处)
1. TagSupport与BodyTagSupport的区别
TagSupport与BodyTagSupport的区别主要是标签处理类是否需要与标签体交互,如果不需要交互就用TagSupport,若需要交互就用BodyTagSupport。
交互就是标签处理类是否要读取标签体的内容和改变标签体返回的内容。
用TagSupport实现的标签,都可以用BodyTagSupport实现,因为BodyTagSupport继承了TagSupport。
2. doStartTag(),doEndTag(),doAfterBody()
1)doStartTag()方法是遇到标签开始时会呼叫的方法,其合法的返回值有EVAL_BODY_INCLUDE和SKIP_BODY。EVAL_BODY_INCLUDE表示将显示标签间的文字,SKIP_BODY则不显示标签间的文字;
2)doEndTag()方法是在遇到标签结束时呼叫的方法,其合法的返回值是EVAL_PAGE和SKIP_PAGE。EVAL_PAGE表示处理完标签后继续执行以下的JSP网页,SKIP_PAGE则不处理接下来的JSP网页;
3)doAfterBody()方法是在显示完标签间的文字后呼叫的,其返回值有EVAL_BODY_AGAIN和SKIP_BODY,EVAL_BODY_AGAIN会再显示一次标签间的文字,SKIP_BODY则继续执行标签处理的下一步。
EVAL_BODY_INCLUDE:把Body读入存在的输出流中,doStartTag()函数可用
EVAL_PAGE:继续处理页面,doEndTag()函数可用
SKIP_BODY:忽略对Body的处理,doStartTag()和doAfterBody()函数可用
SKIP_PAGE:忽略对余下页面的处理,doEndTag()函数可用
EVAL_BODY_TAG:已经废止,由EVAL_BODY_BUFFERED取代
EVAL_BODY_BUFFERED:申请缓冲区,由setBodyContent()函数得到的BodyContent对象来处理tag的 body,如果类实现了BodyTag,那么doStartTag()可用,否则非法。
调用顺序:(图片参考:http://blog.csdn.net/zljjava/article/details/17420809)
假设,此处实现一个通过角色控制的Label,只有角色为admin时才会生成Label并且输出内容
public class AuthorizationLabel extends BodyTagSupport {
/**
* VersionUID
*/
private static final long serialVersionUID = 1L;
private String role;
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
@Override
public int doStartTag() throws JspException {
// 表示需要处理标签体
return EVAL_BODY_BUFFERED;
}
@Override
public int doAfterBody() throws JspException {
// 取得标签体对象
BodyContent body = getBodyContent();
// 取得标签体的字符串内容
String content = body.getString();
JspWriter writer = bodyContent.getEnclosingWriter();
if (role.equals("admin")) {
try {
writer.println("<label style='font-size:25px;'>" + content + "</label>");
} catch (IOException e) {
e.printStackTrace();
}
}
// 结束对标签体的处理
return SKIP_BODY;
}
}
在之前的tld文件中添加这个Label的信息
<tag>
<description>authorization label</description>
<name>authLabel</name>
<tag-class>com.sample.servlet.AuthorizationLabel</tag-class>
<body-content>tagdependent</body-content>
<attribute>
<name>role</name>
<required>true</required>
</attribute>
</tag>
使用实例:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@taglib uri="http://example.com/tag" prefix="cus"%>
<%@include file="./common/include.jsp"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>CustomizeTag</title>
</head>
<body>
<div class="container">
<div class="row" style="margin-top:10px">
<div class="col-md-2" style="text-align:right;">
<cus:authLabel role="admin">Hello world</cus:authLabel>
<cus:authLabel role="visitor">Hello world</cus:authLabel>
</div>
<div class="col-md-1">
<cus:authButton role="admin"></cus:authButton>
<cus:authButton role="visitor"></cus:authButton>
</div>
</div>
</div>
</body>
</html>
只有第一个label会生成
以上两个实例的执行效果图:
以上例子仅作为功能Sample,实际项目中不建议这样通过角色控制控件,个人认为用权限控制更好,例如在Shiro框架下配置指定权限,doTag方法中验证权限。