Struts2自定义标签2自定义一个按班级id查询出该班级下的学生,存放进值栈,并遍历出来。

简介: Struts2自定义标签的流程概念: (1)需要两个类:标签类(继承相应的tag类),基本类(继承Component)。标签类专门负责从客户端取得用户输入的一些属性,这个普通的jsp自定义标签一样,取出来以后,需要把取出的属性值赋给基本类。
Struts2自定义标签的流程概念:
(1)需要两个类:标签类(继承相应的tag类),基本类(继承Component)。标签类专门负责从客户端取得用户输入的一些属性,这个普通的jsp自定义标签一样,取出来以后,需要把取出的属性值赋给基本类。从而可以看到基本类里面的属性也跟tag里面差不多。
(2) tag类里面,需要定义你客户端传来的属性。私有化。并相应的set get。
     必须的两个方法是public Component getBean(ValueStack stack,HttpServletRequest req, HttpServletResponse res);
             protected void populateParams();
    第一个方法就是获得一个基本类的对象。在基本类里面需要有传入ValueStack的构造函数,如果基本类逻辑里面需要request或者response,那么需要有传入ValueStack stack, HttpServletRequest req, HttpServletResponse res的构造函数;
    第二个方法是用来将客户端传来的值赋给基本类。这里是继承来的,所以首先调用super的相应方法。我理解上面第一个方法返回的对象就是全局的一个Component对象,也就是第二个方法里面使用的对象。上面这些就是在准备参数。
(3)所有的逻辑都放到了基本类里面了,基本类里面有两个方法是需要覆盖的,当然这是常用的两个方法,还有很多其它的方法,那些继承自jsp里面的 BodyContentTag(好像是)里面的一些方法。简单说说这两个方法是一个是public boolean start(Writer writer);public boolean end(Writer writer);顾名思义,start是标签开始时的输出,end是标签结束时的输出。这里都必须执行父类里面的方法,因为很多的输出Struts2都做 好了,所以要继承过来。然后再将自己需要输出的逻辑通过writer输出字符串就可以了。
    这里面需要注意start的返回值,如果是true表示将标签内的body内容显示出来,否则不显示。end好像无所谓。
第一步:建立tld文件,str.tld在项目根目录webroot/web-inf下(类似web.xml项目启动时,读取tld文件,利用反射,实例化标签对应的java类)
 1 <?xml version="1.0" encoding="UTF-8"?>  
 2     <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">  
 3     <taglib>     <!-- 自定义库标签的根 -->  
 4     <tlibversion>1.2</tlibversion>     <!-- 版本号 -->  
 5     <jspversion>1.1</jspversion>       <!-- JSP版本号 -->  
 6     <shortname>stu</shortname>        <!-- prefix="stu"标签名称-->  
 7     <uri>StudentTags</uri>   <!-- uri="StudentTags" 外界导入标签时,认识的名字,很重要。-->  
 8       
 9     <tag>  
10      <name>selectAll</name>                            <!-- 标签名称 -->  
11      <tagclass>com.bjsxt.sxf.tag.SeclectAllSt</tagclass>          <!-- 对应的java类的全路径 -->  
12     </tag>  
13       
14     <!-- 有属性的标签,可以有多个属性  <attribute>并列 -->  
15       <tag>  
16            <name>selectBySex</name>  <!-- 标签名称 -->
17             <tagclass>com.bjsxt.sxf.tag.SeclectStBySex</tagclass> 
18             <attribute>   <!-- 对应标签的属性。 -->  
19                  <name>sex</name>  
20                  <required>true</required>  <!-- 是必需写的属性,即没有写属性标签不能被正常使用 -->  
21             </attribute>         
22        </tag>  
23       <!-- 按班级学生id查询出班级集合,存放到属性var指定的变量中,然后利用s标签的迭代标签,将var指定的变量存放的学生集合遍历出来 -->
24        <tag>
25                <name>selectByClassId</name> <!-- 标签名称 --> 
26                <tagclass>com.bjsxt.sxf.tag.MyTag</tagclass> <!-- 对应的java类的全路径 -->  
27                <body-content>JSP</body-content><!-- 如果不需要标签体则设置empty,反之设定jsp,内部可以运行jsp所有的语法 -->
28                <attribute>
29                    <name>classId</name><!--指定属性名 和标签java类一致-->
30                    <required>true</required><!--该属性是否是必须,如果非必须没设置则为空。 -->
31                    <rtexprvalue>true</rtexprvalue><!-- 该属性能不能动态使用表达式为该属性赋值 true可以  false不可以  使用脚本和EL表达式来获取动态的值 -->
32                </attribute>
33                <attribute>
34                    <name>var</name>
35                    <required>true</required>
36                    <rtexprvalue>false</rtexprvalue>
37                </attribute>
38                <attribute>
39                    <name>num</name>
40                    <required>false</required>
41                    <rtexprvalue>false</rtexprvalue>
42                </attribute>
43        </tag>
44        
45     </taglib>  
View Code

第二步:建立标签类MyTag.java继承ComponentTagSupport类

 

 1 package com.bjsxt.sxf.tag;
 2 
 3 import javax.servlet.http.HttpServletRequest;
 4 import javax.servlet.http.HttpServletResponse;
 5 
 6 import org.apache.struts2.components.Component;
 7 import org.apache.struts2.views.jsp.ComponentTagSupport;
 8 
 9 import com.opensymphony.xwork2.util.ValueStack;
10 /**
11  * 标签体,传递标签的参数
12 * @ClassName: MyTag 
13 * @Description: TODO(这里用一句话描述这个类的作用) 
14 * @author 尚晓飞
15 * @date 2014-10-21 下午5:07:16 
16 *
17  */
18 public class MyTag extends ComponentTagSupport {
19     private String classId;//标签属性
20     private String num;//标签属性
21     private String var;//标签属性
22     
23     
24     //继承ComponentTagSupport类是为了获得标签中的属性值,并包装成Component对象。继承Component类是为了从Struts2中的ValueStack中获得相对应的值。
25     @Override
26     public Component getBean(ValueStack valueStack, HttpServletRequest req,
27             HttpServletResponse resp) {
28         System.out.println("MyTag.getBean()");//标签运行第一站
29         return new StuComponent(valueStack, req, resp);//返回标签业务逻辑类的对象
30     }
31     
32     //将标签传递过来的值,赋值给标签业务逻辑类中的属性,业务处理逻辑会用到
33     @Override
34     protected void populateParams() {
35         super.populateParams();
36         System.out.println("MyTag.populateParams()");//标签运行第三站
37         StuComponent stuComponent=(StuComponent) getComponent();
38         stuComponent.setVar(var);//将前台传来的存放结果集合的变量名,赋值给逻辑类的父类中一个属性。个人理解,值栈中的一个存放结果集的集合引用。
39         stuComponent.setClassId(classId);
40         stuComponent.setNum(num);
41         //stuComponent.setVard(var);将储存数据的变量传递到标签逻辑类中
42         
43     }
44 
45     public String getClassId() {
46         return classId;
47     }
48 
49     public void setClassId(String classId) {
50         this.classId = classId;
51     }
52 
53     
54     public String getNum() {
55         return num;
56     }
57 
58     public void setNum(String num) {
59         this.num = num;
60     }
61 
62     public String getVar() {
63         return var;
64     }
65 
66     public void setVar(String var) {
67         this.var = var;
68     }
69     
70     
71 
72 }
View Code

 

 

 

