Last week, I was just outside our nation’s capital teaching Spring Web MVC Framework to a wonderful group of people working for the National Institute of Health (NIH).  They are getting ready to move a collection of Struts 1 projects to Spring Web MVC.  Some questions and discoveries around Spring Web MVC’s @InitBinder operations seemed a good fit for this week’s post.

Spring Web MVC Command Beans

Part of my Spring MVC class is dedicated to teaching students how to have Spring bind data submitted by HTML form or query string parameters to a Java object (otherwise known as a Spring command bean or backing bean under this circumstance).

On the server, the data must be extracted out of the HttpServletRequest object, converted to a proper data format, loaded into an object, and validated. This can be done in code by the developer, but Spring comes with mechanisms to do this work for you automatically. The data, once in an object can be passed to the backend business components for appropriate processing.

In order to have Spring collect and bind the data from an HTML form page (or query string parameter data), just create a plain old Java object/JavaBean with properties that match the request parameter names. For example, if collecting order information from an HTML form like that below…

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<form:form action="addorder.request" method="post" commandName="order">
  <table border="1">
    <tr>
      <th>&nbsp;</th>
      <th>Add Order</th>
    </tr>
    <tr>
      <td bgcolor="cyan">Customer:</td>
      <td><form:input path="customer" size="40" />
       <font color="#FF0000"><form:errors path="customer" /></font></td>
      </tr>
    <tr>
      <td bgcolor="cyan">Product:</td>
      <td><form:input path="product" size="40" />
        <font color="#FF0000"><form:errors path="product" /></font></td>
    </tr>
    <tr>
      <td bgcolor="cyan">Order date:</td>
      <td><form:input path="orderDate" size="40" />
       <font color="#FF0000"><form:errors path="orderDate" /></font></td>
    </tr>
    <tr>
      <td bgcolor="cyan">Ship date:</td>
      <td><form:input path="shipDate" size="40" />
       <font color="#FF0000"><form:errors path="shipDate" /></font></td>
    </tr>
    <tr>
      <td><input type="submit" value="Save" /></td>
      <td><input type="reset" value="Reset" /></td>
    </tr>
  </table>
  <a href="index.jsp">Home</a>
  <form:hidden path="id" />
</form:form>

… you would need a class like Order shown here.

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.intertech.domain;
 
import java.util.Date;
 
public class Order {
 
  private long id;
  private String customer;
  private String product;
  private Date orderDate;
  private Date shipDate;
 
  public long getId() {
    return id;
  }
 
  public void setId(long id) {
    this.id = id;
  }
 
  public String getCustomer() {
    return customer;
  }
 
  public void setCustomer(String customer) {
    this.customer = customer;
  }
 
  public String getProduct() {
    return product;
  }
 
  public void setProduct(String product) {
    this.product = product;
  }
 
  public Date getOrderDate() {
    return orderDate;
  }
 
  public void setOrderDate(Date orderDate) {
    this.orderDate = orderDate;
  }
 
  public Date getShipDate() {
    return shipDate;
  }
 
  public void setShipDate(Date shipDate) {
    this.shipDate = shipDate;
  }
 
  @Override
  public String toString() {
    return "Order [id=" + id + ", customer=" + customer + ", product="
    + product + ", orderDate=" + orderDate + ", shipDate="
    + shipDate + "]";
  }
}

Then a Spring controller automatically will bind request data to the properties in an instance of Order and pass it to the controller handler method.  The addOrder( ) handler method shown here demonstrates how to write a handler method with a Command bean parameter.

 
1
2
3
4
5
6
7
8
9
10
11
12
@RequestMapping(value = "addorder.request", method = RequestMethod.POST)
protected String addOrder(Order order, Errors errors) {
  if (errors.hasErrors()) {
    for (ObjectError error : errors.getAllErrors()) {
      System.out.println("Validation error: "
      + error.getDefaultMessage());
    }
  return "editorder";
  }
  // do the work of adding a new order
  return "successfuladd";
}
Spring Web MVC InitBinder

Spring automatically binds simple data (Strings, int, float, etc.) into properties of your command bean.  However, what happens when the data is more complex?  For example, what happens when you want to capture a String in “Jan 20, 1990” format and have Spring create a Date object from it as part of the binding operation.  Perhaps you have custom types you want created from their string representation.  For example, you want Spring to take a String in ###-###-#### format and populate a PhoneNumber type property you have in your Command bean.

