上篇博客地址指路牌:自定义标签(一)
上一篇博客中我们已经讲述了自定义标签的开发步骤和简单实例,这篇博客我们讲述一下两个比较复杂的自定义标签。
按照自定义标签开发步骤,首先写一个助手类:
items:需要遍历的集合;
name(一般来说用var来表示,我因为之前测试改成了name):保存集合中每个元素的key值;
varStatus:是保存index count 属性的对象的key;
代码详解跟随在代码中:
package com.zengjing.jsp.day0202;
import java.util.Iterator;
import java.util.List;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
public class ForEachTag extends BodyTagSupport{
/**
*
*/
private static final long serialVersionUID = 1L;
private List<Object> items;//需要遍历的集合
private String name;//保存集合中每个元素的key值
private String varStatus;//是保存index count 属性的对象的key
//匿名内部类 将其视作对象,index 和count视作属性来操作
public static class Status{
//定义一个index用来读取下标
public int index=0;
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
/**
* 借助index来获取这是第几个值
* @return
*/
public int getCount() {
return this.index+1;
}
/**
* index自增方法
*/
void incremetn(){
this.index++;
}
}
public String getVarStatus() {
return varStatus;
}
public void setVarStatus(String varStatus) {
this.varStatus = varStatus;
}
public List<Object> getItems() {
return items;
}
public void setItems(List<Object> items) {
this.items = items;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 执行到doAfterBody方法时,有需要操作的代码
*/
@Override
public int doAfterBody() throws JspException {
//获取之前存储的迭代器
Iterator<Object> it =(Iterator<Object>) pageContext.getAttribute("it");
//如果他有下一个值
while(it.hasNext()) {
//如果varStatus有值
if(null!=varStatus && !"".equals(varStatus)) {
//获取到varStatus的值
Status s =(Status) pageContext.getAttribute(varStatus);
//执行自增的方法
s.incremetn();
//重新保存到varStatus
pageContext.setAttribute(varStatus, s);
}
//再获取到迭代器的下一个值
Object next = it.next();
//再保存到name中
pageContext.setAttribute(name, next);
//再执行主体一次
return EVAL_BODY_AGAIN;
}
//如果没有下一个值就会跳出主体结束循环
return super.doAfterBody();
}
/**
* 进入助手类首先执行的doStartTag方法
*/
@Override
public int doStartTag() throws JspException {
//第一次进入doStartTag方法的时候,varStatus如果有值,我们需要new一个Status给它,用来读取下标和个数
if(null!=varStatus && !"".equals(varStatus)) {
pageContext.setAttribute(varStatus, new Status());
}
//当集合不是空的时候,我们需要操作集合
if(null!=items && 0!=items.size()) {
//获取到他的迭代器
Iterator<Object> it = items.iterator();
//通过迭代器获取下一个值
Object next = it.next();
//将下一个值保存到name中
pageContext.setAttribute(name, next);
//将迭代器保存到当前页面
pageContext.setAttribute("it", it);
}
return EVAL_BODY_INCLUDE;
}
}
配置tld文件中的属性:
items:必填可为表达式;
name:必填不可为表达式;
varStatus:非必填不可为表达式;
<tag>
<name>forEach</name>
<tag-class>com.zengjing.jsp.day0202.ForEachTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>items</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>name</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>varStatus</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
头部导入taglib标签:
效果图:
依次是集合中的内容、下标、第几个
写forEach标签助手类的时候,保存值的时候一定不能忘记!否则会报空指针异常:
按照自定义标签开发步骤,首先写一个助手类:
items:需要用select展示的集合
name:select的名字
valueKey:保存option中的value的key
textKey:保存option中text文本的key
cssStyle:样式
headKey:默认展示的key值
headValue:默认展示的文本
selectedOptionValue:默认选中的key值
代码详解在代码中:
package com.zengjing.jsp.day0202;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;
import org.apache.commons.beanutils.PropertyUtils;
public class selectTag extends BodyTagSupport{
private List<Object> items;//需要用select展示的集合
private String name;//select的名字
private String valueKey;//保存option中的value的key
private String textKey;//保存option中text文本的key
private String cssStyle;//样式
private String headKey;//默认展示的key值
private String headValue;//默认展示的文本
private String selectedOptionValue;//默认选中的key值
public String getSelectedOptionValue() {
return selectedOptionValue;
}
public void setSelectedOptionValue(String selectedOptionValue) {
this.selectedOptionValue = selectedOptionValue;
}
public String getHeadKey() {
return headKey;
}
public void setHeadKey(String headKey) {
this.headKey = headKey;
}
public String getHeadValue() {
return headValue;
}
public void setHeadValue(String headValue) {
this.headValue = headValue;
}
public String getCssStyle() {
return cssStyle;
}
public void setCssStyle(String cssStyle) {
this.cssStyle = cssStyle;
}
public List<Object> getItems() {
return items;
}
public void setItems(List<Object> items) {
this.items = items;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValueKey() {
return valueKey;
}
public void setValueKey(String valueKey) {
this.valueKey = valueKey;
}
public String getTextKey() {
return textKey;
}
public void setTextKey(String textKey) {
this.textKey = textKey;
}
/**
* 首先实例化助手类进入doStartTag方法
*/
@Override
public int doStartTag() throws JspException {
//获取到out
JspWriter out = pageContext.getOut();
try {
//通过打印输出方法返回的字符串将内容展示在页面
out.println(toHtml());
} catch (Exception e) {
throw new RuntimeException(e);
}
return super.doStartTag();
}
private String toHtml() throws Exception {
//用StringBuffer拼接需要返回的字符串
StringBuffer sb=new StringBuffer();
//拼接开头
sb.append("");
return sb.toString();
}
}
需要配置的tld文件:
items:必填可为表达式
name:非必填不可为表达式
valueKey:必填不可为表达式
textKey:必填不可为表达式
cssStyle:非必填不可为表达式
headKey:非必填不可为表达式
headValue:非必填不可为表达式
selectedOptionValue:非必填不可为表达式
<tag>
<name>select</name>
<tag-class>com.zengjing.jsp.day0202.selectTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>items</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>name</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>valueKey</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>textKey</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>cssStyle</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>headKey</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>headValue</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>selectedOptionValue</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
1.这里用value作比较时需要.toString(),不然因为它本来是object类型会比较不了:
2.拼接时也一定要小心不要拼错!单引号不要忘了!
3.还有反射需要这两个包: