Spring2+struts2+ibatis整合

文章轉自:http://blog.csdn.net/lidawei201/article/details/8506825

前幾天因爲需要,將spring2、struts2和ibatis進行了整合,整合過程涉及到很多技巧,因此作爲日誌保存在此,以便今後查詢。

各個框架在本項目內的作用:

spring2:主要利用ioc,以及對事物的管理,減少硬性編碼和脫離手動事務控制。

struts2:主要用於MVC以及數據校驗。struts2擺脫了struts1性能上的瓶頸,達到了新的高度,配置更靈活,全面支持ajax,freemark等等,採用ognl動態語言使得輸出也更加靈活。

iBatis:主要用於作orm。開發效率不如hibernate,但是由於是半自動映射,因此更加靈活,並且效率更好,維護更方便。

整合過程(eclipse導包過程省略)

主要配置如下:

配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    <!-- struts2模塊 -->
    <filter>
        <filter-name>struts2</filter-name>
       <!-- 這個就是struts2的核心過濾器 -->
        <filter-class>
            org.apache.struts2.dispatcher.FilterDispatcher
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!-- 項目中的字符編碼處理,與整合無關 -->
    <filter>
        <filter-name>CharacterFilter</filter-name>
        <filter-class>
            com.afl.system.filter.CharacterFilter
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CharacterFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
   <!-- spring listener -->
    <listener>
        <!-- 這個就是今後用到的WebApplicationUtilContent -->
        <listener-class>
