自定义JSP[if,foreach,数据,select]标签

2022-11-18 20:58:37 浏览数 (1)

学习内容:

  1. 自定义if标签
  2. 自定义foreach标签
  3. 自定义数据标签
  4. 自定义select标签(在同一个页面,放在文章的最后,名字叫index.jsp)

自定义if标签(后续三个标签都是这个步骤)

第一步:写业务

第二步:定义助手类

第三步:定义tld文件

第四步:使用自定义jsp标签(在同一个页面,放在文章的最后,名字叫index.jsp)


第一步:写业务:if标签的test属性必须是一个boolean类型的值,如果test的值为true,那么执行if标签的内容,否则不执行。

第二步:定义助手类

代码语言:javascript复制
package com.zking.jsptag.tag;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
//助手类
public class IfTag extends BodyTagSupport{
	private boolean test;

	@Override
	public int doStartTag() throws JspException {
		if(test)
			return EVAL_BODY_INCLUDE;
		else
			return SKIP_BODY;
	}
	@Override
	public int doEndTag() throws JspException {
		// TODO Auto-generated method stub
		return EVAL_PAGE;
	}
	public boolean isTest() {
		return test;
	}
	public void setTest(boolean test) {
		this.test = test;
	}
}

第三步:定义tld文件:tld文件的属性名是什么意思我就不在赘述了,这个也在我前面一篇文章里面讲解了。当我们tld文件定义好后就可以开始在页面上使用自定义jsp标签了

代码语言:javascript复制
<!DOCTYPE taglib
  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
   "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<!-- 标签库描述符 -->
<taglib xmlns="http://java.sun.com/JSP/TagLibraryDescriptor">
	<!-- 代表标签库的版本号 -->
	<tlib-version>1.0</tlib-version>
	<!-- 代表jsp的版本 -->
	<jsp-version>1.2</jsp-version>
	<!-- 你的标签库的简称 -->
	<short-name>z</short-name>
	<!-- 你标签库的引用uri -->
	<uri>/zking</uri>
<tag>
		<!-- 标签名 -->
		<name>if</name>
		<!-- 标签工具类 -->
		<!-- Class.forName("com.zking.jsptag.tag.TestTag") -->
		<tag-class>com.zking.jsptag.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>

自定义foreach标签

第一步:写业务:在定义foreach标签时我们需要了解它的业务是什么:很显然foreach标签需要得到一个集合,然后再这个集合的基础上遍历这个集合。当我们清楚业务逻辑后就可以开始定义foreach标签了。既然是需要得到一个集合,然后再遍历这个集合。那我们就知道了需要两个属性,一个是得到一个集合属性,另一个是遍历这个集合的值。

第二步:定义助手类

代码语言:javascript复制
package com.zking.jsptag.tag;
import java.util.Collection;
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 Object items;
	private List items;
	//每次遍历所定义的变量名,实际上在这里是将每次循环遍历的结果保存到指定作用域,并以var属性命名
	//	for(String obj : items) {
	//		pageContext.setAttribute("n", obj);
	//	}
	//var=n -> ${n}
	private String var;
	@Override
	public int doStartTag() throws JspException {
		// TODO Auto-generated method stub
		//if(items instanceof Collection)
		//else if(items instanceof Object[])
		//判断items是否为空
		if(null==items) {
			return SKIP_BODY;
		}else {
			//获取items的迭代器
			Iterator it = items.iterator();
			//获取迭代器中的下一个元素(移动下标)
			Object value = it.next();
			//将获取的值保存到page作用域中,并以var来命名
			//pageContext.setAttribute("n", "zs"); -> ${n}
			pageContext.setAttribute(var, value);
			//将剩余未遍历完成的迭代器对象保存到page作用域,留到doAfterBody中再次进行遍历
			pageContext.setAttribute("it", it);
			
			return EVAL_BODY_INCLUDE;
		}
	}
	@Override
	public int doAfterBody() throws JspException {
		//将剩余未遍历完的迭代器取出来
		Iterator it = (Iterator) pageContext.getAttribute("it");
		//使用if判断,判断迭代器中的下一个元素是否存在
		if(it.hasNext()) {
			//获取迭代器中的下一个元素(移动下标)
			Object value = it.next();
			//将获取的值保存到page作用域中,并以var来命名
			//pageContext.setAttribute("n", "zs"); -> ${n}
			pageContext.setAttribute(var, value);
			//将剩余未遍历完成的迭代器对象保存到page作用域,留到doAfterBody中再次进行遍历
			pageContext.setAttribute("it", it);
			return EVAL_BODY_AGAIN;
		}else {
			return SKIP_BODY;
		}
	}
	
	@Override
	public int doEndTag() throws JspException {
		// TODO Auto-generated method stub
		return EVAL_PAGE;
	}
	
	public List getItems() {
		return items;
	}
	public void setItems(List items) {
		this.items = items;
	}
	public String getVar() {
		return var;
	}
	public void setVar(String var) {
		this.var = var;
	}
}

