溫故知新:spring_10整合Struts

          整合struts,就需要將action的實(shí)例交由spring去處理,由此可想,我們需要在項(xiàng)目開(kāi)始的時(shí)候就將action的注入對(duì)象加載到spring的工廠里。除了添加struts的依賴,還需要添加struts和spring整合用的插件
           1         <dependency>
           2             <groupId>org.apache.struts</groupId>
           3             <artifactId>struts2-spring-plugin</artifactId>
           4             <version>2.3.7</version>
           5         </dependency>
           6         
           7         <dependency>
           8             <groupId>org.apache.struts</groupId>
           9             <artifactId>struts2-core</artifactId>
          10             <version>2.3.7</version>
          11         </dependency>
          除了在測(cè)試類中能取得工廠,通過(guò)BeanId在工廠中獲取實(shí)例的情況,其他時(shí)候一般是通過(guò)自動(dòng)掃描并注入,因此,在web.xml中,除了struts的過(guò)濾器,還需要額外添加spring上下文的監(jiān)聽(tīng)器,在項(xiàng)目部署的時(shí)候就將action添加到工廠
          1     <listener>
          2         <listener-class>
          3             org.springframework.web.context.ContextLoaderListener
          4         </listener-class>
          5     </listener>
          6     <context-param>
          7         <param-name>contextConfigLocation</param-name>
          8         <param-value>classpath*:beans.xml</param-value>
          9     </context-param>
          因?yàn)樾枰猘ction被spring進(jìn)行管理,還需要在struts.xml配置中設(shè)置以下內(nèi)容
          1     <constant name="struts.objectFactory"
          2         value="org.apache.struts2.spring.StrutsSpringObjectFactory" />
          3     <constant name="struts.devMode" value="true" />
          4     
          5     <package name="user" extends="struts-default" namespace="/">
          6         <action name="*" class="userAction" method="{1}">
          7             <result name="success">/user{1}.jsp</result>
          8         </action>
          9     </package>
          通過(guò)spring進(jìn)行管理之后,action的class配置就無(wú)需再寫詳細(xì)的類目錄,直接寫作注入類的BeanId
           1 package org.duyt.action;
           2 
           3 import java.util.List;
           4 
           5 import javax.annotation.Resource;
           6 
           7 import org.duyt.domain.User;
           8 import org.duyt.service.IuserService;
           9 import org.springframework.context.annotation.Scope;
          10 import org.springframework.stereotype.Controller;
          11 
          12 import com.opensymphony.xwork2.ActionSupport;
          13 import com.opensymphony.xwork2.ModelDriven;
          14 
          15 @Controller("userAction")
          16 //對(duì)于action,需要額外指定Scope為prototype,默認(rèn)是單例模式
          17 @Scope("prototype")
          18 public class UserAction extends ActionSupport implements ModelDriven<User>{
          19 
          20     private static final long serialVersionUID = 2698940294947436354L;
          21     
          22     private User user;
          23     private List<User> userList;
          24     
          25     @Resource
          26     private IuserService userService;
          27     
          28     
          29     public String list() {
          30         
          31         userList = userService.listUser();
          32         
          33         return SUCCESS;
          34     }
          35     
          36     public User getModel() {
          37         if (user == null) {
          38             user = new User();
          39         }
          40         return user;
          41     }
          42 
          43     //get/set方法略
          44 
          45 }
          46 

          上述配置之后,就完成了對(duì)struts的整合,但是整合之后,可能會(huì)遇到以下的問(wèn)題:
          1:關(guān)于聲明式事務(wù)的切入點(diǎn)表達(dá)式。雖然執(zhí)行對(duì)數(shù)據(jù)庫(kù)操作的環(huán)節(jié)是Dao,但是聲明卻不能在Dao進(jìn)行事務(wù)處理,畢竟一個(gè)Dao對(duì)數(shù)據(jù)庫(kù)的操作不一定能代表一個(gè)完整的事務(wù)。所以,切入點(diǎn)應(yīng)該設(shè)置在service接口上,一個(gè)具體的業(yè)務(wù)處理應(yīng)該包含一個(gè)完整的事務(wù)。拿最經(jīng)典的銀行轉(zhuǎn)賬的例子來(lái)說(shuō),一個(gè)賬戶的金額轉(zhuǎn)出操作和另一個(gè)賬戶的轉(zhuǎn)入操作應(yīng)該設(shè)定在一個(gè)service的方法里,當(dāng)事務(wù)對(duì)這個(gè)方法生效,那么不論轉(zhuǎn)入或者轉(zhuǎn)出任何一個(gè)操作出現(xiàn)異常,那么整個(gè)操作都會(huì)回滾。倘若事務(wù)設(shè)定在Dao上,那么轉(zhuǎn)入和轉(zhuǎn)出分別為兩個(gè)方法,其中一個(gè)出現(xiàn)異常之后(一般也就是轉(zhuǎn)出出現(xiàn)異常),會(huì)出現(xiàn)打錢收不到,錢都不知道去哪兒了的情況,這是我們最不想看到的。可能你會(huì)說(shuō),把轉(zhuǎn)入和轉(zhuǎn)出設(shè)定在Dao的一個(gè)方法中不就可以了,對(duì),這樣的話是可以解決問(wèn)題,但是這樣會(huì)導(dǎo)致層和層之間的分工不明確,相互滲透的情況,Dao只是對(duì)數(shù)據(jù)庫(kù)的訪問(wèn),他不應(yīng)該涉及過(guò)分的業(yè)務(wù)邏輯,就像控制層應(yīng)該把更多的精力放在跳轉(zhuǎn)或者參數(shù)傳遞上,而不應(yīng)該和專門控制業(yè)務(wù)處理的service層搶活干。還有就是在Dao一個(gè)方法里進(jìn)行業(yè)務(wù)邏輯操作可能會(huì)涉及Dao之間的嵌套調(diào)用,會(huì)出現(xiàn)問(wèn)題。
          2:在頁(yè)面上使用查詢時(shí)。可能會(huì)出現(xiàn)以下的異常
          1     org.hibernate.LazyInitializationException: could not initialize proxy - no Session
          2     at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:132)
          3     at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:174)
          4     at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
          5     at org.duyt.domain.Address_$$_javassist_0.toString(Address_$$_javassist_0.java)
          6     ...
          這是由于hibernate的懶加載機(jī)制引起的,由于聲明式事務(wù)將事務(wù)設(shè)定在service的接口,導(dǎo)致service方法執(zhí)行完畢就會(huì)關(guān)閉session,那么到了頁(yè)面上需要取得懶加載才能取得的信息時(shí),會(huì)導(dǎo)致出現(xiàn)沒(méi)有session的狀態(tài),那么如何解決呢。可以通過(guò)一個(gè)過(guò)濾器,使用Threadlocal在請(qǐng)求之初就開(kāi)啟session,這樣,整個(gè)流程都可以取得session,請(qǐng)求結(jié)束之時(shí)再關(guān)閉session。新增一個(gè)過(guò)濾器,將spring工廠中的sessionfactory取得,通過(guò)該工廠新建session
           1 package org.duyt.filter;
           2 
           3 import java.io.IOException;
           4 
           5 import javax.servlet.Filter;
           6 import javax.servlet.FilterChain;
           7 import javax.servlet.FilterConfig;
           8 import javax.servlet.ServletException;
           9 import javax.servlet.ServletRequest;
          10 import javax.servlet.ServletResponse;
          11 
          12 import org.hibernate.Session;
          13 import org.hibernate.SessionFactory;
          14 import org.springframework.web.context.WebApplicationContext;
          15 import org.springframework.web.context.support.WebApplicationContextUtils;
          16 
          17 public class OpenSessionInViewFilter implements Filter{
          18     
          19     //spring工廠
          20     private static WebApplicationContext wac;
          21     //hibernateSessionFactory
          22     private static SessionFactory sessionFactory;
          23     //線程間共享的session
          24     private static ThreadLocal<Session> sessionholder = new ThreadLocal<Session>();
          25     
          26     private static void setSession(Session session){
          27         sessionholder.set(session);
          28     }
          29     
          30     public static Session getSession(){
          31         return sessionholder.get();
          32     }
          33     
          34     private static void removeSession(){
          35         sessionholder.remove();
          36     }
          37 
          38     public void destroy() {
          39         
          40     }
          41 
          42     public void doFilter(ServletRequest req, ServletResponse resp,
          43             FilterChain chain) throws IOException, ServletException {
          44         try {
          45             //執(zhí)行操作之前先設(shè)定session
          46             if (sessionFactory != null) {
          47                 setSession(sessionFactory.openSession());
          48             }
          49             chain.doFilter(req, resp);
          50         } finally{
          51             //操作完畢之后在移除session
          52             removeSession();
          53         }
          54     }
          55 
          56     public void init(FilterConfig cfg) throws ServletException {
          57         //將spring的工廠加載到屬性
          58         //這里不要使用new classpathXml.. 去新建工廠,應(yīng)該使用項(xiàng)目啟動(dòng)時(shí)創(chuàng)建的工廠
          59         //如下獲取
          60         wac = WebApplicationContextUtils.getWebApplicationContext(cfg.getServletContext());
          61         sessionFactory = (SessionFactory) wac.getBean("sessionFactory");
          62     }
          63 
          64 }
          65 
          之后,在Dao中進(jìn)行數(shù)據(jù)庫(kù)操作時(shí)就需要使用過(guò)濾器創(chuàng)建的session
          1      OpenSessionInViewFilter.getSession().XXX
          spring本身也提供了一個(gè)叫OpenSessionInViewFilter的過(guò)濾器,能幫助我們解決懶加載時(shí)沒(méi)有session的問(wèn)題,看下web.xml
           1     <!-- 實(shí)現(xiàn)openSessionInView -->
           2     <!-- 注意,本過(guò)濾器要放在struts過(guò)濾器的前面,否則會(huì)失效 -->
           3     <filter>
           4         <filter-name>OpenSessionInViewFilter</filter-name>
           5         <!-- 這是自定義的filter -->
           6         <!-- <filter-class>org.duyt.filter.OpenSessionInViewFilter</filter-class> -->
           7         
           8         <!-- 這是spring提供的 OpenSessionInViewFilter,使用spring自帶的就不用再DAO的實(shí)現(xiàn)中使用filter獲取session-->
           9         <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
          10     </filter>
          11     <filter-mapping>
          12         <filter-name>OpenSessionInViewFilter</filter-name>
          13         <url-pattern>/*</url-pattern>
          14     </filter-mapping>

          posted on 2014-11-09 09:38 都較瘦 閱讀(90) 評(píng)論(0)  編輯  收藏 所屬分類: containerFramework

          <2025年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          導(dǎo)航

          統(tǒng)計(jì)

          公告

          博客定位:囿于目前的水平,博客定位在記錄自己的學(xué)習(xí)心得和隨手的練習(xí)

          常用鏈接

          留言簿

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 四子王旗| 井冈山市| 大城县| 昌图县| 高安市| 玛纳斯县| 普兰县| 凤凰县| 东光县| 济源市| 南雄市| 玉田县| 双桥区| 东乡族自治县| 土默特右旗| 辽宁省| 密云县| 娱乐| 通海县| 板桥市| 增城市| 黑河市| 姜堰市| 乌什县| 金堂县| 林甸县| 麻阳| 怀化市| 睢宁县| 金川县| 奉化市| 大英县| 台北县| 克东县| 自治县| 米脂县| 金塔县| 河西区| 张北县| 准格尔旗| 阿鲁科尔沁旗|