org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
    <!-- springframework config files -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <!-- 把spring的配置文件放到了/WEB-INF/下的springframework包裏,方便統一管理,命名規則是以applicationContent-開頭的xml文件,初始化時會自動搜索所有符合規則的配置文件 -->
        <param-value>
            /WEB-INF/springframework/applicationContext-*.xml
        </param-value>
    </context-param>
    <!-- config servlet -->
    <!-- 這個是dwr的配置文件,與整合無關 -->
    <servlet>
        <servlet-name>dwr</servlet-name>
        <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>true</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>dwr</servlet-name>
        <url-pattern>/dwr/*</url-pattern>
    </servlet-mapping>
</web-app>

配置Spring
applicationContext-iBatis.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
    <!-- 配置數據源,連接池採用的是c3p0,具體各參數代表意義參看c3p0自帶的doc,非常詳細。 -->
    <bean id="dataSource"
       class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close">
        <property name="driverClass" value="${jdbc.driverClass}" />
        <property name="jdbcUrl" value="${jdbc.url}" />
        <property name="user" value="${jdbc.user}" />
        <property name="password" value="${jdbc.password}" />
        <property name="minPoolSize" value="${jdbc.minPoolSize}" />
        <property name="maxPoolSize" value="${jdbc.maxPoolSize}" />
        <property name="maxIdleTime" value="${jdbc.maxIdleTime}" />
        <property name="acquireIncrement"
            value="${jdbc.acquireIncrement}" />
        <property name="maxStatements" value="${jdbc.maxStatements}" />
        <property name="initialPoolSize"
            value="${jdbc.initialPoolSize}" />
        <property name="idleConnectionTestPeriod"
            value="${jdbc.idleConnectionTestPeriod}" />
        <property name="acquireRetryAttempts"
            value="${jdbc.acquireRetryAttempts}" />
    </bean>

    <!-- 配置iBatis的sqlMapClient,這裏當然是交給了spring去處理,其中,將SqlMapConfig文件放到了WEB-INF的iBatis目錄下,也是便於管理 -->
    <bean id="sqlMapClient"
       class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
        <property name="configLocation">
            <value>/WEB-INF/iBatis/SqlMapConfig.xml</value>
        </property>
        <!-- 這裏使用的數據源就是上面配置的數據源 -->
        <property name="dataSource">
            <ref bean="dataSource" />
        </property>
    </bean>

   <!-- 上面的數據源的value值用的是表達式,原因就在這裏,這將配置文件放到了iBatis目錄下,也就是jdbc.properties,設置了c3p0的各項參數 -->
    <bean id="propertyConfig"
       class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location">
            <value>/WEB-INF/iBatis/jdbc.properties</value>
        </property>
    </bean>

   <!-- 這個就是spring的事務管理了,採用的DataSource事務管理,要管理的DataSource當然也是上面配置的DataSource -->
    <bean id="transactionManager"
       class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource">
            <ref bean="dataSource" />
        </property>
    </bean>

<!-- 事務管理的代理類,將其抽象化abstruct=true,以後需要進行事務管理直接繼承此類就行了,非常方便 -->
    <bean id="transactionProxy"
       class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
        <!-- 這個就是剛纔配置的事務管理器 -->
        <property name="transactionManager">
            <ref bean="transactionManager"/>
        </property>
        <!-- 下面是spring事務管理的策略,可以看到,凡是涉及數據庫插入、修改的操作都應當以add、insert、edit、update、delete開頭,這樣才能由spring進行事務管理 -->
        <property name="transactionAttributes">
            <props>
                <prop key="insert*">PROPAGATION_REQUIRED,-Exception</prop>
                <prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
                <prop key="update*">PROPAGATION_REQUIRED,-Exception</prop>
                <prop key="edit*">PROPAGATION_REQUIRED,-Exception</prop>
                <prop key="delete*">PROPAGATION_REQUIRED,-Exception</prop>
                <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="query*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>

    <!-- 這是項目中註冊類,使用的sqlMapClient由spring去注入 -->
    <bean id="registerDAO"
        class="com.afl.register.service.dao.impl.RegisterDAOImpl">
        <property name="sqlMapClient">
            <ref bean="sqlMapClient" />
        </property>
        <property name="dataSource">
            <ref bean="dataSource" />
        </property>
    </bean>

    <!-- 項目中,我將事務管理放到了service層上,因爲dao只負責與數據庫基本交互,在此項目中一般只操作一個表,無需事務。而service層上根據業務需要處理多表,因此將事務放在了service層上,其中的parent就是上面配置並abstract的代理 -->
    <bean id="registerService" parent="transactionProxy">
        <property name="target">
            <bean class="com.afl.register.service.impl.RegisterServiceImpl">
                <property name="registerDAO">
                    <ref bean="registerDAO"/>
                </property>
            </bean>
        </property>
    </bean>
</beans>

jdbc.properties
這個就是spring裏面c3p0對應的值
jdbc.driverClass=com.microsoft.sqlserver.jdbc.SQLServerDriver
jdbc.url=jdbc:sqlserver://localhost:1433;DatabaseName=數據庫名
jdbc.user=sa
jdbc.password=密碼
jdbc.minPoolSize=5
jdbc.maxPoolSize=20
jdbc.maxIdleTime=1800
jdbc.acquireIncrement=5
jdbc.maxStatements=50
jdbc.initialPoolSize=10
jdbc.idleConnectionTestPeriod=1800
jdbc.acquireRetryAttempts=30

接下來繼續iBatis和spring的整合
根據上面的配置,在WEB-INF/iBatis中應該還有SqlMapConfig.xml文件,內容如下


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN" 
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
    <!-- 就像hibernate的hbm.xml文件一樣,一個實體對應一個xml -->
    <!-- 用戶信息表 -->
    <sqlMap resource="com/afl/system/entity/User.xml" />
</sqlMapConfig>

接着就是User.java和User.xml的內容
User.java

public class User {
    // 主鍵 id
    private Long id;

    // 用戶名
    private String username;

    // 密碼
    private String password;
      ....... 以下省略 ......
}
User.xml
<!-- 沒啥多說的,參看iBatis文檔 -->

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"      
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap>
    <typeAlias alias="User" type="com.afl.system.entity.User" />
    <!-- 保存註冊信息 -->
    <insert id="insertUser" parameterClass="User">
        insert into
        AFL_User(username,password)values(#username#,#password#)
    </insert>
</sqlMap>

至此,iBatis與Spring的整合完成。接着是整合struts2

由於從spring配置文件中讀取bean會經常用到WebApplicationContext,並且struts2採用了vs機制,因此想要像struts1那樣操作request,response,session需要做一些處理,所以建立了一個基類,以後的action由此派生

BaseAction.java
下面紅色的就是需要的基類,可以集成後獲得request,response,session以爲web上下文,從此除了按struts2方式處理外,遇到難題仍然可以像struts1那樣處理問題了

/**
* 所有Action的基類,繼承自BaseAction的action都可以直接使用HttpServletRequest,HttpServletResponse和Session
*/
package com.afl.system.struts2.action;

