3.自定义标签实例
3.1 foreach标签
(1)助手类tag
package com.YU; import java.util.ArrayList; 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 List<Object> items = new ArrayList<>(); //封装对象指针:指向数据源中的对象 private String var; public ForeachTag() { // TODO Auto-generated constructor stub } public List<Object> getItems() { return items; } public void setItems(List<Object> items) { this.items = items; } public String getVar() { return var; } public void setVar(String var) { this.var = var; } @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; } @Override public int doStartTag() throws JspException { //判断是否为空,若为空则返回空 if(items==null||items.size()==0) return SKIP_BODY; //获取第一个迭代器对象 Iterator<Object> it = items.iterator(); /** * 获取到的数据源中的第一条数据 */ //将获取到的第一个迭代器对象保存到对象指针中 pageContext.setAttribute(var, it.next()); //将迭代后的迭代器对象保存起来方便再次调用 pageContext.setAttribute("it", it); return EVAL_BODY_INCLUDE; } }
首先封装数据源和指针对象,编写get,set方法,重写doAfterBody和doStartTag方法
在doStartTag方法中先根据数据源获取到迭代器对象并将迭代器保存到对象指针和it对象中,方便后续调用,doStartTag的作用是判断数据源是否为空和获取到数据源中的第一条数据
继续编写doAfter时,先获取到刚刚保存的it对象,然后进行判断数据源中是否有数据,再进行返回数据源中的数据,若没有数据则返回空
(2)tld
<?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"> <description>JSTL 1.1 core library</description> <display-name>JSTL core</display-name> <tlib-version>1.1</tlib-version> <short-name>c</short-name> <uri>http://jsp.YU.cn</uri> <tag> <name>foreach</name> <tag-class>com.YU.ForeachTag</tag-class> <body-content>JSP</body-content> <attribute> <name>items</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>var</name> <required>true</required> <rtexprvalue>false</rtexprvalue> </attribute> </tag> </taglib>
根据助手类定义tag标签
<attribute>:包含属性
<name>:标签名,<required> :指定属性是必须的还是可选的
<rtexprvalue>:表示是否支持EL表达式
标签名为:foreach
将助手类路径写入tag-class标签中
属性为数据源items和对象指针var
两者都为必须,数据源items需要支持EL表达式
注:一定要指定uri路径(需自定义)
(3)jsp
首先引入taglib
uri就是我们之前定义的再tld中定义的uri
1.模拟数据
<% List<Goods> list = new ArrayList(); list.add(new Goods(1,"食品")); list.add(new Goods(2,"服饰")); list.add(new Goods(3,"日用")); request.setAttribute("list", list); %>
2.对比C标签和自定义标签
2.1 C标签
<h1>这是c标签的foreach</h1> <c:forEach items = "${list }" var = "l"> ${l.id }:${l.type } <hr/> </c:forEach>
2.2 自定义标签
<h1>这是自定义标签的foreach</h1>
<Y:foreach items="${list }" var="l">
${l.id }:${l.type } <hr/>
</Y:foreach>
除了方法名不同,效果都是相同的
运行结果:
3.2 数据标签
1.为什么要写数据标签?
当我们需要频繁得访问数据库数据时,为了减轻浏览器压力,提高性能,我们可以将获取到的数据用一个数据标签包裹,方便各个页面进行调用
2.编写流程
2.1 编写助手类
package com.YU; import java.util.ArrayList; import java.util.List; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyTagSupport; public class GoodsTag 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<Goods> list = new ArrayList<>(); list.add(new Goods(1,"食品")); list.add(new Goods(2,"服饰")); list.add(new Goods(3,"日用")); //将数据保存到封装的变量中 pageContext.setAttribute(var, list); return SKIP_BODY; } }
(1).首先定义一个变量保存数据,然后在doStartTag方法中模拟数据库中的数据,再将数据保存到封装的变量中
2.2 在jsp页面中调用
<Y:Goods var="ds"> </Y:Goods> 一号连锁店的商品:${ds }
同样的,保存在数据标签后,在其他页面模块也可以进行调用
<Y:Goods var="ds"> </Y:Goods> 二号连锁店的商品:${ds } </body>
运行结果:
1.
2.
3.3 select标签
1.select助手类
package com.YU; 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<Object>(); //封装下拉框中option的value值 private String optionVal; //封装下拉框中option的标签体内容 private String optionText; public SelectTag() { // TODO Auto-generated constructor stub } 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 { //利用流对象输出下拉框内容 JspWriter out = pageContext.getOut(); try { out.print(toHTML()); } catch (Exception e) { e.printStackTrace(); } return super.doStartTag(); } private String toHTML() throws Exception { //利用StringBuffer增加select标签 StringBuffer select = new StringBuffer("<select>"); //遍历数据源,将option标签和数据添加到select标签中 for (Object object : items) { //编写方法获取到对象中的属性值 String optionval = getObjectAttrValue(object,optionVal); String optiontext = getObjectAttrValue(object, optionText); select.append("<option value='"+optionval+"'>"+optiontext+"</option>"); } select.append("</select>"); return select.toString(); } /** * 编写方法利用反射获取到对象中的属性值 * @param object * @param attr * @return * @throws SecurityException * @throws Exception */ private String getObjectAttrValue(Object object, String attr) throws Exception, SecurityException { Class clz = object.getClass(); Field f = clz.getDeclaredField(attr); f.setAccessible(true); return f.get(object).toString(); } }
先定义好数据源和value值及标签体内容
然后重写doStartTag方法,通过流对象输出下拉框内容
编写一个增加select标签的方法
这里需要注意的是:利用StringBuffer对象存储select标签,提高性能
最后用反射去获取到对象中的属性值
2.dtl
<tag> <name>select</name> <tag-class>com.YU.SelectTag</tag-class> <body-content>JSP</body-content> <attribute> <name>items</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>optionVal</name> <required>true</required> <rtexprvalue>false</rtexprvalue> </attribute> <attribute> <name>optionText</name> <required>true</required> <rtexprvalue>false</rtexprvalue> </attribute> </tag>
设置标签名及属性值
3.导入taglib包
最后进行测试
<% List<Goods> list = new ArrayList<>(); list.add(new Goods(1,"食品")); list.add(new Goods(2,"服饰")); list.add(new Goods(3,"日用")); request.setAttribute("list", list); System.out.println(list); %> ${list } <Y:select items="${list }" optionVal="id" optionText="type"></Y:select>
输出结果: