Java框架之Struts2(六)

一、OGNL表达式语言

Ognl Object Graphic Navigation Language(对象图导航语言),它是一种功能强大的表达式语言(Expression Language,简称为EL),通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。

它使用相同的表达式去存取对象的属性

Struts 2 默认的表达式语言是 OGNL,原因是它相对其它表达式语言具有下面几大优势:

1.支持对象方法调用,如xxx.doSomeSpecial();

2.支持类静态的方法调用和值访问,表达式的格式为@[类全名(包括包路径)]@[方法名 | 值名],

例如:

@[email protected](‘foo %s‘, ‘bar‘)或@[email protected]_NAME;

3.支持赋值操作和表达式串联,如price=100, discount=0.8, calculatePrice(price*discount),这个表达式会返回80;

4.访问OGNL上下文(OGNL context)和ActionContext;

5.操作集合对象。

6.可以直接new一个对象

OGNL 的应用场景

在标签中:

<s:property value="user.username" />  //这个 user.username 是个ognl表达式

配置文件中

<result type="redirect"  > /main.jsp?name=${userName} </result>   //这里的 ${userName} 是ognl表达式

OGNL

访问属性

访问方法

访问静态属性或方法

访问构造函数

访问数组

访问集合

lambda

二、OGNL 应用举例

1) 属性获取

<s:property value="userName"/>  = ${userName}
<s:property value="user.userId"/>    //对象的某属性

多级属性

<s:property value="user.schoolInfo.schoolName" />

2) 调用action中的静态方法

<s:property value="@[email protected]()" />
 /* 附: 必须要加入一个常量
<constant name="struts.ognl.allowStaticMethodAccess" value="true" />  才可以在ognl中调用静态方法
可以在  /org/apache/struts2/default.properties 中,查看到所有常量的值 */

3) 调用JDK 中类的静态方法

<s:property value="@[email protected](50.99)"/>

4) 调用值栈中对象的普通方法

<s:property value="user.testUser()"/> 

5) 调用普通类中的静态属性

<s:property value="@[email protected]"/>

6) 调用构造方法

<s:property value="new cat.bean.UserInfo(100,‘张三‘).userName"/> 

本例要在UserInfo 类中 增加一个构造函数

public UserInfo(int id,String userName){
          this.id=id;
          this.userName=userName;
          System.out.println("this is a dog");
}

7) 获取集合中的内容

假如值栈中有一个ArrayList,里面放的是 叫 userList ,里面的值是 "aaa","bbb","ccc"则可以: <s:property value="userList[0]"/> 得到 aaa

假如值栈中有一个 List<UserInfo>userList,则可以以数组的方式取数据 <s:property value="userList[0].userName"/>

8)  获取 map 中的值

<s:property value="userMap[‘aaa‘].userName"/>  //aaa 是个key

集合的伪属性

OGNL 能调用集合的一些特殊属性,它些属性并不是javaBean 模式的

主要有以下几个

size, isEmpty,

iterator

keys,values

next hasNext

nextElement,hasMoreElements

获取 map 中所有的键<s:property value="userMap.keys"/>

取 list 的长度 <s:property value="userList.size"/>

三、ActionContext 和值栈 

Strut2中 OGNL Context 实现者为 ActionContext 它的结构如下

--- ValueStack (值栈,是根对象)

--- parameters

--- request

--- session

--- application

--- attr

当 struts 接受一个请求的时候, 会迅速的创建 ActionContext, ValueStack, Action, 然后把 Action放到 ValueStack 中,Action 实例对象可以被 OGNL 访问。

注意:

在页面用OGNL设置值()这些访问的都是上下文中的这些对象的属性)

<s:property value="#request.requestKey"/>  注意要用# 不用是访问不到的
<s:property value="#session.sessionKey"/> 

用el表达式也能达到相同的效果

${ requestKey}
${ sessionKey}    

parameters 的应用场景

<result type="redirect">/b.jsp?name=1234455</result>  //注意如果这里不是redirect 方式,是取不到的
<s:property value=#attr.name / >

四、串连多个Action的值栈

1 写两个Action, A,和 B, 里面分别各自放两个不同名和字段,放一个同名的字段

public class A {
         private  String  a_userName;
         private String  a_password;
         private String xxx;

