beauty_beast

上善若水 厚德载物

Spring学习笔记二----Web MVC

Posted on 2006-06-24 10:59 柳随风 阅读(5718) 评论(1)  编辑  收藏 所属分类: 开源框架

花了两个星期学习 Spring WebMVC 总体感觉收获不少,感受比较深的是 Spring 框架的确解决了在 j2EE 开发中经常遇到的问题 , 自己也写了一个覆盖框架主要功能的简单例子,和大家一起交流、分享一下,如有错误,欢迎大家多指正。

-、相对于WebWork的特性

1、  表单处理功能比较强大,将数据初始化、展现、封装、效验等功能做了分解,代码功能更加清晰(优)

举个例子,我们要更新一个产品的信息,一般实现步骤如下:

a.       根据主键查找到该产品信息,作为 Request 属性对象传递到编辑页面

b.       在编辑页面时往往还需要其他一些数据,如每个产品都有产品类别,因此也会将相关数据作为 Request 属性对象传递到编辑页面

c.       完成对编辑页面客户端效验

d.       编辑页面提交后,将页面输入数据封装成产品对象,然后效验,如果有错误,需要将此时的产品对象再返回到编辑页面,提示用户错误信息。

e.       效验正常后,调用业务逻辑方法处理后,页面调转到查询页面,注意避免用户刷新重复提交,往往我们使用 redirect 方式调整

而这些功能在 Spring 框架时如何实现的,只需要大家继承于 org.springframework.web.servlet.mvc.SimpleFormController 类,针对上述步骤,我们需要分别重写如下方法:

 a、  protected  Object formBackingObject(HttpServletRequest request)  throws  SimpleException
 b、
protected  Map referenceData(HttpServletRequest request, Object command,   Errors errors)  throws  SimpleException
    
 d、
protected   void  onBindAndValidate(HttpServletRequest request,   Object command, BindException errors)  throws  SimpleException

 e、
protected  ModelAndView onSubmit(HttpServletRequest request,            HttpServletResponse response, Object command, BindException errors) throws  SimpleException


说明:

 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、  使用标准标签库时,页面不能含有中文字符,否则抛出异常、是否标签库对字符集有限制?

Feedback

# re: Spring学习笔记二----Web MVC  回复  更多评论   

2006-11-09 17:24 by po
其实一般很少使用 SimpleFormController 这个东西。

只有注册用户登录后才能发表评论。


网站导航: