自定义标签实现(out,if,forEach,dept,select)

目录

1.自定义out标签

2.自定义if标签

3.自定义forEach标签

4.自定义dept数据标签

5.自定义select下拉框标签


在上篇给大家介绍了自定义标签的使用步骤,这篇我们来使用自定义标签

1.自定义out标签

<c:out value=""/>

out标签是空标签,有value属性,创建OutTag标签助手类,定义属性value

package com.zking.tag;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;
import java.io.IOException;

/**
 * 自定义out标签
 */
public class OutTag extends BodyTagSupport {

    private Object value;

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }

    @Override
    public int doStartTag() throws JspException {
        
        JspWriter out = pageContext.getOut();
        try {
            out.write(value.toString());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return SKIP_BODY;
    }

    @Override
    public int doEndTag() throws JspException {
        return EVAL_PAGE;
    }
}

在 mytag.tld标签描述文件中定义out输出标签及属性信息

<tag>
		<!-- 标签名 -->
		<name>out</name>
		<!-- 标签工具类 -->
		<!--Class.forName(com.zking.tag.TestTag)
		ClASSNotFoundException异常
		-->
		<tag-class>com.zking.tag.OutTag</tag-class>
		<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
		<body-content>empty</body-content>
		<!-- 自定义标签的属性定义,请注意一定要在标签类中提供对应的get/set方法 -->
		<attribute>
			<!-- 自定义标签的属性名称 -->
			<name>value</name>
			<!-- true表示必填 -->
			<required>true</required>
			<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
			<rtexprvalue>true</rtexprvalue>
		</attribute>
	</tag>

在指定jsp界面应用自定义out标签

<h2>自定义out标签</h2>
<z:out value="${name}"/>

2.自定义if标签

if是标准标签,有test属性,创建ifTag标签助手类,定义属性text

package com.zking.tag;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;

public class IfTag extends BodyTagSupport {

    //定义if标签的条件判断属性test
    private boolean test;

    public boolean isTest() {
        return test;
    }

    public void setTest(boolean test) {
        this.test = test;
    }

    @Override
    public int doStartTag() throws JspException {
        if(this.test)
            return EVAL_BODY_INCLUDE;
        else
            return SKIP_BODY;
    }

    @Override
    public int doEndTag() throws JspException {
        return EVAL_PAGE;
    }
}

在mytag.tld标签描述文件中定义if判断标签及属性信息

<tag>
		<!-- 标签名 -->
		<name>if</name>
		<!-- 标签工具类 -->
		<!--Class.forName(com.zking.tag.TestTag)
		ClASSNotFoundException异常
		-->
		<tag-class>com.zking.tag.IfTag</tag-class>
		<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
		<body-content>jsp</body-content>
		<!-- 自定义标签的属性定义,请注意一定要在标签类中提供对应的get/set方法 -->
		<attribute>
			<!-- 自定义标签的属性名称 -->
			<name>test</name>
			<!-- true表示必填 -->
			<required>true</required>
			<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
			<rtexprvalue>true</rtexprvalue>
		</attribute>
	</tag>

在指定jsp界面应用自定义if标签

<z:if test="${name eq 'hhh'}">
        今天也很棒

    </z:if>

3.自定义forEach标签

forEach是标准标签,有属性var和items,创建forEachTag标签助手类,定义属性var和items

package com.zking.tag;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
import java.util.Iterator;
import java.util.List;

public class ForEachTag extends BodyTagSupport {

    //循环遍历的变量名
    //将每次循环遍历的结果保存到作用域俄中,并以var属性命名
    //request.setAttribute(var,循环变量的值)
    private String var;

    //循环遍历的集合
    private List items;


    public String getVar() {
        return var;
    }

    public void setVar(String var) {
        this.var = var;
    }

    public List getItems() {
        return items;
    }

    public void setItems(List items) {
        this.items = items;
    }

    @Override
    public int doStartTag() throws JspException {
        if(null!=items && items.size()>0){
            //获取items的迭代器对象
            Iterator it = items.iterator();
            //通过next方法移动下标并取出元素
            Object value = it.next();
            //把当前取出的元素保存到pageContext作用域,并以var属性来命名
            //四大作用域:page/request/session/application
            pageContext.setAttribute(var,value);
            //将没有遍历完成的it迭代器对象保存到page作用域,留到doAfterBody中再次判断是否继续执行
            pageContext.setAttribute("it",it);
            return EVAL_BODY_INCLUDE;

        }
        return SKIP_BODY;
    }