         public String execute(){
                  a_userName="张三";
                  a_password="sys123";
                  xxx="这是A里的xxx的值";
                  return "success";
              }
            }

         public class B {
             private String b_goodsName;
             private String b_goodsNo;
             private String xxx;

         public String execute(){
                b_goodsName="茶杯";
                b_goodsNo="009";
                xxx="这是b里xxx的值";
                return "success";
            }
            <package name="packageOne" namespace="" extends="struts-default">
                <action name="a" class="cat.action.A">
                    <result type="chain">
                        <param name="actionName">b</param>
                    </result>
                </action>

                <action name="b" class="cat.action.B">
                    <result>/Main.jsp</result>
                </action>
            </package>

注意:当struts2接收一个请求的时候,它会迅速的创建一个 上下文对象 ActionContex,然后创建 ValueStack,然后创建。

action,再将 action放到ValueStack中

action  已经放到根对象中去了,我们要访问根对象中的属性,是不需要#号的

五、使用ognl操作集合

采用ognl表达式创建 List/Map集合对象

<s:set> 标签用于将某个值放入指定范围。它有以下两个属性

scope:指定变量被放置的范围,该属性可以接受application、session、request、 page或action。如果没有设置该属性,则默认放置在 OGNL Context 中。

value:赋给变量的值.如果没有设置该属性,则将 ValueStack栈项的值赋给变量。

//例一:操作 List集合
            <s:set var="userList" value="{‘黄世仁‘,‘邓世昌‘,‘李刚‘,‘杨达才‘}" />
             ---//例一
                     s:iterator 标签在迭代时有一个特点,会把当前迭代的对象放在值栈的栈顶
                     <s:iterator value="#userList">
                              <s:property /> <br> //对于 s:property  如果不指定value 则value取值栈顶的值
                     </s:iterator>
             ---//例二
                     <s:iterator value="#userList" id="user">
                             <s:property  value="user" /> <br>  //这里指定了 property的 value 就是 上边的 id
                                 ${user } //这里用El表达式也行
                     </s:iterator>
               --- //例三 (处理声明时使用了scope 属性的集合)
                 <s:set var="userList" value="{‘黄世仁‘,‘邓世昌‘,‘李刚‘,‘杨达才‘}" scope="session" />
                    <s:iterator value="#session.userList" id="user" >
                             <s:property  value="user" /> <br>
                            ${user }
                </s:iterator>
//例二:操作 Map 集合
             //注意,如果map中key对应的value是数字型,则可以不用‘‘号
             <s:set var="userMap" value="#{‘1号首长‘:‘江‘,‘二号首长‘:‘涛‘,‘三号首长‘:‘平‘ }" />
             <s:iterator value="#userMap" >
                  <s:property value="key"/>=    <s:property value="value"/> <br>
             </s:iterator>

               对于集合类型,OGNL表达式可以使用in和not in两个元素符号判断元素是否在某个集合中=============
                <s:if test="‘aaa‘ in {‘aaa‘,‘bbb‘}">
                  在
                  </s:if>
                  <s:else>
                       不在
                 </s:else>

               如果集合是个变量也可以
               <s:if test="‘黄世仁‘ in #userList">
                    在
                  </s:if>
                  <s:else>
                       不在
                 </s:else>

六、ognl表达式的投影功能

1 对项目添加数据库访问,然后在Action中,查出用户列表 userList 放在值栈里

2 UserManage.jsp 中

==全部取出

<s:iterator  value="userList">
<s:property value="userId"/>=<s:property value="userName"/><br>
</s:iterator>

==带投影的

?:获得所有符合逻辑的元素。

^:获得符合逻辑的第一个元素。

$:获得符合逻辑的最后一个元素。

<s:iterator value="userList.{?#this.id>200}">
<s:property value="id"/>=<s:property value="userName"/><br>
</s:iterator>

==用jstl的

<c:forEach var="user" items="${userList}" >
${user.userId}     |     ${user.userName}    <br>
</c:forEach> 

七、struts 标签库概述

Struts2标签分类

(1)UI标签:(User  Interface, 用户界面)标签,主要用于生成HTML元素标签,

UI标签又可分为表单标签非表单标签

(2)非UI标签,主要用于数据访问,逻辑控制等的标签。非UI标签可分为流程控制标签

(包括用于实现分支、循环等流程控制的标签)和数据访问标签(主要包括用户输出ValueStack中的值,完成国际化等功能的)

(3)ajax标签

==流程控制标签

if

elseif

else

append  //合并多个集合到一个新集合里

generator  //把字符串按某种标志进行切割成集合

iterator

merge   //合并多个集合到一个新集合里

sort

subset

==数据访问标签

a

action

bean

date

debug

i18n

include

param

property

push

set

text

url

八、Struts2 数据访问标签

(一)<s:set>  标签  //设置值

<s:set var="dog" value="‘安倍晋三‘" /> 严重注意,dog 是要用单引号扩起来的, var 可以换写成name,但name被废弃了
//取值:
<s:property value="#dog"/> //可以
<s:property value="dog"/> //可以
${dog } //可以
<s:debug />

结过观察,发现如果不指定scope, 它是放在 Stack Context (其实就是context map, Acton Context,OGNL Context,) 中的<hr/>

<c:set var="num1" value="ooooooooo" scope="request" />  这是jstl 标签

关于 scope :
               The scopes available are as follows :-
            application - the value will be set in application scope according to servlet spec. using the name as its key
            session - the value will be set in session scope according to servlet spec. using the name as key
            request - the value will be set in request scope according to servlet spec. using the name as key
            page - the value will be set in page scope according to servlet sepc. using the name as key
            action - the value will be set in the request scope and Struts‘ action context using the name as key    ‘

关于 set 的 参数
                Name     Required  Default Evaluated  Type       Description
                id           false                      false         String       Deprecated. Use ‘var‘ instead  //Deprecated 这个单词是不选成,反对的意思
                name     false                      false         String       Deprecated. Use ‘var‘ instead
                scope    false       action      false         String      The scope in which to assign the variable. Can be application, session, request, page, or action.
                value     false                      false         String       The value that is assigned to the variable named name
                var        false                       false         String       Name used to reference the value pushed into the Value Stack

2.<s:property> 标签

用于输出表达式的值,如果指定value 属性,就输出value 对应的值,如果没有指定,它会输出ValueStack 栈顶的值
1,访问Action值栈中的普通属性:

<s:property value="attrName"/>  

2,访问Action值栈中的对象属性(要有get set方法):

<s:property value="obj.attrName"/>
<s:property value="obj1.obj2.attrName"/> 

3,访问值栈中对象属性的方法

<s:property value="obj.methodName()"/> 

4,访问值栈中action的普通方法:

 <s:property value="methodName()"/> 

5,访问静态方法:

<s:property value="@[email protected]()"/> 

6,访问静态属性:

配置属性文件,允许ognl访问静态方法struts.ognl.allow...=true

<s:property value="@[email protected]"/> 

7,访问Math类的静态方法:

<s:property value="@@min(9,7)"/> 

8,访问普通类的构造方法:

<s:property value="new com.softeem.User(2)"/> 

9,访问集合:

①list集合对象

<s:property value="listName"/> 

②list集合中的某个元素

<s:property value="listName[1]"/> 

③list中某个属性的集合

<s:property value="listName.{field}"/> 

④list中某个属性集合的特定值

<s:property value="listName.{field}[0]"/> 

⑤访问set

<s:property value="setName"/> 

⑥访问set中某个元素

<s:property value="setName[0]"/> 

⑦访问map

<s:property value="mapName"/> 

⑧根据key访问Map中的元素

<s:property value="mapName.username"/>
<s:property value="mapName[‘username‘]"/>
<s:property value="mapName[/"username/"]"/> 

⑨访问map中所有的key

<s:property value="mapName.keys"/> 

10,访问map中所有的values

<s:property value="mapName.values"/> 

11,访问map的大小

<s:property value="mapName.size()"/> 

12,投影

<s:property value="listName.{?#this.age==1}"/>
<s:property value="listName.{^#this.age>1}"/>
<s:property value="listName.{$#this.age==1}"/>
<s:property value="listName.{$#this.age==1}.{age}==null"/>
[]:<s:property value="[0]"/>值栈中的对象 

default:可选属性,如果需要输出的属性值为null,则显示该属性指定的值

escape:可选属性,指定是否格式化HTML代码,不搭荐,应该用escapeHtml

value:可选属性,指定需要输出的属性值,如果没有指定该属性,则默认输出ValueStack栈顶的值。

id:可选属性,指定该元素的标识 这个属性好象在新版本中已经没了

Name                   Required   Default           Evaluated     Type     Description
                default             false                            false                String      The default value to be used if value attribute is null
        //    escape              false        true                  false                Boolean      Deprecated. Use ‘escapeHtml‘. Whether to escape HTML
                escapeCsv            false        false                     false                Boolean      Whether to escape CSV (useful to escape a value for a column)
                escapeHtml          false       true                      false                Boolean      Whether to escape HTML
                escapeJavaScript    false        false                     false                Boolean      Whether to escape Javascript
                escapeXml            false        false                     false                Boolean      Whether to escape XML
                value                false        <top of stack> false                Object      Value to be displayed

//例子:
<s:set var="userName" value="‘struts标签真烂‘"  />  严重注意, 里面要有单引号
<s:property value="#userName" /> //正常该加 #
<s:property value="userName" />  //不加也能取出来
<c:out value="${userName}"></c:out> //用jstl标签也能取

上边的功能完全可以用 jstl标签取代 如下:

<c:set var="userMsg" value="struts 标签库的设计者是白痴" />
${userMsg}
<c:out value="${cat_name}" default  ="--------------------"/>

(二)<s:action> 标签

是用来调用Action的标签,在JSP中页面中,可以具体指定某一命名空间中的某一Action。而标签的主体用于显示及渲染Actionr的处理结果。

action标签有如下几个属性:

1、id:  可选,作为该action的引用ID //作废

2、name:  必填,调用action的名字

3、namespace:  可选,action所在的nqmespace

4、executeResult,可选,指定是否将action的处理结果页面包含到本页面。

5、ignoreContextParame:  可选,指定该页面的请求参数是否需要传入action.

6、var

7、rethrowException

8、flush

//这个userAction的名字,是给本页面中别的标签引用用的,
          <s:action name="listUser" var="page_userAction" executeResult="false"> 如果把executeResult换成true则会把result对应的视图传过来
                <s:param name="paramAAA">调Action时传一个参数</s:param> 可以通过这种方法给被调用的action传参数,在action中可以用值栈的方式取到它
            </s:action>

            <s:iterator value="#userAction.userList"> 可以这样取出被调用的action中的值,注意,这些值是放在 StackContext中的,所以要加#
                <s:property value="userName" />
            </s:iterator>

            <c:forEach var="user" items="${page_userAction.userList}"> 使用jstl 标签,把传过来的值生成一组复选框
                 ${user.userName}: <input type="checkbox" value=‘${user.userId}‘ />
          </c:forEach>

            <s:debug />
== <s:push> 把表达式的值放入valueStack 的栈顶== <s:url> 标签
<s:url action="UserAction" namespace="/test">
<s:param name="userId" value="10"/>
<s:param name="userName" value="‘赵铁冷‘"/> 需要注意: 如果value是汉字,早要加单引号 ,如果是中文,会被url编码
</s:url>
//实例: 访问UserAction
<a href=‘<s:url action="UserAction" namespace=""> //UserAction是配置在xml文件中的名字
   <s:param name="userId" value="10"/>
   <s:param name="userName" value="‘赵铁冷‘"/>
</s:url>‘
> 去Action里串串门 </a>

知识点回顾: 在UserAction中取出 userName

可以在UserAction 中定义一个 userName 字段,生成get和set方法,这是前面常用的 struts取请求参数的方法。硬生生的取得request对象,从requet中取得,这是以前常用的方法,如下:

 HttpServletRequest request=ServletActionContext.getRequest();
                String tempStr=request.getParameter("userName");
                tempStr=new String(userName.getBytes("ISO8859-1"),"UTF-8");
            String userName=URLDecoder.decode(tempStr,"UTF-8"); //其实在这个地方不decode也行
          //打印 userName 

         <s:set name="myurl" value="‘http://www.baidu.com‘"/>
             <s:url value="#myurl" />
         <s:url value="%{#myurl}" />  //它的value默认接收的是字符串,而不是ognl表达式,如果想用表达式得转一下

九、Struts2 流程控制标签

==iterator标签

它的参数,还有 begin 和 end 从第几个元素开始,迭代几个 begin ="2" end="4",用于对集合进行迭代,这里的集合包含List、Set和数组。

<s:set name="list" value="{‘西瓜‘,‘哈密瓜‘,‘大傻瓜‘,‘半拉瓜‘}" />
            <s:iterator value="#list" var="瓜名" status="st">  //这里的var 也可以用 id,但id 不推荐
                <font color=
                           <s:if test="#st.odd">red</s:if>
                           <s:else>blue</s:else>
                         >
                       <s:property value="瓜名"/>
                    count:     <s:property value="#st.getCount()" />
                    index:     <s:property value="#st.getIndex()" />
                </font><br>
            </s:iterator> 

== if else

 <s:set var="广告名" value="‘脑白金‘" />

            <s:if test="#广告名==‘脑白金‘"> //注意,这里不用 #可就不行了
                脑残广告,傻子才买
            </s:if>
            <s:elseif test="#广告名==‘梦酒‘">
                五粮醇风,古方秘制,钦誉中外,独占鳌头
            </s:elseif>
            <s:else>
                说不定是就锅王胡师傅
         </s:else> 

可以用jstl代替上边的功能:

<c:choose>
            <c:when test="${广告名==‘梦酒‘}"> 一看就想喝的梦酒</c:when>
            <c:when test="${广告名==‘脑白金‘}">让人想吐的脑白金</c:when>
            <c:otherwise>估计十有八九是锅王胡师傅</c:otherwise>
</c:choose>
//对于上例,可以指定 scope
            <s:set name="广告名" value="‘脑白金‘"  scope="request"/> 指定泛围为 request
            <s:if test="#request.广告名==‘脑白金‘"> 取的时候也要用 request.
                脑残广告,傻子才买
            </s:if>
            <s:elseif test="#request.广告名==‘梦酒‘">
                五粮醇风,古方秘制,钦誉中外,独占鳌头
            </s:elseif>
            <s:else>
                说不定是就锅王胡师傅
            </s:else> 

十、Struts2 UI标签

== 主题和模板

Struts2提供了三种主题,ajax, simple, css_xhtml,xhtml,它默认的是xhtml主题,开发时我们一般都选simple。因为Struts2所有的UI标签都是基于主题和模板的,主题和模板是Struts2所有UI标签的核心。模板是一个UI标签的外在表示形式,例如:当我们使用<s:select ... ... />标签时,Struts2就会根据对应select模板来生成一个有模板特色的下拉列表框。如果为所有的UI标签都提供了对应的模板,那么这系列的模板就形成了一个主题。

对于一个JSP页面里包含的UI标签而言,即可以直接设置该UI标签需要使用的模板,也可以设置该UI标签使用的主题。实际上对开发者而言,并不推荐直接设置模板属性,而是应该选择特定主题。设置主题的方法有以下几种:

1,通过设定特定UI标签上的theme属性来指定主题。

2,通过设定特定UI标签外围的Form标签的theme属性来指定主题。

3,通过取得page\request\session\application 会话范围内以theme为名称的属性来确定主题。

4,通过取得名为struts.ui.theme的常量(默认值是xhtml)来确定主题,该常量可以在struts.properties文件或者struts.xml文件中确定。如:

<constantname="struts.ui.theme" value="simple" />

==表单标签

1 <s:checkboxlist>

====如果集合为list

<s:checkboxlist name="list" list="{‘Java‘,‘.Net‘,‘RoR‘,‘PHP‘}" value="{‘Java‘,‘.Net‘}"/>

生成如下html代码:

<input type="checkbox" name="list" value="Java" checked="checked"/><label>Java</label>
<input type="checkbox" name="list" value=".Net" checked="checked"/><label>.Net</label>
<input type="checkbox" name="list" value="RoR"/><label>RoR</label>
<input type="checkbox" name="list" value="PHP"/><label>PHP</label>

它默认会生成一些主题相关的tr td等,如果不想要,可以在struts.xml中配置  <constant name="struts.ui.theme" value="simple" />

====如果集合为MAP

<s:checkboxlist name="map" list="#{1:‘瑜珈用品‘,2:‘户外用品‘,3:‘球类‘,4:‘自行车‘}" listKey="key" listValue="value" value="{1,2,3}"/>

生成如下html代码:

<input type="checkbox" name="map" value="1" checked="checked"/><label>瑜珈用品</label>
<input type="checkbox" name="map" value="2" checked="checked"/><label>户外用品</label>
<input type="checkbox" name="map" value="3" checked="checked"/><label>球类</label>
<input type="checkbox" name="map" value="4"/><label>自行车</label>

====如果集合是里放的是javaBean

 <%
                          Person person1 = new Person(1,"第一个");
                          Person person2 = new Person(2,"第二个");
                          List<Person> list = new ArrayList<Person>();
                          list.add(person1);
                          list.add(person2);
                          request.setAttribute("persons",list);
                          %>
                        <s:checkboxlist name="beans" list="#request.persons" listKey="personid" listValue="name"/>

Personid和name为Person的属性

生成如下html代码:

<input type="checkbox" name=“beans" value="1"/><label>第一个</label>
<input type="checkbox" name=“beans" value="2"/><label>第二个</label>

例子:在 UserManage.jsp 中 (因为前面已经做过列出用户的例子,所以现在可以直接取内容)

<s:checkboxlist name="beans" list="userList" listKey="id" listValue="userName"/>然后 访问 http://localhost:8080/OGNL/UserAction!getAllUser

2 <s:radio>

该标签的使用和checkboxlist复选框相同。如果集合里存放的是javabean(personid和name为Person的属性)

 <s:checkboxlist name="beans" list="#request.persons" listKey="personid" listValue="name"/>

生成如下html代码:

<input type="radio" name="beans" id="beans1" value="1"/><label>第一个</label>
<input type="radio" name="beans" id="beans2" value="2"/><label>第二个</label>

如果集合为MAP

<s:radio name="map" list="#{1:‘瑜珈用品‘,2:‘户外用品‘,3:‘球类‘,4:‘自行车‘}" listKey="key" listValue="value“ value="1"/>

生成如下html代码:

<input type="radio" name="map" id="map1" value="1"/><label for="map1">瑜珈用品</label>
<input type="radio" name="map" id="map2" value="2"/><label for="map2">户外用品</label>
<input type="radio" name="map" id="map3" value="3"/><label for="map3">球类</label>
<input type="radio" name="map" id="map4" value="4"/><label for="map4">自行车</label>

如果集合为list

<s:radio name="list" list="{‘Java‘,‘.Net‘}" value="‘Java‘"/>

生成如下html代码:

<input type="radio" name="list" checked="checked" value="Java"/><label>Java</label>
<input type="radio" name="list" value=".Net"/><label>.Net</label>

十一、<s:token > 用来防止表单重复提交

例子:重复提交的例子

1.

private UserInfo userInfo;
        public String add(){
            UserDao dao=new UserDao();
          dao.addUser(this.userInfo);
                return "success";

}

2 struts.xml中 配置Action

<action name="UserAction_Add" class="cat.action.UserAction" method="add">
       <result name="success">/Succ.jsp</result>
</action>

3 UserAdd.jsp中

<s:form action="UserAction_Add" namespace="" method="post">
     姓名:<s:textfield name="userInfo.userName" />
     账号:<s:textfield name="userInfo.userId" />
     密码:<s:password name="userInfo.password" />
     备注:<s:textarea name="userInfo.note" />
<s:submit value="提交" />
</s:form>

4 进行提交,看刷新后的重复提交的结果

使用 tokey 标签防止重复提交,用法如下:

1 在表单中加入<s:token />
...
<s:token/>  //加入这个tokey

....

2 在XML中

<action name="UserAction_Add" class="pinkcat.action.UserAction" method="add">
         <interceptor-ref name="defaultStack"/>   //注意,默认的拦截器栈一定要加上
         <interceptor-ref name="token"/>
         <result name="invalid.token">/UserAdd.jsp</result>   //设置用户如果重复提交,则返回添加页
<result name="success">/Succ.jsp</result>

3 在UserAction 中 让其继承自 extends ActionSupport

十一、拦截器

Interceptor

和过滤器很象,但它只捕获 Action。在Struts2 中 许多Action通常都有一些共同需要关心的问题,比如有一些Action 它们都需要对页面上的输入进行校验,有一些Action需要对上传的文件进行一下预处理,还有一些Action可能需要防止表单的重复提交 (double submit) 还有很多Action需要在页面显示之前将下拉列表和其它一些控件事先装好值,通过拦截器策略,Struts2 框架使得共享这些问题更容易。

拦截器能在 Action 被调用之前和被调用之后执行一些 "代码",Struts2 框架的大部分功能都是通过拦截器来实现的,如防止重复提交,类型转换,对象封装,校验,文件上传,页面装载等等。每一个拦截器都是独立装载的(pluggable) ,可以根据实际的需要为每一个Action 配置需要用的拦截器. 例如: 一个Action 需要用到类型转换器 和 文件上传,那么我们可以给它设置两个拦截器。

拦截器是Struts2 框架的核心,包括解析请求参数,将请求参数赋值给Action属性,执行数据校验,文件上传等工作都是用它实现的Struts2设计的灵巧性,更多的得益与拦截器的设计.当需要进行扩展时,只需要提供对应的拦截器,并将它配置在Struts2容器中即可,反之可以摘掉  (AOP) 面向切面。

十二、struts2 自带的拦截器

Struts2 内建了大量拦截器,它们 以 name-class 对的形式配置在 struts-defalut.xml 文件中

alias: 实现在不同请示中相似参数别外的转换

autowiring 自动装配的拦截器,用于和Spring 进行整合

chain 构建一个Action链,使当前的Action可以访问前一个Action的属性 一般和 <result type="cahin"> 一起使用

conversionError 处理类型转换错误 它负责将类型转换错误从ActionContext 中取出,并转换成Action 的FieldError 错误

createSession 负责创建一个HttpSession对象

debugging 当使用Struts2 开发模式时,它会提交更多的调试信息

execAndWait 后台执行Action,负责将等待画面发送给用户

execption 处理异常,将异常映射为结果

fileupload 文件上传,解析表单域中的内容

i18n 国际化,负责把所选语言,区域放入用户Session中

ogger 日志记录,主要是输出Action 的名字

model-driven 一个用于模型驱动的拦截器, 当某个Action 类实现了 ModeDriven接口时,它负责把getModel() 方法的结果堆入ValueStack中

scope-model-driven

params 最基本的一个拦截器,负责解析Http请示中的参数,并将参数值设置成Action对应的属性值

prepare 如果Action实现了Prepareable 接口,会调用访栏截器中的prepare()方法

static - params 将XML中<action>标签下的<param>标签中的参数传入 Action

scope 范围转换 可以将Action 状态信息保存到 HttpSession 或 ServletContext 范围内

servlet-config 如果某个Action 需要直接访问 Servlet Api ,则通过它实现(尽量避免在Action中直接访问Servlet Api,高耦合)

roles JAAS java权限和认证服务 拦截器,有权才能调用该拦截器拦截的Action

timer 输出Action执行时间 分析Action性能的瓶颈时有用

token 阻止重复提交

token -session 和上面相似,只是把token保存在HttpSesison中

validation 通过执行在xxxAction-validation.xml中定义的校验器.从而完成数据校验

workflow 负再调用 Action类中的 validation 方法,如失败则返回 Input视图

十三、自定义拦截器  

自定义拦截器有三种方式

1) 实现 Interceptor 接口

