SSH整合之配置文件篇

为web应用提供Struts2支持

1.编辑web应用的web.xml配置文件,配置Struts2的核心Filter来拦截用户请求。

      由于Web应用是基于请求/响应架构的应用,所以不管哪个MVC Web框架,都需要在web.xml中配置该框架的核心Servlet或Filter,这样才可以让该框架介入Web应用中。

<!--定义struts2的核心Filter(过滤器)-->
  <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
  </filter>
  <!--让Struts2的核心Filter拦截所有的请求-->
 <filter-mapping>
         <filter-name>struts2</filter-name>
         <url-pattern>/*</url-pattern>
  </filter-mapping>

2.如果需要以POST方式提交请求,则定义包含表单数据的JSP页面。如果仅仅只是以GET方式发送请求,则无须经过这一步。

3.定义处理用户请求的Action。

      这一步也是所有MVC框架中必不可少的,因为这个Action就是MVC中的C,也就是控制器。该控制器负责调用Model里的方法来处理请求。

      MVC框架的底层机制是:核心Servlet或Filter接收到用户请求后,通常会对用户请求进行简单的预处理,例如解析、封装参数等,然后通过反射来创建Action实例,并调用Action的指定方法。当Servlet或Filter拦截用户请求后,通过配置文件或利用约定来确定创建哪个Action的实例。

      在MVC框架中,控制器实际上由2个部分共同组成,即拦截所有用户请求,处理请求的通用代码都由核心控制器完成,而实际的业务控制器则由Action处理。

4.配置Action

      配置Action就是指定哪个请求对应用哪个Action进行处理,从而让核心控制器根据该配置来创建合适的Action实例。配置文件(struts.xml)片段为

<action name="login" class="com.PM.action.LoginAction">
     ...
</action>

 

 

 

5.配置处理结果和物理视图之间的对应关系

      当Action处理用户请求结束后,通常会返回一个处理结果(通常使用简单的字符串就可以了),我们可以认为该名称是逻辑视图名,这个逻辑视图名要和指定物理视图资源关联才有价值。所以我们还需要配置处理结果之间的对应关系。配置文件片段为:

<action name="login" class="com.PM.action.LoginAction">
     <!--定义了3个逻辑视图和物理视图资源之间的映射-->
     <result name="input">/login.jsp</result>     
     <result name="error">/error.jsp</result>
     <result name="success">/welcome.jsp</result>
</action>
6.编写视图资源

 

为web应用提供Spring支持

        使用Spring的Web应用,无须手动创建Spring容器,而是通过配置文件,声明式地创建Spring容器,直接在web.xml文件中配置创建Spring容器。为了让Spring容器随着Web应用的启动而启动,借助于ServletContextListener监听器即可完成,该监听器可以在Web应用启动时回调自定义方法—该方法可以启动Spring容器。

        Spring提供了一个ContextLoaderListener,该监听器类实现了ServletContextListener接口。该类可以作为Listener使用,它会在创建时自动查找WEB-INF/下的applicationContext.xml文件,因此,如果只有一个配置文件,并且文件名为applicationContext.xml,则只需在web.xml文件中增加如下配置片段即可。

<listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

 

       如果有多个配置文件需要载入,则考虑使用<context-param.../>元素来确定配置文件的文件名。ContextLoaderListener加载时,会查找contextConfigLocation的初始化参数。因此,配置<context-param.../>时应指定参数名为contextConfigLocation,配置文件web.xml增加如下配置片段。

<!-- 指定多个配置文件 -->
<context-param>
     <!--参数名为contextConfigLocation -->
    <param-name>contextConfigLocation</context-param>
    <!-- 多个配置文件之间以“,”隔开 –>
    <param-value>/WEB-INF/daoContext.xml,/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

      如果没有使用 contextConfigLocation指定配置文件,则Spring自动查找applicationContext.xml配置文件;如果有contextConfigLocation,则利用该参数确定的配置文件。如果无法找到合适的配置文件,Spring将无法正常初始化。

      Spring根据配置文件创建WebApplicationContext对象,并将其保存在Web应用的ServletContext中。大部分情况下,应用中的Bean无需感受到ApplicationContext的存在,只要利用ApplicationContext的IoC即可。

 

Hibernate的使用

    Hibernatede 配置信息(如连接哪个数据库,以及连接数据库时所用的连接池、用户名、密码等详细信息)使用配置文件指定(hibernate.cfg.xml)。配置文件如下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
          <property  name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
          <property  name="connection.ul">jdbc:sqlserver://localhost:1433;DatabaseName=PM</property>
          <property  name="connection.username">sa</property>
          <property  name="connection.password"></property>
          <!--指定连接池最大连接数-->
          <property  name="hibernate.c3p0.max_size">40</property>
          <!--指定连接池最小连接数-->
          <property  name="hibernate.c3p0.min_size">1</property>
          <!--指定数据库方言-->
          <property  name="dialect">org.hibernate.dialect.SQLServerDialect</property>
          <!--根据需要自动创建数据表-->
          <property  name="hbm2ddl.auto">update</property>
          <!--罗列所有的映射文件-->
          <mapping resource="com/PM/domain/News.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

     Hibernate配置文件的默认文件名为hibernate.cfg.xml,当程序调用Configuration对象的configure()方法时,Hibernate将自动加载该文件。

    完成保存Member的代码如下,如代码所示程序需要手动获取SessionFactory实例。

public class MemberManager {

      public void main(String[] args){
          //实例化Configuration
          Configuration conf=new Configuration()
          //下面的方法默认加载hibernate.cfg.xml文件
          .configure();
          //以Configuration创建SessionFactory
          SessionFactory sf=conf.buildSessionFactory();
          //创建Session
          Session sess=sf.openSession();
          //开始事务
           Transaction tx=sess.beginTransaction();
          Member m=new Member();
          m.setPassword("123");
          //保存
          sess.save(m);
          //提交事务
          tx.commit();
          //关闭Session
         sess.close();
         sf.close();
          
      }
}

      为了使用Hibernate进行持久化操作,通常有如下操作步骤:

  • 开发持久化类,由POJO加映射文件组成。
  • 获取Configuration。
  • 获取SessionFactory。
  • 获取Session,打开事务。
  • 用面向对象的方式操作数据库。
  • 关闭事务,关闭Session。

 

Spring整合Struts

1.MVC框架与Spring整合的思考

      控制器应该如何获得业务逻辑组件?最容易想到的策略是,直接通过new关键字创建业务逻辑组件,然后调用业务逻辑组件的方法,根据业务逻辑方法的返回值确定结果。但是这是一种非常差的策略,因为

  • 控制器直接创建业务逻辑组件,导致控制器和业务逻辑组件的耦合降低到代码层次,不利于高层次解耦。(解耦)
  • 控制器不应该负责业务逻辑组件的创建,控制器只是业务逻辑组件的使用者,无须关系业务逻辑组件的实现。(职责明确)
  • 每次创建新的业务逻辑组件导致性能下降。(性能)

     答案是采用工厂模式,或者服务定位器模式。经典Java EE应用就是使用的服务定位器模式。对于轻量级的Java EE应用,工厂模式是更实际的策略。工厂可以保证该组件的实例只需一个就够了,可以避免重复实例化造成的系统开销。采用工厂模式,将控制器与业务逻辑组件的实现分离,从而提供更好的解耦。在采用工厂模式的访问策略中,所有的业务逻辑组件的创建由工厂负责,业务逻辑组件的运行也由工厂负责。而控制器只需定位工厂实例即可。

      如果系统采用Spring框架,则Spring成为最大的工厂。Spring负责业务逻辑组件的创建和生成,并可管理业务逻辑组件的生命周期。可以如此理解:Spring是个性能非常优秀的工厂,可以生产出所有的实例,从业务逻辑组件,到持久层组件,甚至控制器组件。

      为了Action访问Spring的业务逻辑组件,有两种策略:

  • Spring容器负责管理控制器Action,并利用依赖注入为控制器注入业务逻辑组件。
  • 利用Spring的自动装配,Action将会自动从Spring容器中获取所需的业务逻辑组件。

2.策略一:让Spring管理控制器

      让Spring容器管理应用中的控制器,可以充分利用Spring的IoC特性,但需配置Struts2的控制器部署在Spring容器中,因此导致配置文件冗余。

      我们把Action实例交由Spring容器来管理,而不是由Struts2产生的。那么,核心控制器如何知道调用Spring容器中的Action,而不是自行创建Action实例呢?这个工作由Struts2提供的Spring插件完成。struts2-spring-plugin-xxx.jar文件,这种JAR包就是Struts2整合Spring的插件,简称Spring插件,将这个JAR包复制到Web应用的WEB-INF/lib目录下。

      Spring插件提供了一种伪Action,当我们在struts.xml文件中配置Action时,通常需要指定class属性,该属性就是用于创建Action实例的实现类。但Spring插件允许我们指定class属性时,不再指定Action的实际实现类,而是指定Spring容器中的BeanID,这样Struts2不再自己负责创建Action实例,而是直接通过Spring容器去获取Action对象。在这种整合策略下,处理用户请求的Action由Spring插件负责创建,但Spring插件创建Action实例时,并不是利用配置Action指定的class属性来创建该Action实例,而是从Spring容器中取出对应的Bean实例完成创建。

      Spring和Struts2整合的关键所在是Spring容器为控制器注入业务逻辑组件。

      配置文件struts.xml的相应片段如下:

<!--定义处理用户请求的Action,该Action的class属性不是实际处理类,
     而是Spring容器中的Bean实例-->
<action name="loginPro" class="loginAction">
      <result name="error">/error.jsp</result>
      <result name="success">/welcome.jsp</result>
</action>
    配置文件applicationContext.xml的相应片段如下:
<!--定义一个业务逻辑组件,实现类为MyServiceImpl -->
<bean id="myService"  class="com.PM.service.impl.MyServiceImpl"/>
<!--让Spring容器管理Action实例-->
<bean id="loginAciton" class="com.PM.action.LoginAction" scope="prototype">
    <!--依赖注入业务逻辑组件-->
    <property name="ms" ref="myService"/>
</bean>

      当Spring管理Struts2的Action时,一定要配置scope属性,因为Action里包含了请求的状态信息,所以必须为每个请求对应一个Action,所以不能将Action实例配置成单例模式。

      这种策略充分利用了Spring的IoC特性,是一种较为优秀的解耦策略,这种策略也有一些不足之处。

  • Spring管理Action,必须将所有的Action配置在Spring容器中,而struts.xml文件中还需要配置一个“伪Action”,从而导致配置文件冗余,臃肿。
  • Action的业务逻辑组件接收容器的注入,将导致代码的可读性降低。

3.策略二:使用自动装配

      在这种策略下,Action还是由Spring插件创建,Spring插件在创建Action实例时,利用Spring的自动装配策略,将对应的业务逻辑组件注入Action实例。这种整合策略配置文件简单,但控制器和业务逻辑组件耦合又提升到了代码层次,耦合较高。

      所谓自动装配,即让Spring自动管理Bean与Bean之间的依赖关系,无须使用ref显示指定依赖Bean。Spring容器会自动检查XML配置文件内容,为主调Bean注入依赖Bean。自动装配可以减少配置文件的工作量,但会降低依赖关系的透明性和清晰性。此处的自动装配策略与Spring自身所提供的自动装配完全相同。

      在这种装配策略下,我们还采用传统的方式来配置Struts2的Action,配置Action时一样指定其具体的实现类,配置文件struts.xml片段如下。因为使用了自动装配,Spring插件创建Action实例时,是根据Action的class属性指定实现类来创建Action实例的。

<!--定义处理用户请求的Action-->
<action name="loginPro" class="com.PM.action.LoginAction">
      <result name="error">/error.jsp</result>
      <result name="success">/welcome.jsp</result>
</action>

     此时Struts2的配置文件里配置的依然是Action的实现类,该配置文件与不整合Spring时的配置文件没有任何区别。整合Spring框架与不整合时当然存在区别,只是这个区别不是在配置文件中体现,而是在创建该Action实例时体现出来的。如果不整合Spring框架,则Struts2框架负责创建Action实例, 创建成功后就结束;如果整合Spring框架,则当Action实例创建完成后,Spring插件还会负责将该Action所需的业务逻辑组件注入给该Action实例。Action类代码片段如下:

//系统所有的业务逻辑组件
private MyService ms;
//设置注入业务逻辑组件所必需的setter方法
public void setMs(MyService ms){
      this.ms=ms;
}
   通过上面的setter方法,可以看出该Action所需的业务逻辑组件名为ms,因此我们必需在配置业务逻辑组件时,指定其id属性为ms。配置文件applicationContext.xml片段为:
<!--- 定义一个业务逻辑组件,实现类为MyServiceImpl-->
<bean id="ms" class="com.PM.service.impl.MyServiceImpl"/>

    因为在配置业务逻辑组件时,指定了该业务逻辑组件的id为ms,则Spring插件可以在创建Action实例时将该业务逻辑组件注入给Action实例。

    在这种整合策略下,Spring插件负责为Action自动装配业务逻辑组件,从而可以简化配置文件的配置。这种方式也存在如下两个缺点。

  • Action与业务逻辑组件的耦合降低到了代码层次,必须在配置文件中配置Action所需业务逻辑组件同名的业务逻辑组件,不利于高层次解耦。
  • Action接受Spring容器的自动装配,代码的可读性较差。

 

 

 

Spring整合Hibernate

  1.管理Hibernate的SessionFactory

       当通过Hibernate进行持久层访问时,必须先获得SessionFactory对象,它是单个数据库映射关系编译后的内存镜像。大部分情况下,一个Java EE应用对应一个数据库,即对应一个SessionFactory对象。纯粹的Hibernate访问中,应用程序需要手动创建SessionFactory实例,在实际开发中,我们希望以一种声明式的方式管理SessionFactory实例,直接以配置文件来管理SessionFactory实例。Spring的IoC容器正好提供了这种管理方式,它不仅能以声明式的方式配置SessionFactory实例,也可以充分利用IoC容器的作用,为SessionFactory注入数据源引用。

<!-- 定义数据源Bean 使用c3p0数据源实现-->
   <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
           destroy-method="close">
          <!--指定连接数据库的驱动-->
          <property  name="driverClass" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
          <property  name="jdbcUrl" value="jdbc:sqlserver://localhost:1433;DatabaseName=PM;SelectMethod=cursor"/>
          <property  name="user" value="sa"/>
          <property  name="password" value=""/>
          <property  name="maxPoolSize" value="40"/>
          <property  name="minPoolSize" value="1"/>
          <!--指定连接数据库连接池的初始化连接数-->
          <property  name="initialPoolSize" value="1"/>
          <!--指定连接数据库连接池的连接的最大空闲时间-->
          <property  name="maxIdleTime" value="20"/>
   </bean>
   <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
         <property name="dataSource" ref="dataSource"/>
         <!--用来列出所有的PO映射文件 -->
         <property name="mappingResources">
            <list>
                <value>com/PM/domain/Admin.hbm.xml</value>
                <value>com/PM/domain/Member.hbm.xml</value>
                <value>com/PM/domain/Department.hbm.xml</value>
            </list>
         </property>
         <!--设置Hibernate属性 -->
         <property name="hibernateProperties">
               <props>
                    <!--配置连接数据库的方言-->
                    <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
                    <!--设置当创建SessionFactory时,是否根据映射文件自动建立数据库表—>
                    <prop key="hibernate.hbm2ddl.auto">create</prop>
                    <!--是否将SQL语句转化成格式良好的SQL –>
                    <prop key="hibernate.format_sql">true</prop>
               </props>
         </property>
   </bean>

     一旦在Spring的IoC容器中配置了SessionFactory Bean,它将随应用的启动而加载,并可以充分利用IoC容器的功能,将SessionFactory Bean注入任何Bean,比如DAO组件,一旦DAO组件获得了SessionFactory Bean的引用,就可以完成时间的数据库访问。

     当以声明式的方式来管理SessionFactory时,可以让应用在不同的数据源之间切换。如果应用需要更换数据库等持久层资源,只需对配置文件进行简单修改即可。声明式的方式管理SessionFactory,是为了提供更好的适应性:当持久层服务需要更改时,程序代码无需任何改变。

2.使用声明式事务

      Spring的事务机制非常优秀,它允许我们在开发过程中无须理会任何事务逻辑,等到应用开发完成后使用声明式事务来进行统一的事务管理。只需要在配置文件中增加事务控制的片段,业务逻辑组件的方法将会具有事务性;而且Spring的声明式事务支持在不同事务策略之间自由切换。

      配置Spring声明式事务时,通常推荐使用BeanNameAutoProxyCreator自动创建事务代理。通过这种自动事务代理的配置策略,增加业务逻辑组件,只需在BeanNameAutoProxyCreator Bean配置中增加一行即可,从而避免了增量式配置。

      为业务逻辑组件添加事务执行如下几个步骤。

  1. 针对不同的事务策略配置对应的事务管理器。
  2. 使用<tx:advice.../>元素配置事务增强处理Bean,配置事务增强处理Bean时使用多个<method.../>元素为不同的方法指定相应的事务语义。
  3. 在<aop:config.../>元素中使用<aop:advisor>元素配置自动事务代理。

   只需在Spring配置文件中增加如下配置片段,业务逻辑组件的方法将会具有事务性。

   <!-- 配置Hibernate的局部事务管理器,使用HibernateTransactionManager类-->
   <!-- 该类实现PlatformTransactionManager接口,是针对Hibernate的特定实现类-->
   <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
         <property name="sessionFactory" ref="sessionFactory"/>
   </bean>
   <!--配置事务增强处理Bean,指定事务管理器-->
   <tx:advice id="txAdvice" transaction-manager="transactionManager">
         <!--用于配置详细的事务语义-->
         <tx:attributes>
             <!-- 所有以'get'开头的方法是read-only-->
             <tx:method name="get*" read-only="true"/>
             <!-- 其他方法使用默认的事务设置-->
             <tx:method name="*"/>
         </tx:attributes>
   </tx:advice>
   <aop:config>
          <!--配置一个切入点 "*"匹配符表示一个任意类型的参数 "."匹配符表示零个或多个任意类型的参数-->
          <aop:pointcut id="servicePointcut" expression="execution(* com.PM.service.impl.*.*(..))"/>          
          <!--指定在servicePointcut切入点应用txAdvice事务增强处理-->
          <aop:advisor  advice-ref="txAdvice" pointcut-ref="servicePointcut"/>
   </aop:config>
尽量使用声明式事务配置方式,而不要在代码中完成事务逻辑。
posted @ 2013-01-03 20:33  游园惊梦  阅读(888)  评论(0编辑  收藏  举报