前言
只有光头才能变强。
文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y
为什么要用到简单标签?
上一篇博客中我已经讲解了传统标签,想要开发自定义标签,大多数情况下都要重写doStartTag(),doAfterBody()和doEndTag()方法,并且还要知道SKIP_BODY,EVAL_BODY等等的变量代表着什么,在什么方法中使用。这样实在是太麻烦了!
因此,为了简化标签开发的复杂度,在JSP 2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口来实现标签的功能。。
一般来说,实现了SimpeTag接口的标签称之为简单标签
SimpleTag接口
public interface SimpleTag extends JspTag { void doTag() throws JspException, IOException; void setParent(JspTag var1); JspTag getParent(); void setJspContext(JspContext var1); void setJspBody(JspFragment var1);}interface SimpleTag extends JspTag {
void doTag() throws JspException, IOException;
void setParent(JspTag var1);
JspTag getParent();
void setJspContext(JspContext var1);
void setJspBody(JspFragment var1);
}
void doTag() throws JspException, IOException;void setJspContext(JspContext var1);void setJspBody(JspFragment var1);
void setJspContext(JspContext var1);
void setJspBody(JspFragment var1);
快速入门
public class Demo1 extends SimpleTagSupport { String format = null; @Override public void doTag() throws JspException, IOException { SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format); this.getJspContext().getOut().write(simpleDateFormat.format(new Date())); } public String getFormat() { return format; } public void setFormat(String format) { this.format = format; }}class Demo1 extends SimpleTagSupport {
String format = null;
@Override
public void doTag() throws JspException, IOException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
this.getJspContext().getOut().write(simpleDateFormat.format(new Date()));
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
}
<tag> <name>formatDate</name> <tag-class>tag.Demo1</tag-class> <body-content>tagdependent</body-content> <attribute> <name>format</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute></tag>
<name>formatDate</name>
<tag-class>tag.Demo1</tag-class>
<body-content>tagdependent</body-content>
<attribute>
<name>format</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/2cce58885013b3cd46103f8650630bfe.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/88d58f1c9c3b6c355f6a29a9ecde41bc.png)
SimpleTagSupport类的执行顺序:
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/deb916b315f9c922bfac704049e4b909.png)
深入简单标签
在我们讲解传统标签的时候,配合着SKIP_BODY、SKIP_PAGE等变量可以实现如下的功能:
控制jsp页面某一部分内容(标签体)是否执行。
控制整个jsp页面是否执行。
控制jsp页面内容重复执行。
修改jsp页面内容输出。
throw new SkipPageException();new SkipPageException();
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/c5d6c59a2d3aa66cbcdcf6ecc088c3a4.png)
带标签体的简单标签
public abstract class JspFragment { public JspFragment() { } public abstract void invoke(Writer var1) throws JspException, IOException; public abstract JspContext getJspContext();}abstract class JspFragment {
public JspFragment() {
}
public abstract void invoke(Writer var1) throws JspException, IOException;
public abstract JspContext getJspContext();
}
JspFragment对象十分简单,重要的只有invoke(Writer var1)方法(获取JspContext对象并不重要,在标签描述器上就可以获取到了)
public abstract void invoke(java.io.Writer out) :
public class Demo1 extends SimpleTagSupport { @Override public void doTag() throws JspException, IOException { //得到代表标签体的对象 JspFragment jspFragment = getJspBody(); //invoke方法接收的是一个Writer,如果为null,就代表着JspWriter(),将标签体的数据写给浏览器! jspFragment.invoke(null); }}class Demo1 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
//得到代表标签体的对象
JspFragment jspFragment = getJspBody();
//invoke方法接收的是一个Writer,如果为null,就代表着JspWriter(),将标签体的数据写给浏览器!
jspFragment.invoke(null);
}
}
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/91fdf1d75414232b76376b70536bf645.png)
public void doTag() throws JspException, IOException { //得到代表标签体的对象 JspFragment jspFragment = getJspBody(); //jspFragment.invoke(null);}
//得到代表标签体的对象
JspFragment jspFragment = getJspBody();
//jspFragment.invoke(null);
}
public void doTag() throws JspException, IOException { //得到代表标签体的对象 JspFragment jspFragment = getJspBody(); jspFragment.invoke(null); jspFragment.invoke(null);}
//得到代表标签体的对象
JspFragment jspFragment = getJspBody();
jspFragment.invoke(null);
jspFragment.invoke(null);
}
//得到代表标签体的对象JspFragment jspFragment = getJspBody();//创建可以存储字符串的Writer对象StringWriter stringWriter = new StringWriter();//invoke()方法把标签体的数据都写给流对象中jspFragment.invoke(stringWriter);//把流对象的数据取出来,流对象的数据就是标签体的内容String value = stringWriter.toString();//将数据改成是大写的,写到浏览器中getJspContext().getOut().write(value.toUpperCase());
JspFragment jspFragment = getJspBody();
//创建可以存储字符串的Writer对象
StringWriter stringWriter = new StringWriter();
//invoke()方法把标签体的数据都写给流对象中
jspFragment.invoke(stringWriter);
//把流对象的数据取出来,流对象的数据就是标签体的内容
String value = stringWriter.toString();
//将数据改成是大写的,写到浏览器中
getJspContext().getOut().write(value.toUpperCase());
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/5530e59b98b226ab0245c73f3d1e9b87.png)
我们可以发现,传统标签能完成的功能,简单标签都可以完成,并且更为简单!
自定义标签的应用
既然我们学了简单标签,我们就用简单标签来做开发吧!
防盗链
在讲解request对象的时候,我们讲解过怎么实现防盗链的功能。现在我们使用标签来进行防盗链!
模拟下场景:1.jsp页面是海贼王资源,2.jsp页面提示非法盗链,index1.jsp是我的首页。别人想要看我的海贼王资源,就必须通过我的首页点进去看,否则就是非法盗链!
@Overridepublic void doTag() throws JspException, IOException { //如果想要做成更加灵活的,就把站点设置和资源设置成标签属性传递进来! //等会我们要获取得到request对象,需要使用到JspContext的子类PageContext PageContext pageContext = (PageContext) this.getJspContext(); //获取request对象 HttpServletRequest httpServletRequest = (HttpServletRequest) pageContext.getRequest(); //获取到referer String referer = httpServletRequest.getHeader("Referer"); //获取到response对象,等会如果是非法盗链,就重定向别的页面上 HttpServletResponse httpServletResponse = (HttpServletResponse) pageContext.getResponse(); //非法盗链! if (referer == null || !referer.startsWith("http://localhost:8080/zhongfucheng")) { //2.jsp提示了非法盗链! httpServletResponse.sendRedirect("/zhongfucheng/2.jsp"); //不执行页面下面的内容了,保护页面 throw new SkipPageException(); }}
public void doTag() throws JspException, IOException {
//如果想要做成更加灵活的,就把站点设置和资源设置成标签属性传递进来!
//等会我们要获取得到request对象,需要使用到JspContext的子类PageContext
PageContext pageContext = (PageContext) this.getJspContext();
//获取request对象
HttpServletRequest httpServletRequest = (HttpServletRequest) pageContext.getRequest();
//获取到referer
String referer = httpServletRequest.getHeader("Referer");
//获取到response对象,等会如果是非法盗链,就重定向别的页面上
HttpServletResponse httpServletResponse = (HttpServletResponse) pageContext.getResponse();
//非法盗链!
if (referer == null || !referer.startsWith("http://localhost:8080/zhongfucheng")) {
//2.jsp提示了非法盗链!
httpServletResponse.sendRedirect("/zhongfucheng/2.jsp");
//不执行页面下面的内容了,保护页面
throw new SkipPageException();
}
}
<zhongfucheng:Referer/><html><head> <title></title></head><body>海贼王最新资源</body></html>
<html>
<head>
<title></title>
</head>
<body>
海贼王最新资源
</body>
</html>
<h1>这是首页!</h1><a href="${pageContext.request.contextPath}/1.jsp"> 海贼王最新资源</a></h1>
<a href="${pageContext.request.contextPath}/1.jsp"> 海贼王最新资源</a>
<body>你是非法盗链的!!!!!!</body>
你是非法盗链的!!!!!!
</body>
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/b73802e0a9089ce31fd8e79a414fa2c7.gif)
if标签
在JSTL中,我们已经使用过了<c:if/>
标签了,现在我们学习了自定义标签,可以开发类似于JSTL的if标签了!
既然是if标签,那么就需要编写带属性和带标签体的标签(需要判断是true还是false呀!,通过判断是否为真值来决定是否执行标签体的内容)
public class Demo1 extends SimpleTagSupport { //定义一个Boolean类型的变量 boolean test ; @Override public void doTag() throws JspException, IOException { //获取到代表标签体内容的对象 JspFragment jspFragment = this.getJspBody(); //如果为真值才执行标签体的内容 if (test == true) { jspFragment.invoke(null); } } public boolean isTest() { return test; } public void setTest(boolean test) { this.test = test; }}class Demo1 extends SimpleTagSupport {
//定义一个Boolean类型的变量
boolean test ;
@Override
public void doTag() throws JspException, IOException {
//获取到代表标签体内容的对象
JspFragment jspFragment = this.getJspBody();
//如果为真值才执行标签体的内容
if (test == true) {
jspFragment.invoke(null);
}
}
public boolean isTest() {
return test;
}
public void setTest(boolean test) {
this.test = test;
}
}
<tag> <name>if</name> <tag-class> tag.Demo1</tag-class> <body-content>scriptless</body-content> <attribute> <name>test</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute></tag>if</name>
<tag-class> tag.Demo1</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>test</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/bde6204ac43225ccb11a65f5017553be.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/065f7a53305cf41616a69f1cdbefbba0.png)
forEach标签
forEach标签最基本的功能:遍历集合、数组
public class Demo2 extends SimpleTagSupport { //遍历的是List集合,于是标签的属性就为List private List items; //遍历出来的对象就用Object存着,因为我们不知道List集合保存的是什么元素 private Object var; @Override public void doTag() throws JspException, IOException { //获取到迭代器 Iterator iterator = items.iterator(); //遍历集合 while (iterator.hasNext()) { //获取到集合的元素 var = iterator.next(); //.....var属性代表的就是集合的元素,现在问题来了,好像在标签体内无法获取到这个对象.... //做到这里完成不下去了.... } } public void setItems(List items) { this.items = items; } public void setVar(Object var) { this.var = var; }}class Demo2 extends SimpleTagSupport {
//遍历的是List集合,于是标签的属性就为List
private List items;
//遍历出来的对象就用Object存着,因为我们不知道List集合保存的是什么元素
private Object var;
@Override
public void doTag() throws JspException, IOException {
//获取到迭代器
Iterator iterator = items.iterator();
//遍历集合
while (iterator.hasNext()) {
//获取到集合的元素
var = iterator.next();
//.....var属性代表的就是集合的元素,现在问题来了,好像在标签体内无法获取到这个对象....
//做到这里完成不下去了....
}
}
public void setItems(List items) {
this.items = items;
}
public void setVar(Object var) {
this.var = var;
}
}
上面的思路是正常的,但是做不下去!我们换一个思路呗。上面的问题主要是在标签体获取不到被遍历出来的对象!
我们这样做:把var定义成String类型的,如果遍历得到对象了,就设置PageContext的属性,var为关键字,对象为值。在标签体用EL表达式搜索以var为关键字的对象!每遍历出一个对象,就执行一次标签体!
public class Demo1 extends SimpleTagSupport { //遍历的是List集合,定义List集合成员变量 private List items; //以var为关键字存储到PageContext private String var; @Override public void doTag() throws JspException, IOException { //获取到集合的迭代器 Iterator iterator = items.iterator(); //获取到代表标签体内容的对象 JspFragment jspFragment = this.getJspBody(); //遍历集合 while (iterator.hasNext()) { Object o = iterator.next(); //把遍历出来的对象存储到page范围中,关键字为标签的属性var(在标签体中使用EL表达式${var},就能够获取到集合的对象了!) this.getJspContext().setAttribute(var, o); //每设置了一个属性,我就执行标签体 jspFragment.invoke(null); } } public void setItems(List items) { this.items = items; } public void setVar(String var) { this.var = var; }}class Demo1 extends SimpleTagSupport {
//遍历的是List集合,定义List集合成员变量
private List items;
//以var为关键字存储到PageContext
private String var;
@Override
public void doTag() throws JspException, IOException {
//获取到集合的迭代器
Iterator iterator = items.iterator();
//获取到代表标签体内容的对象
JspFragment jspFragment = this.getJspBody();
//遍历集合
while (iterator.hasNext()) {
Object o = iterator.next();
//把遍历出来的对象存储到page范围中,关键字为标签的属性var(在标签体中使用EL表达式${var},就能够获取到集合的对象了!)
this.getJspContext().setAttribute(var, o);
//每设置了一个属性,我就执行标签体
jspFragment.invoke(null);
}
}
public void setItems(List items) {
this.items = items;
}
public void setVar(String var) {
this.var = var;
}
}
<tag> <name>forEach</name> <tag-class>tag.Demo1</tag-class> <body-content>scriptless</body-content> <attribute> <name>var</name> <rtexprvalue>true</rtexprvalue> <!--字符串即可,不需要EL表达式的支持--> <required>false</required> </attribute> <attribute> <name>items</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute></tag>
<name>forEach</name>
<tag-class>tag.Demo1</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>var</name>
<rtexprvalue>true</rtexprvalue>
<!--字符串即可,不需要EL表达式的支持-->
<required>false</required>
</attribute>
<attribute>
<name>items</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<% List list = new ArrayList(); list.add("zhongfucneng"); list.add("1"); list.add("2"); list.add("3"); request.setAttribute("list",list);%><zhongfucheng:forEach items="${list}" var="str"> ${str}</zhongfucheng:forEach>new ArrayList();
list.add("zhongfucneng");
list.add("1");
list.add("2");
list.add("3");
request.setAttribute("list",list);
%>
<zhongfucheng:forEach items="${list}" var="str">
${str}
</zhongfucheng:forEach>
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/0d13c272bf0b125a8eb91b9d8bcd234e.png)
上面写的仅仅能够遍历List集合,做一个通用的forEach标签麻烦的是在:不知道传进来的是什么类型的数组、什么类型集合!,需要逐一去判断
//如果items是Collection类型的,就强转为Colletionif (items instanceof Collection) { collection = (Collection) items;}//如果itmes是Map类型的,那么就强转为Map,再获取到<Map.Entry<K, V>,这个是Set集合的!if (items instanceof Map) { Map map = (Map) items; collection = (Collection) map.entrySet();}//对象数组if (items instanceof Object[]) { Object[] objects = (Object[]) items; collection = Arrays.asList(objects);}//int[],Byte[],char[]等八大基本数据类型.....
if (items instanceof Collection) {
collection = (Collection) items;
}
//如果itmes是Map类型的,那么就强转为Map,再获取到<Map.Entry<K, V>,这个是Set集合的!
if (items instanceof Map) {
Map map = (Map) items;
collection = (Collection) map.entrySet();
}
//对象数组
if (items instanceof Object[]) {
Object[] objects = (Object[]) items;
collection = Arrays.asList(objects);
}
//int[],Byte[],char[]等八大基本数据类型.....
还有int[],byte[],char[]等八大基本数据类型,这八大基本数据类型就不能用Arrays.asList()把引用传进去了。因为JDK5以后会把引用自动装箱成Interger[]、Byte[]等等,而不是获取到数组的元素数据。
public static void main(String[] args) { int[] ints = new int[]{1, 2, 3}; Object[] objects = new Object[]{"1", "2", "3"}; if (objects instanceof Object[]) { Collection collection = Arrays.asList(objects); System.out.println(collection); } if (ints instanceof int[]) { Collection collection1 = Arrays.asList(ints); System.out.println(collection1); }}
int[] ints = new int[]{1, 2, 3};
Object[] objects = new Object[]{"1", "2", "3"};
if (objects instanceof Object[]) {
Collection collection = Arrays.asList(objects);
System.out.println(collection);
}
if (ints instanceof int[]) {
Collection collection1 = Arrays.asList(ints);
System.out.println(collection1);
}
}
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/706ac9f4617f54d86ad6ec5780d3d811.png)
if (items instanceof int[]) { int[] ints = (int[]) items; collection = new ArrayList(); for (int anInt : ints) { collection.add(anInt); }}//......这里还要写7个instanceof int[]) {
int[] ints = (int[]) items;
collection = new ArrayList();
for (int anInt : ints) {
collection.add(anInt);
}
}
//......这里还要写7个
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/39e68a69760419a4453a99fb8bce3c60.jpeg)
由于JDK5的新特性,我们又有另外的解决方案,Class对象能够判断是否为数组类,reflect反射包下Array类:
public class Demo1 extends SimpleTagSupport { //遍历的是未知的集合或数组,定义成Object private Object items; //每次被遍历的对象存储关键字 private String var; //Colletion private Collection collection; //在WEB容器设置标签的属性的时候,判断是什么类型的数组和集合 public void setItems(Object items) { this.items = items; //如果items是Collection类型的,就强转为Colletion if (items instanceof Collection) { collection = (Collection) items; } //如果itmes是Map类型的,那么就强转为Map,再获取到<Map.Entry<K, V>,这个是Set集合的! if (items instanceof Map) { Map map = (Map) items; collection = (Collection) map.entrySet(); } //可以这样解决,Class对象判断是否是一个数组类 if (items.getClass().isArray()) { //创建Collection集合添加数组的元素! collection = new ArrayList(); //再利用reflect包下的Array类获取到该数组类的长度 int len = Array.getLength(items); //遍历并添加到集合中 for (int i = 0; i < len; i++) { collection.add(Array.get(items, i)); } } } public void setVar(String var) { this.var = var; } @Override public void doTag() throws JspException, IOException { //获取到代表标签体内容的对象 JspFragment jspFragment = this.getJspBody(); Iterator iterator = collection.iterator(); //遍历集合 while (iterator.hasNext()) { Object o = iterator.next(); //把遍历出来的对象存储到page范围中(在标签体中使用EL表达式${var},就能够获取到集合的对象了!) this.getJspContext().setAttribute(var, o); jspFragment.invoke(null); } }}class Demo1 extends SimpleTagSupport {
//遍历的是未知的集合或数组,定义成Object
private Object items;
//每次被遍历的对象存储关键字
private String var;
//Colletion
private Collection collection;
//在WEB容器设置标签的属性的时候,判断是什么类型的数组和集合
public void setItems(Object items) {
this.items = items;
//如果items是Collection类型的,就强转为Colletion
if (items instanceof Collection) {
collection = (Collection) items;
}
//如果itmes是Map类型的,那么就强转为Map,再获取到<Map.Entry<K, V>,这个是Set集合的!
if (items instanceof Map) {
Map map = (Map) items;
collection = (Collection) map.entrySet();
}
//可以这样解决,Class对象判断是否是一个数组类
if (items.getClass().isArray()) {
//创建Collection集合添加数组的元素!
collection = new ArrayList();
//再利用reflect包下的Array类获取到该数组类的长度
int len = Array.getLength(items);
//遍历并添加到集合中
for (int i = 0; i < len; i++) {
collection.add(Array.get(items, i));
}
}
}
public void setVar(String var) {
this.var = var;
}
@Override
public void doTag() throws JspException, IOException {
//获取到代表标签体内容的对象
JspFragment jspFragment = this.getJspBody();
Iterator iterator = collection.iterator();
//遍历集合
while (iterator.hasNext()) {
Object o = iterator.next();
//把遍历出来的对象存储到page范围中(在标签体中使用EL表达式${var},就能够获取到集合的对象了!)
this.getJspContext().setAttribute(var, o);
jspFragment.invoke(null);
}
}
}
<% /*list集合*/ List list = new ArrayList(); list.add("zhongfucneng"); list.add("1"); list.add("2"); list.add("3"); request.setAttribute("list",list); /*基本数据类型数组*/ int[] ints = new int[]{1, 2, 3, 4, 5}; request.setAttribute("ints", ints); /*对象数组*/ Object[] objects = new Object[]{2, 3, 4, 5, 6}; request.setAttribute("objects", objects); /*map集合*/ Map map = new HashMap(); map.put("aa", "aa"); map.put("bb", "bb"); map.put("cc", "cc"); request.setAttribute("map",map);%> List集合: <zhongfucheng:forEach items="${list}" var="str"> ${str} </zhongfucheng:forEach> <hr> <hr> 基本数据类型数组: <zhongfucheng:forEach items="${ints}" var="i"> ${i} </zhongfucheng:forEach> <hr> <hr> 对象数组: <zhongfucheng:forEach items="${objects}" var="o"> ${o} </zhongfucheng:forEach> <hr> <hr> map集合: <zhongfucheng:forEach items="${map}" var="me"> ${me.key} = ${me.value} </zhongfucheng:forEach>/*list集合*/
List list = new ArrayList();
list.add("zhongfucneng");
list.add("1");
list.add("2");
list.add("3");
request.setAttribute("list",list);
/*基本数据类型数组*/
int[] ints = new int[]{1, 2, 3, 4, 5};
request.setAttribute("ints", ints);
/*对象数组*/
Object[] objects = new Object[]{2, 3, 4, 5, 6};
request.setAttribute("objects", objects);
/*map集合*/
Map map = new HashMap();
map.put("aa", "aa");
map.put("bb", "bb");
map.put("cc", "cc");
request.setAttribute("map",map);
%>
List集合:
<zhongfucheng:forEach items="${list}" var="str">
${str}
</zhongfucheng:forEach>
<hr>
<hr>
基本数据类型数组:
<zhongfucheng:forEach items="${ints}" var="i">
${i}
</zhongfucheng:forEach>
<hr>
<hr>
对象数组:
<zhongfucheng:forEach items="${objects}" var="o">
${o}
</zhongfucheng:forEach>
<hr>
<hr>
map集合:
<zhongfucheng:forEach items="${map}" var="me">
${me.key} = ${me.value}
</zhongfucheng:forEach>
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/0863aa5436a2c364cf5369e596369a05.png)
HTML转义标签
要开发这个标签就很简单了,只要获取到标签体的内容,再通过经过方法转义下标签体内容,输出给浏览器即可!
public class Demo1 extends SimpleTagSupport { @Override public void doTag() throws JspException, IOException { //获取到标签体的内容再修改 StringWriter stringWriter = new StringWriter(); JspFragment jspFragment = this.getJspBody(); jspFragment.invoke(stringWriter); String content = stringWriter.toString(); //经过filter()转义,该方法在Tomcat可以找到 content = filter(content); //再把转义后的内容输出给浏览器 this.getJspContext().getOut().write(content); } private String filter(String message) { if (message == null) return (null); char content[] = new char[message.length()]; message.getChars(0, message.length(), content, 0); StringBuffer result = new StringBuffer(content.length + 50); for (int i = 0; i < content.length; i++) { switch (content[i]) { case '<': result.append("<"); break; case '>': result.append(">"); break; case '&': result.append("&"); break; case '"': result.append("""); break; default: result.append(content[i]); } } return (result.toString()); }}class Demo1 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
//获取到标签体的内容再修改
StringWriter stringWriter = new StringWriter();
JspFragment jspFragment = this.getJspBody();
jspFragment.invoke(stringWriter);
String content = stringWriter.toString();
//经过filter()转义,该方法在Tomcat可以找到
content = filter(content);
//再把转义后的内容输出给浏览器
this.getJspContext().getOut().write(content);
}
private String filter(String message) {
if (message == null)
return (null);
char content[] = new char[message.length()];
message.getChars(0, message.length(), content, 0);
StringBuffer result = new StringBuffer(content.length + 50);
for (int i = 0; i < content.length; i++) {
switch (content[i]) {
case '<':
result.append("<");
break;
case '>':
result.append(">");
break;
case '&':
result.append("&");
break;
case '"':
result.append(""");
break;
default:
result.append(content[i]);
}
}
return (result.toString());
}
}
<zhongfucheng:filter><a href="2.jsp">你好啊</a> </zhongfucheng:filter><br><a href="2.jsp">你好啊
<br>
<a href="2.jsp">你好啊
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/8c6e4635011528f0d44db55a8b1f5289.png)
if else标签
在JSTL中并没有if else的标签,JSTL给予我们的是choose,when,otherwise标签,现在我们模仿choose,when,otherwise开发标签
思路:when标签有个test属性,但otherwise怎么判断标签体是执行还是不执行呢?这时就需要choose标签的支持了!choose标签默认定义一个Boolean值为false,。当when标签体被执行了,就把Boolean值变成true,只要Boolean值为false就执行otherwise标签体的内容。
看程序就容易理解上面那句话了:!
public class Choose extends SimpleTagSupport { private boolean flag; @Override public void doTag() throws JspException, IOException { this.getJspBody().invoke(null); } public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; }}class Choose extends SimpleTagSupport {
private boolean flag;
@Override
public void doTag() throws JspException, IOException {
this.getJspBody().invoke(null);
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
public class When extends SimpleTagSupport { private boolean test ; @Override public void doTag() throws JspException, IOException { Choose choose = (Choose) this.getParent(); //如果test为true和flag为false,那么执行该标签体 if (test == true && choose.isFlag() == false) { this.getJspBody().invoke(null); //修改父标签的flag choose.setFlag(true); } } public void setTest(boolean test) { this.test = test; }}class When extends SimpleTagSupport {
private boolean test ;
@Override
public void doTag() throws JspException, IOException {
Choose choose = (Choose) this.getParent();
//如果test为true和flag为false,那么执行该标签体
if (test == true && choose.isFlag() == false) {
this.getJspBody().invoke(null);
//修改父标签的flag
choose.setFlag(true);
}
}
public void setTest(boolean test) {
this.test = test;
}
}
public class OtherWise extends SimpleTagSupport { @Override public void doTag() throws JspException, IOException { Choose choose = (Choose) this.getParent(); //如果父标签的flag为false,就执行标签体(如果when标签没执行,flag值就不会被修改!when标签没执行,就应该执行otherwise标签!) if (choose.isFlag() == false) { getJspBody().invoke(null); //改父标签的flag为false choose.setFlag(true); } }}class OtherWise extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
Choose choose = (Choose) this.getParent();
//如果父标签的flag为false,就执行标签体(如果when标签没执行,flag值就不会被修改!when标签没执行,就应该执行otherwise标签!)
if (choose.isFlag() == false) {
getJspBody().invoke(null);
//改父标签的flag为false
choose.setFlag(true);
}
}
}
<zhongfucheng:choose> <zhongfucheng:when test="${user!=null}"> user为空 </zhongfucheng:when> <zhongfucheng:otherwise> user不为空 </zhongfucheng:otherwise></zhongfucheng:choose>"${user!=null}">
user为空
</zhongfucheng:when>
<zhongfucheng:otherwise>
user不为空
</zhongfucheng:otherwise>
</zhongfucheng:choose>
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/28c01acb1d20bf6ea96e85112548dc1d.png)
DynamicAttribute接口
此接口的主要功能是用于完成动态属性的设置!前面我们讲解属性标签的时候,属性都是写多少个,用多少个的。现在如果我希望属性可以动态的增加,只需要在标签处理器类中实现DynamicAttribute接口即可!
现在我要开发一个动态加法的标签:
public class Demo1 extends SimpleTagSupport implements DynamicAttributes { //既然有动态属性和动态的值,那么我们就用一个Map集合存储(1-1对应的关系),做的加法运算,值为Double类型的。 Map<String, Double> map = new HashMap<>(); @Override public void doTag() throws JspException, IOException { //定义一个sum变量用于计算总值 double sum = 0.0; //获取到Map集合的数据 Iterator iterator = map.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, Double> entry = (Map.Entry<String, Double>) iterator.next(); sum += entry.getValue(); } //向浏览器输出总和是多少 this.getJspContext().getOut().write(String.valueOf(sum)); } //对于这个要实现的方法,我们只要关注第2个参数和第3个参数即可 //第二个参数表示的是动态属性的名称,第三个参数表示的是动态属性的值 @Override public void setDynamicAttribute(String s, String localName, Object value) throws JspException { //将动态属性的名字和值加到Map集合中 map.put(localName, Double.valueOf(Float.valueOf(value.toString()))); }}class Demo1 extends SimpleTagSupport implements DynamicAttributes {
//既然有动态属性和动态的值,那么我们就用一个Map集合存储(1-1对应的关系),做的加法运算,值为Double类型的。
Map<String, Double> map = new HashMap<>();
@Override
public void doTag() throws JspException, IOException {
//定义一个sum变量用于计算总值
double sum = 0.0;
//获取到Map集合的数据
Iterator iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Double> entry = (Map.Entry<String, Double>) iterator.next();
sum += entry.getValue();
}
//向浏览器输出总和是多少
this.getJspContext().getOut().write(String.valueOf(sum));
}
//对于这个要实现的方法,我们只要关注第2个参数和第3个参数即可
//第二个参数表示的是动态属性的名称,第三个参数表示的是动态属性的值
@Override
public void setDynamicAttribute(String s, String localName, Object value) throws JspException {
//将动态属性的名字和值加到Map集合中
map.put(localName, Double.valueOf(Float.valueOf(value.toString())));
}
}
<tag> <name>dynamicAttribute</name> <tag-class> tag.Demo1</tag-class> <body-content> empty</body-content> <!--这个必须要设置为true--> <dynamic-attributes>true</dynamic-attributes></tag>
<name>dynamicAttribute</name>
<tag-class> tag.Demo1</tag-class>
<body-content> empty</body-content>
<!--这个必须要设置为true-->
<dynamic-attributes>true</dynamic-attributes>
</tag>
<zhongfucheng:dynamicAttribute num="1.1" num2="2.2" num3="1"/>"2.2" num3="1"/>
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/11155177b35b62476137929a86201f9c.png)
开发自定义函数
至于怎么开发自定义函数,在EL表达式的博客中有!
最后
乐于输出干货的Java技术公众号:Java3y。公众号内有200多篇原创技术文章、海量视频资源、精美脑图,不妨来关注一下!
![640](https://i-blog.csdnimg.cn/blog_migrate/4d6c064f75740d9ba93b0ebd0a25a4de.png)