2) 继承自 AbstractInterceptor

3) 继承自 MethodFilterInterceptor

例一 计算一个Action的执行时间的拦截器,继承自 AbstractInterceptor方式实现

1) 定义一个拦截器类

public class MyInterceptor extends AbstractInterceptor {

                //这个String 代表执行完Action后的返回值
                public String intercept(ActionInvocation invocation) throws Exception {
                    System.out.println("拦截开始");
                    long begintime=System.currentTimeMillis();

                    String result=invocation.invoke(); //执行A    ction中的对应的方法

                    long endtime=System.currentTimeMillis();
                    System.out.println("该action 共执行了:"+(endtime-begintime)+" ms");

                    System.out.println("拦截结束");

                    return result;
                }
            }

关于 ActionInvocation

ActionInvocation就是Action的调用者。ActionInvocation在Action的执行过程中,负责Interceptor、Action和Result等一系列元素的调度。Interceptor通过ActionInvocation可以完全的改变 Action行为:不让它执行、改变返回值、甚至可以细颗粒的操作Action的方法。它有getActionProxy(),getResultCode();getInvocationContext();getAction() 等方法。比如 可以通过 getAction 拿到Action对象,并执行里面的方法:

MoreMethodAction M=(MoreMethodAction)invocation.getAction();
                 M.test(); 