For this work, you need to inform Spring Web MVC to use PropertyEditor instances as part of the binding process.  The JavaBean API defines a java.beans.PropertyEditor interface. This interface defines methods to convert a property’s value to a String (getAsText()), and to set a property given a String (setAsText(String)). In particular, Spring Web MVC converts incoming request String data to the appropriate data type using PropertyEditors for the fields of the command beans.

Some PropertyEditors are provided and used by Spring Web MVC by default (this is how simple data types are handled).  How do you specify custom property editors for your command beans for the more complex typed fields?  In a method of the controller annotated with @InitBinder, you register and configure your custom PropertyEditors for Spring Web MVC to use at the time of data binding.  An example @InitBinder method is shown below to add a customized Date PropertyEditor to accept date strings in the format of “Jan 20, 1990” and convert these strings to java.util.Date objects for the Order object’s fields.  Note, the name of the annotated method is arbitrary.  The important part of this controller method is the @InitBinder annotation on the method.

 
1
2
3
4
5
6
@InitBinder
public void bindingPreparation(WebDataBinder binder) {
  DateFormat dateFormat = new SimpleDateFormat("MMM d, YYYY");
  CustomDateEditor orderDateEditor = new CustomDateEditor(dateFormat, true);
  binder.registerCustomEditor(Date.class, orderDateEditor);
}

Note also the WebDataBinder (a subclass of the more generic DataBinder) parameter of  the @InitBinder method.  This object manages the Spring binding process and holds a registry of the PropertyEditors used in the binding operation.In this example, Order’s orderDate and shipDate can be captured in “MMM d, YYYY” string format and be bound to java.util.Date objects by Spring.

Handling Two Properties of the Same Type

A problem arises when the binding operation must deal with two properties of the same type and String data for those properties is formatted differently.  This is the problem three of my students (Nick, Erik and Nivedita) worked on and solved in last week (thanks guys!).

For example, if you note, there are two Date properties in the Order type above.  Currently, the WebDataBinder has been given just one CustomDateEditor that uses the “MMM d, YYYY” format for accepting date Strings into both the shipDate and orderDate properties.  So, under this design, all Date data would have to be provided in this format by the user in order for it to be accepted by Spring Web MVC for Orders.  What if you have two different formats for Dates?  For example, what if order dates are to be provided in “d-MM-yyyy” format and ship dates are to be provided in “MMM d, YYYY” format?

As Nick, Erik and Nivedita discovered, there is an overloaded registerCustomEditor( ) method in the DataBinder class.  The registerCustomEditor( ) calls in the @InitBinder method above pass in the target class type and the PropertyEditor instance to be used to perform the binding of that type of property.  Another registerCustomEditor method call allows you to specify the command bean field to which the custom PropertyEditor applies.  This allows you to set up PropertyEditors per property/field versus per general property data type.  Below, the @InitBinder method now contains the registration of two CustomDateEditors.  One used for orderDates (in d-MM-yyyy” format) while the other is used for shipment dates (in “MMM d, YYYY”) format.

 
1
2
3
4
5
6
7
8
9
@InitBinder
public void bindingPreparation(WebDataBinder binder) {
  DateFormat dateFormat1 = new SimpleDateFormat("d-MM-yyyy");
  CustomDateEditor orderDateEditor = new CustomDateEditor(dateFormat1, true);
  DateFormat dateFormat2 = new SimpleDateFormat("MMM d, YYYY");
  CustomDateEditor shipDateEditor = new CustomDateEditor(dateFormat2, true);
  binder.registerCustomEditor(Date.class, "orderDate", orderDateEditor);
  binder.registerCustomEditor(Date.class, "shipDate", shipDateEditor);
}
Wrap Up

My thanks again to the folks at NIH and Nick, Eric, and Nivedita in particular for asking questions about this feature and digging into the DataBinder details.  If you are looking to learn Spring, please consider taking one of our Spring Framework classes.  Our class materials were just updated to cover Spring Framework 4.  So come learn the latest and greatest about Spring in our fantastic learning environment.

https://www.intertech.com/Blog/spring-frameworks-webdatabinder/

