博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Injecting and Binding Objects to Spring MVC Controllers--转
阅读量:5934 次
发布时间:2019-06-19

本文共 9408 字,大约阅读时间需要 31 分钟。

I have written two previous posts on how to inject custom, non Spring specific objects into the request handling methods of a controller in Spring MVC. One was using 

the other with .
An adventurous reader of these posts would have discovered, that even if you remove the implementedHandlerMethodArgumentResolver or the @ModelAttribute annotation the custom objects would still be instantiated and provided to the controller method!
Yes, try it!
The only problem is that the properties of the instantiated object would be null, that is they won't have been initialized (this won't be the case though, if these properties are instantiated in the default constructor).
So if we have a our Person object:

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
class
Person {
  
    
private
String firstName;
    
private
String lastName;
 
    
public
Person() {
    
}
  
    
public
void
setFirstName(String fname) {
        
this
.firstName = fname;
    
}
 
    
public
String getFirstname() {
        
return
firstName;
    
}
 
    
public
void
setLastName(String lname) {
        
this
.lastName = lname;
    
}
 
    
public
String getLastName() {
        
return
lastName;
    
}
  
}

And a controller with the Person object as method parameter:

1
2
3
@RequestMapping
(value=
"/index"
, method = RequestMethod.GET)
public
String printWelcome(ModelMap model, Person person) {
}

Typing in the URL that maps into the controller above would not give any error, even though there is noHandlerMethodArgumentResolver defined or @modelAttribute. Spring would still instantiate the Person Object by calling its default constructor and make it available to the controller. 
This is the default object creation and dependency injection available to controllers in Spring MVC.
If the object you need injected, can be created and ready for use without the need of any external arguments supplied to the constructor, then you are good to go, but often that not, this is not the case. The object creation would either need external inputs for its creation or for its initialization after creation (setting properties etc). This is where an object Factory likeHandlerMethodArgumentResolver comes in handy.
But there is another alternative way Spring makes available which in the absence of HandlerMethodArgumentResolver, and @ModelAttribute, makes it possible to have objects created, initialized with required properties and ready for use. This is via Spring's data binding feature.
As we have seen, by just having a custom object, as a controller's method argument, guarantees that it would be instantiated...data binding, on the other hand guarantees that the created object is fully initialized and values are bound to its properties.
But if data binding guarantees object initialization, where then, does the value used in binding comes from?...from the HTTP request body...
We would look into the various ways values coming from a request can be mapped into properties of an object i.e. data binding to the object provided to the controller.

Binding Values from HTML Form

If you have an HTML form whose action URL points to a controller method, and the field names of the form inputs corresponds to the properties of a custom object that is part of the method arguments of the controller, then Spring would automatically extract the values sent through that form and bind it as properties of the object. This object is usually referred to as a Form Backing Object.

 

For this to work, the Form backing object would need to follow the   convention: which is, among other things, have public setter methods (and getter methods) that can be used to set and retrieve the object's properties.

For example if the Person class above serves as the Form backing object and we have the HTML thus:
<form action="/person" method="post">
<input name="firstName" type="text" />
<input name="lastName" type="text" />
<input type="submit" />
</form>
and the controller is as before: 

1
2
3
@RequestMapping
(value=
"/index"
, method = RequestMethod.POST)
public
String printWelcome(ModelMap model, Person person) {
}

The Person object instantiated would have its properties automatically bound with whatever is sent through the form.

Binding Values From Path Variables and Request Parameters

Since the data binding is done via extraction of values from the HTTP request and mapped to the object, path variables and request parameters can also be used to pass across values to be bound to the backing object that would be injected into the controller method.

For example using request parameters, this URL:
http://example.com/person/?firstName=akpos&lastName=merenge
would automatically bind the firstName and lastName to the Person object in the printWelcome method just as the HTML form did. The only thing is that the @RequestMapping's method needs to be changed to RequestMethod.GET
Same data binding can also be achieved using the values retrieved from the path variable. Just that the controller method would need some slight modification.
It would have to be updated to have the variable used to designate the path variable match the properties of the object...
To illustrate let's say we have this URL:
http://example.com/person/akpos/merenge
In other to have the values specified, i.e, the /akpos/merenge/ part, mapped to the Person object, the printWelcomemethod would need to be updated thus:

1
2
3
@RequestMapping
(value=
"/index/{firstName}/{lastName}"
, method = RequestMethod.POST)
public
String printWelcome(ModelMap model, Person person) {
}

The changes being in the request mapping /index/{firstName}/{lastName}.
The above ensures the values in the URL's path variable would be extracted and bound to the Person Object.