或者通过它拿到 ActionContext 对象

ActionContext act=invocation.getInvocationContext();

2) 在配置文件中配置

<package name="packageOne" extends="struts-default" >
         <interceptors>
         <interceptor name="myInte_AAA" class="cat.interceptor.MyInterceptor" />
         </interceptors>
         <action name="userAction_*" class="cat.action.UesrAction" method="{1}" >
                    <result name="success">/main.jsp</result>
                    <interceptor-ref name="myInte_AAA" />
                    <interceptor-ref name="defaultStack" />      //如果引入了自定义的拦截器,系统就不再提供默认的拦截器栈了,所以要自己手功引入
         </action>
</package>

3) action

public class UesrAction {
                        public String add(){
                            System.out.println("add 方法被调用了");
                            return "success";
                        }

                        public String del(){
                            System.out.println("del 方法被调用了");
                            return "success";
                        }
                        public String update(){
                            System.out.println("update 方法被调用了");
                            return "success";
                        }
                        public String search(){
                            System.out.println("search 方法被调用了");
                            return "success";
                        }
                    }

例二 灵活的限定拦截哪些方法,不拦截哪些方法= //通过继承 MethodFilterInterceptor 方式实现

1) 拦截器

public class MyInterceptor2  extends MethodFilterInterceptor{
                protected String doIntercept(ActionInvocation invocation) throws Exception {
                    System.out.println("MethodFilterInterceptor 启动");
                    String result=invocation.invoke();
                    System.out.println("MethodFilterInterceptor 结束");
                    return result;
                }
            }

