文章轉自: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>
至此整合完成!