Struts2知識總結4

十九、OGNL表達式語言
1、OGNL表達式語言簡介
OGNL是Object Graphic Navigation Language(對象圖導航語言)的縮寫,它是一個開源項目。Struts2框架使用OGNL作爲默認的表達式語言。
    相對於EL表達式,它提供了平時我們需要的一些功能,如:
* 支持對象方法調用,如xxx.sayHello();
    * 支持類靜態方法調用和直接訪問,表達式的格式爲@[類全名(包括包路徑)]@[方法名|值名],例如:@java.lang.String@format("foo %s","bar")或@com.rlcc.Constant@APP_NAME;
* 操作集合對象。

2、上下文中對象的訪問
ognl有一個上下文(Context)概念,說白了上下文就是一個MAP結構,它實現了java.util.Map接口,在Struts中上下文(Context)的實現爲ActionContext。下面爲ognl上下文結構示意圖:
OGNL Context(在Struts中的實現爲ActionContext):
ValueStack(值棧,它是根對象)
Parameters
    request
    session
    application
    attr
當struts2接收一個請求時,會迅速創建ActionContext,ValueStack,action。然後把action存放進ValueStack,所以action的實例變量可以被OGNL訪問。

    訪問上下問(Context)中的對象需要使用 #符號標註命名空間,如#application、#session
另外OGNL會設定一個根對象(root對象),在Struts2中根對象就是ValueStack(值棧)。如果要訪問根對象(即ValueStack)中的屬性,則可以省略#命名空間,直接訪問該對象的屬性即可。
    在struts2中,根對象ValueStack的實現類爲OgnlValueStack,該對象不是我們想像的只存放單個值,而是存放一組對象。在OgnlValueStack類裏有一個List類型的root變量,就是使用他存放一組對象
context-----------------request
                                      application
      OgnlValueStack   root變量[action,OgnlUtil,...]
      session
      attr
      parameters
在root變量中處於第一位的對象叫棧頂對象。通常我們在OGNL表達式裏直接寫上屬性的名稱即可訪問root變量裏對象的屬性,搜索順序是從棧頂對象開始尋找,如果棧頂對象不存在該屬性,就會從第二個對象尋找,如果沒有找到就從第三個對象尋找,依次往下訪問,直到找到爲止。
    注意:Struts2中,OGNL表達式需要配合Struts標籤纔可以使用。如:<s:property value="name"/> ,value屬性的值爲OGNL表達式

    由於ValueStack(值棧)是Struts2中OGNL的根對象,如果用戶需要訪問值棧中的對象,在JSP頁面可以直接通過下面的EL表達式訪問ValueStack中對象的屬性:
${foo}//獲得值棧中某個對象的foo屬性
    如果訪問其他Context中的對象,由於他們不是根對象,所以在訪問時,需要添加#前綴。
* application對象:用於訪問ServletContext,例如#application.userName或者#application['userName'],相當於調用ServletContext的getAttribute("userName")。
* session對象:用於訪問HttpSession,例如#session.userName或者#session['userName'],相當於調用session.getAttribute("userName")。
* request對象:用於訪問HttpServletRequest,例如#request.userName或者#request['userName'],相當於調用request.getAttribute("userName")。
* parameters對象:用於訪問HTTP的請求參數,例如#parameters.userName或者#parameters['userName'],相當於調用request.getParameter("userName")。
* attr對象:用於按page->request->session->application順序訪問其屬性。

3、爲何使用EL表達式能夠訪問ValueStack中對象的屬性
    原因是Struts2對HttpServletRequest作了進一步的封裝。簡略代碼如下:
