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
支持,虽然这个程序中使用了几个很无聊的切面。