1
、
Web
程序的設計原則:
The following items should be noted regarding the web application implementation design:
-
all JSP's are stored under /WEB-INF/jsp except for index.jsp which is the configured "welcome-file"
-
The use of JSP technology in the application is not exposed to the user, i.e., the end user never sees a URL ending in ".jsp".
-
By convention, all URL's in the application ending in ".do" are handled by web application controllers. Static html pages ending in ".html", such as Javadoc, will be directly served to the end user.
-
The results of all form entries are handled using browser round trip redirection to minimize possible end user confusion.
-
All pages are extremely simple JSP implementations that focus only on providing the necessary functionality.
-
References to Entity objects are passed around in the application by supplying the object's
ID
as a request parameter.
下面的幾項應該在
Web
程序的設計實現中被關注:
1.?????
除了處理
index.jsp
這個被被配置為歡迎頁面的頁面外,所有的
JSP
頁面放置在
/WEB-INF/jsp
下面。
2.?????
這樣的使用
JSP
技術是不被用戶接受的,所以,最終用戶永遠也不應該看到
URL
以
".jsp
"
結尾。
3.?????
根據協議,在程序的所有
URL
都以
".do"
結尾以便于被
web
程序
controllers
處理。靜態
html
頁面以
".html"
結尾,例如
Javadoc,
將直接對最終用戶服務。
4.?????
對于被瀏覽器處理的所有的表單實體對象的結果的往返傳遞應該盡可能地降低用戶理解的混亂。
5.?????
所有的頁面盡可能的簡單,
JSP
的實現集中在僅僅提供必須的功能。
6.?????
對于實體對象的引用應該是將對象
ID
作為
request
參數在應用程序中的傳遞來提供的。
?
2
、
JNDI Dababase connections pools
技術
我使用
PetClinic Tutorial
中介紹的方法根本不能實現。我想應該是
Tutorial
中介紹的不全面或者是我有什么地方不正確,這里先留著,等以后能上網后在搞定,后面使用
Tomcat
推薦的方式來實現。
在
context.xml
中作如下配置:
<Resource name="jdbc/petclinicMYSQL" auth="Container" type="javax.sql.DataSource" maxActive="50"
maxIdle="10" maxWait="10000" removeAbandoned="true" removeAbandonedTimeout="60" logAbandoned="true"
????? driverClassName="org.gjt.mm.mysql.Driver" username="pc" password="pc"
????? url="jdbc:mysql://localhost:3306/petclinic?autoReconnect=true"/>
?
在
web.xml
中作如下配置:
??????
?????? <resource-ref>
????????????? <res-ref-name>jdbc/petclinicMYSQL</res-ref-name>
????????????? <res-type>javax.sql.DataSource</res-type>
????????????? <res-auth>Container</res-auth>
?????? </resource-ref>
聲明那個你將要請求的使用的
JNDI
的名稱。
?
3
、
Spring2.0
的
幾個
annotation
支持
1
)、
@Service
org.springframework.stereotype.Service??????
指明一個被注解的類是一個“
Service
”
(
例如
.
一個業務服務門面
)
。
這個
annotation
當作一種特性的
@Component
被使用,允許
classpath
掃描自動探測。
2
)、
@ManagedResource
org.springframework.jmx.export.annotation.ManagedResource
JDK 1.5+
類庫級別的
annotaion
用來指明注冊一個使用了
JMX
服務器和
ManagedResource
屬性通信的類的實例。
?
4
、
Spring2.0
的
JDBC
支持
1
)、
org.springframework.jdbc.core.support.JdbcDaoSupport
DAO
的便利的父類。需要一個
javax.sql.DataSource
,通過
getJdbcTemplate()
方法提供一個
org.springframework.jdbc.core.JdbcTemplate
給子類。
這個基礎類主要供
JdbcTemplate
使用,但是它也可以在一個直接連接或者使用
org.springframework.jdbc.object
包中的類操作對象。
這個類也就是給實現
DAO
的提供了一個模版。
?
??????
2
)、
org.springframework.jdbc.object.MappingSqlQuery
一個有用的查詢工具類其具體的子類必須實現
abstract
的
mapRow(ResultSet ,int)
方法去將
JDBCResultSet
的每一行轉換為一個對象。
通過減少參數和上下文信息簡化了
MappingSqlQueryWithParameters API
。絕大多數的子類不用關心參數。如果你不使用上下文相關的信息,這個子類將取代
MappingSqlQueryWithParameters
。
org.springframework.jdbc.object.RdbmsOperation.compile()
編譯這個
Query
語句,忽略以后的編譯。做的其實就是設置
preparedStatementFactory
的參數,為該查詢語句的查詢做好準備。必須在構造方法中編譯,否則無法生成指定的
PreparedStatement
。
?
3
)、
org.springframework.jdbc.core.SqlParameter
代表一個
SQL
參數定義的對象。
參數可以是匿名的,如
”name”
屬性可以是
null
。但是,所有的參數必須一個根據
java.sql.Types
定義了
SQL
類型。
?
4
)、
org.springframework.jdbc.object.SqlUpdate
可重用的操作對象代表了一個
SQL undate
。
這個類提供一個許多的
update
方法,就類似于
query
對象中的
execute
方法。
這個類是具體的。盡管它可以被子類化
(
例如去增加一個自定義的
update
方法
)
,但是能很容易的通過設置
SQL
語句和聲明參數來參數化。
就像所有裝載在
Spring
框架中的
RdbmsOperation
類一樣,
SqlQuery
實例在其初始化完成后是線程安全的。準確的說,在它們通過它們的
setter
方法構造和配置后,它們能在多線程中安全使用。
?????? 5
)、
HibernateTemplate
的
merge
方法。
??????
注意:
Hibernate3
的
merge
操作不能在當前的
HibernateSession
中再次組合
entity
。作為替代,它將總是拷貝狀態到一個注冊了的這個
entity
的代表。新的
entity
它將會注冊一個拷貝,但是將不會更新傳遞進來的對象的
id
。為了仍然更新原始的
object
的
id
,我們需要在我們的
SessionFactory
中注冊一個
Spring
的
IdTransferringMergeEventListener
。
典型的使用情況是,將
IdTransferringMergeEventListener
作為一個
entry
,使用“
merge
”鍵值,配置到
LocalSessionFactoryBean
得
”eventListeners”
的
Map
中。
5
、
Spring2.5
的
Annotation
支持
???????? 1
)、
@Repository
org.springframework.stereotype.Repository
??????
指出一個注解的類是“
Repository
(倉庫)”(或者“
DAO
”)。
??????
一個這樣注解的類是能夠使用
Spring org.springframework.dao.DataAccessException
處理異常合格的類了。注解過的類也能夠作為整個程序體系的工具類使用,例如
aspects
等等。
??????
到
Spring2.5
為止,這個
annotation
也能夠作為一個特殊的
@Component
來使用。允許使注解過的類通過
classpath
掃描來自動裝配。
2
)、
@Transactional
org.springframework.transaction.annotation.Transactional
??????
在一個方法或類上描述事務屬性。
??????
這個注解類型一般能夠直接與
Spring
的
org.springframework.transaction.interceptor.RuleBasedTransactionAttribute
相比較,而且實際上
AnnotationTransactionAttributeSource
也能夠直接將數據轉換成接下的類,因此
Spring
的事務支持代碼不必要去了解
annotations
。假如沒有
exception
相關的規則,它將會當作
org.springframework.transaction.interceptor.DefaultTransactionAttribute
(在運行時異常發生的時候回滾)。
3
)、
@Autowired
org.springframework.beans.factory.annotation.Autowired
????????
標記一個構造器,域,
setter
方法或者配置方法能夠被
Spring
依賴注入的工具自動綁定。
??????
任何給定的類最多只有一個構造器可能帶有該注解,標志這個類作為一個
Spring bean
使用時,標志這個構造器自動綁定。這樣的構造器不必一定是
public
的。
??????
域在一個
bean
構造器調用后,所有的配置方法被調用前,被注入。這樣的配置域不必一定是
public
的。
??????
配置方法可以擁有任意的名字和任意數量的參數;那些參數中的每一個將在
Spring
容器中匹配的
bean
自動綁定。
Bean
屬性
setter
方法是一個特殊的配置方法。這樣的配置方法不必一定是
public
的。
??????
在多參方法的情況下,‘
required
’屬性可應用到所有的參數中。
??????
在一個依賴
java.util.Collection
或者
java.util.Map
的情況下,這個容器將自動綁定所有的
bean
并匹配聲明的值類型。當
Map
的情況下,
key
必須是
String
類型的并且將會解析成相應的
bean
的名字。
??????
請考慮閱讀
AutowiredAnnotationBeanPostProcessor
類
(
默認,檢查這個
annotation
是否存在
)
的
javadoc
。
4
)、
@ Controller
org.springframework.stereotype.Controller
??????
指出一個注解的淚是一個“
Controller
”
(
一個
Web
控制器
)
。
??????
這個
annotation
作為一個特殊的
@Component
使用,允許實現類通過
classpath
掃描自動發現。典型的使用是,結合基于
org.springframework.web.bind.annotation.RequestMapping
注解的注解的處理器方法。
5
)、
@RequestMapping
org.springframework.web.bind.annotation.RequestMapping
??????
映射
web
請求到特殊處理器類及(或)處理方法。在
Servlet
和
Portlet
環境中提供一致的方式,通過語義結合具體的環境。
??????
注意:方法級別的映射僅僅允許縮小類級別的映射表達。
HTTP paths/portlet modes
需要唯一地映射到特殊的處理
bean
,所有給定的
path/mode
僅允許被映射成一個特殊的處理器
bean
(不會延伸過多處理器
bean
)。強烈的推薦將彼此相關的處理方法放到相同
bean
中。使用該注解注解過的處理方法被允許擁有靈活的簽名。它們可以擁有任意排列的如下類型的參數
(
除了驗證結果外,如果需要,它們需要驗證相關的
command
對象正確
)
:
?
·???????
請求及
/
或響應對象(
Servlet API
或者
Portlet API
)。你可以選擇任何特殊的
request/response
類型,例如
javax.servletRequest/javax.servlet.http.HttpServletRequest
或者
javax.portlet.PortletRequest / javax.portlet.ActionRequest / javax.portlet.RenderRequest
。注意
Portlet
情況下,一個明確的聲明為
action / render
參數也能用作映射特殊的
request
類型成一個處理器方法。(以防,沒有其它給定的
action
和
render
請求的區別的信息)。
·???????
? Session
對象(
Servlet API
或者
Portlet API
):
javax.servlet.http.HttpSession
或者
javax.portlet.PortletSession
。一個這樣類型的參數將強迫相應類型的
session
的存在。結果,這樣一個參數將不能使
null
。注意
session
的訪問可能不是線程安全的,特別是一個
servlet
環境:考慮改換
”synchronizeOnSession”
標記為
”true”
假如多重請求容許同時訪問一個
session
。
·???????
略。
?
6
)、
@SessionAttributes
org.springframework.web.bind.annotation.SessionAttributes
??????
指出一個特殊的處理器使用的
session
屬性的注解。這個將列出將被透明的存儲在
session
或者一些對話存儲中的
model
屬性的名字,作為
form-backing bean
使用。在類級別使用中,應用為注解過的處理類操作的
model
屬性。
??????
注意:使用這個
annotation
的
Session
屬性是滿足一個特殊處理器
model
屬性需要的。
透明的存儲在一個對話
session
中。那些屬性將會在完成處理器的需要后從
session
中刪除。因此,在一個特殊的處理器對話期間內,使用這個工具操作被期望臨時存儲在
session
中的會話屬性。
??????
要用到永久的
session
屬性,例如,一個用戶鑒定對象,請使用傳統的
session.setAttribute
方法代替。可選擇地,考慮使用
org.springframework.web.context.request.WebRequest
接口的屬性管理功能。
6
、
Spring2.5
新加的
schema tag
。
?????? 1
)、
Context tags
用來處理涉及到
plumbing
的
ApplicationContext
配置。也就是說,不是通常的對于終端用戶重要的
bean
,而是是處理許多
Spring
中日常事務的更重要的
Bean
,例如
BeanfactoryPostProcessor
。下面是使
context
命名空間對你起作用的正確的
schema
片段。
?????????????? <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
??????????????
?? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
??????????????
?? xmlns:context="http://www.springframework.org/schema/context"
??????????????
?? xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
?
<!-- <bean/> definitions here -->
?????????????
??????
????????????????????????????????????????????????
注意:該
tag
在
Spring2.5
中才起作用。
?
<context:property-placeholder location="classpath:jdbc.properties"/>
??
這個元素通過指定的屬性文件的地址,使替代標識
${…}placeholders
得以活動。這個元素是一個方便的機制,它通過建立一個
PropertyPlaceholderConfigurer
給你提供一個方便的機制;如果你需要更多的控制
PropertyPlaceholderConfigurer
,那么你自己建一個吧。
<context:annotation-config/>
使
Spring
基礎組織中的能夠自動偵查
bean
類的各種
annotations
:
Spring
的
@Required
和
@Autowired
,還有
JSR 250
規范中的
@PostConstruct
,
@PreDestroy
和
@Resource
(如果可用的話)還有
JPA
的
@PersistenceContext
和
@PersistenceUnit
(如果可用的話)。作為選擇,你可以選擇使用單獨的
BeanPostProcessors
來處理那些
annotations
。
注意:這個元素不能激活對
Spring
的
@Transactional annotation
的處理。請使用
<tx:annotation-driven/>
元素來達到目的。
<context:component-scan base-package="org.springframework.samples.petclinic.web"/>
??????
這個元素能夠掃描并自動偵測到指定的包中的標識為
@Components
的類。
?????????? -
總結
:
petclinic
是
Spring
組織給出的
Spring
使用的示例程序。
??????
?
該程序未將領域對象和其它的業務類沒嚴格分開(沒有明確的分包來標識),而且
Business
層和持久層更是根本混合一起,不是很好的實踐,因為持久層的類,竟然是從
Business
層的類繼承而來,比如
SimpleJdbcClinic
和
HibernateClinic
都是繼承至
Clinic
這個核心業務的
DAO
類
(
很顯然混合就是從這里開始了
)
。
在手冊中提到,該程序主要是用來展示各種的
Spring
數據訪問策略,而僅帶有極其簡單的業務邏輯,所有為了開發效率將業務層和持久層混合一起。很顯然,這里如果我們改變業務方法的話,就需要幾乎修改所有的持久化類了。
我想更好的方式是將持久類對象
Bean
注入到業務類中。因為組合永遠優于繼承,并且如果使用
Spring
進行依賴注入的話會更優良。
使用
Spring
的
MVC
框架,這是一個很優良的框架,比
Struts1.X
要強很多。
使用了
Spring
的
JMX
支持
API
,
JMX
是一個基于
RMI
和
JNDI
的
Java
管理擴展
API
。
使用了
Spring
的聲明式事務管理
API
。
使用
apache
的
DBCP
數據庫連接池技術。
在
petclinic2.5
版中,使用了
annotation
方式進行各種
Spring
配置。
Annotation
方式雖然提高了學習成本,但是無疑是比描述文檔更優的策略,因為它減少了程序員的編寫描述文件成本,而且能提供編譯器的檢查,程序員不用再去編寫可能使我們頭腦炸掉的
XML
描述文檔。
Spring
的
AOP
支持,雖然這個程序中使用了幾個很無聊的切面。
?
?