自定义JSP标签需要严谨对照周期图
一.自定义Foreach 标签
1.1编写助手类
上面可以分析,foreach属性有两个属性--items和var,所以就可以编写助手类了
package com.yinzi.jsp; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.BodyTagSupport; /** * foreach循环助手类 * @author 86131 * */ public class ForeachTag extends BodyTagSupport{ private String var; private List<Object> items=new ArrayList<Object>(); public String getVar() { return var; } public void setVar(String var) { this.var = var; } public List<Object> getItems() { return items; } public void setItems(List<Object> items) { this.items = items; } @Override public int doStartTag() throws JspException { //循环判断 if(items.size()==0||items==null) return SKIP_BODY; //迭代器 Iterator<Object> it=items.iterator(); //保存 pageContext.setAttribute(var, it.next());//保存第一个 pageContext.setAttribute("it", it);//保存剩下的在集合中 return EVAL_BODY_INCLUDE; } @Override public int doAfterBody() throws JspException { //执行上面保存的集合 Iterator<Object> it= (Iterator<Object>) pageContext.getAttribute("it"); //判断是否有下一个,如果有就循环遍历 if(it.hasNext()) { //保存第一个 pageContext.setAttribute(var, it.next()); //保存剩下的在集合中 pageContext.setAttribute("it", it); //如果有就再次循环 return EVAL_BODY_AGAIN; } //如果没有就结束 return SKIP_BODY; } }
1.2详解助手类
单独把两个方法拿出来,讲解步骤:
首先,在dostartTag方法里,做一个判断,要是后面没有值了,就返回skip_body,不再执行后面代码,否则继续执行
其次,在doAdterTag方法里继续判断后面的数值,步骤:
- 获取上方集合
- 再次判断,一直循环,直到没有
1.3编写.tld文件
<tag> <!-- 标签库标签的名字 --> <name>foreach</name> <!-- 对应的助手类 --> <tag-class>com.yinzi.jsp.ForeachTag</tag-class> <!-- 代表JSP标签 --> <body-content>JSP</body-content> <!-- 属性 --> <attribute> <!-- 属性名称 --> <name>var</name> <!-- 是否为必填项 --> <required>true</required> <!-- 是否支持EL表达式 --> <rtexprvalue>false</rtexprvalue> </attribute> <attribute> <!-- 属性名称 --> <name>items</name> <!-- 是否为必填项 --> <required>true</required> <!-- 是否支持EL表达式 --> <rtexprvalue>true</rtexprvalue> </attribute> </tag>
1.4 页面输出
记得导入标签库!!
输出结果:
二.数据标签
当一些数据多个页面或者多个地方多次使用时,就可以将它作为数据标签
2.1 编写助手类
就是保存集合,但在WEB项目中会减少很多代码量
package com.yinzi.jsp; import java.util.ArrayList; import java.util.List; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyTagSupport; import com.yinzi.entity.Student; /** * 数据标签助手类 * @author 86131 * */ public class StudentTag extends BodyTagSupport{ private String var; public String getVar() { return var; } public void setVar(String var) { this.var = var; } @Override public int doStartTag() throws JspException { //模拟从数据库获取数据 List<Student> list=new ArrayList(); list.add(new Student(1,"哈哈")); list.add(new Student(2,"嘿嘿")); list.add(new Student(3,"呵呵")); list.add(new Student(4,"啦啦")); //将其保存 pageContext.setAttribute(var, list); return SKIP_BODY; } }
三.select标签
自定义标签将从前的很多行代码减少到只需要一行代码就可实现
3.1编写助手类
package com.yinzi.jsp; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; /** * 下拉框的助手类 */ import javax.servlet.jsp.tagext.BodyTagSupport; public class SelectTag extends BodyTagSupport{ private List<Object> items=new ArrayList();//保存数据 private String optionVal; //保存下拉框的value值 对应实体类的id private String optionText;//保存标签体的内容 对应实体类的name private String selectVal;//被选中 public String getSelectVal() { return selectVal; } public void setSelectVal(String selectVal) { this.selectVal = selectVal; } public List<Object> getItems() { return items; } public void setItems(List<Object> items) { this.items = items; } public String getOptionVal() { return optionVal; } public void setOptionVal(String optionVal) { this.optionVal = optionVal; } public String getOptionText() { return optionText; } public void setOptionText(String optionText) { this.optionText = optionText; } @Override public int doStartTag() throws JspException { //select没有标签体,又要输出内容,所有要用流对象 JspWriter out = pageContext.getOut(); //拼接,写一个拼接的方法 try { out.print(pinjie()); } catch (Exception e) { e.printStackTrace(); } return super.doStartTag(); } /** * 拼接的方法 * @return * @throws Exception */ private String pinjie() throws Exception { //用StringbBuffer StringBuffer sb = new StringBuffer("<select>"); //循环遍历数据 for (Object object : items) { System.out.println(object); //在这里要获取值,所有写一个根据对象取值 String val=getObjattrvalue(object,optionVal);//value值 String text=getObjattrvalue(object, optionText);//标签体内容 sb.append("<option "+(val.equals(selectVal) ? "selected":"")+" value='"+val+"'>"+text+"</option>"); } sb.append("</select>"); return sb.toString(); } /** * 根据对象取值 * @param object 对象 * @param attr 属性 * @return * @throws Exception * */ private String getObjattrvalue(Object object, String attr) throws Exception { //要反射因为不知道有哪些属性和类 //类类 Class c = object.getClass(); Field f = c.getDeclaredField(attr); //打开访问权限 f.setAccessible(true); return f.get(object).toString(); } }
3.2 详解助手类
因为select没有标签体,但是要输出内容,所以需要用流对象进行拼接
拼接的方法,获取值在进行拼接
一切反射从获取类类开始