??xml version="1.0" encoding="utf-8" standalone="yes"?>
1、 mvc-convention
The Spring MVC Convention Over Configuration application showcases the
new Convention Over Configuration support introduced in Spring 2.0.
The web application is *very* simplistic, because the intent is
to convey the essenceQ本质) of the convention over configuration supportQ配|文协议支
持)
and nothing else.
<!-- maps request URLs to Controller names 请求与Controllercd自动匚w 如hello.do自动
查找HelloController实例处理
但是必须要遵守命名规范,它是Ҏh路径URI中的路径来匹配ControllerQ最后一个也是
文g名,在默认的MethodNameResolver中是
用来匚wController的方法,如果没有路径Q那么也根据这个文件名来匹配Controller-->
<bean
class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>
<bean id="baseRecipeController" abstract="true">
<property name="recipeManager" ref="recipeManager"/>
</bean>
<!-- Controller names are not important when using the above HandlerMapping
implementation
单的l承一个虚拟的c,Cq里的承不是真正意义上的基Q而是在Spring层次上的l?/p>
?->
<bean class="org.springframework.showcase.coverc.web.SwitchBoardController"
parent="baseRecipeController"/>
<bean class="org.springframework.showcase.coverc.web.EditRecipeController"
parent="baseRecipeController">
<property name="commandName" value="recipe"/>
<property name="commandClass"
value="org.springframework.showcase.coverc.domain.Recipe"/>
<property name="formView" value="editRecipe"/>
<property name="successView" value="redirect:switchboard/listRecipes.htm"/>
</bean>
<!-- this bean with the well known name generates view names for us -->
<!-- not strictly required since we just want to accept the defaults-->
<!-- 在Spring2.0中可以不指定ViewQ而由RequestToViewNameTranslatorQ根据请求来提供View?/p>
U。如想?br /> RequestToViewNameTranslator那么请作如下配置Q那么就会根据请求来选择提供ViewQ然后在
viewResolver中找面 -->
<bean id="viewNameTranslator"
class="org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator"/>
<!-- View层解析器Q根据传回ModelAndView实例名称来选择View面 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
程说明Q在web.xml中配|:
<servlet>
<servlet-name>coverc</servlet-name> <servlet-
class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
q个前端控制器,来负责将客户的请求{发给控制对象ControllerQ针对于转发ҎQ我们?br />org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping
来映控制器Q将h与Controllercd自动匚wQ如hello.do自动查找HelloController实例处理Q但
是必要遵守命名规范?br />如果有映到的ControllerQ那么用q个Controller来具体的控制Q然后根据在Controller中的
handleRequest中返回的ModelAndViewҎ的名U来查找View面Qƈ且将业务层数据来提交lView面
?br />我们使用org.springframework.web.servlet.view.InternalResourceViewResolverq个viewResolver?/p>
ҎModelAndView的名U来选择View 面Q我们可以配| ?<property name="prefix"
value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
来确定View面的地点,prefix是文件夹Qsuffix是文件后~?br /> 在Spring2.0中可以不指定ViewQ而由RequestToViewNameTranslatorQ根据请求来提供View?/p>
U。如想用RequestToViewNameTranslator那么请作如下配置Q?br /><bean id="viewNameTranslator"
class="org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator"/>
那么׃Ҏh来选择提供ViewQ然后在viewResolver中找面?/p>
属性编辑器Q?br />a) 在BaseCommandController及其子类中的属性编辑器Q重写initBinderq个Ҏ中注册:
binder.registerCustomEditor(Long.class, new RecipeEditor());
l承至java.beans.PropertyEditorSupport 参数{换ؓ指定的对象用setAsTextQ如果想?/p>
指定的对象{换成StringLgetAsText?br />b) q有通过CustomEditorConfigurerq个BeanFactoryPostProcessor来配|PropertyEditor。做如下?/p>
|:
<bean id=”configBean?class=?/p>
org.springframework.beans.factory.config.CustomEditorConfigurer?gt;
<property name=”customEditors?gt;
<map>
<entry key=”onlyfun.caterpillar.User?gt;
<bean id=”userEditor?class=”onlyfun.caterpillar.UserEditor?>
</entry>
</map>
</property>
</bean>
2、 formtags
1)、如果WebApp中没有配|Handler MappingQ那么它׃使用默认的Handler Mapping Q也是
BeanNameUrlHandlerMapping,它根据Controller定义中的Bean标签中的name属性的URIQ来军_使用哪个
Controller?br /> 2)、ModelAndView中的addObject 通过q里得到存储在modelObject中的对象的简单的cd在加
上Conventions提供的suffixQListQ就成ؓd在ModelMap中的对象了?br />3)、如果在Spring中没有配|RequestToViewNameTranslatorQ那么系l会l我们一个默认的
DefaultRequestToViewTranslatorQ根据URIhQ或者映\径生。如果我们没有指定viewNameQ那
么则使用RequestToViewNameTranslator?br />ViewName付给当前的ModelAndViewQ然后根据当前ModelAndView取得View对象Q有View对象q行数据?/p>
储,以及ҎViewNameq行面的{发或跌{?br />4)、可以在下面配置commandName ?commandClassQ?否则使用默认的,也就是根据返回的对象的实?/p>
的Class信息为commandClassQ以默认的“command”ؓcommandNameQ我们从JSP面中可以用这一?/p>
U读取数据?br /> <bean name="/form.htm"
<property name=”commandName?value=”user?>
<property name=”commandClass?value=”test.User?>
class="org.springframework.showcase.formtags.web.FormController">
</bean>
5)、主要流E?br />DispatcherServlet的doServiceҎ调用doDispatch为处理者处理实际的面分派d?br />通过servlet的HandlerMapping取得实际的HandlerQ然后委托给一个servlet预装的HandlerAdapterq行
实际的处理工作,再用q个handlerAdapter取得实际Controllerq行实际的操作?br />首先调用其handlerRequestҎQ其实是调用实际的AbstractController的handlerRequestҎQ这?/p>
做了一些session的同步处理,然后调用handleRequestInternalҎq行实际的处理,每种不同?/p>
Controller实现有该Ҏ有不同的实现Q?br />我这里是AbstractFormControllerQ是一U从request中对FormBean能进行自动的l装的ControllerQ针
对不同的hisFormSubmissionQPOST==trueQ采用不同的{略QGETh时调用showNewFormҎ昄
表单面Q?br />如果是POSTh那么则进行request参数的FormBeanl定自动装配Q进行处理各U验证处理等Q然后调?/p>
processFormSubmissionҎQ如果有M错误或异帔R会调用showFormҎq回的form面Q最后调?/p>
onSubmitq行面跌{?br />6)、ȝQ?
使用Spring的form tag虽然是在使用Spring MVC的最优方案,它能优美的request的参C
model模型对象q行l定Q而不像struts那样需要定义额外的formbeanc?当然Struts动态bean也可以避
?Q所以如果用Spring MVC务必请用Spring Form TagQ至于View的逻辑控制请用JSTL?/p>
始?
q个主要在WEB UI中用。具有代表的Q一个实例将被以列示一列beanQ将它们攄到session中,然后
它们导Zؓ一个model(模型)。所有的属性将E序化set/getQ但是最常用的方式是数据l定Q例如组
装请求参C的bean。View层中主要用到getterҎ?br />使用一个属性“sort”,通过一个SortDifinition实现基本的list排序。默认,一?/p>
MutableSortDefinition实例被使用Q用相同的属性将递增l定的倹{?br /> BeanWrapper要求Q绑定数据名必须被称作“pageSize”和 “sort.ascending”?注意Q名?/p>
和嵌套语法匹配各自的JSTL EL表达式,例如“myModelAttr.pageSize”和
“myModelAttr.sort.ascending”?br /> 其实Q就是用来提供给表现分页用的?/p>
2. org.springframework.beans.factory.InitializingBean
q是一个能够被bean实现的接口,如果q个bean需要一旦它所有的属性被注入(q有指定?/p>
BeanFactoryAware和ApplicationContextAware接口相关的方法都被执?后就做出反应Q例如,执行一
个自定义的初始化Q或者仅仅是查所有托的属性是否被正确的注入。可以通过抛出异常Ll箋?/p>
始化?br /> 我们也可以选择指定一个自定义?init-method来代替实现InitializingBeanQ这个init-
method通过一个描qbean定义的XML定义?br />
3. org.springframework.aop. AfterReturningAdvice
After returning advice 仅仅在正常的Ҏq回后调用,而不是在抛出异常时调用。这个通知能够看到
q回|但是不能改变它?br />它唯一的方法ؓQvoid afterReturning(Object returnValue, Method method, Object[] args,
Object target) throws Throwable;
在指定的Ҏ(其实是JoinPoint)成功q回后被调用?br /> 参数 returnValueQ?指定的方法的q回倹{?br /> 参数 methodQ被调用的方法?br /> 参数 argsQ方法的参数?br /> 参数 targetQ方法期待的目标。可以null。JoinPoint所在的对象?br /> @throws Q如果当前对象希望中断调用,则抛出异常。所有方法签名中允许抛出的异
常将会返回给调用者。否则将会被包装行期异常?/p>
4. org.springframework.mail.SimpleMailMessage
设计一个简单mail 信息Q它包括收信人mail、发信hmail、主题和内容?br /> 考虑JavaMailSender ?JavaMailMimeMessage 来创建更复杂的信息,例如带有附g的信息,
ҎW号Q或者私人邮件?br />5. org.springframework.samples.jpetstore.domain.logic. PetStoreImpl
q里是该E序的作者对其说明,很有意义?br /> JPetStore主要业务对象?br />q个对象使用?个DAO对象Q从具体的操作持久化API工作中解脱出来。因此,虽然q个E序使用
iBATIS 做数据访问,但是如果要用其它的持久化工h讉KQ就不需要修改这个类的Q何代码?br />q个对象使用DAO实例是通过Spring容器依赖注入?使用依赖注入使DAO变成是可配置?。我们这里
用的setter注入Q暴露每个DAO的setterҎl用戗这意味着我们只要在配|该cȝbeanӞ使用?/p>
property”属性就可以注入DAO。这里的属性是只写?write-only)Q相应的setterҎ没有对应?/p>
getterҎ。GetterҎ是可选的Q只有当你的业务对象需要访问这些属性时Q才L露getterҎ?br /> 在JPetStoreE序中只有一个该cȝ对象。在Spring术语中,q叫做一个“singleton?单例)
对象。这意味着每个E序上下文都只有一个。工厂创Z个单例对象;在这里没有必要提供一个私?/p>
的构造器Q静态工厂方法等是单例模式的传统实现方式?br /> q是一个POJO(普通的Java对象Q自我维护自w的状态,处理本n的属性及存取Ҏ外,一般不
提供MAPI)。它不依赖于M的Spring API。在Spring容器外,仍然可用Q而且能够在用JUnit ?/p>
试时Q初始化该对象。但是,我们仍然使用声明式事务管理,而依赖Spring的AOP?br /> q个cȝ每个Ҏ定义了一个默认的事务属性?br /> 注意Q这个属性定义仅仅在使用Commons Attribute auto-proxying (即用Common Attribute
?AnnotationӞ Annotation是Spring提供的APIQ所以依赖了Spring API或Common Attribute API)
时才是必M用的?br />?war/WEB-INF 目录下的默认applicationContext.xml 文g中的TransactionFactoryProxyBean不需?/p>
定义attributes?br />而在接下来用Commons Attributes attribute 语法来定义的attribute?/p>
6. org.springframework.orm.ibatis.support.SqlMapClientDaoSupport
liBATIS SqlMapClientDAO提供的方便的父类。需要设|一个SqlMapClientQ提供给子类一个基于设?/p>
的SqlMapClient的SqlMapClinetTemplate?br />你也可以传递一个已l配|好的SqlMapClientTemplate实例来代替传递一个SqlMapClient(也就是代曉K
认的SqlMapClientTemplateQ默认的SqlMapClientTemplate使用了传入的SqlMapClient)。这样就使得?/p>
所有的DAO的分享同一个SqlMapClientTemplate配置Q例如,一个自定义的SQLExceptionTranslator也可
以用这个SqlMapClientTemplate?/p>
7. org.springframework.orm.ibatis.SqlMapClientTemplate
一个帮助类Q用来简化用iBATIS com.ibatis.sqlmap.client.SqlMapClient APIq行数据?/p>
问,依照org.springframework.dao 异常模型Q将被检查性异常SQLExceptions转换成不受检异?/p>
DataAccessExceptions。用和org.springframework.jdbc.core.JdbcTemplate相同?/p>
org.springframework.jdbc.support.SQLExceptionTranslator机制?br /> q个cȝ主要Ҏ执行了数据访问行为的回调。此外,该类提供了众多的Ҏ去镜?/p>
com.ibatis.sqlmap.client.SqlMapExecutor的执行方法?br /> q个模版一般都使用了方便而简单的ҎL?query/insert/update/delete 操作。但是,
更复杂的操作例如扚w更新Q就必须自定义一个SqlMapClientCallbackQ常帔R是用匿名的内部cd
现。例如:
getSqlMapClientTemplate().execute(new SqlMapClientCallback() {
public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
executor.startBatch();
executor.update("insertSomething", "myParamValue");
executor.update("insertSomethingElse", "myOtherParamValue");
executor.executeBatch();
return null;
}
});
q个模版需要一个SqlMapClient来工作,可以通过”sqlMapClient”属性来传递。一个Spring
上下文都典型C用一个SqlMapClientFactoryBeanL建SqlMapClient。模版还需要配|一?/p>
DataSource来取得连接,但是Q如果在传入的SqlMapClient中指定了DataSource(典型圎ͼ使用
SqlMapClientFactoryBean的”dataSource”属?Q那么这不是必须的?br /> 所谓的回调是指,一个对象通过调用另一个对象的Ҏ来完成既定的行ؓQ也可以说是委托
l另一个对象来完成Q,而本对象可以L行其它的操作?br />8. org.springframework.samples.jpetstore.web.struts. BaseAction
JPetStore的Web层的所有Struts Action的父c?br />从ServletContext中获得WebApplicationContextQ然后又从WebApplicationContext中获?/p>
PetStoreFacadeQ然后通过一个getterҎ提供l子cR?或者是l承Spring提供的ActionSupportc,
它预实现了WebApplicatinContext的查?但是q里在Struts中插入了Spring的API。所以增加了耦合?/p>
Q该Actioncd其子cM能脱Spring使用,q里q不是最佛_c?br />比较好的方式是:配置SpringAction作ؓBean托管Q用ContextLoaderPluginQƈ在Spring context
?br /> * 中设|依赖关pR具体看Spring手册?/p>
9. org.springframework.util.StringUtils
String工具Ҏ的合类?br />主要在Spring框架内工作;请参考Jakarta's Commons Lang 来了解更多而全面的String 工具cȝ信息
?br />q个提供了一些处理core Java String ?StringBuffer的简单功能,例如替换一个目标字W串中所?/p>
l定的子字符串的功能。它也提供易使用的方法去转换定界字符Ԍ如CSV字符Ԍ和集合以及数l?br />关于持久层DAO接口的好处(个hxQ?br /> 事实上,在程序中有很多对象依赖了DAOQ如果我们直接用DAOQ而不是用DAO的接口的话,
那么如果我们改变底层的数据库Ӟ或者是不同的ORM框架Q,相关的依赖该DAO的对象的c,或者配|?/p>
必须修改。例如,我们使用AOP可配|编E时Q我们就必须修改l入的DAOQ而如果我们用DAO接口Q我
们可以直接织入到接口上,那么我们不需要修改Q何代码。业务层和持久层也应该通过接口通信?br /> 同样QDAO接口也获得所有接口必获得的好处Q那么就是耦合度的下降?br /> 具体来说是Q避免其它API的污染,增加APIl护和用的复杂性;另外是提供l一个更?/p>
zȝ多态实玎ͼ也就是说在我们无法修Ҏ码的情况下,也能改变具体实现Q而且我们应该L避免Q?/p>
因ؓ我们常常没有q样的权限,那么pAPI的设计者提供更好的实现Q开--闭原理)Q这里是通过
XML配置文g的方式?br /> 但是昄Q这里增加了间接性,增加了代码量Q似乎增加了复杂性,然而恰恰相反,合理的
用接口得程序的l构更加的清晰?br /> JPetStore使用了SecureBaseAction 主要是提供了当HttpSession中未包含登陆信息Ӟ跛_?/p>
陆页面,其实所有扩展了q个cȝcȝ实例Q都是需要在安全条g?用户权限控制)使用的,其实我们
可以用filter代替。但是这h然效率更高,但是耦合度也更高了,因ؓ我们不可以配|自q安全{?/p>
略了?br /> JPetStore在Struts Web控制代码中用了大量的Spring APIQ其实这是不推荐使用的,例如Q?/p>
BaseAction中用了WebApplicationContextQSearchProductsAction使用?/p>
org.springframework.util.StringUtilsQ还有用很频繁?/p>
org.springframework.beans.support.PagedListHolder?br /> JPetStore在用StrutsӞ大量使用了HttpSessionQ好的徏议是量用HttpSessionQ所
以这里也不是好的实践Q例如,所有的面都找出来Q但是是~存在HttpSession中,虽然提高了客?/p>
端的用户感受Q但是会l服务器以沉重的负担?br /> JPetStore中将ActionForm做了两种作用Q一U主要是用于数据的提?Form中用)Q一般以
working开_一U主要用于处理过后的数据的显C和数据的保存。因为都是存储在HttpSession中,?/p>
了区分采用了不同的名字,而working FormBean的生命周期是在提交了数据后结束,因此在这Ӟ我们
应该内存空间收回?br />