2) 配置文件

<package name="packageOne" extends="struts-default" >
                <interceptors>
                    <interceptor name="myInte_AAA" class="cat.interceptor.MyInterceptor" />
                    <interceptor name="myInte_BBB" class="cat.interceptor.MyInterceptor2" >  //这是针对  MyInterceptor2 的
                        <param name="excludeMethods">search,update,del</param> //这里的面的方法,不会被拦截
                    </interceptor>
                </interceptors>
                <action name="userAction_*" class="cat.action.UesrAction" method="{1}" >
                    <result name="success">/main.jsp</result>
                    <interceptor-ref name="myInte_AAA" />
                    <interceptor-ref name="myInte_BBB" />  //引用声明的拦截器
                    <interceptor-ref name="defaultStack" />
                </action>
</package>

3) action 同上例一样,略

访问 userAction_add,userAction_del 等方法,可以发现, <param name="excludeMethods">search,update,del</param> 中声明的这几个方法没有被拦截。

附: 使用拦截器栈

<package name="packageOne" extends="struts-default" >
                        <interceptors>
                            <interceptor name="myInte_AAA" class="cat.interceptor.MyInterceptor" />
                            <interceptor name="myInte_BBB" class="cat.interceptor.MyInterceptor2" >
                                <param name="excludeMethods">search,update,del</param>
                            </interceptor>

                            <interceptor-stack name="myStack">   //将自己声明的两个拦截器和系统的 defaultStack 组成一个拦截器栈
                                <interceptor-ref name="myInte_BBB" />
                                <interceptor-ref name="myInte_AAA" />
                                <interceptor-ref name="defaultStack" />
                            </interceptor-stack>
                        </interceptors>

                        <action name="userAction_*" class="cat.action.UesrAction" method="{1}" >
                            <result name="success">/main.jsp</result>
                            <interceptor-ref name="myStack" />  //引用拦截器栈
                        </action>
                    </package>

