溫故知新: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添加到工廠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>
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>
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>
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>
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
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ò)該工廠新建session2 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 ...
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)建的session2
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
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>
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