第三步:建立标签业务逻辑类StuComponent.java类继承ContextBean类

  1 package com.bjsxt.sxf.tag;
  2 
  3 import java.io.Writer;
  4 import java.util.List;
  5 import java.util.Map;
  6 
  7 import javax.servlet.http.HttpServletRequest;
  8 import javax.servlet.http.HttpServletResponse;
  9 
 10 
 11 import org.apache.struts2.ServletActionContext;
 12 
 13 import org.apache.struts2.components.ContextBean;
 14 import org.apache.struts2.views.annotations.StrutsTag;
 15 import org.apache.struts2.views.annotations.StrutsTagAttribute;
 16 
 17 import org.springframework.context.ApplicationContext;
 18 import org.springframework.web.context.support.WebApplicationContextUtils;
 19 
 20 
 21 
 22 import com.bjsxt.sxf.dao.StudentDao;
 23 import com.bjsxt.sxf.po.Student;
 24 import com.opensymphony.xwork2.util.ValueStack;
 25 
 26 /**
 27  * MyTag标签的业务逻辑
 28 * @ClassName: StuComponent 
 29 * @Description: TODO(这里用一句话描述这个类的作用) 
 30 * @author 尚晓飞
 31 * @date 2014-10-21 下午5:12:31 
 32 *
 33  */
 34 //注解现在还不清楚什么意思,就当时描述作用,没有也行。
 35 @StrutsTag(name="selectByClassId", tldBodyContent="JSP", tldTagClass="com.bjsxt.sxf.tag.MyTag", description="sxf zdy")
 36 public class StuComponent extends ContextBean {
 37     protected  String classId;
 38     protected  String callBack="data";
 39     protected  String num;
 40     protected String vard;
 41     //标签进来,先运行该方法
 42     public StuComponent(ValueStack stack,HttpServletRequest req, HttpServletResponse res) {
 43         super(stack);
 44         System.out.println("StuComponent.StuComponent()");//标签运行第二站
 45         //下面可以直接获取,也可以通过标签体中的populateParams()方法,给该对象中的属性赋值set方法
 46 //        classId=req.getParameter("classId");
 47 //        num=req.getParameter("num");
 48                 
 49     }
 50     
 51     
 52     
 53     
 54     
 55 
 56 
 57     //业务逻辑开始
 58     @Override
 59     public boolean start(Writer writer) {
 60         //班级id
 61         System.out.println("StuComponent.start()");//标签运行第四站
 62         Integer classIds=Integer.valueOf(classId);
 63         //查询出该班级的集合
 64         //ssh框架获取spring的ioc容器,从而获取与数据库交互的dao对象
 65         ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(ServletActionContext.getServletContext());
 66         //获取与数据库交互的dao
 67         StudentDao dao=(StudentDao) app.getBean("StudentDao");
 68         List<Student> students=dao.queryByClassId(classIds);
 69         //获取标签的储存属性名
 70         String varString=getVar();//此方法是继承ContextBean才有的,返回的是存储数据的变量名
 71         if(varString!=null){
 72             callBack=varString;
 73         }
 74         //将得到的数据库数据集合,存放入集合。
 75         //应该是struts2中的值栈,用来存放显示层要去的从数据库查询出来的值
 76         ValueStack stack=getStack();
 77         Map<String, Object> listMap=stack.getContext();
 78         
 79         //标签逻辑类继承ContextBean类时,该类里有getVar()方法返回引用数据的变量
 80         listMap.put(callBack, students);
 81         
 82         //标签类继承Component类时,该类里没有getVar()方法,但可以从标签类中,将引用数据的变量通过 populateParams()
 83         //传递到逻辑类里,直接存放到值栈的map中
 84         //说白了,标签中取出的数据,都是从值栈的map中取,只要值栈的map<key:vlaue>中有key,就能得到value
 85         //listMap.put(vard, students);
 86         
 87         return true;//retrun true则执行标签体内的jsp页面内容,return false则跳过标签体内容,执行标签后面的内容
 88     }
 89 
 90     @Override
 91     public boolean end(Writer writer, String body) {
 92         System.out.println("StuComponent.end()");//标签运行第五站
 93         //清空引用,可以使垃圾回收机制,回收没用的对象,减轻内存压力
 94         getStack().getContext().remove(vard);
 95         
 96         return false;//return false 或true意思暂时不明确
 97     }
 98 
 99 
100     
101     public String getClassId() {
102         return classId;
103     }
104     @StrutsTagAttribute(description="classId",required=true)//必须有
105     public void setClassId(String classId) {
106         this.classId = classId;
107     }
108     public String getCallBack() {
109         return callBack;
110     }
111     public void setCallBack(String callBack) {
112         this.callBack = callBack;
113     }
114     public String getNum() {
115         return num;
116     }
117     @StrutsTagAttribute(description="num",required=false)//非必须
118     public void setNum(String num) {
119         this.num = num;
120     }
121 
122 
123 
124 
125 
126 
127 
128     public String getVard() {
129         return vard;
130     }
131 
132 
133 
134 
135 
136 
137 
138     public void setVard(String vard) {
139         this.vard = vard;
140     }
141 
142     
143     
144     
145     
146 
147 }
View Code

 