例三 系统拦截器的调用,登录延时提醒ExecuteAndWaitInterceptor 很适合在后台长时间运行的action时,它可以可为用户一个友好的等待界面,例如进度条。

不在默认的 defaultStack 中
1)

<action name="loginAction" class="cat.action.UesrAction" method="login">
                    <result name="success">/main.jsp</result>
                    <result name="wait" >/wait.jsp</result>
                    <interceptor-ref name="defaultStack"></interceptor-ref>
                    <interceptor-ref name="execAndWait">
                        <param name="delay">2000</param>
                    </interceptor-ref>
          </action>

2) wait.jsp 中

<meta http-equiv="refresh" content="1;URL=loginAction" >
//或
response.setHeader("refresh", "3;URL=loginAction");

3) 在loginAction 设置 Thread.sleep(4000)

本例说明:

当调用 loginAction 的时候,程序会根据 配置文件中 delay 属性( 2000 )等待Action先执行 2000 毫秒, 但由于Action 中 sleep(4000), 所以它没执行完,这时拦截器就把请求发到 wait 视图上去了,wait 视图中每隔一秒 访问一下 loginAction,但这时loginAction对应的那个 Action还在沉睡中,所以访问也是无效的,(这些请求都被忽略了?) 直到它睡醒, 这时刷过去的请求就直接到result上了。