import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import org.apache.struts2.interceptor.SessionAware;
import org.apache.struts2.util.ServletContextAware;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.opensymphony.xwork2.ActionSupport;

/**
* @author zcpeng

*/
public class BaseAction extends ActionSupport implements SessionAware,
        ServletRequestAware, ServletResponseAware, ServletContextAware {
    protected Map session;

    protected HttpServletRequest request;

    protected HttpServletResponse response;

    protected ServletContext context;

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.struts2.util.ServletContextAware#setServletContext(javax.servlet.ServletContext)
     */
    public void setServletContext(ServletContext context) {
        // TODO Auto-generated method stub
        this.context = context;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.struts2.interceptor.ServletResponseAware#setServletResponse(javax.servlet.http.HttpServletResponse)
     */
    public void setServletResponse(HttpServletResponse response) {
        // TODO Auto-generated method stub
        this.response = response;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.struts2.interceptor.ServletRequestAware#setServletRequest(javax.servlet.http.HttpServletRequest)
     */
    public void setServletRequest(HttpServletRequest request) {
        // TODO Auto-generated method stub
        this.request = request;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.struts2.interceptor.SessionAware#setSession(java.util.Map)
     */
    public void setSession(Map session) {
        // TODO Auto-generated method stub
        this.session = session;
    } 
    <!-- 這個就是獲得設備上下文的方法,和struts1一樣吧^-^ -->

    public ApplicationContext getApplicationContext() {
        return WebApplicationContextUtils.getWebApplicationContext(context);
    } 
<!-- 作了個處理,以後需要調用spring的bean,直接調用此方法就可以了 -->

    public Object getObject(String beanName) {
        return getApplicationContext().getBean(beanName);
    }

}

接下來在/web-inf/springframework目錄下建立applicationContext-action.xml,這裏全是struts2的action,並且交給spring產生
生成方式採用的是prototype,至於爲什麼,參閱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"
    xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
    <!-- struts2's Action Mapping -->
    <!-- 基礎Action -->
    <bean name="baseAction"
        class="com.afl.system.struts2.action.BaseAction" scope="prototype">
    </bean>
    <!-- 用戶註冊action -->
    <bean name="registerAction"
        class="com.afl.register.action.RegisterAction" scope="prototype">
    </bean>

</beans>

最後,也是最重要的一個配置文件struts.xml,這個文件是在classes目錄下

<?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>
    <!-- 這是一個重要的地方,很多人在使用<s:include>子頁面後,發現子頁面亂碼,怎麼改都不行,原因就在次,struts2的默認編碼爲UTF-8,亂碼的同志請看看你的jsp頁面上的編碼是不是和這個不一致呢。只要把這裏和jsp編碼改一致就行了 -->
    <constant name="struts.i18n.encoding" value="UTF-8" />
  <!-- 告訴struts2,我要用spring裝配工廠,其實默認就是這個了-_-!!! -->
    <constant name="struts.objectFactory" value="spring" />
  <!-- struts2的擴展名,比如struts1的時候,用的.do,struts2默認爲.action,可以改成其它的,比如.dxd -->
    <constant name="struts.action.extension" value="action" />
<!-- 資源文件 -->
    <constant name="struts.custom.i18n.resources"
        value="messageResource">
    </constant>

    <!-- 用戶註冊類 -->
<!-- abstract屬性就說明了該action繼承自自己定義的基礎action,而class採用的registerAction是由spring產生的 -->
    <package name="register" extends="struts-default"
        abstract="baseAction">
        <action name="addUser" class="registerAction"
            method="addUser">
            <!-- 註冊成功 -->
            <result name="success">
                /register/register_success.jsp
            </result>
            <!-- 註冊失敗 -->
            <result name="input">/register/register.jsp</result>
        </action>
    </package> 
</struts>

至此整合完成!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章