第三步:定义tld文件

代码语言:javascript复制
<!DOCTYPE taglib
  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
   "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<!-- 标签库描述符 -->
<taglib xmlns="http://java.sun.com/JSP/TagLibraryDescriptor">
	<!-- 代表标签库的版本号 -->
	<tlib-version>1.0</tlib-version>
	<!-- 代表jsp的版本 -->
	<jsp-version>1.2</jsp-version>
	<!-- 你的标签库的简称 -->
	<short-name>z</short-name>
	<!-- 你标签库的引用uri -->
	<uri>/zking</uri>
<tag>
		<!-- 标签名 -->
		<name>forEach</name>
		<!-- 标签工具类 -->
		<!-- Class.forName("com.zking.jsptag.tag.TestTag") -->
		<tag-class>com.zking.jsptag.tag.ForeachTag</tag-class>
		<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
		<body-content>jsp</body-content>
		<!-- 自定义标签的属性定义,请注意一定要在标签类中提供对应的get/set方法 -->
		<attribute>
			<!-- 自定义标签的属性名称 -->
			<name>items</name>
			<!-- true表示必填 -->
			<required>true</required>
			<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<!-- 自定义标签的属性名称 -->
			<name>var</name>
			<!-- true表示必填 -->
			<required>true</required>
			<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
			<rtexprvalue>false</rtexprvalue>
		</attribute>
	</tag>

自定义数据(data)标签

第一步:写业务

第二步:定义助手类

代码语言:javascript复制
package com.zking.jsptag.tag;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
import com.zking.jsptag.entity.Dept;
import com.zking.jsptag.entity.RoleType;
/**
 * 助手类
 * 自定义的数据标签,大家可以参考从数据库中获取数据,此案例用的是静态数据
 * @author Administrator
 *
 */
public class DeptTag extends BodyTagSupport {
	//将查询出来的数据保存到指定的作用域,并以var属性命名
	private String var;
	//可以通过该参数指明你所需要存储的作用域(page/request/session/application)默认page
	private String scope;
	
	@Override
	public int doStartTag() throws JspException {
		//1)从数据库中查询数据(大家自行考虑)
		//2)本案例的静态数据填充
		/*List<Dept> lst = new ArrayList<>();
		lst.add(new Dept(1,"研发部"));
		lst.add(new Dept(2,"人事部"));
		lst.add(new Dept(3,"市场部"));*/
		List<RoleType> lst = new ArrayList<>();
		lst.add(new RoleType(1,"管理员"));
		lst.add(new RoleType(2,"高级用户"));
		lst.add(new RoleType(3,"普通用户"));
		//获取Request对象
		HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
		//获取Session对象
		HttpSession session = request.getSession();
		//获取Application
		ServletContext application = pageContext.getServletContext();
		//判断scope
		if(null==scope) {
			pageContext.setAttribute(var, lst);
		}else if(scope.equals("request")) {
			request.setAttribute(var, lst);
		}else if(scope.equals("session")) {
			request.setAttribute(var, lst);
		}else if(scope.equals("application")) {
			request.setAttribute(var, lst);
		}else {
			pageContext.setAttribute(var, lst);
		}
		return SKIP_BODY;
	}
	
	@Override
	public int doEndTag() throws JspException {
		// TODO Auto-generated method stub
		return EVAL_PAGE;
	}
	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;
	}
}