例四 Session 权限拦截器

public class SessionInterceptor  extends MethodFilterInterceptor{

                @Override
                protected String doIntercept(ActionInvocation invocation) throws Exception {
                    //方式一 (取到sesssion中的内容)
                    /*ActionContext ctx=ActionContext.getContext();
                    ctx.getSession()*/

                    //方式二
                    //ServletActionContext.getRequest().getSession();

                    //方式三
                    UserInfo user=(UserInfo)invocation.getInvocationContext().getSession().get("userInfo");

                    if(user!=null){
                        return invocation.invoke();
                    }
                    else{
                        System.out.println("没有登录");
                        ActionContext.getContext().put("msg","您还没有登录");
                        return "no_login";
                    }
                }
            }

        <interceptor name="session_Inte" class="cat.interceptor.SessionInterceptor" >
                <param name="excludeMethods">login</param>
        </interceptor>
              ... 

      <action name="sessionAction_*" class="cat.action.UesrAction" method="{1}" >
            <result name="success">/main.jsp</result>
            <interceptor-ref name="session_Inte" />
            <interceptor-ref name="defaultStack" />
        </action>

十四、在struts2中使用Ajax

(通过 stream 类型的 result 实现)

public class AjaxAction {
            private String userName;
            private String result;
             ... get  set 方法

            public String checkUser(){
                if("admin".equals(userName)){
                    result="用户名已经被别人使用";
                    return "success";
                }
                else{
                    result="用户名可用";
                    return "success";
                }
            }

            //把字符串转成  ByteArrayInputStream
            public InputStream getInputStream() throws UnsupportedEncodingException {
                return new ByteArrayInputStream(result.getBytes("utf-8"));
            }

页面: ajax_test.jsp

$(function() {
                $("#btn1").click(function(){
                    $.ajax({
                        url:"ajaxAction_checkUser",
                        data:{userName:"admin"},
                        type:"post",
                        success:function(data){
                            $("#divResult").html(data);
                        }
                    });
                });
            });

        //或  $("#div2").load("ajaxAction_checkUser",{userName:"admin"});  //这样写更简单

        <package name="packageTwo" extends="struts-default" >
            <action name="ajaxAction_*" class="cat.action.AjaxAction" method="{1}">
                <result type="stream" >
                    <param name="contentType">text/html</param>
                    <param name="inputName">InputStream</param>
                </result>
            </action>
        </package>

十五、在struts2中使用Ajax

(通过 json 插件实现)