Spring Framework’s WebDataBinder的更多相关文章

  1. 最新漏洞:Spring Framework远程代码执行漏洞

    Spring Framework远程代码执行漏洞 发布时间 2022-03-31 漏洞等级 High CVE编号 CVE-2022-22965 影响范围:同时满足以下三个条件可确定受此漏洞影响: JD ...

  2. 浅谈对Spring Framework的认识

    Spring Framework,作为一个应用框架,官方的介绍如下: The Spring Framework provides a comprehensive programming and con ...

  3. Hello Spring Framework——依赖注入(DI)与控制翻转(IoC)

    又到年关了,还有几天就是春节.趁最后还有些时间,复习一下Spring的官方文档. 写在前面的话: Spring是我首次开始尝试通过官方文档来学习的框架(以前学习Struts和Hibernate都大多是 ...

  4. 手动创建Spring项目 Spring framework

    之前学习框架一直是看的视频教程,并且在都配套有项目源码,跟着视频敲代码总是很简单,现在想深入了解,自己从官网下载文件手动搭建,就遇到了很多问题记载如下. 首先熟悉一下spring的官方网站:http: ...

  5. 转-Spring Framework中的AOP之around通知

    Spring Framework中的AOP之around通知 http://blog.csdn.net/xiaoliang_xie/article/details/7049183 标签: spring ...

  6. spring 官方下载地址(Spring Framework 3.2.x&Spring Framework 4.0.x)

    spring官方网站改版后,建议都是通过 Maven和Gradle下载,对不使用Maven和Gradle开发项目的,下载就非常麻烦,下给出Spring Framework jar官方直接下载路径: h ...

  7. Spring Framework------>version4.3.5.RELAESE----->Reference Documentation学习心得----->Spring Framework中的spring web MVC模块

    spring framework中的spring web MVC模块 1.概述 spring web mvc是spring框架中的一个模块 spring web mvc实现了web的MVC架构模式,可 ...

  8. Spring Framework------>version4.3.5.RELAESE----->Reference Documentation学习心得----->Spring Framework中web相关的知识(概述)

    Spring Framework中web相关的知识 1.概述: 参考资料:官网documentation中第22小节内容 关于spring web mvc:  spring framework中拥有自 ...

  9. Spring Framework------>version4.3.5.RELAESE----->Reference Documentation学习心得----->关于spring framework中的beans

    Spring framework中的beans 1.概述 bean其实就是各个类实例化后的对象,即objects spring framework的IOC容器所管理的基本单元就是bean spring ...

随机推荐

  1. spring boot 使用 HandlerInterceptor

    # 背景 在实际项目中,接口出于安全考虑,都会有验签的计算.目前接触的项目来看基本都是时间戳+干扰因子 然后md5计算的方式.现在学习,写一个简单demo, 其实如果不引入拦截器的话,验签计算全部在c ...

  2. C#图片处理,缩略图制作

    准备参数:图片文件流.文件名 方法:1.先将图片流通过System.Drawing.Image.FromStream方法转成图片对象 2.通过图片对象.GetThumbnailImage方法生成自定义 ...

  3. Day 27 类的进阶-反射

    11. __new__ 和 __metaclass__ 阅读以下代码: 1 2 3 4 5 6 class Foo(object): def __init__(self): pass obj = Fo ...

  4. XCode - 无法对iPhone真机调试的解决方法!

    OSX:10.14 XCode:10.1 真机:iPhone 4S 错误很多啊,并非编译错误,编译已经成功了,但是无法安装到真机,我真不理解啊!!由于真的没有想到能够解决,有的错误没有截图,先看部分错 ...

  5. Nginx + uWSGI 部署Django 项目,并实现负载均衡

    一.uWSGI服务器 uWSGI是一个Web服务器,它实现了WSGI协议.uwsgi.http等协议.Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换. 要注意 WSGI ...

  6. [JavaScript] 获取昨日前天的日期

    var day = new Date(); day.setDate(day.getDate()-1); console(day.pattern('yyyy-MM-dd'));//昨天的日期 day.s ...

  7. [bug]微信小程序使用 <scroll-view> 和 box-shadow 引起页面抖动

    背景 为了实现点点点动态loading效果,并且方便使用(只需要给一个空元素加一个.loading),有如下代码: .loader { background-color: #fff; font-siz ...

  8. python多态和鸭子类型

    多态与多态性 多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承). 比如:文件分为文本文件,可执行文件(在定义角度) 比如 我们按下 F1 键这个动作: 如果当前在 Fl ...

  9. 验证resneXt,densenet,mobilenet和SENet的特色结构

    简介 图像分类对网络结构的要求,一个是精度,另一个是速度.这两个需求推动了网络结构的发展. resneXt:分组卷积,降低了网络参数个数. densenet:密集的跳连接. mobilenet:标准卷 ...

  10. 语义分割Semantic Segmentation研究综述

    语义分割和实例分割概念 语义分割:对图像中的每个像素都划分出对应的类别,实现像素级别的分类. 实例分割:目标是进行像素级别的分类,而且在具体类别的基础上区别不同的实例. 语义分割(Semantic S ...