    @Override
    public int doAfterBody() throws JspException {
        //将page作用域中未遍历完的it迭代器对象去出来
        Iterator it = (Iterator)pageContext.getAttribute("it");
        //判断it迭代器对象中的下一个元素是否存在
        if(it.hasNext()){
            //通过next方法移动下标并取出元素
            Object value = it.next();
            //将取出的元素保存到pageContext作用域,并以var属性来命名
            pageContext.setAttribute(var,value);
            //将没有遍历完成的it迭代器对象保存到page作用域,留到doAfterBody中再次判断是否继续执行
            pageContext.setAttribute("it",it);
            return EVAL_BODY_AGAIN;

        }
        return SKIP_BODY;
    }

    @Override
    public int doEndTag() throws JspException {
        return EVAL_PAGE;
    }
}

在mytag.tld标签描述文件中定义forEach循环标签及属性信息

<tag>
		<!-- 标签名 -->
		<name>forEach</name>
		<!-- 标签工具类 -->
		<!--Class.forName(com.zking.tag.TestTag)
		ClASSNotFoundException异常
		-->
		<tag-class>com.zking.tag.ForEachTag</tag-class>
		<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
		<body-content>jsp</body-content>
		<!-- 自定义标签的属性定义,请注意一定要在标签类中提供对应的get/set方法 -->
		<attribute>
			<!-- 自定义标签的属性名称 -->
			<name>var</name>
			<!-- true表示必填 -->
			<required>true</required>
			<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
			<rtexprvalue>false</rtexprvalue>
		</attribute>
		<attribute>
			<!-- 自定义标签的属性名称 -->
			<name>items</name>
			<!-- true表示必填 -->
			<required>true</required>
			<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
			<rtexprvalue>true</rtexprvalue>
		</attribute>
	</tag>

在指定jsp界面应用自定义forEach标签

 <h2>自定义forEach标签</h2>
    <z:forEach items="${names}" var="n">
        你是${n}
    </z:forEach>

4.自定义dept数据标签

创建DeptTag标签助手类,定义属性var和scope,并在mytag.tld标签描述文件中定义DeptTag标签及属性信息

package com.zking.tag;

import com.zking.dao.StudentDao;
import com.zking.entity.Student;

import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
import java.util.List;

public class DeptTag extends BodyTagSupport {

    private String var;

    private String scope;

    public String getVar() {
        return var;
    }

    public void setVar(String var) {
        this.var = var;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }

    @Override
    public int doStartTag() throws JspException {
        //调用Dao层代码从数据库中获取部门数据
        List<Student> lst = new StudentDao().getLike();

        if(null==scope || scope.equalsIgnoreCase("page")){
            pageContext.setAttribute(var,lst);
        }else if(scope.equalsIgnoreCase("request")){
            ServletRequest request = pageContext.getRequest();
            request.setAttribute(var,lst);
        }else if(scope.equalsIgnoreCase("session")){
            HttpSession session = pageContext.getSession();
            session.setAttribute(var,lst);
        }else if(scope.equalsIgnoreCase("application")){
            ServletContext application = pageContext.getServletContext();
            application.setAttribute(var,lst);
        }else{
            pageContext.setAttribute(var,lst);
        }


        return SKIP_BODY;
    }

    @Override
    public int doEndTag() throws JspException {
        return EVAL_PAGE;
    }
}
<tag>
		<!-- 标签名 -->
		<name>dept</name>
		<!-- 标签工具类 -->
		<!--Class.forName(com.zking.tag.TestTag)
		ClASSNotFoundException异常
		-->
		<tag-class>com.zking.tag.DeptTag</tag-class>
		<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
		<body-content>empty</body-content>
		<!-- 自定义标签的属性定义,请注意一定要在标签类中提供对应的get/set方法 -->
		<attribute>
			<!-- 自定义标签的属性名称 -->
			<name>scope</name>
			<!-- true表示必填 -->
			<required>false</required>
			<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
			<rtexprvalue>false</rtexprvalue>
		</attribute>
		<attribute>
			<!-- 自定义标签的属性名称 -->
			<name>var</name>
			<!-- true表示必填 -->
			<required>true</required>
			<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
			<rtexprvalue>false</rtexprvalue>
		</attribute>
	</tag>

5.自定义select下拉框标签

创建SelectTag标签助手类,定义相关属性,并在mytag.tld标签描述文件中定义SelectTag标签及属性信息

