??Spring JPetStore總體架構屬于三層結構. 分為業務服務層? 表現層? 數據訪問層
??
?????? 業務服務層使用由POJO(java類)實現, 它們運行在輕量級的容器Spring中. 輕量級容器的功能在于,?一 管理業務對象的生命周期. 二 借助于Spring?的IOC(Inversion of Control, 控制反轉)功能來完成對象之間的依賴關系, 而不用編程一顯示完成. 三 借助于Spring的AOP(Aspect-Oriented Programming, 面向方面的程序設計)?為運行在容器中的對象提供一些企業服務, 比如聲明式的事務管理. 業務層放棄了EJB而使用運行在輕量級容器的服務層, 會有以下好處:
1.? 能夠在Servlet引擎中運行. 不用EJB容器的服務器, tomcat就能搞定, 軟件的費用低, 容易管理, 負載小.
2?. 容易在不同的應用服務器或serverlet引擎之間移植. 要想達到高可移植性, 對于EJB容器來說要比web容器困難, 比如, 就需要確保不同的EJB容器在啟動時都會運行某一些代碼.
3.??實現更為簡單.
4. 不需要那么累贅的部署文件.
不好的地方:
1.? 缺乏對遠程調用的內置支持.
2.? 缺乏一個標準的環境, 用于容納, 管理業務對象.
3.? 沒有清晰的業務層.
4.? 在不同的應用系統之間缺乏一致性, 第個系統都可能會有自己的一套做法: 怎么訪問業務對象?怎么解決事務管理 怎么訪問數據等.
雖然如此但現在我們有了spring一切就有了解決之道了.
????? 表現層中, Spring JPetStore提供了兩種不同的web層實現, 二者都要依靠同一個中間層, 一個是基于Structs的,另一個則是Spring的MVC框架. 二者都是基于JSTL的JSP視圖.
????? 數據訪問層,使用了J2EE模式中的"數據訪問對象"(Data Access Object, DAO),?他用一個DAO接口隱藏了持久化操作的細節, 這樣使用這個模式的業務對象無需知道底層的持久化技術的細節. Spring JPetStore中使用了iBATIS框架.
下面讓我們來看一下應用中的細節內容吧, 先在Eclipse下把應用加進來方便調試, 運行.
Eclipse可到(http://www.eclipse.org/downloads/上下載)他是壓縮包解壓后就可用(可以再去下MyEclipe http://www.myeclipse.com是Eclipese的開發插件方便開發, 不過要付費可以下載它的破解文件http://jinxinxin.bokee.com/inc/myeclipse_keygens.rar?MyEclipse的安裝如果不會去Google一下吧). 好了開發工具安裝后新建一工程jpetstore, 然后用..\spring-jpetstore\samples\jpetstore下的src目錄復蓋你的eclipse工作空間下的\jpetstore下的src目錄,然后再把..\spring-jpetstore\samples\jpetstore下的war目錄下的全部內容拷到你的eclipse工作空間下的\jpetstore下的WebRoot目錄下復蓋WEB-INF.回到eclipse下刷新工程你可看到如下:
先從數據訪問層說起吧, 他使用iBATIS框架來訪問數據庫,在..\spring-jpetstore\samples\jpetstore\db目錄下有它的各種數據庫的schema有hsql, mysql, oracle, postges你使用拿一種數據庫是通過..\spring-jpetstore\samples\jpetstore\war\WEB-INF下的jdbc.properties來配置的.默認的是hsql數據庫:
# Properties file with JDBC-related settings.
# Applied by PropertyPlaceholderConfigurer from "dataAccessContext-local.xml".
# Targeted at system administrators, to avoid touching the context XML files.
jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://localhost:9002
jdbc.username=sa
jdbc.password=
要改為用mysql只要改為:
#jdbc.driverClassName=org.hsqldb.jdbcDriver
#jdbc.url=jdbc:hsqldb:hsql://localhost:9002
#jdbc.username=sa
#jdbc.password=
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/jpetstore
jdbc.username=root
jdbc.password=
即可.業務層能過...jpetstore.dao包下的接口來訪問....jpetstore.dao.ibatis包從而通過iBATIS框架訪問數據庫中的數據的部份代碼如下:
package org.springframework.samples.jpetstore.dao;
public interface AccountDao {
? Account getAccount(String username, String password) throws DataAccessException;
? ...........
}
package org.springframework.samples.jpetstore.dao.ibatis;
public class SqlMapAccountDao extends SqlMapDaoSupport implements AccountDao {
??? public Account getAccount(String username, String password) throws DataAccessException {
??? Account account = new Account();
??? account.setUsername(username);
??? account.setPassword(password);
??? return (Account) getSqlMapTemplate().executeQueryForObject("getAccountByUsernameAndPassword", account);
? }
..............
}
Account.xml
<mapped-statement name="getAccountByUsernameAndPassword" result-map="result">
??? select
????? SIGNON.USERNAME as USERID,
????? ACCOUNT.EMAIL,
????? ACCOUNT.FIRSTNAME,
????? ACCOUNT.LASTNAME,
????? ACCOUNT.STATUS,
????? ACCOUNT.ADDR1,
????? ACCOUNT.ADDR2,
????? ACCOUNT.CITY,
??????..???
??? from ACCOUNT, PROFILE, SIGNON, BANNERDATA
??? where ACCOUNT.USERID = #username#
????? and SIGNON.PASSWORD = #password#
????? and SIGNON.USERNAME = ACCOUNT.USERID
????? and PROFILE.USERID = ACCOUNT.USERID
????? and PROFILE.FAVCATEGORY = BANNERDATA.FAVCATEGORY
? </mapped-statement>
然后到了業務層, 業務層為表達層提供服務,操縱數據層來完成業務邏輯比如從數據庫中讀出客啟信息傳給表達層 向數據庫中插入訂單等.業務層還要完成對數據庫操作的完整性,正確性即事務管理. 此應用是通過Spring的AOP來完成無需編程實現如下:
dataAccessContex-local.xml
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
??<property name="driverClassName"><value>${jdbc.driverClassName}</value></property>
??<property name="url"><value>${jdbc.url}</value></property>
??<property name="username"><value>${jdbc.username}</value></property>
??<property name="password"><value>${jdbc.password}</value></property>
?</bean>
?<!-- Transaction manager for a single JDBC DataSource -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
? <property name="dataSource">
?? <ref local="dataSource" />
? </property>
? <property name="mappingResources">
?? <list>
??? <value>org/springframework/samples/jpetstore/Hibernate/Account.hbm.xml</value>
?? </list>
? </property>
? <property name="hibernateProperties">
?? <props>
??? <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
??? <prop key="hibernate.show_sql">true</prop>
?? </props>
? </property>
?</bean>
?
?<!-- (see dataAccessContext-jta.xml for an alternative) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
? <property name="sessionFactory">
?? <ref local="sessionFactory" />
? </property>
?</bean>
?<!-- SqlMap setup for iBATIS Database Layer -->
?<bean id="sqlMap" class="org.springframework.orm.ibatis.SqlMapFactoryBean">
??<property name="configLocation"><value>WEB-INF/sql-map-config.xml</value></property>
?</bean>
?<!-- ========================= DAO DEFINITIONS: IBATIS IMPLEMENTATIONS ========================= -->
?<bean id="accountDao" class="org.springframework.samples.jpetstore.dao.hibdaoimp.AccountDaoImp">
? <property name="sessionFactory">
?? <ref local="sessionFactory" />
? </property>
? ?
?</bean>
................
</beans>
applicationContex.xml
<bean id="petStoreTarget" class="org.springframework.samples.jpetstore.domain.logic.PetStoreImpl">
??<property name="accountDao"><ref bean="accountDao"/></property>
??<property name="categoryDao"><ref bean="categoryDao"/></property>
??<property name="productDao"><ref bean="productDao"/></property>
??<property name="itemDao"><ref bean="itemDao"/></property>
??<property name="orderDao"><ref bean="orderDao"/></property>
?</bean>
?<!-- Transactional proxy for the JPetStore primary business object -->
?<bean id="petStore" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
??<property name="transactionManager"><ref bean="transactionManager"/></property>
??<property name="target"><ref local="petStoreTarget"/></property>
??<property name="transactionAttributes">
???<props>
????<prop key="insert*">PROPAGATION_REQUIRED</prop>
????<prop key="update*">PROPAGATION_REQUIRED</prop>
????<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
???</props>
??</property>
?
從上面的配置代碼我們可看到通過Spring的IOC完成了org.springframework.samples.jpetstore.domain.logic.PetStoreImpl等類的注入. 通過AOP用org.springframework.transaction.interceptor.TransactionProxyFactoryBean來完成事務代理
業務層通過一個門面(facada)PetStoreFacade.java接口來為表達層提供服務:
package org.springframework.samples.jpetstore.domain.logic;
public interface PetStoreFacade {
?Account getAccount(String username);
?Account getAccount(String username, String password);
?void insertAccount(Account account);
?void updateAccount(Account account);
..........
}
用PetStoreImp.java來實現:
package org.springframework.samples.jpetstore.domain.logic;
public class PetStoreImpl implements PetStoreFacade, OrderService {
? private AccountDao accountDao;
?.........
?public void setAccountDao(AccountDao accountDao) {
??this.accountDao = accountDao;
?}
?public Account getAccount(String username) {
??? return this.accountDao.getAccount(username);
? }
? public Account getAccount(String username, String password) {
??return this.accountDao.getAccount(username, password);
? }
? public void insertAccount(Account account) {
??this.accountDao.insertAccount(account);
? }
? .......
}
表達層這里介紹Structs,Structs中通過PetStoreFacade接口來訪問業務層:
package org.springframework.samples.jpetstore.web.struts;
public abstract class BaseAction extends Action {
? private
PetStoreFacade petStore;
?public void setServlet(ActionServlet actionServlet) {
??super.setServlet(actionServlet);
??ServletContext servletContext = actionServlet.getServletContext();
??WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
??this.petStore = (PetStoreFacade) wac.getBean("petStore");
?}
?protected PetStoreFacade getPetStore() {
??return petStore;
?}
}
public class SignonAction extends BaseAction {
? public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
???????AccountActionForm acctForm = (AccountActionForm) form;
????? String username = acctForm.getUsername();
????? String password = acctForm.getPassword();
????? Account account = getPetStore().getAccount(username, password);
.....
??????????????? return mapping.findForward("success");
????}
Structs框架通過struct-config.xml文來控制相關映射轉發的:????
struct-config.xml???????
<action path="/signon" type="org.springframework.samples.jpetstore.web.struts.SignonAction"
???name="accountForm" scope="request"
???validate="false">
???<forward name="success" path="/index.jsp"/>
??</action>
關于jsp就不在多說了下面再來看一下它的web.xml文件:
??<context-param>
??<param-name>contextConfigLocation</param-name>
??<param-value>
???/WEB-INF/dataAccessContext-local.xml? /WEB-INF/applicationContext.xml
??</param-value>
???</context-param>
<servlet>
??<servlet-name>context</servlet-name>
??<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
??<load-on-startup>1</load-on-startup>
?</servlet>
?<servlet>
??<servlet-name>action</servlet-name>
??<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
??<load-on-startup>3</load-on-startup>
?</servlet>
??
??<servlet-mapping>
???<servlet-name>action</servlet-name>
??
??<url-pattern>*.do</url-pattern>
?</servlet-mapping>
?
還有關于遠程機制有Caucho的Hessian(一個借助HTTP的二進制協議) Burlap(一個基于XML的借助HTTP的傳輸協議), Apache Axis提供的JAX-RPC(基于SOAP的借助HTTP傳輸的web serverice), 還有基于RMI的遠程調用.
想了解更多還是自已細看里面的代碼吧!
請繼續關注Spring JPetStore(三) 在其上實現自已的Sunlight Netstore