第三步:定义tld文件

代码语言:javascript复制
<!DOCTYPE taglib
  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
   "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<!-- 标签库描述符 -->
<taglib xmlns="http://java.sun.com/JSP/TagLibraryDescriptor">
	<!-- 代表标签库的版本号 -->
	<tlib-version>1.0</tlib-version>
	<!-- 代表jsp的版本 -->
	<jsp-version>1.2</jsp-version>
	<!-- 你的标签库的简称 -->
	<short-name>z</short-name>
	<!-- 你标签库的引用uri -->
	<uri>/zking</uri>
<tag>
		<!-- 标签名 -->
		<name>dept</name>
		<!-- 标签工具类 -->
		<!-- Class.forName("com.zking.jsptag.tag.TestTag") -->
		<tag-class>com.zking.jsptag.tag.DeptTag</tag-class>
		<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
		<body-content>empty</body-content>
		<!-- 自定义标签的属性定义,请注意一定要在标签类中提供对应的get/set方法 -->
		<attribute>
			<!-- 自定义标签的属性名称 -->
			<name>var</name>
			<!-- true表示必填 -->
			<required>true</required>
			<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
			<rtexprvalue>false</rtexprvalue>
		</attribute>
		<attribute>
			<!-- 自定义标签的属性名称 -->
			<name>scope</name>
			<!-- true表示必填 -->
			<required>false</required>
			<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
			<rtexprvalue>false</rtexprvalue>
		</attribute>
	</tag>

自定义select标签

第一步:写业务:使用select标签无疑就是要用到下拉按钮,在下来按钮中我们可以设置样式,可以设置id,可以设置name属性,还可以设置默认选中的值。所以这些都是我们在定义select标签中需要考虑的。那接下来就可以开始我们的助手类了

第二步:定义助手类

