SpringMVC应用程序架构----高级特性
2010-10-24 23:38
337 查看
Web 应用与MVC
目前比较好的MVC,老牌的有Struts、Webwork。新兴的MVC 框架有Spring MVC、Tapestry、JSF等。这些大多是著名团队的作品,另外还有一些边缘团队的作品,也相当出色,如Dinamica、VRaptor等。
这些框架都提供了较好的层次分隔能力。在实现良好的MVC 分隔的基础上,通过提供一些现成的辅助类库,同时也促进了生产效率的提高。
如何选择一个合适的框架?什么是考量一个框架设计是否优秀的标准?很难定夺的问题。旁观各大论坛中铺天盖地的论战,往往在这一点上更加迷茫。
从实际Web产品研发的角度而言(而非纯粹设计上,扩展性上,以及支持特性上的比较),目前Struts 也许是第一选择。作为一个老牌MVC Framework,Struts 拥有成熟的设计,同时,也拥有最丰富的信息资源和开发群体。换句实在点的话,产品基于Struts 构建,如果公司发生人事变动,那么,找个熟悉Struts的替代程序员成本最低。
从较偏向设计的角度出发,WebWork2 的设计理念更加先进,其代码与Servlet API 相分离,这使得单元测试更加便利,同时系统从BS结构转向CS接口也较为简单。另外,对于基于模板的表现层技术(Velocity、Freemarker和XSLT)的支持,也为程序员提供了除JSP之外的更多的选择(Struts也支持基于模板的表现层技术,只是实际中不太常用)。而对于Spring而言,首先,它提供了一个相当灵活和可扩展的MVC实现,与WebWork2相比,它在依赖注入方面、AOP 等方面更加优秀,但在MVC 框架与底层构架的分离上又与Webworks 存在着一定差距(Spring 的MVC 与Servlet API 相耦合,难于脱离Servlet容器独立运行,在这点的扩展性上,比Webwork2稍逊一筹)。
我们还要注意到,Spring对于Web应用开发的支持,并非只限于框架中的MVC部分。即使不使用其中的MVC实现,我们也可以从其他组件,如事务控制、ORM模板中得益。同时,Spring也为其他框架提供了良好的支持,如我们很容易就可以将Struts 与Spring 甚至WebWork与Spring 搭配使用(与WebWork 的搭配可能有些尴尬,因为两者相互覆盖的内容较多,如WebWork中的依赖注入机制、AOP机制等与Spring中的实现相重叠)。因此,对于Spring在Web应用中的作用,应该从一个更全面的角度出发。
第一个SpringMVC实例:
下面的实例,实现了一个常见的用户登录逻辑,即用户通过用户名和密码登录,系统对用户名和密码进行检测,如果正确,则在页面上显示几条通知信息。如果登录失败,则返回失败界面。
(示例中,表示层以JSP2.0实现。)
出于简洁考虑,这里的“用户名/密码”检测以及通知信息的生成均在代码中以硬编码实现。
首先来看登录界面:
对应的index.html:
[b]<form action="login.do" method="post">
<table>
<tr>
<td>[/b]用户名:</td>
[b]<td><input
type="text" name="username" /></td>
</tr>
<tr>
<td>[/b]密码:</td>
[b]<td><input
type="password" name="password"></td>
</tr>
<tr>
<td
colspan="2" align="right"><input
type="submit" value="[/b]提交"
/></td>
[b]</tr>
</table>
</form>[/b]
MVC
关键流程的第一步,即收集页面输入参数,并转换为请求数据对象。这个静态页面提供了一个基本的输入界面,下面这些输入的数据将被发送至何处,将如何被转换为请求数据对象?
现在来看接下来发生的事情:
当用户输入用户名密码提交之后,此请求被递交给Web 服务器处理,上面我们设定form提交目标为"/login.do",那么Web服务器将如何处理这个请求?
显然,标准Http
协议中,并没有以.do
为后缀的服务资源,这是我们自己定义的一种请求匹配模式。此模式在web.xml中设定:
<?xml version="1.0" encoding="UTF-8"?>
[b]<web-app version="2.4"
xmlns="[/b]http://java.sun.com/xml/ns/j2ee"
[b] xmlns:xsi="[/b]http://www.w3.org/2001/XMLSchema-instance"
[b] xsi:schemaLocation="[/b]http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
[b] <servlet>
<servlet-name>Dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/Config.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
Config.xml[/b]配置文件:
[b]<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"[/b]http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
[b]<bean
id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass">
<value>org.springframework.web.servlet.view.JstlView</value>
</property>
</bean>
<bean
id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/login.do">LoginAction</prop>
</props>
</property>
</bean>
<bean
id="LoginAction" class="com.hit.action.LoginAction">
<property
name="commandClass">
<value>com.hit.action.LoginInfo</value>
</property>
<property name="fail_view">
<value>/WEB-INF/loginFail.jsp</value>
</property>
<property
name="success_view">
<value>/WEB-INF/loginSuccess.jsp</value>
</property>
</bean>
</beans>[/b]
View
Resolver的viewClass参数
这里我们使用JSP页面作为输出,因此,设定为:
org.springframework.web.servlet.view.JstlView
其余可选的viewClass还有:
Ø org.springframework.web.servlet.view.freemarker.FreeMarkerView(用于基于FreeMarker模板的表现层实现)
Ø org.springframework.web.servlet.view.velocity.VelocityView(用于基于velocity模板的表现层实现)等。
“urlMapping”关系映射
可以看到,这里我们将“/login.do”请求映射到处理单元LoginAction。<props>节点下可以有多个映射关系存在,目前我们只定义了一个。
LoginAction定义
这里定义了逻辑处理单元LoginAction
的具体实现,这里,LoginAction
的实现类为com.hit.action.LoginAction。
LoginAction的请求数据对象
commandClass 参数源于LoginAction
的基类BaseCommandController,BaseCommandControlle
包含了请求数据封装和验证方法(
BaseCommandController.bindAndValidate ),它将根据传入的HttpServletRequest构造请求数据对象。
这里我们指定commandClass
为com.hit.action.LoginInfo,这是一个非常简单的Java
Bean,它封装了登录请求所需的数据内容:
package com.hit.action;
public
class LoginInfo {
[b] private String username;
private String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}[/b]
}
Spring会根据LoginAction的commandClass定义自动加载对应的LoginInfo实例。
之后,对Http
请求中的参数进行遍历,并查找LoginInfo
对象中是否存在与之同名的属性,如果找到,则将此参数值复制到LoginInfo对象的同名属性中.请求数据转换完成之后,我们得到了一个封装了所有请求参数的Java 对象,并将此对象作为输入参数传递给LoginAction。
返回视图定义
对于这里的LoginAction
而言,有两种返回结果,即登录失败时返回错误界面,登录成功时进入系统主界面。对应我们配置了fail_view、success_view两个自定义参数。之后,Resolver 会将LoginAction的返回数据与视图相融合,返回最终的显示界面。
LoginAction.java:
[b]public class LoginAction extends SimpleFormController {
private String success_view;
private String fail_view;[/b]
public
String getFail_view() {
[b] return fail_view;
}[/b]
public
void setFail_view(String fail_view) {
[b] this.fail_view = fail_view;
}[/b]
public
String getSuccess_view() {
[b] retiurn success_view;
}[/b]
public
void setSuccess_viiew(String success_view) {
[b] this.success_view = success_view;
}[/b]
@Override
[b] protected ModelAndView onSubmit(HttpServletRequest
request,
HttpServletResponse response,
Object obj,
BindException ex) throws Exception {
request.setAttribute("message",
"success");
return new
ModelAndView(this.getSuccess_view());
}[/b]
}
其中:
⑴ onSubmit方法
我们在子类中覆盖了父类的onSubmit方法;而onSubmit方法用于处理业务请求。
负责数据封装和请求分发的Dispatcher,将对传入的HttpServletRequest进行
封装,形成请求数据对象,之后根据配置文件,调用对应业务逻辑类的入口方法(这
里就是LoginAction)的onSubmit()方法,并将请求数据对象及其他相关资源引
用传入。
onSubmit方法包含了两个或者四个参数:Object obj和BindException ex。
前面曾经多次提到请求数据对象,这个名为obj的Object型参数,正是传入的请求
数据对象的引用。
BindException ex参数则提供了数据绑定错误的跟踪机制。它作为错误描述工具,
用于向上层反馈错误信息。
在Spring
MVC中,BindException将被向上层表现层反馈,以便在表现层统一处
理异常情况(如显示对应的错误提示)
目前比较好的MVC,老牌的有Struts、Webwork。新兴的MVC 框架有Spring MVC、Tapestry、JSF等。这些大多是著名团队的作品,另外还有一些边缘团队的作品,也相当出色,如Dinamica、VRaptor等。
这些框架都提供了较好的层次分隔能力。在实现良好的MVC 分隔的基础上,通过提供一些现成的辅助类库,同时也促进了生产效率的提高。
如何选择一个合适的框架?什么是考量一个框架设计是否优秀的标准?很难定夺的问题。旁观各大论坛中铺天盖地的论战,往往在这一点上更加迷茫。
从实际Web产品研发的角度而言(而非纯粹设计上,扩展性上,以及支持特性上的比较),目前Struts 也许是第一选择。作为一个老牌MVC Framework,Struts 拥有成熟的设计,同时,也拥有最丰富的信息资源和开发群体。换句实在点的话,产品基于Struts 构建,如果公司发生人事变动,那么,找个熟悉Struts的替代程序员成本最低。
从较偏向设计的角度出发,WebWork2 的设计理念更加先进,其代码与Servlet API 相分离,这使得单元测试更加便利,同时系统从BS结构转向CS接口也较为简单。另外,对于基于模板的表现层技术(Velocity、Freemarker和XSLT)的支持,也为程序员提供了除JSP之外的更多的选择(Struts也支持基于模板的表现层技术,只是实际中不太常用)。而对于Spring而言,首先,它提供了一个相当灵活和可扩展的MVC实现,与WebWork2相比,它在依赖注入方面、AOP 等方面更加优秀,但在MVC 框架与底层构架的分离上又与Webworks 存在着一定差距(Spring 的MVC 与Servlet API 相耦合,难于脱离Servlet容器独立运行,在这点的扩展性上,比Webwork2稍逊一筹)。
我们还要注意到,Spring对于Web应用开发的支持,并非只限于框架中的MVC部分。即使不使用其中的MVC实现,我们也可以从其他组件,如事务控制、ORM模板中得益。同时,Spring也为其他框架提供了良好的支持,如我们很容易就可以将Struts 与Spring 甚至WebWork与Spring 搭配使用(与WebWork 的搭配可能有些尴尬,因为两者相互覆盖的内容较多,如WebWork中的依赖注入机制、AOP机制等与Spring中的实现相重叠)。因此,对于Spring在Web应用中的作用,应该从一个更全面的角度出发。
第一个SpringMVC实例:
下面的实例,实现了一个常见的用户登录逻辑,即用户通过用户名和密码登录,系统对用户名和密码进行检测,如果正确,则在页面上显示几条通知信息。如果登录失败,则返回失败界面。
(示例中,表示层以JSP2.0实现。)
出于简洁考虑,这里的“用户名/密码”检测以及通知信息的生成均在代码中以硬编码实现。
首先来看登录界面:
对应的index.html:
[b]<form action="login.do" method="post">
<table>
<tr>
<td>[/b]用户名:</td>
[b]<td><input
type="text" name="username" /></td>
</tr>
<tr>
<td>[/b]密码:</td>
[b]<td><input
type="password" name="password"></td>
</tr>
<tr>
<td
colspan="2" align="right"><input
type="submit" value="[/b]提交"
/></td>
[b]</tr>
</table>
</form>[/b]
MVC
关键流程的第一步,即收集页面输入参数,并转换为请求数据对象。这个静态页面提供了一个基本的输入界面,下面这些输入的数据将被发送至何处,将如何被转换为请求数据对象?
现在来看接下来发生的事情:
当用户输入用户名密码提交之后,此请求被递交给Web 服务器处理,上面我们设定form提交目标为"/login.do",那么Web服务器将如何处理这个请求?
显然,标准Http
协议中,并没有以.do
为后缀的服务资源,这是我们自己定义的一种请求匹配模式。此模式在web.xml中设定:
<?xml version="1.0" encoding="UTF-8"?>
[b]<web-app version="2.4"
xmlns="[/b]http://java.sun.com/xml/ns/j2ee"
[b] xmlns:xsi="[/b]http://www.w3.org/2001/XMLSchema-instance"
[b] xsi:schemaLocation="[/b]http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
[b] <servlet>
<servlet-name>Dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/Config.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
Config.xml[/b]配置文件:
[b]<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"[/b]http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
[b]<bean
id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass">
<value>org.springframework.web.servlet.view.JstlView</value>
</property>
</bean>
<bean
id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/login.do">LoginAction</prop>
</props>
</property>
</bean>
<bean
id="LoginAction" class="com.hit.action.LoginAction">
<property
name="commandClass">
<value>com.hit.action.LoginInfo</value>
</property>
<property name="fail_view">
<value>/WEB-INF/loginFail.jsp</value>
</property>
<property
name="success_view">
<value>/WEB-INF/loginSuccess.jsp</value>
</property>
</bean>
</beans>[/b]
View
Resolver的viewClass参数
这里我们使用JSP页面作为输出,因此,设定为:
org.springframework.web.servlet.view.JstlView
其余可选的viewClass还有:
Ø org.springframework.web.servlet.view.freemarker.FreeMarkerView(用于基于FreeMarker模板的表现层实现)
Ø org.springframework.web.servlet.view.velocity.VelocityView(用于基于velocity模板的表现层实现)等。
“urlMapping”关系映射
可以看到,这里我们将“/login.do”请求映射到处理单元LoginAction。<props>节点下可以有多个映射关系存在,目前我们只定义了一个。
LoginAction定义
这里定义了逻辑处理单元LoginAction
的具体实现,这里,LoginAction
的实现类为com.hit.action.LoginAction。
LoginAction的请求数据对象
commandClass 参数源于LoginAction
的基类BaseCommandController,BaseCommandControlle
包含了请求数据封装和验证方法(
BaseCommandController.bindAndValidate ),它将根据传入的HttpServletRequest构造请求数据对象。
这里我们指定commandClass
为com.hit.action.LoginInfo,这是一个非常简单的Java
Bean,它封装了登录请求所需的数据内容:
package com.hit.action;
public
class LoginInfo {
[b] private String username;
private String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}[/b]
}
Spring会根据LoginAction的commandClass定义自动加载对应的LoginInfo实例。
之后,对Http
请求中的参数进行遍历,并查找LoginInfo
对象中是否存在与之同名的属性,如果找到,则将此参数值复制到LoginInfo对象的同名属性中.请求数据转换完成之后,我们得到了一个封装了所有请求参数的Java 对象,并将此对象作为输入参数传递给LoginAction。
返回视图定义
对于这里的LoginAction
而言,有两种返回结果,即登录失败时返回错误界面,登录成功时进入系统主界面。对应我们配置了fail_view、success_view两个自定义参数。之后,Resolver 会将LoginAction的返回数据与视图相融合,返回最终的显示界面。
LoginAction.java:
[b]public class LoginAction extends SimpleFormController {
private String success_view;
private String fail_view;[/b]
public
String getFail_view() {
[b] return fail_view;
}[/b]
public
void setFail_view(String fail_view) {
[b] this.fail_view = fail_view;
}[/b]
public
String getSuccess_view() {
[b] retiurn success_view;
}[/b]
public
void setSuccess_viiew(String success_view) {
[b] this.success_view = success_view;
}[/b]
@Override
[b] protected ModelAndView onSubmit(HttpServletRequest
request,
HttpServletResponse response,
Object obj,
BindException ex) throws Exception {
request.setAttribute("message",
"success");
return new
ModelAndView(this.getSuccess_view());
}[/b]
}
其中:
⑴ onSubmit方法
我们在子类中覆盖了父类的onSubmit方法;而onSubmit方法用于处理业务请求。
负责数据封装和请求分发的Dispatcher,将对传入的HttpServletRequest进行
封装,形成请求数据对象,之后根据配置文件,调用对应业务逻辑类的入口方法(这
里就是LoginAction)的onSubmit()方法,并将请求数据对象及其他相关资源引
用传入。
onSubmit方法包含了两个或者四个参数:Object obj和BindException ex。
前面曾经多次提到请求数据对象,这个名为obj的Object型参数,正是传入的请求
数据对象的引用。
BindException ex参数则提供了数据绑定错误的跟踪机制。它作为错误描述工具,
用于向上层反馈错误信息。
在Spring
MVC中,BindException将被向上层表现层反馈,以便在表现层统一处
理异常情况(如显示对应的错误提示)
相关文章推荐
- JDBC第六章知识点总结——JDBC高级特性4--对象关系映射,应用程序架构
- Java高级架构,java8新特性,P2P金融项目
- J2EE架构的6个最佳实践--利用高级J2EE最佳实践来改善现有和将来的J2EE应用程序的架构和设计
- 搭建一个springMVC架构的应用程序
- 《MySQL技术精粹:架构、高级特性、性能优化与集群实战》目录
- Redis学习(6)-Redis高级实用特性
- Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC
- 【翻译】微软应用程序架构指南:如何组织应用程序的结构
- SpringMVC整合MongoDB开发 架构搭建
- [iPhone高级] 基于XMPP的IOS聊天客户端程序(XMPP服务器架构)
- 一. PHP模式设计----PHP类和对象的高级特性
- C++函数的高级特性-函数重载
- 应用程序架构(Application Framework)
- 第8章 C++函数的高级特性
- 浅谈单片机应用程序架构
- springmvc架构原理分析
- springmvc注解开发-高级之 拦截器
- 阅读JVM高级特性与最佳实践-1
- ActiveMQ高级特性:虚拟Destinations实现消费者分组与简单路由 .
- Java高级特性之枚举