花了两个星期学习
Spring WebMVC
,
总体感觉收获不少,感受比较深的是
Spring
框架的确解决了在
j2EE
开发中经常遇到的问题
,
自己也写了一个覆盖框架主要功能的简单例子,和大家一起交流、分享一下,如有错误,欢迎大家多指正。
-、相对于WebWork的特性
1、
表单处理功能比较强大,将数据初始化、展现、封装、效验等功能做了分解,代码功能更加清晰(优)
举个例子,我们要更新一个产品的信息,一般实现步骤如下:
a.
根据主键查找到该产品信息,作为
Request
属性对象传递到编辑页面
b.
在编辑页面时往往还需要其他一些数据,如每个产品都有产品类别,因此也会将相关数据作为
Request
属性对象传递到编辑页面
c.
完成对编辑页面客户端效验
d.
编辑页面提交后,将页面输入数据封装成产品对象,然后效验,如果有错误,需要将此时的产品对象再返回到编辑页面,提示用户错误信息。
e.
效验正常后,调用业务逻辑方法处理后,页面调转到查询页面,注意避免用户刷新重复提交,往往我们使用
redirect
方式调整
而这些功能在
Spring
框架时如何实现的,只需要大家继承于
org.springframework.web.servlet.mvc.SimpleFormController
类,针对上述步骤,我们需要分别重写如下方法:
说明:
SimpleException
是自定义的异常,我们在实际开发中都会定义自己的业务异常
Spring
在上述步骤时基本都有其他的实现方法,如
d
步骤也可调用
onBind
带
BindException
参数的方法进行效验,
e
步骤就有更多的同名方法实现,我们可以根据不同的应用场景选择相对应的方法
2、
容器负责截取异常,根据配置提供相关异常展现页面(优)
目前在
WebWork
中异常直接是由
ServletDispatcher
类捕获相关异常,发送
500
错误,
WebWork
中实际上还是比较容易实现该功能,定义一个拦截器,注意必须配置时将其配置为第一个拦截器,在调用拦截方法中捕获系统相关异常,根据配置调整到异常错误处理页面
我以前在
webwork
实现都是定义在
Action,
拦截器中捕获异常,将异常绑定在
ActionError
中,然后跳转到错误页面,
3、
附件上传功能比较方便(优)
4、
url
映射是可以采用通配符匹配的形式,更加灵活(优)
5、
值对象数据封装比较麻烦,如果有属性为整型,页面值为空串时无法转换为空指针(缺)
6、
Spring
将上下文环境对象作为
Request
属性对象传递,感觉这一块比较冗余,没有必要,除了必要的配置信息需要传递,其他没有必要,不够精确,在方面
webwork
比较好,它是只将
Action
对象作为
Request
属性对象传递(缺)
二、处理请求过程
DispatcherServlet
处理请求过程
1
、绑定上下文对象于
DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE
请求属性
2
、绑定
locale resolver,
解析本地化信息(没有忽略该过程)
3
、绑定
theme resolver
,确定使用主题(
没有忽略该过程)
4
、判断是否为
multipart,
如果是就解析封装
5
、查找处理器、执行对应的拦截器,获取视图模型
6
、根据
view resolver
选择相对应的视图
1
-
6
过程中如有异常,可以被
handlerexception resolver
捕获
表单处理过程:
1、
判断是否是提交表单请求,
2、
如果不是,调用
showNewForm(request, response, errors)
方法,
2.1
、
如果子类重写方法调用
formBackingObject
方法
2.2
、
如果有重写
referenceData
方法,
2.3
、
如果属性
bindOnNewForm=true
,系统将
request
对应参数值绑定到对应的对象中
2.4
、
最后根据属性
formView
跳转到相对应的表单录入页面
3
、如果是表单提交请求
3.1
如果不是会话表单或会话中有对应表单对象,
3.1.1
、
系统从会话中获取或者调用调用
formBackingObject
方法创建数据绑定对象,
根据页面输入值绑定数据对象,中间可能会产生绑定异常
3.1.2
、
如子类重写了
onBind
方法,会回调对应的方法,对应绑定异常会一直传递下去
3.1.3
、
如果子类有相对应的效验类,并且需要在绑定时效验,就回调对应的效验类的效验方法,对应绑定异常会一直传递下去
3.1.4
、
如果子类重写了
onBindAndValidate
方法,系统会回调对应的绑定效验方法
3.1.5
、
如果有异常,调用
showForm(request, response, errors)
,不是会话表单,重新获取辅助数据,执行方法
referenceData
返回表单编辑页面。
3.1.6
、
如果无异常调用
onSubmit(request, response, command, errors),
返回成功提交后的页面
3
.
2
如果是会话表单并且会话中没有该表单对象,会根据
formBackingObject
初始化值对象
,
然后处理过程和
3.1.1
执行过程一致。
说明:
步骤
3.1.1
会回调一次
formBackingObject
方法,然后再绑定页面数据,为何回调该方法的原因是因为我们在页面中有些属性不需要显示,如果只通过页面封装数据,哪些不需要显示的就无法封装数据。因此在使用该方法的时候特别要注意性能问题,避免在该方法中调用数据库查询等等影响性能的方法(我还是使用
hidden
控件,虽然安全性低了一点)
个人认为步骤
2.3
位置应该
2.1
在前,因为往往我们在实际使用中是先根据页面传递的值来再构造对应的值对象的。并且这样的话
页面传递的变量会覆盖
formBackingObject
值
个人建议尽可能的不要使用会话表单
三、开发注意事项、心得
1、
自定义拦截器只需实现
org.springframework.web.servlet.HandlerInterceptor
接口
2、
上传多个文件时注意事项:建议采用重写
protected ModelAndView onSubmit(HttpServletRequest request,HttpServletResponse response, Object command, BindException errors) throws Exception
方法,直接通过
MultiHttpServletRequest getFileMap()
方法,对应
map
存储对象为
MultipartFile
接口实现类,建议通过接口访问,这样如果通过其他方式处理上传的,只需要修改配置文件,通过对应的
transferTo
方法处理上传的文件。
3、
在
web
环境中如何获取应用上下文对象
ApplicationContext acx=(ApplicationContext)req.getAttribute(
DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
4、
在配置
multipart
解析器
配置时
id="multipartResolver"
<bean id="multipartResolver" class="
org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize"><value>10485760</value>
</property>
</bean>
5、
在配置资源信息
配置时
id=
messageSource
<bean id="messageSource" class="
org.springframework.context.support.ResourceBundleMessageSource">
6、
如果视图要采用
redirect
方式,配置类似如下
<property name="successView">
<value>redirect:/viewpro.action</value>
</property>
7
、
如果要实现一个简单的页面数据绑定功能
只需要继承
BaseCommandController
类,重写
handleRequestInternal(
HttpServletRequest request, HttpServletResponse response)
throws Exception
方法
在该方法中只要创建数据绑定对象,调用绑定方法,然后封装在对应的视图中
8
、标签库的使用,请参考如下文章:
http://www-128.ibm.com/developerworks/cn/java/j-jstl0211/index.html
四、简单例子
我的应用环境
AppServer weblogic814
框架版本
Spring 1.2 RC2
数据库
Oracle 9.2.0.1
运行例子注意事项:
1
、修改
build.properties
lib.src
对应目录改为你本机
spring
目录
2
、执行数据库脚本
product.sql,
修改对应的
jdbc.properties
文件
3
、如果使用其他的
AppServer
注意在
lib
中加入相关数据库的驱动,并设定
Request
请求中数据编码格式为
GBK
4
、如果使用其他数据库,修改
jdbc.properties
、
hibernate
相关属性,并且修改
product.hbm.xml
的主键生成规则,本例子是用
sequence
生成。
代码下载:
http://www.blogjava.net/Files/beauty_beast/springweb_example.rar
五、遗留问题
1、
如何将页面数据和
List,Map
对象绑定?
2、
使用标准标签库时,页面不能含有中文字符,否则抛出异常、是否标签库对字符集有限制?