Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
爱吃血肠
spring-framework
提交
f4adf227
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,发现更多精彩内容 >>
提交
f4adf227
编写于
7月 27, 2011
作者:
R
Rossen Stoyanchev
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
SPR-6464 Add @FlashAttributes annotation and FlashStatus method argument
上级
2c504012
变更
15
展开全部
隐藏空白更改
内联
并排
Showing
15 changed file
with
1104 addition
and
540 deletion
+1104
-540
org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java
...t/mvc/method/annotation/RequestMappingHandlerAdapter.java
+29
-11
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/AbstractServletHandlerMethodTests.java
.../method/annotation/AbstractServletHandlerMethodTests.java
+112
-0
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/FlashAttributesServletTests.java
...et/mvc/method/annotation/FlashAttributesServletTests.java
+215
-0
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java
...otation/RequestMappingHandlerAdapterIntegrationTests.java
+1
-1
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java
.../method/annotation/RequestMappingHandlerAdapterTests.java
+1
-1
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletAnnotationControllerHandlerMethodTests.java
...tation/ServletAnnotationControllerHandlerMethodTests.java
+251
-279
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/UriTemplateServletAnnotationControllerHandlerMethodTests.java
...emplateServletAnnotationControllerHandlerMethodTests.java
+75
-114
org.springframework.web/src/main/java/org/springframework/web/bind/annotation/FlashAttributes.java
.../springframework/web/bind/annotation/FlashAttributes.java
+56
-0
org.springframework.web/src/main/java/org/springframework/web/bind/support/FlashStatus.java
...ava/org/springframework/web/bind/support/FlashStatus.java
+51
-0
org.springframework.web/src/main/java/org/springframework/web/bind/support/SimpleFlashStatus.java
...g/springframework/web/bind/support/SimpleFlashStatus.java
+37
-0
org.springframework.web/src/main/java/org/springframework/web/method/annotation/FlashAttributesHandler.java
...amework/web/method/annotation/FlashAttributesHandler.java
+108
-0
org.springframework.web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java
...g/springframework/web/method/annotation/ModelFactory.java
+59
-44
org.springframework.web/src/main/java/org/springframework/web/method/annotation/SessionAttributesHandler.java
...ework/web/method/annotation/SessionAttributesHandler.java
+57
-71
org.springframework.web/src/test/java/org/springframework/web/method/annotation/ModelFactoryTests.java
...ingframework/web/method/annotation/ModelFactoryTests.java
+48
-15
org.springframework.web/src/test/java/org/springframework/web/method/annotation/SessionAttributesHandlerTests.java
.../web/method/annotation/SessionAttributesHandlerTests.java
+4
-4
未找到文件。
org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java
浏览文件 @
f4adf227
...
...
@@ -50,8 +50,10 @@ import org.springframework.web.bind.annotation.RequestMapping;
import
org.springframework.web.bind.annotation.SessionAttributes
;
import
org.springframework.web.bind.support.DefaultDataBinderFactory
;
import
org.springframework.web.bind.support.DefaultSessionAttributeStore
;
import
org.springframework.web.bind.support.FlashStatus
;
import
org.springframework.web.bind.support.SessionAttributeStore
;
import
org.springframework.web.bind.support.SessionStatus
;
import
org.springframework.web.bind.support.SimpleFlashStatus
;
import
org.springframework.web.bind.support.SimpleSessionStatus
;
import
org.springframework.web.bind.support.WebBindingInitializer
;
import
org.springframework.web.bind.support.WebDataBinderFactory
;
...
...
@@ -59,6 +61,7 @@ import org.springframework.web.context.request.ServletWebRequest;
import
org.springframework.web.context.request.WebRequest
;
import
org.springframework.web.method.HandlerMethod
;
import
org.springframework.web.method.HandlerMethodSelector
;
import
org.springframework.web.method.annotation.FlashAttributesHandler
;
import
org.springframework.web.method.annotation.ModelFactory
;
import
org.springframework.web.method.annotation.SessionAttributesHandler
;
import
org.springframework.web.method.annotation.support.ErrorsMethodArgumentResolver
;
...
...
@@ -146,6 +149,9 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
private
final
Map
<
Class
<?>,
SessionAttributesHandler
>
sessionAttributesHandlerCache
=
new
ConcurrentHashMap
<
Class
<?>,
SessionAttributesHandler
>();
private
final
Map
<
Class
<?>,
FlashAttributesHandler
>
flashAttributesHandlerCache
=
new
ConcurrentHashMap
<
Class
<?>,
FlashAttributesHandler
>();
private
HandlerMethodArgumentResolverComposite
argumentResolvers
;
private
HandlerMethodArgumentResolverComposite
initBinderArgumentResolvers
;
...
...
@@ -481,19 +487,27 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
}
/**
* Whether the given handler type defines any handler-specific session attributes
via {@link SessionAttributes}.
*
Also initializes the sessionAttributesHandlerCache for the given handler type
.
* Whether the given handler type defines any handler-specific session attributes
*
via {@link SessionAttributes}
.
*/
private
boolean
hasSessionAttributes
(
Class
<?>
handlerType
)
{
SessionAttributesHandler
h
andler
=
null
;
SessionAttributesHandler
sessionAttrsH
andler
=
null
;
synchronized
(
this
.
sessionAttributesHandlerCache
)
{
handler
=
this
.
sessionAttributesHandlerCache
.
get
(
handlerType
);
if
(
handler
==
null
)
{
handler
=
new
SessionAttributesHandler
(
handlerType
,
sessionAttributeStore
);
this
.
sessionAttributesHandlerCache
.
put
(
handlerType
,
handler
);
sessionAttrsHandler
=
this
.
sessionAttributesHandlerCache
.
get
(
handlerType
);
if
(
sessionAttrsHandler
==
null
)
{
sessionAttrsHandler
=
new
SessionAttributesHandler
(
handlerType
,
sessionAttributeStore
);
this
.
sessionAttributesHandlerCache
.
put
(
handlerType
,
sessionAttrsHandler
);
}
}
FlashAttributesHandler
flashAttrsHandler
=
null
;
synchronized
(
this
.
flashAttributesHandlerCache
)
{
flashAttrsHandler
=
this
.
flashAttributesHandlerCache
.
get
(
handlerType
);
if
(
flashAttrsHandler
==
null
)
{
flashAttrsHandler
=
new
FlashAttributesHandler
(
handlerType
);
this
.
flashAttributesHandlerCache
.
put
(
handlerType
,
flashAttrsHandler
);
}
}
return
handler
.
hasSession
Attributes
();
return
sessionAttrsHandler
.
hasSessionAttributes
()
||
flashAttrsHandler
.
hasFlash
Attributes
();
}
/**
...
...
@@ -509,12 +523,13 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
ServletWebRequest
webRequest
=
new
ServletWebRequest
(
request
,
response
);
SessionStatus
sessionStatus
=
new
SimpleSessionStatus
();
FlashStatus
flashStatus
=
new
SimpleFlashStatus
();
ModelAndViewContainer
mavContainer
=
new
ModelAndViewContainer
();
modelFactory
.
initModel
(
webRequest
,
mavContainer
,
requestMethod
);
requestMethod
.
invokeAndHandle
(
webRequest
,
mavContainer
,
sessionStatus
);
modelFactory
.
updateModel
(
webRequest
,
mavContainer
,
sessionStatus
);
requestMethod
.
invokeAndHandle
(
webRequest
,
mavContainer
,
sessionStatus
,
flashStatus
);
modelFactory
.
updateModel
(
webRequest
,
mavContainer
,
sessionStatus
,
flashStatus
);
if
(!
mavContainer
.
isResolveView
())
{
return
null
;
...
...
@@ -569,7 +584,10 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
modelAttrMethods
.
add
(
attrMethod
);
}
return
new
ModelFactory
(
modelAttrMethods
,
binderFactory
,
sessionAttributesHandlerCache
.
get
(
handlerType
));
SessionAttributesHandler
sessionAttrsHandler
=
sessionAttributesHandlerCache
.
get
(
handlerType
);
FlashAttributesHandler
flashAttrsHandler
=
flashAttributesHandlerCache
.
get
(
handlerType
);
return
new
ModelFactory
(
modelAttrMethods
,
binderFactory
,
sessionAttrsHandler
,
flashAttrsHandler
);
}
private
ServletInvocableHandlerMethod
createRequestMappingMethod
(
HandlerMethod
handlerMethod
,
...
...
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/AbstractServletHandlerMethodTests.java
0 → 100644
浏览文件 @
f4adf227
/*
* Copyright 2002-2011 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.springframework.web.servlet.mvc.method.annotation
;
import
static
junit
.
framework
.
Assert
.
assertNotNull
;
import
javax.servlet.ServletException
;
import
org.junit.After
;
import
org.springframework.beans.factory.support.RootBeanDefinition
;
import
org.springframework.context.ApplicationContextInitializer
;
import
org.springframework.mock.web.MockServletConfig
;
import
org.springframework.web.context.WebApplicationContext
;
import
org.springframework.web.context.support.GenericWebApplicationContext
;
import
org.springframework.web.servlet.DispatcherServlet
;
import
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver
;
import
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
;
/**
* Base class for tests using on the DispatcherServlet and HandlerMethod infrastructure classes:
* <ul>
* <li>RequestMappingHandlerMapping
* <li>RequestMappingHandlerAdapter
* <li>ExceptionHandlerExceptionResolver
* </ul>
*
* @author Rossen Stoyanchev
*/
public
class
AbstractServletHandlerMethodTests
{
private
DispatcherServlet
servlet
;
@After
public
void
tearDown
()
{
this
.
servlet
=
null
;
}
protected
DispatcherServlet
getServlet
()
{
assertNotNull
(
"DispatcherServlet not initialized"
,
servlet
);
return
servlet
;
}
/**
* Initialize a DispatcherServlet instance registering zero or more controller classes.
*/
protected
WebApplicationContext
initServletWithControllers
(
final
Class
<?>...
controllerClasses
)
throws
ServletException
{
return
initServlet
(
null
,
controllerClasses
);
}
/**
* Initialize a DispatcherServlet instance registering zero or more controller classes
* and also providing additional bean definitions through a callback.
*/
@SuppressWarnings
(
"serial"
)
protected
WebApplicationContext
initServlet
(
final
ApplicationContextInitializer
<
GenericWebApplicationContext
>
initializer
,
final
Class
<?>...
controllerClasses
)
throws
ServletException
{
final
GenericWebApplicationContext
wac
=
new
GenericWebApplicationContext
();
servlet
=
new
DispatcherServlet
()
{
@Override
protected
WebApplicationContext
createWebApplicationContext
(
WebApplicationContext
parent
)
{
for
(
Class
<?>
clazz
:
controllerClasses
)
{
wac
.
registerBeanDefinition
(
clazz
.
getSimpleName
(),
new
RootBeanDefinition
(
clazz
));
}
Class
<?>
mappingType
=
RequestMappingHandlerMapping
.
class
;
wac
.
registerBeanDefinition
(
"handlerMapping"
,
new
RootBeanDefinition
(
mappingType
));
Class
<?>
adapterType
=
RequestMappingHandlerAdapter
.
class
;
wac
.
registerBeanDefinition
(
"handlerAdapter"
,
new
RootBeanDefinition
(
adapterType
));
Class
<?>
resolverType
=
ExceptionHandlerExceptionResolver
.
class
;
wac
.
registerBeanDefinition
(
"requestMappingResolver"
,
new
RootBeanDefinition
(
resolverType
));
resolverType
=
ResponseStatusExceptionResolver
.
class
;
wac
.
registerBeanDefinition
(
"responseStatusResolver"
,
new
RootBeanDefinition
(
resolverType
));
resolverType
=
DefaultHandlerExceptionResolver
.
class
;
wac
.
registerBeanDefinition
(
"defaultResolver"
,
new
RootBeanDefinition
(
resolverType
));
if
(
initializer
!=
null
)
{
initializer
.
initialize
(
wac
);
}
wac
.
refresh
();
return
wac
;
}
};
servlet
.
init
(
new
MockServletConfig
());
return
wac
;
}
}
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/FlashAttributesServletTests.java
0 → 100644
浏览文件 @
f4adf227
/*
* Copyright 2002-2011 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.springframework.web.servlet.mvc.method.annotation
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertNull
;
import
java.util.Locale
;
import
java.util.Map
;
import
javax.servlet.ServletException
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
org.junit.Test
;
import
org.springframework.beans.factory.support.RootBeanDefinition
;
import
org.springframework.context.ApplicationContextInitializer
;
import
org.springframework.mock.web.MockHttpServletRequest
;
import
org.springframework.mock.web.MockHttpServletResponse
;
import
org.springframework.stereotype.Controller
;
import
org.springframework.ui.Model
;
import
org.springframework.web.bind.annotation.FlashAttributes
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.bind.support.FlashStatus
;
import
org.springframework.web.context.WebApplicationContext
;
import
org.springframework.web.context.support.GenericWebApplicationContext
;
import
org.springframework.web.method.annotation.FlashAttributesHandler
;
import
org.springframework.web.servlet.View
;
import
org.springframework.web.servlet.ViewResolver
;
/**
* Test controllers with @{@link FlashAttributes} through the DispatcherServlet.
*
* @author Rossen Stoyanchev
*/
public
class
FlashAttributesServletTests
extends
AbstractServletHandlerMethodTests
{
private
static
final
String
MESSAGE_KEY
=
"message"
;
@Test
public
void
successMessage
()
throws
Exception
{
initServletWithModelExposingViewResolver
(
MessageController
.
class
);
MockHttpServletRequest
req
=
new
MockHttpServletRequest
(
"GET"
,
"/message"
);
MockHttpServletResponse
res
=
new
MockHttpServletResponse
();
getServlet
().
service
(
req
,
res
);
assertEquals
(
200
,
res
.
getStatus
());
assertNull
(
getModelAttribute
(
req
,
MESSAGE_KEY
));
assertNull
(
getFlashAttribute
(
req
,
MESSAGE_KEY
));
req
.
setMethod
(
"POST"
);
getServlet
().
service
(
req
,
res
);
assertEquals
(
200
,
res
.
getStatus
());
assertEquals
(
"Yay!"
,
((
Message
)
getModelAttribute
(
req
,
MESSAGE_KEY
)).
getText
());
assertEquals
(
"Yay!"
,
((
Message
)
getFlashAttribute
(
req
,
MESSAGE_KEY
)).
getText
());
req
.
setMethod
(
"GET"
);
getServlet
().
service
(
req
,
res
);
assertEquals
(
200
,
res
.
getStatus
());
assertEquals
(
"Yay!"
,
((
Message
)
getModelAttribute
(
req
,
MESSAGE_KEY
)).
getText
());
assertNull
(
getFlashAttribute
(
req
,
MESSAGE_KEY
));
}
@Test
public
void
successMessageAcrossControllers
()
throws
Exception
{
initServletWithModelExposingViewResolver
(
MessageController
.
class
,
SecondMessageController
.
class
);
MockHttpServletRequest
req
=
new
MockHttpServletRequest
(
"POST"
,
"/message"
);
MockHttpServletResponse
res
=
new
MockHttpServletResponse
();
getServlet
().
service
(
req
,
res
);
req
.
setParameter
(
"another"
,
"true"
);
getServlet
().
service
(
req
,
res
);
assertEquals
(
200
,
res
.
getStatus
());
assertEquals
(
"Nay!"
,
((
Message
)
getModelAttribute
(
req
,
MESSAGE_KEY
)).
getText
());
assertEquals
(
"Nay!"
,
((
Message
)
getFlashAttribute
(
req
,
MESSAGE_KEY
)).
getText
());
req
.
setMethod
(
"GET"
);
req
.
setRequestURI
(
"/second/message"
);
getServlet
().
service
(
req
,
res
);
assertEquals
(
200
,
res
.
getStatus
());
assertEquals
(
"Nay!"
,
((
Message
)
getModelAttribute
(
req
,
MESSAGE_KEY
)).
getText
());
assertNull
(
getFlashAttribute
(
req
,
MESSAGE_KEY
));
}
@Controller
@FlashAttributes
(
"message"
)
static
class
MessageController
{
@RequestMapping
(
value
=
"/message"
,
method
=
RequestMethod
.
GET
)
public
void
message
(
Model
model
)
{
}
@RequestMapping
(
value
=
"/message"
,
method
=
RequestMethod
.
POST
)
public
String
sendMessage
(
Model
model
,
FlashStatus
status
)
{
status
.
setActive
();
model
.
addAttribute
(
Message
.
success
(
"Yay!"
));
return
"redirect:/message"
;
}
@RequestMapping
(
value
=
"/message"
,
method
=
RequestMethod
.
POST
,
params
=
"another"
)
public
String
sendMessageToSecondController
(
Model
model
,
FlashStatus
status
)
{
status
.
setActive
();
model
.
addAttribute
(
Message
.
error
(
"Nay!"
));
return
"redirect:/second/message"
;
}
}
@Controller
static
class
SecondMessageController
{
@RequestMapping
(
value
=
"/second/message"
,
method
=
RequestMethod
.
GET
)
public
void
message
(
Model
model
)
{
}
}
private
static
class
Message
{
private
final
MessageType
type
;
private
final
String
text
;
private
Message
(
MessageType
type
,
String
text
)
{
this
.
type
=
type
;
this
.
text
=
text
;
}
public
static
Message
success
(
String
text
)
{
return
new
Message
(
MessageType
.
success
,
text
);
}
public
static
Message
error
(
String
text
)
{
return
new
Message
(
MessageType
.
error
,
text
);
}
public
MessageType
getType
()
{
return
type
;
}
public
String
getText
()
{
return
text
;
}
public
String
toString
()
{
return
type
+
": "
+
text
;
}
}
private
static
enum
MessageType
{
info
,
success
,
warning
,
error
}
@SuppressWarnings
(
"unchecked"
)
private
Object
getModelAttribute
(
MockHttpServletRequest
req
,
String
key
)
{
Map
<
String
,
?>
model
=
(
Map
<
String
,
?>)
req
.
getAttribute
(
ModelExposingViewResolver
.
REQUEST_ATTRIBITE_MODEL
);
return
model
.
get
(
key
);
}
@SuppressWarnings
(
"unchecked"
)
private
Object
getFlashAttribute
(
MockHttpServletRequest
req
,
String
key
)
{
String
flashAttributesKey
=
FlashAttributesHandler
.
FLASH_ATTRIBUTES_SESSION_KEY
;
Map
<
String
,
Object
>
attrs
=
(
Map
<
String
,
Object
>)
req
.
getSession
().
getAttribute
(
flashAttributesKey
);
return
(
attrs
!=
null
)
?
attrs
.
get
(
key
)
:
null
;
}
private
WebApplicationContext
initServletWithModelExposingViewResolver
(
Class
<?>...
controllerClasses
)
throws
ServletException
{
return
initServlet
(
new
ApplicationContextInitializer
<
GenericWebApplicationContext
>()
{
public
void
initialize
(
GenericWebApplicationContext
wac
)
{
wac
.
registerBeanDefinition
(
"viewResolver"
,
new
RootBeanDefinition
(
ModelExposingViewResolver
.
class
));
}
},
controllerClasses
);
}
static
class
ModelExposingViewResolver
implements
ViewResolver
{
static
String
REQUEST_ATTRIBITE_MODEL
=
"ModelExposingViewResolver.model"
;
public
View
resolveViewName
(
final
String
viewName
,
Locale
locale
)
throws
Exception
{
return
new
View
()
{
public
void
render
(
Map
<
String
,
?>
model
,
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
Exception
{
request
.
setAttribute
(
REQUEST_ATTRIBITE_MODEL
,
model
);
}
public
String
getContentType
()
{
return
null
;
}
};
}
}
}
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java
浏览文件 @
f4adf227
...
...
@@ -92,7 +92,7 @@ import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebA
* <p>If you wish to add high-level tests, consider the following other "integration"-style tests:
* <ul>
* <li>{@link HandlerMethodAnnotationDetectionTests}
* <li>{@link ServletHandlerMethodTests}
* <li>{@link Servlet
AnnotationController
HandlerMethodTests}
* </ul>
*
* @author Rossen Stoyanchev
...
...
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java
浏览文件 @
f4adf227
...
...
@@ -49,7 +49,7 @@ import org.springframework.web.servlet.mvc.method.annotation.support.ServletRequ
*
* <p>For higher-level adapter tests see:
* <ul>
* <li>{@link ServletHandlerMethodTests}
* <li>{@link Servlet
AnnotationController
HandlerMethodTests}
* <li>{@link HandlerMethodAnnotationDetectionTests}
* <li>{@link RequestMappingHandlerAdapterIntegrationTests}
* </ul>
...
...
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletHandlerMethodTests.java
→
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/Servlet
AnnotationController
HandlerMethodTests.java
浏览文件 @
f4adf227
此差异已折叠。
点击以展开。
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/UriTemplateServletHandlerMethodTests.java
→
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/UriTemplateServlet
AnnotationController
HandlerMethodTests.java
浏览文件 @
f4adf227
...
...
@@ -28,16 +28,15 @@ import java.util.HashMap;
import
java.util.Locale
;
import
java.util.Map
;
import
javax.servlet.ServletException
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
org.junit.Test
;
import
org.springframework.beans.factory.support.RootBeanDefinition
;
import
org.springframework.beans.propertyeditors.CustomDateEditor
;
import
org.springframework.context.ApplicationContextInitializer
;
import
org.springframework.mock.web.MockHttpServletRequest
;
import
org.springframework.mock.web.MockHttpServletResponse
;
import
org.springframework.mock.web.MockServletConfig
;
import
org.springframework.stereotype.Controller
;
import
org.springframework.web.bind.WebDataBinder
;
import
org.springframework.web.bind.annotation.InitBinder
;
...
...
@@ -46,45 +45,51 @@ import org.springframework.web.bind.annotation.RequestMapping;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.context.WebApplicationContext
;
import
org.springframework.web.context.support.GenericWebApplicationContext
;
import
org.springframework.web.
servlet.DispatcherServlet
;
import
org.springframework.web.
method.HandlerMethod
;
import
org.springframework.web.servlet.View
;
import
org.springframework.web.servlet.ViewResolver
;
import
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver
;
import
org.springframework.web.servlet.mvc.annotation.UriTemplateServletAnnotationControllerTests
;
import
org.springframework.web.servlet.mvc.annotation.UriTemplateServletAnnotationControllerTests.VariableNamesController
;
import
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
;
import
org.springframework.web.servlet.view.AbstractView
;
/**
* The origin of this test class is {@link UriTemplateServletAnnotationControllerTests} with the tests in this class
* adapted to run against the HandlerMethod infrastructure rather than against the DefaultAnnotationHandlerMapping,
* the AnnotationMethodHandlerAdapter, and the AnnotationMethodHandlerExceptionResolver. Tests that are not supported
* are listed at the bottom.
*
* The origin of this test class is {@link UriTemplateServletAnnotationControllerTests}.
*
* Tests in this class run against the {@link HandlerMethod} infrastructure:
* <ul>
* <li>RequestMappingHandlerMapping
* <li>RequestMappingHandlerAdapter
* <li>ExceptionHandlerExceptionResolver
* </ul>
*
* <p>Rather than against the existing infrastructure:
* <ul>
* <li>DefaultAnnotationHandlerMapping
* <li>AnnotationMethodHandlerAdapter
* <li>AnnotationMethodHandlerExceptionResolver
* </ul>
*
* @author Rossen Stoyanchev
* @since 3.1
*/
public
class
UriTemplateServletHandlerMethodTests
{
private
DispatcherServlet
servlet
;
public
class
UriTemplateServletAnnotationControllerHandlerMethodTests
extends
AbstractServletHandlerMethodTests
{
@Test
public
void
simple
()
throws
Exception
{
init
DispatcherServlet
(
SimpleUriTemplateController
.
class
,
null
);
init
ServletWithControllers
(
SimpleUriTemplateController
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/42"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"test-42"
,
response
.
getContentAsString
());
}
@Test
public
void
multiple
()
throws
Exception
{
init
DispatcherServlet
(
MultipleUriTemplateController
.
class
,
null
);
init
ServletWithControllers
(
MultipleUriTemplateController
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/hotels/42/bookings/21-other"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"test-42-21-other"
,
response
.
getContentAsString
());
}
...
...
@@ -96,16 +101,16 @@ public class UriTemplateServletHandlerMethodTests {
pathVars
.
put
(
"other"
,
"other"
);
WebApplicationContext
wac
=
init
DispatcherServlet
(
ViewRenderingController
.
class
,
new
BeanDefinitionRegistrar
()
{
public
void
register
(
GenericWebApplicationContext
context
)
{
init
Servlet
(
new
ApplicationContextInitializer
<
GenericWebApplicationContext
>
()
{
public
void
initialize
(
GenericWebApplicationContext
context
)
{
RootBeanDefinition
beanDef
=
new
RootBeanDefinition
(
ModelValidatingViewResolver
.
class
);
beanDef
.
getConstructorArgumentValues
().
addGenericArgumentValue
(
pathVars
);
context
.
registerBeanDefinition
(
"viewResolver"
,
beanDef
);
}
});
}
,
ViewRenderingController
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/hotels/42/bookings/21-other"
);
servlet
.
service
(
request
,
new
MockHttpServletResponse
());
getServlet
()
.
service
(
request
,
new
MockHttpServletResponse
());
ModelValidatingViewResolver
resolver
=
wac
.
getBean
(
ModelValidatingViewResolver
.
class
);
assertEquals
(
3
,
resolver
.
validatedAttrCount
);
...
...
@@ -113,153 +118,153 @@ public class UriTemplateServletHandlerMethodTests {
@Test
public
void
binding
()
throws
Exception
{
init
DispatcherServlet
(
BindingUriTemplateController
.
class
,
null
);
init
ServletWithControllers
(
BindingUriTemplateController
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/hotels/42/dates/2008-11-18"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
200
,
response
.
getStatus
());
request
=
new
MockHttpServletRequest
(
"GET"
,
"/hotels/42/dates/2008-foo-bar"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
400
,
response
.
getStatus
());
init
DispatcherServlet
(
NonBindingUriTemplateController
.
class
,
null
);
init
ServletWithControllers
(
NonBindingUriTemplateController
.
class
);
request
=
new
MockHttpServletRequest
(
"GET"
,
"/hotels/42/dates/2008-foo-bar"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
500
,
response
.
getStatus
());
}
@Test
public
void
ambiguous
()
throws
Exception
{
init
DispatcherServlet
(
AmbiguousUriTemplateController
.
class
,
null
);
init
ServletWithControllers
(
AmbiguousUriTemplateController
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/hotels/new"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"specific"
,
response
.
getContentAsString
());
}
@Test
public
void
relative
()
throws
Exception
{
init
DispatcherServlet
(
RelativePathUriTemplateController
.
class
,
null
);
init
ServletWithControllers
(
RelativePathUriTemplateController
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/hotels/42/bookings/21"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"test-42-21"
,
response
.
getContentAsString
());
request
=
new
MockHttpServletRequest
(
"GET"
,
"/hotels/42/bookings/21.html"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"test-42-21"
,
response
.
getContentAsString
());
}
@Test
public
void
extension
()
throws
Exception
{
init
DispatcherServlet
(
SimpleUriTemplateController
.
class
,
null
);
init
ServletWithControllers
(
SimpleUriTemplateController
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/42.xml"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"test-42"
,
response
.
getContentAsString
());
}
@Test
public
void
typeConversionError
()
throws
Exception
{
init
DispatcherServlet
(
SimpleUriTemplateController
.
class
,
null
);
init
ServletWithControllers
(
SimpleUriTemplateController
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/foo.xml"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"Invalid response status code"
,
HttpServletResponse
.
SC_BAD_REQUEST
,
response
.
getStatus
());
}
@Test
public
void
explicitSubPath
()
throws
Exception
{
init
DispatcherServlet
(
ExplicitSubPathController
.
class
,
null
);
init
ServletWithControllers
(
ExplicitSubPathController
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/hotels/42"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"test-42"
,
response
.
getContentAsString
());
}
@Test
public
void
implicitSubPath
()
throws
Exception
{
init
DispatcherServlet
(
ImplicitSubPathController
.
class
,
null
);
init
ServletWithControllers
(
ImplicitSubPathController
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/hotels/42"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"test-42"
,
response
.
getContentAsString
());
}
@Test
public
void
crud
()
throws
Exception
{
init
DispatcherServlet
(
CrudController
.
class
,
null
);
init
ServletWithControllers
(
CrudController
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/hotels"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"list"
,
response
.
getContentAsString
());
request
=
new
MockHttpServletRequest
(
"GET"
,
"/hotels/"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"list"
,
response
.
getContentAsString
());
request
=
new
MockHttpServletRequest
(
"POST"
,
"/hotels"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"create"
,
response
.
getContentAsString
());
request
=
new
MockHttpServletRequest
(
"GET"
,
"/hotels/42"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"show-42"
,
response
.
getContentAsString
());
request
=
new
MockHttpServletRequest
(
"GET"
,
"/hotels/42/"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"show-42"
,
response
.
getContentAsString
());
request
=
new
MockHttpServletRequest
(
"PUT"
,
"/hotels/42"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"createOrUpdate-42"
,
response
.
getContentAsString
());
request
=
new
MockHttpServletRequest
(
"DELETE"
,
"/hotels/42"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"remove-42"
,
response
.
getContentAsString
());
}
@Test
public
void
methodNotSupported
()
throws
Exception
{
init
DispatcherServlet
(
MethodNotAllowedController
.
class
,
null
);
init
ServletWithControllers
(
MethodNotAllowedController
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/hotels/1"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
200
,
response
.
getStatus
());
request
=
new
MockHttpServletRequest
(
"POST"
,
"/hotels/1"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
405
,
response
.
getStatus
());
request
=
new
MockHttpServletRequest
(
"GET"
,
"/hotels"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
200
,
response
.
getStatus
());
request
=
new
MockHttpServletRequest
(
"POST"
,
"/hotels"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
405
,
response
.
getStatus
());
...
...
@@ -267,26 +272,26 @@ public class UriTemplateServletHandlerMethodTests {
@Test
public
void
multiPaths
()
throws
Exception
{
init
DispatcherServlet
(
MultiPathController
.
class
,
null
);
init
ServletWithControllers
(
MultiPathController
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/category/page/5"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"handle4-page-5"
,
response
.
getContentAsString
());
request
=
new
MockHttpServletRequest
(
"GET"
,
"/category/page/5.html"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"handle4-page-5"
,
response
.
getContentAsString
());
}
@Test
public
void
customRegex
()
throws
Exception
{
init
DispatcherServlet
(
CustomRegexController
.
class
,
null
);
init
ServletWithControllers
(
CustomRegexController
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/42"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"test-42"
,
response
.
getContentAsString
());
}
...
...
@@ -295,11 +300,11 @@ public class UriTemplateServletHandlerMethodTests {
*/
@Test
public
void
menuTree
()
throws
Exception
{
init
DispatcherServlet
(
MenuTreeController
.
class
,
null
);
init
ServletWithControllers
(
MenuTreeController
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/book/menu/type/M5"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"M5"
,
response
.
getContentAsString
());
}
...
...
@@ -308,16 +313,16 @@ public class UriTemplateServletHandlerMethodTests {
*/
@Test
public
void
variableNames
()
throws
Exception
{
init
DispatcherServlet
(
VariableNamesController
.
class
,
null
);
init
ServletWithControllers
(
VariableNamesController
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/test/foo"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"foo-foo"
,
response
.
getContentAsString
());
request
=
new
MockHttpServletRequest
(
"DELETE"
,
"/test/bar"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"bar-bar"
,
response
.
getContentAsString
());
}
...
...
@@ -326,11 +331,11 @@ public class UriTemplateServletHandlerMethodTests {
*/
@Test
public
void
variableNamesWithUrlExtension
()
throws
Exception
{
init
DispatcherServlet
(
VariableNamesController
.
class
,
null
);
init
ServletWithControllers
(
VariableNamesController
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/test/foo.json"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"foo-foo"
,
response
.
getContentAsString
());
}
...
...
@@ -339,26 +344,26 @@ public class UriTemplateServletHandlerMethodTests {
*/
@Test
public
void
doIt
()
throws
Exception
{
init
DispatcherServlet
(
Spr6978Controller
.
class
,
null
);
init
ServletWithControllers
(
Spr6978Controller
.
class
);
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
"/foo/100"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"loadEntity:foo:100"
,
response
.
getContentAsString
());
request
=
new
MockHttpServletRequest
(
"POST"
,
"/foo/100"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"publish:foo:100"
,
response
.
getContentAsString
());
request
=
new
MockHttpServletRequest
(
"GET"
,
"/module/100"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"loadModule:100"
,
response
.
getContentAsString
());
request
=
new
MockHttpServletRequest
(
"POST"
,
"/module/100"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
getServlet
()
.
service
(
request
,
response
);
assertEquals
(
"publish:module:100"
,
response
.
getContentAsString
());
}
...
...
@@ -672,50 +677,6 @@ public class UriTemplateServletHandlerMethodTests {
}
}
private
interface
BeanDefinitionRegistrar
{
public
void
register
(
GenericWebApplicationContext
context
);
}
@SuppressWarnings
(
"serial"
)
private
WebApplicationContext
initDispatcherServlet
(
final
Class
<?>
controllerClass
,
final
BeanDefinitionRegistrar
registrar
)
throws
ServletException
{
final
GenericWebApplicationContext
wac
=
new
GenericWebApplicationContext
();
servlet
=
new
DispatcherServlet
()
{
@Override
protected
WebApplicationContext
createWebApplicationContext
(
WebApplicationContext
parent
)
{
wac
.
registerBeanDefinition
(
"controller"
,
new
RootBeanDefinition
(
controllerClass
));
Class
<?>
mappingType
=
RequestMappingHandlerMapping
.
class
;
wac
.
registerBeanDefinition
(
"handlerMapping"
,
new
RootBeanDefinition
(
mappingType
));
Class
<?>
adapterType
=
RequestMappingHandlerAdapter
.
class
;
wac
.
registerBeanDefinition
(
"handlerAdapter"
,
new
RootBeanDefinition
(
adapterType
));
Class
<?>
resolverType
=
ExceptionHandlerExceptionResolver
.
class
;
wac
.
registerBeanDefinition
(
"requestMappingResolver"
,
new
RootBeanDefinition
(
resolverType
));
resolverType
=
ResponseStatusExceptionResolver
.
class
;
wac
.
registerBeanDefinition
(
"responseStatusResolver"
,
new
RootBeanDefinition
(
resolverType
));
resolverType
=
DefaultHandlerExceptionResolver
.
class
;
wac
.
registerBeanDefinition
(
"defaultResolver"
,
new
RootBeanDefinition
(
resolverType
));
if
(
registrar
!=
null
)
{
registrar
.
register
(
wac
);
}
wac
.
refresh
();
return
wac
;
}
};
servlet
.
init
(
new
MockServletConfig
());
return
wac
;
}
// @Ignore("ControllerClassNameHandlerMapping")
// public void controllerClassName() throws Exception {
...
...
org.springframework.web/src/main/java/org/springframework/web/bind/annotation/FlashAttributes.java
0 → 100644
浏览文件 @
f4adf227
/*
* Copyright 2002-2010 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.springframework.web.bind.annotation
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Inherited
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
/**
* Annotation that indicates what attributes should be stored in the session or in
* some conversational storage in order to survive a client-side redirect.
*
* TODO ...
*
* @author Rossen Stoyanchev
* @since 3.1
*
* @see org.springframework.web.bind.support.FlashStatus
*/
@Target
({
ElementType
.
TYPE
})
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Inherited
@Documented
public
@interface
FlashAttributes
{
/**
* The names of flash attributes in the model to be stored.
*
* TODO ...
*/
String
[]
value
()
default
{};
/**
* TODO ...
*
*/
Class
[]
types
()
default
{};
}
org.springframework.web/src/main/java/org/springframework/web/bind/support/FlashStatus.java
0 → 100644
浏览文件 @
f4adf227
/*
* Copyright 2002-2011 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.springframework.web.bind.support
;
import
org.springframework.web.bind.annotation.FlashAttributes
;
/**
* Simple interface to pass into controller methods to allow them to activate
* a mode in which model attributes identified as "flash attributes" are
* temporarily stored in the session to make them available to the next
* request. The most common scenario is a client-side redirect.
*
* <p>In active mode, model attributes that match the attribute names or
* types declared via @{@link FlashAttributes} are saved in the session.
* On the next request, any flash attributes found in the session are
* automatically added to the model of the target controller method and
* are also cleared from the session.
*
* TODO ...
*
* @author Rossen Stoyanchev
* @since 3.1
*/
public
interface
FlashStatus
{
/**
* TODO ...
*/
void
setActive
();
/**
* TODO ...
*/
boolean
isActive
();
}
org.springframework.web/src/main/java/org/springframework/web/bind/support/SimpleFlashStatus.java
0 → 100644
浏览文件 @
f4adf227
/*
* Copyright 2002-2011 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.springframework.web.bind.support
;
/**
* TODO ...
*
* @author Rossen Stoyanchev
* @since 3.1
*/
public
class
SimpleFlashStatus
implements
FlashStatus
{
private
boolean
active
=
false
;
public
void
setActive
()
{
this
.
active
=
true
;
}
public
boolean
isActive
()
{
return
this
.
active
;
}
}
org.springframework.web/src/main/java/org/springframework/web/method/annotation/FlashAttributesHandler.java
0 → 100644
浏览文件 @
f4adf227
/*
* Copyright 2002-2011 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.springframework.web.method.annotation
;
import
java.util.Arrays
;
import
java.util.HashSet
;
import
java.util.LinkedHashMap
;
import
java.util.Map
;
import
java.util.Set
;
import
org.springframework.core.annotation.AnnotationUtils
;
import
org.springframework.web.bind.annotation.FlashAttributes
;
import
org.springframework.web.context.request.WebRequest
;
/**
* Manages flash attributes declared via @{@link FlashAttributes}.
*
* TODO ...
*
* @author Rossen Stoyanchev
* @since 3.1
*/
public
class
FlashAttributesHandler
{
public
static
final
String
FLASH_ATTRIBUTES_SESSION_KEY
=
FlashAttributesHandler
.
class
.
getName
()
+
".attributes"
;
private
final
Set
<
String
>
attributeNames
=
new
HashSet
<
String
>();
private
final
Set
<
Class
<?>>
attributeTypes
=
new
HashSet
<
Class
<?>>();
/**
* TODO ...
*/
public
FlashAttributesHandler
(
Class
<?>
handlerType
)
{
FlashAttributes
annotation
=
AnnotationUtils
.
findAnnotation
(
handlerType
,
FlashAttributes
.
class
);
if
(
annotation
!=
null
)
{
this
.
attributeNames
.
addAll
(
Arrays
.
asList
(
annotation
.
value
()));
this
.
attributeTypes
.
addAll
(
Arrays
.<
Class
<?>>
asList
(
annotation
.
types
()));
}
}
/**
* Whether the controller represented by this handler has declared flash
* attribute names or types via @{@link FlashAttributes}.
*/
public
boolean
hasFlashAttributes
()
{
return
((
this
.
attributeNames
.
size
()
>
0
)
||
(
this
.
attributeTypes
.
size
()
>
0
));
}
/**
* TODO ...
*/
public
boolean
isFlashAttribute
(
String
attributeName
,
Class
<?>
attributeType
)
{
return
(
this
.
attributeNames
.
contains
(
attributeName
)
||
this
.
attributeTypes
.
contains
(
attributeType
));
}
/**
* TODO ...
*/
public
void
storeAttributes
(
WebRequest
request
,
Map
<
String
,
?>
attributes
)
{
Map
<
String
,
Object
>
filtered
=
filterAttributes
(
attributes
);
if
(!
filtered
.
isEmpty
())
{
request
.
setAttribute
(
FLASH_ATTRIBUTES_SESSION_KEY
,
filtered
,
WebRequest
.
SCOPE_SESSION
);
}
}
private
Map
<
String
,
Object
>
filterAttributes
(
Map
<
String
,
?>
attributes
)
{
Map
<
String
,
Object
>
result
=
new
LinkedHashMap
<
String
,
Object
>();
for
(
String
name
:
attributes
.
keySet
())
{
Object
value
=
attributes
.
get
(
name
);
Class
<?>
type
=
(
value
!=
null
)
?
value
.
getClass
()
:
null
;
if
(
isFlashAttribute
(
name
,
type
))
{
result
.
put
(
name
,
value
);
}
}
return
result
;
}
/**
* TODO ...
*/
@SuppressWarnings
(
"unchecked"
)
public
Map
<
String
,
Object
>
retrieveAttributes
(
WebRequest
request
)
{
return
(
Map
<
String
,
Object
>)
request
.
getAttribute
(
FLASH_ATTRIBUTES_SESSION_KEY
,
WebRequest
.
SCOPE_SESSION
);
}
/**
* TODO ...
*/
public
void
cleanupAttributes
(
WebRequest
request
)
{
request
.
removeAttribute
(
FLASH_ATTRIBUTES_SESSION_KEY
,
WebRequest
.
SCOPE_SESSION
);
}
}
\ No newline at end of file
org.springframework.web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java
浏览文件 @
f4adf227
...
...
@@ -26,6 +26,7 @@ import org.springframework.beans.BeanUtils;
import
org.springframework.core.Conventions
;
import
org.springframework.core.GenericTypeResolver
;
import
org.springframework.core.MethodParameter
;
import
org.springframework.ui.Model
;
import
org.springframework.ui.ModelMap
;
import
org.springframework.util.StringUtils
;
import
org.springframework.validation.BindingResult
;
...
...
@@ -34,6 +35,7 @@ import org.springframework.web.bind.WebDataBinder;
import
org.springframework.web.bind.annotation.ModelAttribute
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.SessionAttributes
;
import
org.springframework.web.bind.support.FlashStatus
;
import
org.springframework.web.bind.support.SessionStatus
;
import
org.springframework.web.bind.support.WebDataBinderFactory
;
import
org.springframework.web.context.request.NativeWebRequest
;
...
...
@@ -42,15 +44,16 @@ import org.springframework.web.method.support.InvocableHandlerMethod;
import
org.springframework.web.method.support.ModelAndViewContainer
;
/**
*
Contains methods for creating and updating a model. A {@link ModelFactory} is associated with a specific controller
*
through knowledge of its @{@link ModelAttribute} methods and @{@link SessionAttributes}.
*
Provides methods to initialize the {@link Model} before a controller method
*
invocation and to update it after the controller method has been invoked.
*
* <p>{@link #initModel(NativeWebRequest, ModelAndViewContainer, HandlerMethod)} populates the model
* with handler session attributes and by invoking model attribute methods.
* <p>On initialization the model may be populated with session attributes
* stored during a previous request as a result of a {@link SessionAttributes}
* annotation. @{@link ModelAttribute} methods in the same controller may
* also be invoked to populate the model.
*
* <p>{@link #updateModel(NativeWebRequest, ModelAndViewContainer, SessionStatus)} updates
* the model (usually after the {@link RequestMapping} method has been called) promoting attributes
* to the session and adding {@link BindingResult} attributes as necessary.
* <p>On update attributes may be removed from or stored in the session.
* {@link BindingResult} attributes may also be added as necessary.
*
* @author Rossen Stoyanchev
* @since 3.1
...
...
@@ -61,45 +64,52 @@ public final class ModelFactory {
private
final
WebDataBinderFactory
binderFactory
;
private
final
SessionAttributesHandler
sessionHandler
;
private
final
SessionAttributesHandler
sessionAttributesHandler
;
private
final
FlashAttributesHandler
flashAttributesHandler
;
/**
* Create a ModelFactory instance with the provided {@link ModelAttribute} methods.
* @param attributeMethods {@link ModelAttribute}-annotated methods to invoke when populating a model
* @param binderFactory the binder factory to use when adding {@link BindingResult}s to the model
* @param sessionHandler a session attributes handler to synch attributes with the session
* @param attributeMethods {@link ModelAttribute} methods to initialize model instances with
* @param binderFactory used to add {@link BindingResult} attributes to the model
* @param sessionAttributesHandler used to access handler-specific session attributes
* @param flashAttributesHandler used to access flash attributes
*/
public
ModelFactory
(
List
<
InvocableHandlerMethod
>
attributeMethods
,
WebDataBinderFactory
binderFactory
,
SessionAttributesHandler
sessionHandler
)
{
SessionAttributesHandler
sessionAttributesHandler
,
FlashAttributesHandler
flashAttributesHandler
)
{
this
.
attributeMethods
=
(
attributeMethods
!=
null
)
?
attributeMethods
:
new
ArrayList
<
InvocableHandlerMethod
>();
this
.
binderFactory
=
binderFactory
;
this
.
sessionHandler
=
sessionHandler
;
this
.
sessionAttributesHandler
=
sessionAttributesHandler
;
this
.
flashAttributesHandler
=
flashAttributesHandler
;
}
/**
* Populate the model
for a request with attributes obtained
in the following order:
* Populate the model in the following order:
* <ol>
*
<li>Retrieve "known" (i.e. have been in the model in prior requests) handler session attributes from the session
*
<li>Create attributes by invoking model attribute
methods
*
<li>Check for not yet known handler session attributes in the session
*
<li>Retrieve "remembered" (i.e. previously stored) controller-specific session attributes
*
<li>Invoke @{@link ModelAttribute}
methods
*
<li>Check the session for any controller-specific attributes not yet "remembered".
* </ol>
* <p>As a general rule model attributes are added only once following the above order.
*
* @param request the current request
* @param mavContainer
the {@link ModelAndViewContainer} to add model attributes to
* @param
requestMethod the request handling method for which the model is need
ed
* @throws Exception
if an exception occurs while invoking model attribute
methods
* @param mavContainer
contains the model to initialize
* @param
handlerMethod the @{@link RequestMapping} method for which the model is initializ
ed
* @throws Exception
may arise from the invocation of @{@link ModelAttribute}
methods
*/
public
void
initModel
(
NativeWebRequest
request
,
ModelAndViewContainer
mavContainer
,
HandlerMethod
request
Method
)
public
void
initModel
(
NativeWebRequest
request
,
ModelAndViewContainer
mavContainer
,
HandlerMethod
handler
Method
)
throws
Exception
{
Map
<
String
,
?>
sessionAttributes
=
this
.
sessionHandler
.
retrieveHandlerSessionAttributes
(
request
);
mavContainer
.
addAllAttributes
(
sessionAttributes
);
Map
<
String
,
?>
sessionAttrs
=
this
.
sessionAttributesHandler
.
retrieveAttributes
(
request
);
mavContainer
.
addAllAttributes
(
sessionAttrs
);
Map
<
String
,
?>
flashAttrs
=
this
.
flashAttributesHandler
.
retrieveAttributes
(
request
);
mavContainer
.
addAllAttributes
(
flashAttrs
);
this
.
flashAttributesHandler
.
cleanupAttributes
(
request
);
invokeAttributeMethods
(
request
,
mavContainer
);
check
MissingSessionAttributes
(
request
,
mavContainer
,
request
Method
);
check
HandlerSessionAttributes
(
request
,
mavContainer
,
handler
Method
);
}
/**
...
...
@@ -125,26 +135,26 @@ public final class ModelFactory {
}
/**
* Checks if any
{@link ModelAttribute}-annotated handler method arguments are eligible as handler session
*
attributes, as defined by @{@link SessionAttributes}, and are not yet present in the model.
*
If so, attempts to retrieve them from the session and add them to the model.
* Checks if any
@{@link ModelAttribute} handler method arguments declared as
*
session attributes via @{@link SessionAttributes} but are not already in the
*
model. If found add them to the model, raise an exception otherwise.
*
* @throws HttpSessionRequiredException raised if a handler session attribute could is missing
*/
private
void
check
Missing
SessionAttributes
(
NativeWebRequest
request
,
private
void
check
Handler
SessionAttributes
(
NativeWebRequest
request
,
ModelAndViewContainer
mavContainer
,
HandlerMethod
request
Method
)
throws
HttpSessionRequiredException
{
for
(
MethodParameter
parameter
:
request
Method
.
getMethodParameters
())
{
HandlerMethod
handler
Method
)
throws
HttpSessionRequiredException
{
for
(
MethodParameter
parameter
:
handler
Method
.
getMethodParameters
())
{
if
(
parameter
.
hasParameterAnnotation
(
ModelAttribute
.
class
))
{
String
n
ame
=
getNameForParameter
(
parameter
);
if
(!
mavContainer
.
containsAttribute
(
n
ame
))
{
if
(
session
Handler
.
isHandlerSessionAttribute
(
n
ame
,
parameter
.
getParameterType
()))
{
Object
attrValue
=
session
Handler
.
retrieveAttribute
(
request
,
n
ame
);
String
attrN
ame
=
getNameForParameter
(
parameter
);
if
(!
mavContainer
.
containsAttribute
(
attrN
ame
))
{
if
(
session
AttributesHandler
.
isHandlerSessionAttribute
(
attrN
ame
,
parameter
.
getParameterType
()))
{
Object
attrValue
=
session
AttributesHandler
.
retrieveAttribute
(
request
,
attrN
ame
);
if
(
attrValue
==
null
){
throw
new
HttpSessionRequiredException
(
"Session attribute '"
+
name
+
"' not found in session: "
+
request
Method
);
"Session attribute '"
+
attrName
+
"' not found in session: "
+
handler
Method
);
}
mavContainer
.
addAttribute
(
n
ame
,
attrValue
);
mavContainer
.
addAttribute
(
attrN
ame
,
attrValue
);
}
}
}
...
...
@@ -196,15 +206,20 @@ public final class ModelFactory {
* @param sessionStatus whether session processing is complete
* @throws Exception if the process of creating {@link BindingResult} attributes causes an error
*/
public
void
updateModel
(
NativeWebRequest
request
,
ModelAndViewContainer
mavContainer
,
SessionStatus
sessionStatus
)
throws
Exception
{
public
void
updateModel
(
NativeWebRequest
request
,
ModelAndViewContainer
mavContainer
,
SessionStatus
sessionStatus
,
FlashStatus
flashStatus
)
throws
Exception
{
if
(
sessionStatus
.
isComplete
()){
this
.
sessionHandler
.
cleanupHandlerSessionAttributes
(
request
);
this
.
sessionAttributesHandler
.
cleanupAttributes
(
request
);
}
else
{
this
.
sessionAttributesHandler
.
storeAttributes
(
request
,
mavContainer
.
getModel
());
}
this
.
sessionHandler
.
storeHandlerSessionAttributes
(
request
,
mavContainer
.
getModel
());
if
(
flashStatus
.
isActive
())
{
this
.
flashAttributesHandler
.
storeAttributes
(
request
,
mavContainer
.
getModel
());
}
if
(
mavContainer
.
isResolveView
())
{
updateBindingResult
(
request
,
mavContainer
.
getModel
());
}
...
...
@@ -238,7 +253,7 @@ public final class ModelFactory {
}
Class
<?>
attrType
=
(
value
!=
null
)
?
value
.
getClass
()
:
null
;
if
(
this
.
sessionHandler
.
isHandlerSessionAttribute
(
attributeName
,
attrType
))
{
if
(
this
.
session
Attributes
Handler
.
isHandlerSessionAttribute
(
attributeName
,
attrType
))
{
return
true
;
}
...
...
org.springframework.web/src/main/java/org/springframework/web/method/annotation/SessionAttributesHandler.java
浏览文件 @
f4adf227
...
...
@@ -32,22 +32,15 @@ import org.springframework.web.bind.support.SessionStatus;
import
org.springframework.web.context.request.WebRequest
;
/**
* Provides operations for managing handler-specific session attributes as defined by the
* {@link SessionAttributes} type-level annotation performing all operations through an
* instance of a {@link SessionAttributeStore}.
* Manages handler-specific session attributes declared via @{@link SessionAttributes}.
* Actual storage is performed through an instance of {@link SessionAttributeStore}.
*
* <p>A typical scenario involves a handler adding attributes to the {@link Model} during
* a request. At the end of the request, model attributes that match to session attribute
* names defined through an {@link SessionAttributes} annotation are automatically
* "promoted" to the session. Handler session attributes are then removed when
* {@link SessionStatus#setComplete()} is called by a handler.
*
* <p>Therefore "session attributes" for this class means only attributes that have been
* previously confirmed by calls to {@link #isHandlerSessionAttribute(String, Class)}.
* Attribute names that have never been resolved that way will be filtered out from
* operations of this class. That means initially the actual set of resolved session
* attribute names is empty and it grows gradually as attributes are added to
* the {@link Model} and then considered for being added to the session.
* <p>A typical scenario begins with a controller adding attributes to the {@link Model}.
* At the end of the request, model attributes are checked to see if any of them match
* the names and types declared via @{@link SessionAttributes}. Matching model
* attributes are "promoted" to the session and remain there until the controller
* calls {@link SessionStatus#setComplete()} to indicate the session attributes are
* no longer needed and can be removed.
*
* @author Rossen Stoyanchev
* @since 3.1
...
...
@@ -56,48 +49,48 @@ public class SessionAttributesHandler {
private
final
Set
<
String
>
attributeNames
=
new
HashSet
<
String
>();
@SuppressWarnings
(
"rawtypes"
)
private
final
Set
<
Class
>
attributeTypes
=
new
HashSet
<
Class
>();
private
final
Set
<
Class
<?>>
attributeTypes
=
new
HashSet
<
Class
<?>>();
private
final
Set
<
String
>
resolvedAttributeNames
=
Collections
.
synchronizedSet
(
new
HashSet
<
String
>(
4
));
private
final
SessionAttributeStore
a
ttributeStore
;
private
final
SessionAttributeStore
sessionA
ttributeStore
;
/**
* Creates a {@link SessionAttributesHandler} instance for the specified handlerType.
* <p>Inspects the given handler type for the presence of a {@link SessionAttributes} annotation and
* stores that information for use in subsequent calls to {@link #isHandlerSessionAttribute(String, Class)}.
* If the handler type does not contain such an annotation,
* {@link #isHandlerSessionAttribute(String, Class)} always returns {@code false} and all other operations
* on handler session attributes have no effect on the backend session.
* <p>Use {@link #hasSessionAttributes()} to check if the handler type has defined any session attribute names
* of interest through a {@link SessionAttributes} annotation.
* Creates a {@link SessionAttributesHandler} instance for the specified handler type
* Inspects the given handler type for the presence of an @{@link SessionAttributes}
* and stores that information to identify model attribute that need to be stored,
* retrieved, or removed from the session.
* @param handlerType the handler type to inspect for a {@link SessionAttributes} annotation
* @param
attributeStore the {@link SessionAttributeStore} to delegate to for the actual backend
session access
* @param
sessionAttributeStore used for
session access
*/
public
SessionAttributesHandler
(
Class
<?>
handlerType
,
SessionAttributeStore
a
ttributeStore
)
{
Assert
.
notNull
(
a
ttributeStore
,
"SessionAttributeStore may not be null."
);
this
.
attributeStore
=
a
ttributeStore
;
public
SessionAttributesHandler
(
Class
<?>
handlerType
,
SessionAttributeStore
sessionA
ttributeStore
)
{
Assert
.
notNull
(
sessionA
ttributeStore
,
"SessionAttributeStore may not be null."
);
this
.
sessionAttributeStore
=
sessionA
ttributeStore
;
SessionAttributes
annotation
=
AnnotationUtils
.
findAnnotation
(
handlerType
,
SessionAttributes
.
class
);
if
(
annotation
!=
null
)
{
this
.
attributeNames
.
addAll
(
Arrays
.
asList
(
annotation
.
value
()));
this
.
attributeTypes
.
addAll
(
Arrays
.
asList
(
annotation
.
types
()));
this
.
attributeTypes
.
addAll
(
Arrays
.
<
Class
<?>>
asList
(
annotation
.
types
()));
}
}
/**
*
Returns true if the handler type has specified any session attribute names of interest through a
*
{@link SessionAttributes} annotation
.
*
Whether the controller represented by this handler has declared session
*
attribute names or types of interest via @{@link SessionAttributes}
.
*/
public
boolean
hasSessionAttributes
()
{
return
((
this
.
attributeNames
.
size
()
>
0
)
||
(
this
.
attributeTypes
.
size
()
>
0
));
}
/**
* Indicate whether or not an attribute is a handler session attribute of interest as defined
* in a {@link SessionAttributes} annotation. Attributes names successfully resolved through
* this method are remembered and in other operations.
* Whether the controller represented by this instance has declared a specific
* attribute as a session attribute via @{@link SessionAttributes}.
*
* <p>Attributes successfully resolved through this method are "remembered" and
* used by calls to {@link #retrieveAttributes(WebRequest)} and
* {@link #cleanupAttributes(WebRequest)}. In other words unless attributes
* have been resolved and stored before, retrieval and cleanup have no impact.
*
* @param attributeName the attribute name to check, must not be null
* @param attributeType the type for the attribute, not required but should be provided when
* available as session attributes of interest can be matched by type
...
...
@@ -114,29 +107,32 @@ public class SessionAttributesHandler {
}
/**
* Retrieves the specified attribute through the underlying {@link SessionAttributeStore}.
* Although not required use of this method implies a prior call to
* {@link #isHandlerSessionAttribute(String, Class)} has been made to see if the attribute
* name is a handler-specific session attribute of interest.
* @param request the request for the session operation
* @param attributeName the name of the attribute
* @return the attribute value or {@code null} if none
* Stores a subset of the given attributes in the session. Attributes not
* declared as session attributes via @{@link SessionAttributes} are ignored.
* @param request the current request
* @param attributes candidate attributes for session storage
*/
public
Object
retrieveAttribute
(
WebRequest
request
,
String
attributeName
)
{
return
this
.
attributeStore
.
retrieveAttribute
(
request
,
attributeName
);
public
void
storeAttributes
(
WebRequest
request
,
Map
<
String
,
?>
attributes
)
{
for
(
String
name
:
attributes
.
keySet
())
{
Object
value
=
attributes
.
get
(
name
);
Class
<?>
attrType
=
(
value
!=
null
)
?
value
.
getClass
()
:
null
;
if
(
isHandlerSessionAttribute
(
name
,
attrType
))
{
this
.
sessionAttributeStore
.
storeAttribute
(
request
,
name
,
value
);
}
}
}
/**
* Retrieve attributes for the underlying handler type from the backend session.
* <p>Only attributes that have previously been successfully resolved via calls to
* {@link #isHandlerSessionAttribute(String, Class)} are considered.
* Retrieves "remembered" (i.e. previously stored) session attributes
* for the controller represented by this handler.
* @param request the current request
* @return a map with
attributes or an empty map
* @return a map with
handler session attributes; possibly empty.
*/
public
Map
<
String
,
?>
retrieveHandlerSession
Attributes
(
WebRequest
request
)
{
public
Map
<
String
,
Object
>
retrieve
Attributes
(
WebRequest
request
)
{
Map
<
String
,
Object
>
attributes
=
new
HashMap
<
String
,
Object
>();
for
(
String
name
:
this
.
resolvedAttributeNames
)
{
Object
value
=
this
.
a
ttributeStore
.
retrieveAttribute
(
request
,
name
);
Object
value
=
this
.
sessionA
ttributeStore
.
retrieveAttribute
(
request
,
name
);
if
(
value
!=
null
)
{
attributes
.
put
(
name
,
value
);
}
...
...
@@ -145,34 +141,24 @@ public class SessionAttributesHandler {
}
/**
* Clean up attributes for the underlying handler type from the backend session.
* <p>Only attributes that have previously been successfully resolved via calls to
* {@link #isHandlerSessionAttribute(String, Class)} are removed.
* Cleans "remembered" (i.e. previously stored) session attributes
* for the controller represented by this handler.
* @param request the current request
*/
public
void
cleanup
HandlerSession
Attributes
(
WebRequest
request
)
{
public
void
cleanupAttributes
(
WebRequest
request
)
{
for
(
String
attributeName
:
this
.
resolvedAttributeNames
)
{
this
.
a
ttributeStore
.
cleanupAttribute
(
request
,
attributeName
);
this
.
sessionA
ttributeStore
.
cleanupAttribute
(
request
,
attributeName
);
}
}
/**
* Store attributes in the backend session.
* <p>Only attributes that have previously been successfully resolved via calls to
* {@link #isHandlerSessionAttribute(String, Class)} are stored. All other attributes
* from the input map are ignored.
* A pass-through call to the underlying {@link SessionAttributeStore}.
* @param request the current request
* @param attributes the attribute pairs to consider for storing
* @param attributeName the name of the attribute of interest
* @return the attribute value or {@code null}
*/
public
void
storeHandlerSessionAttributes
(
WebRequest
request
,
Map
<
String
,
Object
>
attributes
)
{
for
(
String
name
:
attributes
.
keySet
())
{
Object
value
=
attributes
.
get
(
name
);
Class
<?>
attrType
=
(
value
!=
null
)
?
value
.
getClass
()
:
null
;
if
(
isHandlerSessionAttribute
(
name
,
attrType
))
{
this
.
attributeStore
.
storeAttribute
(
request
,
name
,
value
);
}
}
Object
retrieveAttribute
(
WebRequest
request
,
String
attributeName
)
{
return
this
.
sessionAttributeStore
.
retrieveAttribute
(
request
,
attributeName
);
}
}
\ No newline at end of file
org.springframework.web/src/test/java/org/springframework/web/method/annotation/ModelFactoryTests.java
浏览文件 @
f4adf227
...
...
@@ -41,6 +41,7 @@ import org.springframework.web.bind.annotation.ModelAttribute;
import
org.springframework.web.bind.annotation.SessionAttributes
;
import
org.springframework.web.bind.support.DefaultSessionAttributeStore
;
import
org.springframework.web.bind.support.SessionAttributeStore
;
import
org.springframework.web.bind.support.SimpleFlashStatus
;
import
org.springframework.web.bind.support.SimpleSessionStatus
;
import
org.springframework.web.bind.support.WebDataBinderFactory
;
import
org.springframework.web.context.request.NativeWebRequest
;
...
...
@@ -63,8 +64,10 @@ public class ModelFactoryTests {
private
InvocableHandlerMethod
handleSessionAttrMethod
;
private
SessionAttributesHandler
handlerSessionAttributeStore
;
private
SessionAttributesHandler
sessionAttrsHandler
;
private
FlashAttributesHandler
flashAttrsHandler
;
private
SessionAttributeStore
sessionAttributeStore
;
private
ModelAndViewContainer
mavContainer
;
...
...
@@ -78,13 +81,14 @@ public class ModelFactoryTests {
Method
method
=
handlerType
.
getDeclaredMethod
(
"handleSessionAttr"
,
String
.
class
);
handleSessionAttrMethod
=
new
InvocableHandlerMethod
(
handler
,
method
);
sessionAttributeStore
=
new
DefaultSessionAttributeStore
();
handlerSessionAttributeStore
=
new
SessionAttributesHandler
(
handlerType
,
sessionAttributeStore
);
sessionAttrsHandler
=
new
SessionAttributesHandler
(
handlerType
,
sessionAttributeStore
);
flashAttrsHandler
=
new
FlashAttributesHandler
(
handlerType
);
mavContainer
=
new
ModelAndViewContainer
();
webRequest
=
new
ServletWebRequest
(
new
MockHttpServletRequest
());
}
@Test
public
void
addAttributeToModel
()
throws
Exception
{
public
void
modelAttributeMethod
()
throws
Exception
{
ModelFactory
modelFactory
=
createModelFactory
(
"modelAttr"
,
Model
.
class
);
modelFactory
.
initModel
(
webRequest
,
mavContainer
,
handleMethod
);
...
...
@@ -92,7 +96,7 @@ public class ModelFactoryTests {
}
@Test
public
void
returnAttributeWith
Name
()
throws
Exception
{
public
void
modelAttributeMethodWithSpecified
Name
()
throws
Exception
{
ModelFactory
modelFactory
=
createModelFactory
(
"modelAttrWithName"
);
modelFactory
.
initModel
(
webRequest
,
mavContainer
,
handleMethod
);
...
...
@@ -100,7 +104,7 @@ public class ModelFactoryTests {
}
@Test
public
void
returnAttribute
WithNameByConvention
()
throws
Exception
{
public
void
modelAttributeMethod
WithNameByConvention
()
throws
Exception
{
ModelFactory
modelFactory
=
createModelFactory
(
"modelAttrConvention"
);
modelFactory
.
initModel
(
webRequest
,
mavContainer
,
handleMethod
);
...
...
@@ -108,7 +112,7 @@ public class ModelFactoryTests {
}
@Test
public
void
returnNullAttribute
Value
()
throws
Exception
{
public
void
modelAttributeMethodWithNullReturn
Value
()
throws
Exception
{
ModelFactory
modelFactory
=
createModelFactory
(
"nullModelAttr"
);
modelFactory
.
initModel
(
webRequest
,
mavContainer
,
handleMethod
);
...
...
@@ -117,11 +121,11 @@ public class ModelFactoryTests {
}
@Test
public
void
retrieveAttributeFromSession
()
throws
Exception
{
public
void
sessionAttribute
()
throws
Exception
{
sessionAttributeStore
.
storeAttribute
(
webRequest
,
"sessionAttr"
,
"sessionAttrValue"
);
// Resolve successfully handler session attribute once
assertTrue
(
handlerSessionAttributeStore
.
isHandlerSessionAttribute
(
"sessionAttr"
,
null
));
assertTrue
(
sessionAttrsHandler
.
isHandlerSessionAttribute
(
"sessionAttr"
,
null
));
ModelFactory
modelFactory
=
createModelFactory
(
"modelAttr"
,
Model
.
class
);
modelFactory
.
initModel
(
webRequest
,
mavContainer
,
handleMethod
);
...
...
@@ -131,7 +135,7 @@ public class ModelFactoryTests {
@Test
public
void
requiredSessionAttribute
()
throws
Exception
{
ModelFactory
modelFactory
=
new
ModelFactory
(
null
,
null
,
handlerSessionAttributeStore
);
ModelFactory
modelFactory
=
new
ModelFactory
(
null
,
null
,
sessionAttrsHandler
,
flashAttrsHandler
);
try
{
modelFactory
.
initModel
(
webRequest
,
mavContainer
,
handleSessionAttrMethod
);
...
...
@@ -145,19 +149,18 @@ public class ModelFactoryTests {
}
@Test
public
void
update
BindingResult
()
throws
Exception
{
public
void
update
ModelBindingResultKeys
()
throws
Exception
{
String
attrName
=
"attr1"
;
Object
attrValue
=
new
Object
();
mavContainer
.
addAttribute
(
attrName
,
attrValue
);
WebDataBinder
dataBinder
=
new
WebDataBinder
(
attrValue
,
attrName
);
WebDataBinderFactory
binderFactory
=
createMock
(
WebDataBinderFactory
.
class
);
expect
(
binderFactory
.
createBinder
(
webRequest
,
attrValue
,
attrName
)).
andReturn
(
dataBinder
);
replay
(
binderFactory
);
ModelFactory
modelFactory
=
new
ModelFactory
(
null
,
binderFactory
,
handlerSessionAttributeStore
);
modelFactory
.
updateModel
(
webRequest
,
mavContainer
,
new
SimpleSessionStatus
());
ModelFactory
modelFactory
=
new
ModelFactory
(
null
,
binderFactory
,
sessionAttrsHandler
,
flashAttrsHandler
);
modelFactory
.
updateModel
(
webRequest
,
mavContainer
,
new
SimpleSessionStatus
()
,
new
SimpleFlashStatus
()
);
assertEquals
(
attrValue
,
mavContainer
.
getModel
().
remove
(
attrName
));
assertSame
(
dataBinder
.
getBindingResult
(),
mavContainer
.
getModel
().
remove
(
bindingResultKey
(
attrName
)));
...
...
@@ -165,6 +168,36 @@ public class ModelFactoryTests {
verify
(
binderFactory
);
}
@Test
public
void
updateModelSessionStatusComplete
()
throws
Exception
{
String
attrName
=
"sessionAttr"
;
String
attrValue
=
"sessionAttrValue"
;
mavContainer
.
addAttribute
(
attrName
,
attrValue
);
sessionAttributeStore
.
storeAttribute
(
webRequest
,
attrName
,
attrValue
);
// Resolve successfully handler session attribute once
assertTrue
(
sessionAttrsHandler
.
isHandlerSessionAttribute
(
attrName
,
null
));
WebDataBinder
dataBinder
=
new
WebDataBinder
(
attrValue
,
attrName
);
WebDataBinderFactory
binderFactory
=
createMock
(
WebDataBinderFactory
.
class
);
expect
(
binderFactory
.
createBinder
(
webRequest
,
attrValue
,
attrName
)).
andReturn
(
dataBinder
);
replay
(
binderFactory
);
SimpleSessionStatus
status
=
new
SimpleSessionStatus
();
status
.
setComplete
();
// TODO: test with active FlashStatus
ModelFactory
modelFactory
=
new
ModelFactory
(
null
,
binderFactory
,
sessionAttrsHandler
,
flashAttrsHandler
);
modelFactory
.
updateModel
(
webRequest
,
mavContainer
,
status
,
new
SimpleFlashStatus
());
assertEquals
(
attrValue
,
mavContainer
.
getAttribute
(
attrName
));
assertNull
(
sessionAttributeStore
.
retrieveAttribute
(
webRequest
,
attrName
));
verify
(
binderFactory
);
}
private
String
bindingResultKey
(
String
key
)
{
return
BindingResult
.
MODEL_KEY_PREFIX
+
key
;
...
...
@@ -181,7 +214,7 @@ public class ModelFactoryTests {
handlerMethod
.
setDataBinderFactory
(
null
);
handlerMethod
.
setParameterNameDiscoverer
(
new
LocalVariableTableParameterNameDiscoverer
());
return
new
ModelFactory
(
Arrays
.
asList
(
handlerMethod
),
null
,
handlerSessionAttributeStore
);
return
new
ModelFactory
(
Arrays
.
asList
(
handlerMethod
),
null
,
sessionAttrsHandler
,
flashAttrsHandler
);
}
@SessionAttributes
(
"sessionAttr"
)
@SuppressWarnings
(
"unused"
)
...
...
org.springframework.web/src/test/java/org/springframework/web/method/annotation/
HandlerSessionAttributeStore
Tests.java
→
org.springframework.web/src/test/java/org/springframework/web/method/annotation/
SessionAttributesHandler
Tests.java
浏览文件 @
f4adf227
...
...
@@ -42,7 +42,7 @@ import org.springframework.web.context.request.ServletWebRequest;
*
* @author Rossen Stoyanchev
*/
public
class
HandlerSessionAttributeStore
Tests
{
public
class
SessionAttributesHandler
Tests
{
private
Class
<?>
handlerType
=
SessionAttributeHandler
.
class
;
...
...
@@ -77,7 +77,7 @@ public class HandlerSessionAttributeStoreTests {
assertTrue
(
sessionAttributesHandler
.
isHandlerSessionAttribute
(
"attr1"
,
null
));
assertTrue
(
sessionAttributesHandler
.
isHandlerSessionAttribute
(
"attr3"
,
TestBean
.
class
));
Map
<
String
,
?>
attributes
=
sessionAttributesHandler
.
retrieve
HandlerSession
Attributes
(
request
);
Map
<
String
,
?>
attributes
=
sessionAttributesHandler
.
retrieveAttributes
(
request
);
assertEquals
(
new
HashSet
<
String
>(
asList
(
"attr1"
,
"attr3"
)),
attributes
.
keySet
());
}
...
...
@@ -92,7 +92,7 @@ public class HandlerSessionAttributeStoreTests {
assertTrue
(
sessionAttributesHandler
.
isHandlerSessionAttribute
(
"attr1"
,
null
));
assertTrue
(
sessionAttributesHandler
.
isHandlerSessionAttribute
(
"attr3"
,
TestBean
.
class
));
sessionAttributesHandler
.
cleanup
HandlerSession
Attributes
(
request
);
sessionAttributesHandler
.
cleanupAttributes
(
request
);
assertNull
(
sessionAttributeStore
.
retrieveAttribute
(
request
,
"attr1"
));
assertNotNull
(
sessionAttributeStore
.
retrieveAttribute
(
request
,
"attr2"
));
...
...
@@ -111,7 +111,7 @@ public class HandlerSessionAttributeStoreTests {
assertTrue
(
sessionAttributesHandler
.
isHandlerSessionAttribute
(
"attr2"
,
null
));
assertTrue
(
sessionAttributesHandler
.
isHandlerSessionAttribute
(
"attr3"
,
TestBean
.
class
));
sessionAttributesHandler
.
store
HandlerSession
Attributes
(
request
,
model
);
sessionAttributesHandler
.
storeAttributes
(
request
,
model
);
assertEquals
(
"value1"
,
sessionAttributeStore
.
retrieveAttribute
(
request
,
"attr1"
));
assertEquals
(
"value2"
,
sessionAttributeStore
.
retrieveAttribute
(
request
,
"attr2"
));
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录