Validating Data Binding

A common operation with data binding is data validation.

When the value to bound is coming from an external source, (HTML form etc) it makes sense to want to specify some validation rule that inputs needs to be adhere to before the actual values are bound to the object. Data validation with data binding is a topic that could deserve a stand alone post on it's own, but I would just quickly point out how it is achieved in Spring.
There are two things needed to be done. First is to specify the validation constraints on the object that we want to bind it properties. Second is to update the handling controller method with the necessary annotation needed to enforce the validation and catch any validation error that occurs.
For specifying the validation constraints/rules, Spring supports declarative bean validation as defined in . This support is activated, automatically, if a JSR 303 provider is found in the application's class path. A popular provider is the . You can add this via Maven:

1
2
3
4
5
<
dependency
>
  
<
groupid
>org.hibernate</
groupid
>
  
<
artifactid
>hibernate-validator</
artifactid
>
  
<
version
>${version}</
version
>
</
dependency
>

Once you have such a validator on your class path you can proceed to enforce validation rules using annotation on the object to be validated. For example, on our Person object, to enforce that no empty value is bound and only alphabets allowed, we would annotate like this:

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
class
Person {
  
    
@NotBlank
    
@Pattern
(regexp =
"^[A-Za-z]*$"
)
    
private
String firstName;
    
@NotBlank
    
@Pattern
(regexp =
"^[A-Za-z]*$"
)
 
    
public
Person() {
    
}
  
    
public
void
setFirstName(String fname) {
        
this
.firstName = fname;
    
}
 
    
public
String getFirstname() {
        
return
firstName;
    
}
 
    
public
void
setLastName(String lname) {
        
this
.lastName = lname;
    
}
 
    
public
String getLastName() {
        
return
lastName;
    
}
  
}

We have used the @NotBlank and @Pattern annotation to achieve this validation rule. For more rules you should look at the
Now that the validation rule has been applied, the controller method needs to be updated to be aware of the validation rules and be able to catch any violation. To do that you annotate the object being bound with  and right next to the object, follow with Spring's  (Note that the BindingResult would need to be placed right after the backing object that is annotated with @Valid for this to work.)
so our printWelcome method would be:

1
2
@RequestMapping
(value=
"/index/{firstName}/{lastName}"
, method = RequestMethod.POST)
public
String printWelcome(ModelMap model, 
1
2
3
4
5
6
7
8
9
10
                
@Valid
Person person, BindingResult result) {
 
if
(result.hasErrors) {
// extract errors and put in model
// return view
}
else
{
// continue with normal code execution
// return view
}
}

As can be seen above, the @Valid annotation is used to apply the validation rules on the Person Object. If any violation, then the result object is updated accordingly (Spring also updates the Model with violation details) and in the controller, you can check if validation passed or failed, extract the error message, and determine what should happen in the view.
In practice though, you may not have to manually extract the error details and update the view manually, most Template technologies have macros that handles the task of extracting validation error and displaying them. I am familiar with the template engine, and Spring has got macros () for handling common task in Freemarker. TheshowError macro handling displaying of validation errors.
The JSR 303 provides an extensive set of definition for enforcing bean validation. Do check the documentation for more information.

reference from:

http://geekabyte.blogspot.com/2014/10/injecting-and-binding-objects-to-spring.html

转载地址:http://wdjtx.baihongyu.com/

你可能感兴趣的文章
屌丝气质难掩,逼人逃离么?
查看>>
OFBiz + Opentaps 目录管理 四. 产品(一)定义产品
查看>>
list泛型类型获取
查看>>
VIM一些用法
查看>>
Nginx 502错误原因与解决办法
查看>>
使用Django来处理对于静态文件的请求
查看>>
dom4j解析xml的简单实用
查看>>
批量进行One-hot-encoder且进行特征字段拼接,并完成模型训练demo
查看>>
MySQL数据库在Windows环境下安装配置
查看>>
由浅入深学习Apache httpd原理与配置
查看>>
用tiny project来激励自己入门
查看>>
制作同时支持armv7,armv7s,arm64,i386,x86_64的静态库.a
查看>>
Beyond Compare的几种实用功能
查看>>
旧工程适配iOS 6和iPhone 5的一些故事
查看>>
CentOS版本怎么安装python的pip及mycli的安装
查看>>
was安装
查看>>
Android Studio 使用艺术
查看>>
Android架构:第四部分-在Android上应用Clean架构,实践(包含源代码)(译)
查看>>
Jenkins打包参数输入多个Cherry-Pick
查看>>
java文件下载(二)
查看>>