public class StrutsRequestWrapper extends HttpServletRequestWrapper{
      public StrutsRequestWrapper(HttpServletRequest req){
        super(req);
      }
      public Object getAttribute(String s){
        ...
ActionContext ctx = ActionContext.getContext();
Object attribute = super.getAttribute(s);//先從request範圍獲取屬性值
if(ctx != null){
  if(attribute == null){//如果從request範圍沒有找到屬性值,即從ValueStack中查找對象的屬性值
......
ValueStack stack = ctx.getValueStack();
    attribute = stack.findValue(s);
    ......
  }
}
return attribute;
      }
    }

  4、採用OGNL表達式創建List/Map集合對象
    如果需要一個集合元素的時候(例如List對象或者Map對象),可以使用OGNL中同集合相關的表達式。使用如下代碼直接生成一個List對象:
<s:set name="list" value="{'zhangming','xiaoi','liming'}"/>
    <s:iterator value="#list">
      <s:property/><br>
    </s:iterator>
    Set標籤用於將某個值放入指定範圍。
scope:指定變量被放置的範圍,該屬性可以接收application、session、request、page或action。如國沒有設置該屬性,則默認放置在OGNL Context中(即該變量和ValueStack、request...等對象並列,使用時可以在變量名前加前綴#)。
value:賦給變量的值。如果沒有設置該屬性,則將ValueStack棧頂的值賦給變量。
    生成一個Map對象:
<s:set name="foobar" value="#{'foo1':'bar1','foo2':'bar2'}"/>
    <s:iterator value="#foobar">
      <s:property value="key"/>=<s:property value="value"/><br>
    </s:iterator>

  5、採用OGNL表達式判斷對象是否存在於集合中
    對於集合類型,OGNL表達式可以使用in和not in兩個元素符號。其中,in表達式用來判斷某個元素是否在指定的集合對象中;not in判斷某個元素是否不在指定的集合對象中,如下所示:
in表達式:
<s:if test="'foo' in {'foo','bar'}">

</s:if>
    <s:else>
不在
</s:else>
    not in表達式:
<s:if test="'foo' not in {'foo','bar'}">
不在
</s:if>
    <s:else>

</s:else>

  6、OGNL表達式實現投影功能
    除了in和not in之外,OGNL還允許使用謀個規則獲得集合對象的子集,常用的有以下3個相關操作符:
    :獲得所有復合邏輯的元素。
^:獲得符合邏輯的第一個元素。
$:獲得符合邏輯的最後一個元素。
    例如代碼:
<s:iterator value="books.{#this.price>35}">
      <s:property value="title"/>-$<s:property value="price"/><br>
    </s:iterator>
在上面代碼中,直接在集合後緊跟.{}運算符表明用於去除該集合的子集,{}內的表達式用於獲取符合條件的元素,this指的是爲了從大集合books篩選數據到小集合,需要對大集合books進行迭代,this代表當前迭代的元素。本例的表達式用於獲取集合中價格大於35的書集合。
public class BookAction extends ActionSupport{
      private List<Book> books;
      ......
      @Override
      public String execute(){
        books = new LinkedList<Book>();
books.add(new Book("A735619678","spring",67));
books.add(new Book("B435555322","ejb3.0",15));
      }
    }

二十、Struts2標籤
1、property標籤
property標籤用於輸出指定值:
<s:set name="name" value="kk"/>
    <s:property value="#name"/>
    default:可選屬性,如果需要輸出的屬性值爲null,則顯示該屬性指定的值。
escape:可選屬性,指定是否格式化HTML代碼。
value:可選屬性,指定需要輸出的屬性值,如果沒有指定該屬性,則默認輸出ValueStack棧頂的值。
id:可選屬性,指定該元素的標識。

2、iterator迭代標籤
iterator標籤用於對集合進行迭代,這裏的集合包括List、Set和數組。該標籤使用時會把集合放在ValueStack的棧頂,所以可以直接用property標籤來輸出集合的元素值。
<s:set name="list" value="{'zhangsan','lisi','wangwu'}"/>
    <s:iterator value="#list" status="st">
      <font color=<s:if test="#st.odd">red</s:if><s:else>blue</s:else>
      ><s:property/></font><br>
    </s:iterator>
    value:可選屬性,指定被迭代的集合,如果沒有設置該屬性,則使用ValueStack棧頂的集合。
id:可選屬性,指定集合理元素的id(已被標註爲過時)
status:可選屬性,該屬性指定迭代時的IteratorStatus實例。該實例包含如下幾個方法:
int getCount,返回當前迭代了幾個元素。
int getIndex(),返回當前被迭代元素的索引。
boolean isEven(),返回當前被迭代元素的索引是否是偶數。
boolean isOdd(),返回當前被迭代元素的索引是否是奇數。
boolean isLast(),返回當前被迭代元素是否是最後一個 元素。

3、if/elseif/else標籤
<s:set name="age" value="21"/>
    <s:if test="#age==23">
      23
    </s:if>
    <s:elseif test="#age==21">
      21
    </s:elseif>
    <s:else>
都不等
</s:else>

  4、url標籤
<s:url action="helloworld_add" namespace="/test">
      <s:param name="personId" value="23"/> //value屬性裏的值默認爲OGNL表達式的值,如果找不到該OGNL表達式值,則原樣輸出,例如:<s:param name="personId" value="#person.id"/>
    </s:url>
生成類似如下路徑:
${pageContext.request.contextPath}/test/helloworld_add.actionpersonId=23

當標籤的屬性value值作爲字符串類型處理時,“%”符號的用途是計算OGNL表達式的值。
<s:set name="myurl" value=" 'http://www.foshanshop.net' "/>
      <s:url value="#myurl"/><br>
      <s:url value="%{#myurl}"/>
輸出結果:
#myurl
    http://www.foshanshop.net

二十一、Struts2表單標籤
1、checkboxlist複選框
a、如果集合爲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>
    b、如果集合爲MAP
    <s:checkboxlist name="map" list="#{1:'Java',2:'.Net',3:'RoR',4:'PHP'}" listKey="key" listValue="value" value="{1,2,3}"/>
生成代碼如下html代碼:
<input type="checkbox" name="map" value="1"  checked="checked"/><label>Java</label>
    <input type="checkbox" name="map" value="2"  checked="checked"/><label>.Net</label>
    <input type="checkbox" name="map" value="3" checked="checked"/><label>RoR</label>
    <input type="checkbox" name="map" value="4"/><label>PHP</label>
注:strut2生成這些html代碼時,會先生成一個<tr><td class="tdLable"></td></tr>主題標籤,如果我們不希望strut2給我們生成這個多餘的主題標籤,則可以在常量裏面配置主題視圖常量:
<constant name="struts.ui.theme" value="simple"/>
     c、如果集合裏存放的是javabean
       <%
         Person person1 = new Person(1,"第一個");
Person person2 = new Person(1,"第二個");
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>

  2、radio單選框
    使用方法和複選框相同
a、如果集合爲list
    <s:radio name="list" list="{'Java','.Net','RoR','PHP'}" value=" 'java' "/>
生成代碼如下html代碼:
<input type="radio" name="list" value="Java"  checked="checked"/><label>Java</label>
    <input type="radio" name="list" value=".Net" /><label>.Net</label>
    <input type="radio" name="list" value="RoR"/><label>RoR</label>
    <input type="radio" name="list" value="PHP"/><label>PHP</label>
    b、如果集合爲MAP
    <s:radio name="map" list="#{1:'Java',2:'.Net',3:'RoR',4:'PHP'}" listKey="key" listValue="value" value="1"/>
生成代碼如下html代碼:
<input type="radio" name="map" value="1"  checked="checked"/><label>Java</label>
    <input type="radio" name="map" value="2"/><label>.Net</label>
    <input type="radio" name="map" value="3"/><label>RoR</label>
    <input type="radio" name="map" value="4"/><label>PHP</label>
     c、如果集合裏存放的是javabean
       <%
         Person person1 = new Person(1,"第一個");
Person person2 = new Person(1,"第二個");
List<Person> list = new ArrayList<Person>();
list.add(person1);
list.add(person2);
request.setAttribute("persons",list);
       %>
       <s:radio name="beans" list="#request.persons" listKey="personid" listValue="name"/>
       personid和name爲Person的屬性
       生成如下html代碼:
<input type="radio" name="beans" value="1"/><label>第一個</label>
       <input type="radio" name="beans" value="2"/><label>第二個</label>

  3、select下拉列表框
  和複選框使用方法一樣
<s:select name="list" list="{'Java','.Net','RoR','PHP'}"/>
  <s:select name="beans" list="#request.persons" listKey="personid" listValue="name"/>
  <s:select name="map" list="#{1:'Java',2:'.Net',3:'RoR',4:'PHP'}" listKey="key" listValue="value" value="3"/>

  4、<s:token/>標籤防止重複提交
<s:token/>標籤防止重複提交,用法如下:
    第一步:在表單中加入<s:token/>
    <s:form action="helloworld_other" method="post" namespace="/test">
      <s:textfield name="person.name"/><s:token/><s:submit/>
    </s:form>
第二步:
<action name="helloworld_*" class="com.rlcc.action.HelloWorldAction" method="{1}">
      <interceptor-ref name="defaultStack"/>
      <interceptor-ref name="token"/>
      <result name="invalid.token">/WEB-INF/page/message.jsp</result>
      <result>/WEB-INF/page/result.jsp</result>
    </action>
以上配置加入了“token”攔截器和“invalid.token”結果,因爲“token”攔截器會話的token與請求的token不一致時,將會直接返回“invalid.token”結果。
    在debug狀態,控制檯會出現下面信息,是因爲Action中並沒有struts.token和struts.token.name屬性,我們不用關心這個錯誤:
    嚴重:ParametersInterceptor-[setParameters]:Unexpected Exception caught setting 'struts.token' on 'class xxx:Error setting expression 'struts.token' with value '[Ljava.lang.String;@19f16f]' '
嚴重:ParametersInterceptor-[setParameters]:Unexpected Exception caught setting 'struts.token.name'

二十二、Struts2+Spring2.5+Hibernate3.3整合開發
1、整合開發時Struts2、hibernate、Spring需要的JAR。
Struts2:
--------------------------------------------------------------------
struts2-core-2.xx.jar:Struts2框架的核心類庫
Xwork-core-2.x.x.jar:XWork類庫,Struts2在其上構建
ognl-2.6.x.jar:對象圖導航語言(Object Graph Navigation Language),struts2框架通過其讀寫對象的屬性
frermarker-2.3.x.jar:Struts2的UI標籤的模版使用FreeMarker編寫
commons-fileupload-1.2.x.jar:文件上傳組件,2.1.6版本後需要加入此jar文件
commons-io-1.3.2.jar:文件上傳組件依賴到該jar文件
struts2-spring-plugin-2.x.x.jar:用於struts2集成Spring的插件

hibernate
----------------------------------------------------------------------
核心包
hibernate3.jar
  lib\bytecode\calib\hibernate-cglib-repack-2.1_3.jar
  lib\required\*.jar
註解包
hibernate-annotations.jar
  lib\ejb3-persistence.jar、hibernate-commons-annotations.jar
針對JPA的實現包(使用hibernate枚舉類型的映射時需要該實現包)
hibernate-entitymanager.jar
  lib\test\log4j.jar、slf4j-log4j12.jar

  Spring
----------------------------------------------------------------------------
dist\spring.jar
  lib\c3p0\c3p0-0.9.1.2.jar
  lib\aspectj\aspectjweaver.jar、aspectjrt.jar
  lib\calib\cglib-nodep-2.1_3.jar
  lib\j2ee\common-annotations.jar
  lib\log4j\log4j-1.2.15.jar
  lib\jakarta-commons\commons-logging.jar

數據庫驅動jar

注:建議先整合spring+hibernate,然後再整合struts2

  2、Spring配置模版
<xml version="1.0" encoding="UTF-8">
  <beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">


  </beans>
  3、在Spring中配置數據源
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="driverClass" value="org.gjt.mm.mysql.Driver"/>
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/dbNameuseUnicode=true&amp;characterEncoding=UTF-8"/>
    <property name="user" value="root"/>
    <property name="password" value="123456"/>
    <!--初始化時獲取的連接數,取值應在minPoolSize與maxPoolSize之間。Default:3-->
    <property name="initialPoolSize" value="1"/>
    <!--連接池中保留的最小連接數-->
    <porperty name="minPoolSize" value="1"/>
    <!--連接池中保留的最大連接數。Default:15-->
    <property name="maxPoolSize" value="300"/>
    <!--最大空閒時間,60秒內未使用則連接被丟棄。若爲0則永不丟棄。Default:0-->
    <property name="maxIdleTime" value="60"/>
    <!--當連接池中的連接耗盡時,c3p0一次同時獲取的連接數。Default:3-->
    <property name="acquireIncrement" value="5"/>
    <!--每60秒檢查所有連接池中的空閒連接。Default:0-->
    <property name="idleConnectionTestPeriod" value="60"/>
  </bean>

  4、集成hibernate
  <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mappingResources">
      <list>
        <value>com/rlcc/bean/buyer.hbm.xml</value>
      </list>
    </property>
    <property name="hibernateProperties">
      <value>
        hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
hibernate.hbm2ddl.auto=update
hibernate.show_sql=false
hibernate.format_sql=false
      </value>
    </property>
  </bean>

  5、使用Spring容器管理事務服務
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
  </bean>
  <!--使用基於註解方式配置事務-->
  <tx:annotation-driven transaction-manager="txManager"/>

  6、配置hibernate實體映射文件buyer.hbm.xml
  <xml version="1.0" encoding="UTF-8">
  <!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  <hibernate-mapping package="com.rlcc.bean">
    <class name="Buyer" table="buyer">
      <id name="username" length="20"/>
      <property name="password" length="20" not-null="true"/>
      <property name="gender" not-null="true" length="5">
        <type name="org.hibernate.type.EnumType">
  <param name="enumClass">com.rlcc.bean.Gender</param>
  <!--12爲java.sql.Types.VARCHAR常量值,即保存枚舉的字面值到數據庫。如果不能指定type參數,保存枚舉的索引值(從0開始)到數據庫-->
  <param name="type">12</param>
</type>
      </property>
    </class>
  </hibernate-mapping>

  7、在web容器中使用Listener實例化spring容器和配置struts2
    <!--指定spring的配置文件,默認從web根目錄尋找配置文件,我們可以通過spring提供的classpath:前綴指定從類路徑下尋找-->
    <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:beans.xml</param-value>
    </context-param>
    <!--對spring容器進行實例化-->
    <listener>
      <listener-class>org.springframework.context.ContextLoaderListener</listener-class>
    </listener>
配置struts2
    <filter>
      <filter-name>struts2</filter-name>
      <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
      <filter-name>struts2</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>

  8、struts2的配置文件模版
struts.xml如下:
    常量struts.objectFactory=spring明確指出將由Spring負責創建Action實例
<xml version="1.0" encoding="UTF-8" >
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">
    <struts>
      <!--默認的視圖主題-->
      <constant name="struts.objectFactory" value="spring"/>
      <package name="person" namespace="/person" extends="struts-default">
        <global-results>
  <result name="message">/WEB-INF/page/message.jsp</result>
</global-results>
<action name="action_*" class="personList" method="{1}">
  <result name="list">/WEB-INF/page/person.jsp</result>
</action>
      </package>
    </struts>
爲了能從spring容器中尋找到Action bean ,要求action配置的class屬性值和spring中的bean名稱相同。
發佈了81 篇原創文章 · 獲贊 30 · 訪問量 28萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章