Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
爱吃血肠
spring-framework
提交
2e7470b2
S
spring-framework
项目概览
爱吃血肠
/
spring-framework
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
spring-framework
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
2e7470b2
编写于
1月 26, 2016
作者:
R
Rossen Stoyanchev
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Allow binding=false on @ModelAttribute
Issue: SPR-13402
上级
806e79b1
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
164 addition
and
10 deletion
+164
-10
spring-web/src/main/java/org/springframework/web/bind/annotation/ModelAttribute.java
...g/springframework/web/bind/annotation/ModelAttribute.java
+22
-2
spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java
.../web/method/annotation/ModelAttributeMethodProcessor.java
+11
-2
spring-web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java
...g/springframework/web/method/annotation/ModelFactory.java
+8
-3
spring-web/src/main/java/org/springframework/web/method/support/ModelAndViewContainer.java
...ngframework/web/method/support/ModelAndViewContainer.java
+22
-0
spring-web/src/test/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessorTests.java
...method/annotation/ModelAttributeMethodProcessorTests.java
+41
-2
spring-web/src/test/java/org/springframework/web/method/annotation/ModelFactoryTests.java
...ingframework/web/method/annotation/ModelFactoryTests.java
+33
-1
src/asciidoc/web-mvc.adoc
src/asciidoc/web-mvc.adoc
+26
-0
src/asciidoc/whats-new.adoc
src/asciidoc/whats-new.adoc
+1
-0
未找到文件。
spring-web/src/main/java/org/springframework/web/bind/annotation/ModelAttribute.java
浏览文件 @
2e7470b2
/*
* Copyright 2002-201
2
the original author or authors.
* Copyright 2002-201
6
the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
...
...
@@ -22,6 +22,7 @@ import java.lang.annotation.Retention;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
import
org.springframework.core.annotation.AliasFor
;
import
org.springframework.ui.Model
;
/**
...
...
@@ -49,6 +50,7 @@ import org.springframework.ui.Model;
* access to a {@link Model} argument.
*
* @author Juergen Hoeller
* @author Rossen Stoyanchev
* @since 2.5
*/
@Target
({
ElementType
.
PARAMETER
,
ElementType
.
METHOD
})
...
...
@@ -56,6 +58,12 @@ import org.springframework.ui.Model;
@Documented
public
@interface
ModelAttribute
{
/**
* Alias for {@link #name}.
*/
@AliasFor
(
"name"
)
String
value
()
default
""
;
/**
* The name of the model attribute to bind to.
* <p>The default model attribute name is inferred from the declared
...
...
@@ -63,7 +71,19 @@ public @interface ModelAttribute {
* based on the non-qualified class name:
* e.g. "orderAddress" for class "mypackage.OrderAddress",
* or "orderAddressList" for "List<mypackage.OrderAddress>".
* @since 4.3
*/
String
value
()
default
""
;
@AliasFor
(
"value"
)
String
name
()
default
""
;
/**
* Allows declaring data binding disabled directly on an
* {@code @ModelAttribute} method parameter or on the attribute returned from
* an {@code @ModelAttribute} method, both of which would prevent data
* binding for that attribute.
* <p>By default this is set to "true" in which case data binding applies.
* Set this to "false" to disable data binding.
*/
boolean
binding
()
default
true
;
}
spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java
浏览文件 @
2e7470b2
/*
* Copyright 2002-201
5
the original author or authors.
* Copyright 2002-201
6
the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
...
...
@@ -101,9 +101,18 @@ public class ModelAttributeMethodProcessor
Object
attribute
=
(
mavContainer
.
containsAttribute
(
name
)
?
mavContainer
.
getModel
().
get
(
name
)
:
createAttribute
(
name
,
parameter
,
binderFactory
,
webRequest
));
if
(!
mavContainer
.
isBindingDisabled
(
name
))
{
ModelAttribute
annotation
=
parameter
.
getParameterAnnotation
(
ModelAttribute
.
class
);
if
(
annotation
!=
null
&&
!
annotation
.
binding
())
{
mavContainer
.
setBindingDisabled
(
name
);
}
}
WebDataBinder
binder
=
binderFactory
.
createBinder
(
webRequest
,
attribute
,
name
);
if
(
binder
.
getTarget
()
!=
null
)
{
bindRequestParameters
(
binder
,
webRequest
);
if
(!
mavContainer
.
isBindingDisabled
(
name
))
{
bindRequestParameters
(
binder
,
webRequest
);
}
validateIfApplicable
(
binder
,
parameter
);
if
(
binder
.
getBindingResult
().
hasErrors
()
&&
isBindExceptionRequired
(
binder
,
parameter
))
{
throw
new
BindException
(
binder
.
getBindingResult
());
...
...
spring-web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java
浏览文件 @
2e7470b2
...
...
@@ -132,9 +132,11 @@ public final class ModelFactory {
while
(!
this
.
modelMethods
.
isEmpty
())
{
InvocableHandlerMethod
modelMethod
=
getNextModelMethod
(
container
).
getHandlerMethod
();
ModelAttribute
annot
=
modelMethod
.
getMethodAnnotation
(
ModelAttribute
.
class
);
String
modelName
=
annot
.
value
();
if
(
container
.
containsAttribute
(
modelName
))
{
ModelAttribute
annotation
=
modelMethod
.
getMethodAnnotation
(
ModelAttribute
.
class
);
if
(
container
.
containsAttribute
(
annotation
.
name
()))
{
if
(!
annotation
.
binding
())
{
container
.
setBindingDisabled
(
annotation
.
name
());
}
continue
;
}
...
...
@@ -142,6 +144,9 @@ public final class ModelFactory {
if
(!
modelMethod
.
isVoid
()){
String
returnValueName
=
getNameForReturnValue
(
returnValue
,
modelMethod
.
getReturnType
());
if
(!
annotation
.
binding
())
{
container
.
setBindingDisabled
(
returnValueName
);
}
if
(!
container
.
containsAttribute
(
returnValueName
))
{
container
.
addAttribute
(
returnValueName
,
returnValue
);
}
...
...
spring-web/src/main/java/org/springframework/web/method/support/ModelAndViewContainer.java
浏览文件 @
2e7470b2
...
...
@@ -16,7 +16,9 @@
package
org.springframework.web.method.support
;
import
java.util.HashSet
;
import
java.util.Map
;
import
java.util.Set
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.ui.Model
;
...
...
@@ -55,6 +57,9 @@ public class ModelAndViewContainer {
private
boolean
redirectModelScenario
=
false
;
/* Names of attributes with binding disabled */
private
final
Set
<
String
>
bindingDisabledAttributes
=
new
HashSet
<
String
>(
4
);
private
HttpStatus
status
;
private
final
SessionStatus
sessionStatus
=
new
SimpleSessionStatus
();
...
...
@@ -133,6 +138,23 @@ public class ModelAndViewContainer {
}
}
/**
* Register an attribute for which data binding should not occur, for example
* corresponding to an {@code @ModelAttribute(binding=false)} declaration.
* @param attributeName the name of the attribute
* @since 4.3
*/
public
void
setBindingDisabled
(
String
attributeName
)
{
this
.
bindingDisabledAttributes
.
add
(
attributeName
);
}
/**
* Whether binding is disabled for the given model attribute.
*/
public
boolean
isBindingDisabled
(
String
name
)
{
return
this
.
bindingDisabledAttributes
.
contains
(
name
);
}
/**
* Whether to use the default model or the redirect model.
*/
...
...
spring-web/src/test/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessorTests.java
浏览文件 @
2e7470b2
...
...
@@ -62,6 +62,7 @@ public class ModelAttributeMethodProcessorTests {
private
MethodParameter
paramErrors
;
private
MethodParameter
paramInt
;
private
MethodParameter
paramModelAttr
;
private
MethodParameter
paramBindingDisabledAttr
;
private
MethodParameter
paramNonSimpleType
;
private
MethodParameter
returnParamNamedModelAttr
;
...
...
@@ -75,13 +76,15 @@ public class ModelAttributeMethodProcessorTests {
this
.
processor
=
new
ModelAttributeMethodProcessor
(
false
);
Method
method
=
ModelAttributeHandler
.
class
.
getDeclaredMethod
(
"modelAttribute"
,
TestBean
.
class
,
Errors
.
class
,
int
.
class
,
TestBean
.
class
,
TestBean
.
class
);
TestBean
.
class
,
Errors
.
class
,
int
.
class
,
TestBean
.
class
,
TestBean
.
class
,
TestBean
.
class
);
this
.
paramNamedValidModelAttr
=
new
SynthesizingMethodParameter
(
method
,
0
);
this
.
paramErrors
=
new
SynthesizingMethodParameter
(
method
,
1
);
this
.
paramInt
=
new
SynthesizingMethodParameter
(
method
,
2
);
this
.
paramModelAttr
=
new
SynthesizingMethodParameter
(
method
,
3
);
this
.
paramNonSimpleType
=
new
SynthesizingMethodParameter
(
method
,
4
);
this
.
paramBindingDisabledAttr
=
new
SynthesizingMethodParameter
(
method
,
4
);
this
.
paramNonSimpleType
=
new
SynthesizingMethodParameter
(
method
,
5
);
method
=
getClass
().
getDeclaredMethod
(
"annotatedReturnValue"
);
this
.
returnParamNamedModelAttr
=
new
MethodParameter
(
method
,
-
1
);
...
...
@@ -167,6 +170,41 @@ public class ModelAttributeMethodProcessorTests {
assertTrue
(
dataBinder
.
isValidateInvoked
());
}
@Test
public
void
resolveArgumentBindingDisabledPreviously
()
throws
Exception
{
String
name
=
"attrName"
;
Object
target
=
new
TestBean
();
this
.
container
.
addAttribute
(
name
,
target
);
// Declare binding disabled (e.g. via @ModelAttribute method)
this
.
container
.
setBindingDisabled
(
name
);
StubRequestDataBinder
dataBinder
=
new
StubRequestDataBinder
(
target
,
name
);
WebDataBinderFactory
factory
=
mock
(
WebDataBinderFactory
.
class
);
given
(
factory
.
createBinder
(
this
.
request
,
target
,
name
)).
willReturn
(
dataBinder
);
this
.
processor
.
resolveArgument
(
this
.
paramNamedValidModelAttr
,
this
.
container
,
this
.
request
,
factory
);
assertFalse
(
dataBinder
.
isBindInvoked
());
assertTrue
(
dataBinder
.
isValidateInvoked
());
}
@Test
public
void
resolveArgumentBindingDisabled
()
throws
Exception
{
String
name
=
"noBindAttr"
;
Object
target
=
new
TestBean
();
this
.
container
.
addAttribute
(
name
,
target
);
StubRequestDataBinder
dataBinder
=
new
StubRequestDataBinder
(
target
,
name
);
WebDataBinderFactory
factory
=
mock
(
WebDataBinderFactory
.
class
);
given
(
factory
.
createBinder
(
this
.
request
,
target
,
name
)).
willReturn
(
dataBinder
);
this
.
processor
.
resolveArgument
(
this
.
paramBindingDisabledAttr
,
this
.
container
,
this
.
request
,
factory
);
assertFalse
(
dataBinder
.
isBindInvoked
());
assertTrue
(
dataBinder
.
isValidateInvoked
());
}
@Test
(
expected
=
BindException
.
class
)
public
void
resolveArgumentBindException
()
throws
Exception
{
String
name
=
"testBean"
;
...
...
@@ -281,6 +319,7 @@ public class ModelAttributeMethodProcessorTests {
Errors
errors
,
int
intArg
,
@ModelAttribute
TestBean
defaultNameAttr
,
@ModelAttribute
(
name
=
"noBindAttr"
,
binding
=
false
)
@Valid
TestBean
noBindAttr
,
TestBean
notAnnotatedAttr
)
{
}
}
...
...
spring-web/src/test/java/org/springframework/web/method/annotation/ModelFactoryTests.java
浏览文件 @
2e7470b2
...
...
@@ -115,6 +115,30 @@ public class ModelFactoryTests {
assertNull
(
this
.
mavContainer
.
getModel
().
get
(
"name"
));
}
@Test
public
void
modelAttributeWithBindingDisabled
()
throws
Exception
{
ModelFactory
modelFactory
=
createModelFactory
(
"modelAttrWithBindingDisabled"
);
HandlerMethod
handlerMethod
=
createHandlerMethod
(
"handle"
);
modelFactory
.
initModel
(
this
.
webRequest
,
this
.
mavContainer
,
handlerMethod
);
assertTrue
(
this
.
mavContainer
.
containsAttribute
(
"foo"
));
assertTrue
(
this
.
mavContainer
.
isBindingDisabled
(
"foo"
));
}
@Test
public
void
modelAttributeFromSessionWithBindingDisabled
()
throws
Exception
{
Foo
foo
=
new
Foo
();
this
.
attributeStore
.
storeAttribute
(
this
.
webRequest
,
"foo"
,
foo
);
ModelFactory
modelFactory
=
createModelFactory
(
"modelAttrWithBindingDisabled"
);
HandlerMethod
handlerMethod
=
createHandlerMethod
(
"handle"
);
modelFactory
.
initModel
(
this
.
webRequest
,
this
.
mavContainer
,
handlerMethod
);
assertTrue
(
this
.
mavContainer
.
containsAttribute
(
"foo"
));
assertSame
(
foo
,
this
.
mavContainer
.
getModel
().
get
(
"foo"
));
assertTrue
(
this
.
mavContainer
.
isBindingDisabled
(
"foo"
));
}
@Test
public
void
sessionAttribute
()
throws
Exception
{
this
.
attributeStore
.
storeAttribute
(
this
.
webRequest
,
"sessionAttr"
,
"sessionAttrValue"
);
...
...
@@ -250,7 +274,7 @@ public class ModelFactoryTests {
}
@SessionAttributes
(
"sessionAttr"
)
@SuppressWarnings
(
"unused"
)
@SessionAttributes
(
{
"sessionAttr"
,
"foo"
}
)
@SuppressWarnings
(
"unused"
)
private
static
class
TestController
{
@ModelAttribute
...
...
@@ -273,6 +297,11 @@ public class ModelFactoryTests {
return
null
;
}
@ModelAttribute
(
name
=
"foo"
,
binding
=
false
)
public
Foo
modelAttrWithBindingDisabled
()
{
return
new
Foo
();
}
public
void
handle
()
{
}
...
...
@@ -280,4 +309,7 @@ public class ModelFactoryTests {
}
}
private
static
class
Foo
{
}
}
src/asciidoc/web-mvc.adoc
浏览文件 @
2e7470b2
...
...
@@ -1704,6 +1704,31 @@ With a `BindingResult` you can check if errors were found in which case it's com
render the same form where the errors can be shown with the help of Spring's `
<errors>
`
form tag.
Note that in some cases it may be useful to gain access to an attribute in the
model without data binding. For such cases you may inject the `Model` into the
controller or alternatively use the `binding` flag on the annotation:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ModelAttribute
public AccountForm setUpForm() {
return new AccountForm();
}
@ModelAttribute
public Account findAccount(@PathVariable String accountId) {
return accountRepository.findOne(accountId);
}
@RequestMapping(path="update", method=POST)
public String update(@Valid AccountUpdateForm form, BindingResult result,
**@ModelAttribute(binding=false)** Account account) {
// ...
}
----
In addition to data binding you can also invoke validation using your own custom
validator passing the same `BindingResult` that was used to record data binding errors.
That allows for data binding and validation errors to be accumulated in one place and
...
...
@@ -1747,6 +1772,7 @@ See <<validation-beanvalidation>> and <<validation>> for details on how to confi
use validation.
[[mvc-ann-sessionattrib]]
==== Using @SessionAttributes to store model attributes in the HTTP session between requests
...
...
src/asciidoc/whats-new.adoc
浏览文件 @
2e7470b2
...
...
@@ -666,6 +666,7 @@ Spring 4.3 also improves the caching abstraction as follows:
* `@ResponseStatus` supported on the class level and inherited on all methods.
* New `@SessionAttribute` annotation for access to session attributes (see <<mvc-ann-sessionattrib-global, example>>).
* New `@RequestAttribute` annotation for access to session attributes (see <<mvc-ann-requestattrib, example>>).
* `@ModelAttribute` allows preventing data binding via `binding=false` attribute (see <<mvc-ann-modelattrib-method-args, reference>>).
* `AsyncRestTemplate` supports request interception.
=== WebSocket Messaging Improvements
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录