第四步:页面测试代码

 

 1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 2 <%@ taglib uri="StudentTags" prefix="stu" %>
 3 <%@ taglib uri="/struts-tags" prefix="s"%>
 4 <%
 5 String path = request.getContextPath();
 6 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
 7 %>
 8 
 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
10 <html>
11   <head>
12   </head>
13   
14   <body>
15     This is my JSP page. <br>
16     <a href="<%=request.getContextPath()%>/StudentAction!reportStudent.action">班级表单下载</a>
17     <!-- 查询出所有学生 -->
18        <stu:selectAll></stu:selectAll>
19        <!-- 查询出指定性别的学生 -->
20        <stu:selectBySex sex="男"></stu:selectBySex>
21        <!-- 查询出指定班级的学生 -->
22        <stu:selectByClassId var="students" classId="1" >
23            <table border="2">
24                <tr>
25                    <td>id</td>
26                    <td>姓名</td>
27                    <td>性别</td>
28                    <td>班级</td>
29                </tr>
30                <s:iterator value="#students" var="stu">
31                    <tr>
32                        <td><s:property value="#stu.id"/></td>
33                        <td><s:property value="#stu.name"/></td>
34                        <td><s:property value="#stu.sex"/></td>
35                        <td><s:property value="#stu.classRoom.name"/></td>
36                    </tr>
37                </s:iterator>
38            </table>
39        </stu:selectByClassId>
40        
41        <h1>我是中国人</h1>
42   </body>
43   
View Code

 

第五步:效果图(只截图了最后一个自定义标签的效果图)

 

 

 

 
   
struts2自定义标签编写tld文件时。<body-content>的意思
 
body-content的值有下面4种:

<xsd:enumeration value="tagdependent"/>

    <xsd:enumeration value="JSP"/>

    <xsd:enumeration value="empty"/>

    <xsd:enumeration value="scriptless"/>

 

 

tagdependent标签体内容直接被写入BodyContent,由自定义标签类来进行处理,而不被JSP容器解释,

如下:

<test:myList>

select name,age from users

</test:myList>

 

JSP接受所有JSP语法,如定制的或内部的tag、scripts、静态HTML、脚本元素、JSP指令和动作。如:

<my:test>

    <%=request.getProtocol()%>      //

</my:test>

具体可参考后面附源码。

 

empty空标记,即起始标记和结束标记之间没有内容。

下面几种写法都是有效的,

<test:mytag />

<test:mytag uname="Tom" />

<test:mytag></test:mytag>

 

scriptless接受文本、EL和JSP动作。如上述使用<body-content> scriptless </body-content>则报错,具体可参考后面附源码。

相关文章
|
1月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
30 1
|
19天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
42 5
|
1月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
27天前
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
43 0
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
166 9
|
1月前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
1月前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
51 4
|
2月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
44 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
1月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
2月前
初步认识栈和队列
初步认识栈和队列
61 10