一.為什麼要用架構和模式
1.為什麼要用模式?
因為模式是一種指導,在一個良好的指導下,有助于你完成任務,有助于你作出一個優良的設計方案,達到事半功倍的效果。而且會得到解決問題的最佳辦法。
2.為什麼要用架構?
因為軟體系統發展到今天已經很複雜了,特别是伺服器端軟體,設計到的知識,内容,問題太多。在某些方面使用别人成熟的架構,就相當于讓别人幫你完成一些基礎工作,你隻需要集中精力完成系統的業務邏輯設計。而且架構一般是成熟,穩健的,他可以處理系統很多細節問題,比如,事物處理,安全性,資料流控制等問題。還有架構一般都經過很多人使用,是以結構很好,是以擴充性也很好,而且它是不斷更新的,你可以直接享受别人更新代碼帶來的好處。總之:就是讓開發更簡單,讓我們成功。
持久層:spirng的hibernate支援
struts+spring方案一
原理:在action中擷取beanfactory,并通過beanfactory對象擷取業務邏輯對象。
1建立web應用
2spring和struts內建
安裝struts{
struts的jar包
修改web.xml檔案,定義struts的actionservlet
提供struts-config.xml檔案
提供國際化資源檔案}
安裝spring
拷貝spring的jar包
提供spring的配置檔案
3在struts的action中調用如下代碼取出beanfactory
beanfactory factory=webapplicationcontextutils
.getrequiredwebapplicationcontext(servletcontext);
4通過beanfactory取得業務對象,調用業務邏輯方法(不管理action)
struts+spring方案二
(耦合度比方案一低,最大的不便是所有的action 必須同時在struts 和
spring 的配置檔案中各配置一次。)
原理:将業務邏輯對象通過spring注入到action中,進而避免了在action中直接代碼查找。
3因為action中需要調用業務邏輯,在action中提供setter方法,讓spring将業務邏輯對象注入給我們
4struts-config.xml檔案中的<action>标簽要改
5spring配置
local屬性是在同一個配置檔案中的bean
bean屬性是指出一個bean,可以不在同一個配置檔案中
一般用get不用load,因為get沒有值傳回null,而load會抛異常
spring需要配置hibernate的懶加載能夠讓session解釋完成再關閉,避免懶加載異常。opensessioninviewfilter模式web.xml中加入
<filter>
<filter-name>hibernatefilter</filter-name>
<filter-class>org.springframework.orm.hibernate.support.opensessioninviewfilter</filter-class>
</filter>
<filter-mapping>
<url-pattern>/*</url-pattern>
</filter-mapping>
window/show view/springbeans
show in spring beans view看spring bean的屬性,看bean直接的依賴關聯情況:在springbeans工作區裡右鍵.xml檔案/show graph.
建立 spring 配置檔案,将檔案放到src目錄下,檔案名稱為 applicationcontext.xml, 編譯後放到 web-inf/classes/ 下.配置struts-config.xml檔案,添加 spring的插件, 位置在 struts-config 檔案的<message-resources>标簽末尾.
<!-- 加載spring,xml -->
<plug-in classname="org.springframework.web.struts.contextloaderplugin">
<set-property property="contextconfiglocation" value="web-inf/classes/applicationcontext-action.xml,web-inf/classes/applicationcontext-business.xml,web-inf/classes/applicationcontext-dao.xml,web-inf/classes/applicationcontext-pojos.xml,web-inf/classes/applicationcontext-sessionfactory.xml" />
</plug-in>
<!--action注入service、pojo,service注入dao,dao注入sessionfactory-->
方法二:web.xml中加入
<context-param>
<param-name>contextconfiglocation</param-name>
<param-value>
web-inf/applicationcontext-*xml,classpath*:/applicationcontext-*xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.contextloaderlistener
</listener-class>
</listener>
3. 修改 struts 的 struts-config.xml 中的action配置
原:
<action
attribute="loginform"
input="/login.jsp"
name="loginform"
path="/login"
scope="request"
validate="true"
type="com.test.struts.action.loginaction" />
改為:
type="org.springframework.web.struts.delegatingactionproxy" />
type 部份為修改内容, 這裡将使用spring的代理器來對action進行控制. 沒有調用到dao的action的type沒有必要改代理類來截獲,
當送出到/login.do是将控制權交給了spring,然後由spring來把它轉回到struts的action.
修改 struts 的 struts-config.xml 中的action配置方法二
在<message-resources>标簽前添加
<controller>
<set-property property="processorclass"
value="org.springframework.web.struts.delegatingrequestprocessor"/>
</controller>
增加這些設定之後,不管你查詢任何類型的 action,sping都自動在它的context配置檔案中尋找。實際上,你甚至不需要指定類型。下面兩個代碼片斷都可以工作:
<action path="/user" type="com.whatever.struts.useraction"/>
<action path="/user"/>
如果你使用 struts 的 modules 特性,你的 bean 命名必須含有 module 的字首。 舉個例子,如果一個 action 的定義為 <action path="/user"/>,而且它的 module 字首為“admin”, 那麼它應該對應名為 <bean name="/admin/user"/> 的 bean。注意:
action bean必須使用name屬性,不能用id屬性
那麼屬性必須和struts-config.xml中的<action>标簽的path屬性值一緻
最好将scope設定為prototype(或singleton=false),即每次請求建立一個action,進而避免了struts action的線程安全
4. 配置spring 來執行個體化被删除的 action type.
<beans>
<bean name="/login" class="com.test.struts.action.loginaction" scope=prototype></bean>
</beans>
spring 通過 org.springframework.web.struts.delegatingactionproxy 這個類, 然後根據 struts 配置檔案中的 <action path="/login" ..> 和 spring 配置檔案中的 <bean name="/login" ..> 來将 spring 管理下的 struts action 類和送出的路徑比對起來, 這些就是關于轉交控制權的配置内容.
hibernate.cfg.xml中
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="show_sql">true</property> <!--終端輸出sql-->
<property name="format_sql">true</property> <!-- 使sql語句格式更加美觀統一 -->
<property name=" use_sql_comments ">true</property> <!--添加sql注釋-->
<property name="connection.useunicode">true</property>
<property name="connection.characterencoding">utf-8</property>
spring.xml中
<prop key="show_sql">true</prop>
<prop key="format_sql">true</prop>
<prop key="connection.useunicode">true</prop>
<prop key="connection.characterencoding">utf-8</prop>
middlegen+ant+xdoclet能很友善建構項目.配置環境變量可以使用或友善使用因為可以指令行直接輸入指令,不需要到該目錄下。
spring事務管理
gethibernatetemplate().executefind()傳回list。
靜态方法不能用gethibernatetemplate()是以可以用hibernatetemplate。hibernatetemplate對hibernate session操作進行了封裝,借助hibernatetemplate我們可以脫離每次資料操作必須首先獲得session執行個體、啟動事務、送出/復原事務以及煩雜的try/catch/finally的繁瑣操作。
<bean id="hibernatetemplate"
class="org.springframework.orm.hibernate3.hibernatetemplate">
<property name="sessionfactory">
<ref bean="sessionfactory" />
</proper
</bean>
jdk 的代理機制來實作事務管理的解決方案, 相比起來它有一個麻煩的地方就是必須需要生成一個 dao 的接口才能工作. 那麼另一種比較簡單的解決方案就是用 cgblib, 可以不用編寫接口, 那麼下面是 spring 參考文檔中的内容:
基于jdk和cglib的代理
這個小節作為說明性文檔,解釋了對于一個目标對象(需要被代理的對象),proxyfactrybean是如何決定究竟建立一個基于jdk還是cglib的代理的。
注意
proxyfactorybean需要建立基于jdk還是cglib代理的具體行為在版本1.2.x和2.0中有所不同。現在proxyfactorybean在關于自動檢測接口方面使用了與transactionproxyfactorybean相似的語義。
如果一個需要被代理的目标對象的類(後面将簡單地稱它為目标類)沒有實作任何接口,那麼一個基于cglib的代理将被建立。這是最簡單的場景,因為jdk代理是基于接口的,沒有接口意味着沒有使用jdk進行代理的可能。 在目标bean裡将被插入探測代碼,通過interceptornames屬性給出了攔截器的清單。注意一個基于cglib的代理将被建立即使proxyfactorybean的proxytargetclass屬性被設定為false。 (很明顯這種情況下對這個屬性進行設定是沒有意義的,最好把它從bean的定義中移除,因為雖然這隻是個多餘的屬性,但在許多情況下會引起混淆。)
如果目标類實作了一個(或者更多)接口,那麼建立代理的類型将根據proxyfactorybean的配置來決定。
如果proxyfactorybean的proxytargetclass屬性被設為true,那麼一個基于cglib的代理将建立。這樣的規定是有意義的,遵循了最小驚訝法則(保證了設定的一緻性)。 甚至當proxyfactorybean的proxyinterfaces屬性被設定為一個或者多個全限定接口名,而proxytargetclass屬性被設定為true仍然将實際使用基于cglib的代理。
如果proxyfactorybean的proxyinterfaces屬性被設定為一個或者多個全限定接口名,一個基于jdk的代理将被建立。被建立的代理将實作所有在proxyinterfaces屬性裡被說明的接口;如果目标類實作了全部在proxyinterfaces屬性裡說明的接口以及一些額外接口,傳回的代理将隻實作說明的接口而不會實作那些額外接口。
如果proxyfactorybean的proxyinterfaces屬性沒有被設定,但是目标類實作了一個(或者更多)接口,那麼proxyfactorybean将自動檢測到這個目标類已經實作了至少一個接口, 一個基于jdk的代理将被建立。被實際代理的接口将是目标類所實作的全部接口;實際上,這和在proxyinterfaces屬性中列出目标類實作的每個接口的情況是一樣的。然而,這将顯著地減少工作量以及輸入錯誤的可能性。
好了, 詳細闡述這個解決方案.
用 myeclipse 的自動生成功能産生的 spring + hibernate 的 dao 有時候會出現不能儲存資料但是可以查詢資料的問題, 這是因為預設生成的 spring 配置檔案裡面沒有包含對事務的操作, 也就是沒有 commit hibernate transaction 的調用是以無法儲存資料. 也就是正确的調用需要 begintran, save, commit, 但是現在就少了 tran 的調用代碼部分.
解決方法是在配置檔案裡"侵入性"(必須這樣做, 做額外的配置和修改, 否則就無法正常工作, 是以是侵入性的)的加入事務配置後就可以正常的儲存資料了.
1. 用 eclipse 的重構給自動生成的 usersdao 類添加一個接口, 裡面包含所有的方法聲明, 例如 iusersdao, 加入接口的目的是為了使用 jdk 的動态代理方式實作的 spring aop 來工作,
2. 修改配置檔案給原來的 usersdao 加入代理類來進行事務管理:
<?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/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
.................
<!-- usersdao implements iusersdao 接口 -->
<bean id="usersdao" class="dao.usersdao">
</property>
</bean>
................
1.基于cglib的代理, 修改配置檔案給原來的 usersdao 加入代理類來進行事務管理:
<!--右鍵new sessionfactory-->
<bean id="sessionfactory"
class="org.springframework.orm.hibernate3.localsessionfactorybean">
<property name="configlocation"
value="file:src/hibernate.cfg.xml">
<!-- 以下兩個 bean transactionmanager 和basetxproxy 是新加入的内容, 用來配置事務 -->
<!-- 聲明一個 hibernate 3 的 事務管理器供代理類自動管理事務用 -->
<bean id="transactionmanager"
class="org.springframework.orm.hibernate3.hibernatetransactionmanager">
<ref local="sessionfactory" />
<!-- 這個代理類是最後對外公開的類, 否則因為沒有進行事務操作,
儲存時沒有送出 hibernate 的事務, 這将無法對資料庫進行改動, 也就是原來要調用 usersdao 的地方都要轉而調用這個代理對象 basetxproxy; 具體的屬性配置在 target 參數那裡指定了這個對象對原來的 usersdao 對象進行代理;
也因為要使用代理, 隻有通過它來作為原來配置的usersdao 的代理工作, 才能讓 spring 在儲存資料的時候自動打開hibernate 的transaction 并送出, 即屬性 transactionmanager 配置的 hibernatetransactionmanager -->
<bean id="basetxproxy" lazy-init="true"
class="org.springframework.transaction.interceptor.transactionproxyfactorybean">
<property name="transactionmanager"><ref bean="transactionmanager"/></property>
<!-- 注意這個屬性, 必須為 true 使用cglib才不用強制編寫dao接口,使用dao接口不需要-->
<property name="proxytargetclass">
<value>true</value>
<property name="target">
<ref local="userservicetarget " />
</property>
<property name="transactionattributes">
<props>
<prop key="save*">propagation_required</prop>
<prop key="update*">propagation_required</prop>
<prop key="get*">propagation_required,readonly</prop>
<prop key="delete*">propagation_required</prop>
<prop key="is*">propagation_required,readonly</prop>
<prop key="*">propagation_required</prop>
<!-- *是通配符,可以表示沒有注冊的所有方法 -->
</props>
<bean id="userservicetarget" class="org.mzone.service.impl.userservicetarget">
<property name="userdao"><ref local="userdao"/></property>
<property name="articledao"><ref local="articledao"/></property>