    //页面
      $("#btn2").click(function(){
             $.ajax({
                url:"ajaxAction2_getAllUser",
                type:"post",
                dataType:"json",
                success:function(userList){
                    $.each(userList,function(key,user){
                        var trStr="<tr><td>"+user.id+"</td><td>"+user.userName+"</td><td>"+user.password+"</td></tr>";
                        $("#table1").append(trStr);
                    });
                }
            }); 

     //Action
            public class AjaxAction2 {
                private String userName;
                private String result;
                List<UserInfo> userList;

                public String getAllUser(){
                    userList=new UserDao().getAllUser();
                    return "success";
                }

    //配置文件
            <package name="packageThree" extends="json-default" >
                <action name="ajaxAction2_*" class="cat.action.AjaxAction2" method="{1}">
                    <result name="success" type="json" >
                    <param name="root">userList</param>
                </action>
            </package>

附加说明:

如果在上面的 action 中不指定     <param name="root">userList</param> 这个选项,则它会把整个action 对象做为json 数据返回,如果这样,前而取数据的方式如下:

$("#btn2").click(function(){
             $.ajax({
                url:"ajaxAction2_getAllUser",
                type:"post",
                dataType:"json",
                success:function(action){
                  var userList=action.userList;  //因为返回的是整个action 所以这里要这样取出
                     console.info(userList);
                    $.each(userList,function(key,user){

                        var trStr="<tr><td>"+user.id+"</td><td>"+user.userName+"</td><td>"+user.password+"</td></tr>";
                        $("#table1").append(trStr);
                    });
                }
}); 

原文地址:https://www.cnblogs.com/1693977889zz/p/8110953.html

时间: 2024-11-02 21:56:29

Java框架之Struts2(六)的相关文章

java框架篇---Struts2的处理流程

一.Struts2的处理流程: 客户端产生一个HttpServletRequest的请求,该请求被提交到一系列的标准过滤器(Filter)组建链中(如ActionContextCleanUp:它主要是清理当前线程的ActionContext.Dispatcher,FilterDispatcher主要是通过ActionMapper来决定需要调用那个Action,FilterDispatcher是控制器的核心,也是MVC中控制层的核心组建). 核心控制器组建FilterDispatcher根据Act

Java - 框架之 Struts2

一. Package 标签 1. 标签属性:name        : 包的名称,只有在一个项目中不重名即可.extends       : 继承哪个包,默认为 struts-default.namespace  : 名称空间,与<action> 标签中的 name 属性决定访问路径    - 名称空间写法:         - 带名称的: namespace="/a"        - 不带名称: namespace="/"        - 默认空间

java web 框架之struts2

简介:struts2是一个典型的mvc架构.利用它可是方便的实现某些功能. struts2 的工作流程图以及动态的action: 浏览器请求经过web容器,进入到struts2过滤器,然后搜索匹配,如果有与之对应的action对象,就会调用action对象的execut()方法,并根据处理的结果返回相应的值.通过创建多个action对象可以实现动态的action.也就是为了解决业务请求的多样性. 园长第一次接触框架,对于struts2框架的配置并不是很熟悉,对于初学者来说,很有必要讲讲strut

java 框架 面试 2

1.谈谈你对Struts的理解. 答: 1. struts是一个按MVC模式设计的Web层框架,其实它就是一个大大的servlet,这个Servlet名为ActionServlet,或是ActionServlet的子类.我们可以在web.xml文件中将符合某种特征的所有请求交给这个Servlet处理,这个Servlet再参照一个配置文件(通常为/WEB-INF/struts-config.xml)将各个请求分别分配给不同的action去处理. 一个扩展知识点:struts的配置文件可以有多个,可

框架: Struts2 讲解 1

一.框架概述 1.框架的意义与作用: 所谓框架,就是把一些繁琐的重复性代码封装起来,使程序员在编码中把更多的经历放到业务需求的分析和理解上面. 特点:封装了很多细节,程序员在使用的时候会非常简单. 2.三大框架: Struts2,Hibernate,Spring 3.学好框架: 由于框架中细节很多,知识点比较零散,课后总结和做好笔记就变得尤为重要. 二.关于三层架构 Struts2 : MVC框架. Hibernate:持久层框架(DAO,与数据库打交道).   Spring :IoC(控制反转

spring框架学习(六)AOP

spring框架学习(六)AOP AOP(Aspect-OrientedProgramming)面向方面编程,与OOP完全不同,使用AOP编程系统被分为方面或关注点,而不是OOP中的对象. AOP的引入 在OOP面向对象的使用中,无可避免的会出现代码重复,而且使用面向对象的编程方式,这种重复无法避免,比如用户权限判断中,根据相应的权限执行相应的方法:在servlet中设置编码格式时,同样相同的代码出现很多次,而且还根业务无关,很容易忘记写,结果运行的时候就出现乱码拉.这种重复代码不仅使编码麻烦,

Java框架服务

Java从诞生到现在,一路飙升,可以说红遍全球,红到发紫.随着Java的流行,促生了许多java框架:Spring.WebWork.Struts.HIbernate.JDiy.JFinal.Quartz.Welocity.IBATIS.Compiere ERP&CRM Spring Framework[Java开源J2EE框架] Spring是一个解决了许多在J2EE开发中常见的问题的强大框架.Spring提供了管理业务对象的一致方法并且鼓励了注入对接口编程而不是对类编程的良好习惯.Spring

ssh框架搭建Struts2.06+spring2.5+hibernate3.2整合实例代码教程步骤

原创整理不易,转载请注明出处:ssh框架搭建Struts2.06+spring2.5+hibernate3.2整合实例代码教程步骤 代码下载地址:http://www.zuidaima.com/share/1760074977233920.htm 最近闲来无事可做,于是开始学习struts2.Struts2和struts1.webwork2有什么区别我也不说了,网上有很多这方面的资料.以前在项目中从未使用过struts,一直使用spring+hibernate,现在既然学习了Struts,也不能

Spring框架整合Struts2使用Validation框架验证表单用户输入数据的详细教程

原创整理不易,转载请注明出处:Spring框架整合Struts2使用Validation框架验证表单用户输入数据的详细教程 代码下载地址:http://www.zuidaima.com/share/1778685765291008.htm 在<Struts2教程4:使用validate方法验证数据>中曾讲到使用validate方法来验证客户端提交的数据,但如果使用validate方法就会将验证代码和正常的逻辑代码混在一起,但这样做并不利于代码维护,而且也很难将过些代码用于其他程序的验证.在St