package com.zking.tag;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;
import java.lang.reflect.Field;

import java.util.List;

public class SelectTag extends BodyTagSupport {

    //设置select中option的值
    private String value;
    //设置select中option的显示文本
    private String text;

    //数据源
    private List<Object> items;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public List<Object> getItems() {
        return items;
    }

    public void setItems(List<Object> items) {
        this.items = items;
    }

    @Override
    public int doStartTag() throws JspException {
        JspWriter out = pageContext.getOut();
        try {
            out.print(toHtml());
        }catch (Exception e){
            e.printStackTrace();
        }
        return SKIP_BODY;
    }

    private String toHtml() throws NoSuchFieldException {
            //创建Stringbuffer
            StringBuffer sb=new StringBuffer();

            //拼接select标签(开始标签)
            sb.append("<select>");
            for (Object object : items) {
                //反射获取对象中的属性
                //获取Student对象中id属性的值
                Object optionValue=this.getObjValue(value,object);
                //获取Student对象中nmae属性的值
                Object optionText = this.getObjValue(text, object);

                //拼接option标签
                sb.append("<option value='"+optionValue+"'>"+optionText+"</option>");
            }
            //拼接select标签(开始标签)
            sb.append("</select>");
            return sb.toString();
    }

    /**
     *获取对象中属性的值
     * @param fieldName 获取对象中的哪一个属性值的属性名
     * @param obj 获取属性的对象(Student)
     * @return
     */
    private Object getObjValue(String fieldName,Object obj) throws NoSuchFieldException {
        Object val=null;
        try {
            //获取类对象
            Class cls = obj.getClass();

            //获取对象中的属性
            Field[] fields = cls.getDeclaredFields();

            //循环遍历属性
            for (Field field : fields) {
                //判断循环遍历的属性名与传入的参数属性名是否一致
                if(field.getName().toUpperCase().equals(fieldName.toUpperCase())){
                    field.setAccessible(true);
                    //获取属性的值
                    val=field.get(obj);
                    break;
                }
            }

        }catch (Exception e){
            e.printStackTrace();
        }
        return val;

    }

    @Override
    public int doEndTag() throws JspException {
        return EVAL_PAGE;
    }
}
<tag>
		<!-- 标签名 -->
		<name>select</name>
		<!-- 标签工具类 -->
		<!--Class.forName(com.zking.tag.TestTag)
		ClASSNotFoundException异常
		-->
		<tag-class>com.zking.tag.SelectTag</tag-class>
		<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
		<body-content>empty</body-content>
		<!-- 自定义标签的属性定义,请注意一定要在标签类中提供对应的get/set方法 -->
		<attribute>
			<!-- 自定义标签的属性名称 -->
			<name>value</name>
			<!-- true表示必填 -->
			<required>true</required>
			<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
			<rtexprvalue>false</rtexprvalue>
		</attribute>
		<attribute>
			<!-- 自定义标签的属性名称 -->
			<name>text</name>
			<!-- true表示必填 -->
			<required>true</required>
			<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
			<rtexprvalue>false</rtexprvalue>
		</attribute>
		<attribute>
			<!-- 自定义标签的属性名称 -->
			<name>items</name>
			<!-- true表示必填 -->
			<required>true</required>
			<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
			<rtexprvalue>true</rtexprvalue>
		</attribute>
	</tag>

最后是jsp页面自定义标签引用

<%@ page import="java.util.Arrays" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="z" uri="/zking"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
        request.setAttribute("name","hhh");
        String[] names={"hh","aa","cc"};
        request.setAttribute("names", Arrays.asList(names));
    %>

    <h2>自定义test标签</h2>
    <z:test name="${name}">123</z:test>
    <h2>自定义out标签</h2>
    <z:out value="${name}"/>
    <c:out value=""/>
    <h2>自定义if标签</h2>
    <z:if test="${name eq 'hhh'}">
        今天也很棒

    </z:if>

    <h2>自定义forEach标签</h2>
    <z:forEach items="${names}" var="n">
        你是${n}
    </z:forEach>

    <h2>自定义dept标签</h2>
    <z:dept var="depts" scope="request"/>
    ${pageScope.depts}
    <z:forEach items="${requestScope.depts}" var="d">
        编号=${d.getId()} , 姓名=${d.getName()}<br>
    </z:forEach>

    <h2>自定义select标签</h2>
    <z:select value="id" text="name" items="${depts}"/>




