自定义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 + "]"; } }