温故知新:spring_10整合Struts

整合struts,就需要将action的实例交由spring去处理,由此可想,我们需要在项目开始的时候就将action的注入对象加载到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>
除了在测试类中能取得工厂,通过BeanId在工厂中获取实例的情况,其他时候一般是通过自动扫描并注入,因此,在web.xml中,除了struts的过滤器,还需要额外添加spring上下文的监听器,在项目部署的时候就将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>
因为需要action被spring进行管理,还需要在struts.xml配置中设置以下内容
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>
通过spring进行管理之后,action的class配置就无需再写详细的类目录,直接写作注入类的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 //对于action,需要额外指定Scope为prototype,默认是单例模式
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 

上述配置之后,就完成了对struts的整合,但是整合之后,可能会遇到以下的问题:
1:关于声明式事务的切入点表达式。虽然执行对数据库操作的环节是Dao,但是声明却不能在Dao进行事务处理,毕竟一个Dao对数据库的操作不一定能代表一个完整的事务。所以,切入点应该设置在service接口上,一个具体的业务处理应该包含一个完整的事务。拿最经典的银行转账的例子来说,一个账户的金额转出操作和另一个账户的转入操作应该设定在一个service的方法里,当事务对这个方法生效,那么不论转入或者转出任何一个操作出现异常,那么整个操作都会回滚。倘若事务设定在Dao上,那么转入和转出分别为两个方法,其中一个出现异常之后(一般也就是转出出现异常),会出现打钱收不到,钱都不知道去哪儿了的情况,这是我们最不想看到的。可能你会说,把转入和转出设定在Dao的一个方法中不就可以了,对,这样的话是可以解决问题,但是这样会导致层和层之间的分工不明确,相互渗透的情况,Dao只是对数据库的访问,他不应该涉及过分的业务逻辑,就像控制层应该把更多的精力放在跳转或者参数传递上,而不应该和专门控制业务处理的service层抢活干。还有就是在Dao一个方法里进行业务逻辑操作可能会涉及Dao之间的嵌套调用,会出现问题。
2:在页面上使用查询时。可能会出现以下的异常
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的懒加载机制引起的,由于声明式事务将事务设定在service的接口,导致service方法执行完毕就会关闭session,那么到了页面上需要取得懒加载才能取得的信息时,会导致出现没有session的状态,那么如何解决呢。可以通过一个过滤器,使用Threadlocal在请求之初就开启session,这样,整个流程都可以取得session,请求结束之时再关闭session。新增一个过滤器,将spring工厂中的sessionfactory取得,通过该工厂新建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             //执行操作之前先设定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.. 去新建工厂,应该使用项目启动时创建的工厂
59         //如下获取
60         wac = WebApplicationContextUtils.getWebApplicationContext(cfg.getServletContext());
61         sessionFactory = (SessionFactory) wac.getBean("sessionFactory");
62     }
63 
64 }
65 
之后,在Dao中进行数据库操作时就需要使用过滤器创建的session
1      OpenSessionInViewFilter.getSession().XXX
spring本身也提供了一个叫OpenSessionInViewFilter的过滤器,能帮助我们解决懒加载时没有session的问题,看下web.xml
 1     <!-- 实现openSessionInView -->
 2     <!-- 注意,本过滤器要放在struts过滤器的前面,否则会失效 -->
 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的实现中使用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 都较瘦 阅读(78) 评论(0)  编辑  收藏 所属分类: containerFramework


只有注册用户登录后才能发表评论。


网站导航:
 
<2024年5月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

导航

统计

公告

博客定位:囿于目前的水平,博客定位在记录自己的学习心得和随手的练习

常用链接

留言簿

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