代码语言:javascript复制
package com.zking.jsptag.tag;
import java.io.IOException;
import java.lang.reflect.Field;
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 {
	//被遍历的集合或数组List<Dept> -> Dept [deptId,deptName]
	private List items;
	//用于指定绑定到option标签中的value属性的值,值可以被理解为循环遍历对象中的属性名
	//例如:optionValue="deptId"
	private String optionValue;
	//用于指定绑定到option标签中的标签体的值,值可以被理解为循环遍历对象中的属性名
	//例如:optionText="deptName"
	private String optionText;
	@Override
	public int doStartTag() throws JspException {
		try {
			JspWriter out = pageContext.getOut();
			//编写逻辑
			out.write(toSelect());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return SKIP_BODY;
	}
	
	private String toSelect() {
		//面试题:String/StringBuffer/StringBuilder的区别
		
		StringBuffer sb = new StringBuffer();
		//拼接<select>
		sb.append("<select>");
		//拼接请选择
		sb.append("<option value=''>----请选择----</option>");
		//循环遍历items,用于循环生成option标签
		//此处的obj就是Dept,obj可以是任意对象
		for(Object obj : items) {
			//问题:如何从obj中取出对应的属性的值,由optionValue和optionText来决定
			String value = this.getObjValue(obj, this.optionValue);
			String text = this.getObjValue(obj, this.optionText);

			//拼接option标签
			sb.append("<option value='" value "'>" text "</option>");
		}
		//拼接</select>
		return sb.toString();
	}
	
	private String getObjValue(Object obj,String fieldName) {
		String value = null;
		try {
			//一切和反射相关的代码都是从获取类对象开始
			Class cls = obj.getClass();
			//获取对象的属性数组
			Field[] fields = cls.getDeclaredFields();
			//循环遍历属性
			for (Field field : fields) {
				//将对象中的属性名与传入的fieldName进行比较,如果相同,则获取数据,不相同,则不获取数据
				if(field.getName().toUpperCase().equals(fieldName.toUpperCase())) {
					//设置访问权限
					field.setAccessible(true);
					//获取数据
					value = field.get(obj).toString();
				}
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return value;
	}
	
	@Override
	public int doEndTag() throws JspException {
		// TODO Auto-generated method stub
		return EVAL_PAGE;
	}
	public List getItems() {
		return items;
	}
	public void setItems(List items) {
		this.items = items;
	}
	public String getOptionValue() {
		return optionValue;
	}
	public void setOptionValue(String optionValue) {
		this.optionValue = optionValue;
	}
	public String getOptionText() {
		return optionText;
	}
	public void setOptionText(String optionText) {
		this.optionText = optionText;
	}
}

第三步:定义tld文件

代码语言:javascript复制
<!DOCTYPE taglib
  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
   "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<!-- 标签库描述符 -->
<taglib xmlns="http://java.sun.com/JSP/TagLibraryDescriptor">
	<!-- 代表标签库的版本号 -->
	<tlib-version>1.0</tlib-version>
	<!-- 代表jsp的版本 -->
	<jsp-version>1.2</jsp-version>
	<!-- 你的标签库的简称 -->
	<short-name>z</short-name>
	<!-- 你标签库的引用uri -->
	<uri>/zking</uri>
<tag>
		<!-- 标签名 -->
		<name>select</name>
		<!-- 标签工具类 -->
		<!-- Class.forName("com.zking.jsptag.tag.TestTag") -->
		<tag-class>com.zking.jsptag.tag.SelectTag</tag-class>
		<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
		<body-content>empty</body-content>
		<!-- 自定义标签的属性定义,请注意一定要在标签类中提供对应的get/set方法 -->
		<attribute>
			<!-- 自定义标签的属性名称 -->
			<name>items</name>
			<!-- true表示必填 -->
			<required>true</required>
			<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<!-- 自定义标签的属性名称 -->
			<name>optionValue</name>
			<!-- true表示必填 -->
			<required>true</required>
			<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
			<rtexprvalue>false</rtexprvalue>
		</attribute>
		<attribute>
			<!-- 自定义标签的属性名称 -->
			<name>optionText</name>
			<!-- true表示必填 -->
			<required>true</required>
			<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
			<rtexprvalue>false</rtexprvalue>
		</attribute>
	</tag>
</taglib>

private String html()方法

在这个方法中我们需要显示下拉款功能。因为我们是需要使用在jsp页面中的,所以我们需要在这个方法中写入HTML代码。在java代码中要写入HTML代码的话就需要使用拼接的方式来完成。这里有三种方法,第一个StringBuilder,第二个String,第三个StringBuffer。这三个有什么区别呢?(面试题)

StringBuilder

线程不安全,但是在使用拼接的时候速度会很快

String

在每次new的时候会产生新的节点,但是在jdk8之后使用拼接是跟StringBuilder一样的效果

StringBuffer

线程安全,但是速度慢


对应上面的这些,我有两个实体类,下面给你们把代码放出来,第一个是Dept.java,第二个是RoleType.java

代码语言:javascript复制
package com.zking.jsptag.entity;

import java.io.Serializable;

public class Dept implements Serializable {
	private Integer deptId;
	private String deptName;
	
	public Integer getDeptId() {
		return deptId;
	}
	public void setDeptId(Integer deptId) {
		this.deptId = deptId;
	}
	public String getDeptName() {
		return deptName;
	}
	public void setDeptName(String deptName) {
		this.deptName = deptName;
	}
	public Dept() {
		super();
	}
	public Dept(Integer deptId, String deptName) {
		super();
		this.deptId = deptId;
		this.deptName = deptName;
	}
	@Override
	public String toString() {
		return "Dept [deptId="   deptId   ", deptName="   deptName   "]";
	}
	

}
代码语言:javascript复制
package com.zking.jsptag.entity;

import java.io.Serializable;

public class RoleType implements Serializable{
	private Integer roleId;
	private String roleName;
	public Integer getRoleId() {
		return roleId;
	}
	public void setRoleId(Integer roleId) {
		this.roleId = roleId;
	}
	public String getRoleName() {
		return roleName;
	}
	public void setRoleName(String roleName) {
		this.roleName = roleName;
	}
	public RoleType() {
		super();
	}
	public RoleType(Integer roleId, String roleName) {
		super();
		this.roleId = roleId;
		this.roleName = roleName;
	}
	@Override
	public String toString() {
		return "RoleType [roleId="   roleId   ", roleName="   roleName   "]";
	}
}

以上就是几天的分享!

0 人点赞