</body>
</html>

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以在自定义类中实现 IEnumerable 接口,并在该接口中实现 GetEnumerator 方法,返回一个 IEnumerator 对象,然后就可以使用 foreach 循环遍历该自定义类的实例了。具体实现可以参考以下代码: class MyClass : IEnumerable { private int[] data = { 1, 2, 3, 4, 5 }; public IEnumerator GetEnumerator() { return new MyEnumerator(data); } private class MyEnumerator : IEnumerator { private int[] data; private int position = -1; public MyEnumerator(int[] data) { this.data = data; } public object Current { get { return data[position]; } } public bool MoveNext() { position++; return (position < data.Length); } public void Reset() { position = -1; } } } // 使用 foreach 遍历 MyClass 的实例 MyClass myClass = new MyClass(); foreach (int i in myClass) { Console.WriteLine(i); } ### 回答2: 要在C#中自定义实现foreach功能,需要实现一个可迭代的接口(Iterable Interface)和一个迭代器(Iterator)。 首先,我们的自定义类需要实现一个可迭代的接口,该接口定义了一个用于返回迭代器的方法。通常,这个接口是IEnumerable。使用范型,我们可以定义一个可迭代的接口,接受我们自定义类中的类型作为参数。 接下来,我们需要在自定义类中实现一个迭代器(Iterator)。这个迭代器需要实现一个MoveNext方法和一个Current属性。MoveNext方法用于移动迭代器到下一个元素,并返回一个布尔值,指示是否有更多元素可迭代。Current属性用于获取当前迭代器位置的元素。 下面是一个示例,演示了如何在自定义类中实现foreach功能: ```csharp using System; using System.Collections; using System.Collections.Generic; namespace CustomClassForeachDemo { // 自定义类 class MyCollection<T> : IEnumerable<T> { private T[] elements; public MyCollection(T[] array) { elements = array; } public IEnumerator<T> GetEnumerator() { return new MyEnumerator<T>(elements); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } // 迭代器 class MyEnumerator<T> : IEnumerator<T> { private T[] elements; private int position = -1; public MyEnumerator(T[] array) { elements = array; } public T Current { get { return elements[position]; } } object IEnumerator.Current { get { return Current; } } public bool MoveNext() { position++; return (position < elements.Length); } public void Reset() { position = -1; } public void Dispose() { // 清理资源 } } class Program { static void Main(string[] args) { // 使用自定义类 string[] array = { "A", "B", "C" }; MyCollection<string> collection = new MyCollection<string>(array); foreach (string element in collection) { Console.WriteLine(element); } } } } ``` 在上述示例中,我们首先创建了一个自定义类MyCollection,它实现了IEnumerable<T>接口。在GetEnumerator方法中,我们创建了一个自定义的迭代器MyEnumerator<T>。然后,在Main方法中,我们创建了一个MyCollection<string>对象,并使用foreach语句迭代遍历了数组中的元素。 运行上述代码,会输出以下结果: ``` A B C ``` 通过以上实现,在自定义的类中就可以使用foreach语句进行迭代操作了。 ### 回答3: 在C#中,如果想要使用自定义类的对象来进行foreach循环,需要在该自定义类中实现 IEnumerable 接口。这个接口定义了一个 GetEnumerator 方法,使得类的对象可以返回一个可枚举的枚举器。以下是一个实现示例: ```csharp using System; using System.Collections; // 自定义类 public class MyClass { public int[] numbers; // 构造函数 public MyClass() { // 初始化数组 numbers = new int[] { 1, 2, 3, 4, 5 }; } // 实现 GetEnumerator 方法 public IEnumerator GetEnumerator() { return numbers.GetEnumerator(); } } class Program { static void Main(string[] args) { // 创建 MyClass 对象 MyClass myObject = new MyClass(); // 使用 foreach 进行迭代 foreach (int num in myObject) { Console.WriteLine(num); } } } ``` 在上述示例中,MyClass 类实现了 IEnumerable 接口,并在GetEnumerator方法中返回了 numbers 数组的枚举器。程序中创建了 MyClass 类对象 myObject,并使用 foreach 进行迭代操作,以输出 numbers 数组中的元素。 使用自定义类在 foreach 循环中进行迭代需要实现 IEnumerable 接口,并在 GetEnumerator 方法中返回一个可枚举的枚举器。这样就可以像对待数组或集合一样对待自定义类的对象,并使用 foreach 进行迭代操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值