学习内容:
- 自定义if标签
- 自定义foreach标签
- 自定义数据标签
- 自定义select标签(在同一个页面,放在文章的最后,名字叫index.jsp)
自定义if标签(后续三个标签都是这个步骤)
第一步:写业务
第二步:定义助手类
第三步:定义tld文件
第四步:使用自定义jsp标签(在同一个页面,放在文章的最后,名字叫index.jsp)
第一步:写业务:if标签的test属性必须是一个boolean类型的值,如果test的值为true,那么执行if标签的内容,否则不执行。
第二步:定义助手类
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标签了
<!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标签了。既然是需要得到一个集合,然后再遍历这个集合。那我们就知道了需要两个属性,一个是得到一个集合属性,另一个是遍历这个集合的值。
第二步:定义助手类
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文件
<!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)标签
第一步:写业务
第二步:定义助手类
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文件
<!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标签中需要考虑的。那接下来就可以开始我们的助手类了
第二步:定义助手类
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文件
<!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
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 + "]";
}
}
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 + "]";
}
}