all @SessionAttributes get exposed to the model before handler method execution; MultipartRequest is available as a mixin interface on (Native)WebRequest as well

This commit is contained in:
Juergen Hoeller 2009-09-25 10:42:49 +00:00
parent e49869ea78
commit 9cb1338b94
6 changed files with 194 additions and 47 deletions

View File

@ -102,6 +102,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.bind.support.WebArgumentResolver; import org.springframework.web.bind.support.WebArgumentResolver;
import org.springframework.web.bind.support.WebBindingInitializer; import org.springframework.web.bind.support.WebBindingInitializer;
@ -117,7 +118,6 @@ import org.springframework.web.servlet.mvc.AbstractController;
import org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver; import org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver;
import org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping; import org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping;
import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.RedirectView;
import org.springframework.web.util.NestedServletException; import org.springframework.web.util.NestedServletException;
/** /**
@ -293,6 +293,39 @@ public class ServletAnnotationControllerTests {
assertEquals("", response.getContentAsString()); assertEquals("", response.getContentAsString());
} }
@Test
public void sessionAttributeExposure() throws Exception {
@SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
@Override
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
wac.registerBeanDefinition("controller", new RootBeanDefinition(MySessionAttributesController.class));
wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class));
wac.refresh();
return wac;
}
};
servlet.init(new MockServletConfig());
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage");
MockHttpServletResponse response = new MockHttpServletResponse();
servlet.service(request, response);
HttpSession session = request.getSession();
assertTrue(session.getAttribute("object1") != null);
assertTrue(session.getAttribute("object2") != null);
assertTrue(((Map) session.getAttribute("model")).containsKey("object1"));
assertTrue(((Map) session.getAttribute("model")).containsKey("object2"));
request = new MockHttpServletRequest("POST", "/myPage");
request.setSession(session);
response = new MockHttpServletResponse();
servlet.service(request, response);
assertTrue(session.getAttribute("object1") != null);
assertTrue(session.getAttribute("object2") != null);
assertTrue(((Map) session.getAttribute("model")).containsKey("object1"));
assertTrue(((Map) session.getAttribute("model")).containsKey("object2"));
}
@Test @Test
public void adaptedHandleMethods() throws Exception { public void adaptedHandleMethods() throws Exception {
doTestAdaptedHandleMethods(MyAdaptedController.class); doTestAdaptedHandleMethods(MyAdaptedController.class);
@ -1029,16 +1062,6 @@ public class ServletAnnotationControllerTests {
assertEquals(201, response.getStatus()); assertEquals(201, response.getStatus());
} }
@Test
public void responseStatusRedirect() throws ServletException, IOException {
initServlet(ResponseStatusRedirectController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/something");
MockHttpServletResponse response = new MockHttpServletResponse();
servlet.service(request, response);
assertEquals(201, response.getStatus());
}
@Test @Test
public void mavResolver() throws ServletException, IOException { public void mavResolver() throws ServletException, IOException {
@SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() { @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
@ -1248,6 +1271,25 @@ public class ServletAnnotationControllerTests {
} }
} }
@Controller
@RequestMapping("/myPage")
@SessionAttributes({"object1", "object2"})
public static class MySessionAttributesController {
@RequestMapping(method = RequestMethod.GET)
public String get(Model model) {
model.addAttribute("object1", new Object());
model.addAttribute("object2", new Object());
return "myPage";
}
@RequestMapping(method = RequestMethod.POST)
public String post(@ModelAttribute("object1") Object object1) {
//do something with object1
return "myPage";
}
}
@Controller @Controller
public static class MyFormController { public static class MyFormController {
@ -1592,6 +1634,20 @@ public class ServletAnnotationControllerTests {
} }
} }
private static class ModelExposingViewResolver implements ViewResolver {
public View resolveViewName(String viewName, Locale locale) throws Exception {
return new View() {
public String getContentType() {
return null;
}
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) {
request.getSession().setAttribute("model", model);
}
};
}
}
public static class ParentController { public static class ParentController {
@RequestMapping(method = RequestMethod.GET) @RequestMapping(method = RequestMethod.GET)
@ -1769,17 +1825,6 @@ public class ServletAnnotationControllerTests {
} }
} }
@Controller
public static class ResponseStatusRedirectController {
@RequestMapping("/something")
@ResponseStatus(HttpStatus.CREATED)
public RedirectView handle(Writer writer) throws IOException {
return new RedirectView("somelocation.html", false, false);
}
}
@Controller @Controller
public static class ModelAndViewResolverController { public static class ModelAndViewResolverController {

View File

@ -66,7 +66,6 @@ import org.springframework.web.bind.support.WebBindingInitializer;
import org.springframework.web.bind.support.WebRequestDataBinder; import org.springframework.web.bind.support.WebRequestDataBinder;
import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.WebRequest; import org.springframework.web.context.request.WebRequest;
import org.springframework.web.multipart.MultipartRequest;
/** /**
* Support class for invoking an annotated handler method. Operates on the introspection results of a * Support class for invoking an annotated handler method. Operates on the introspection results of a
@ -127,21 +126,32 @@ public class HandlerMethodInvoker {
Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod); Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);
try { try {
boolean debug = logger.isDebugEnabled(); boolean debug = logger.isDebugEnabled();
for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName);
if (attrValue != null) {
implicitModel.addAttribute(attrName, attrValue);
}
}
for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) { for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {
Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod); Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);
Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel); Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);
if (debug) { if (debug) {
logger.debug("Invoking model attribute method: " + attributeMethodToInvoke); logger.debug("Invoking model attribute method: " + attributeMethodToInvoke);
} }
Object attrValue = doInvokeMethod(attributeMethodToInvoke, handler, args);
String attrName = AnnotationUtils.findAnnotation(attributeMethodToInvoke, ModelAttribute.class).value(); String attrName = AnnotationUtils.findAnnotation(attributeMethodToInvoke, ModelAttribute.class).value();
if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
continue;
}
Object attrValue = doInvokeMethod(attributeMethodToInvoke, handler, args);
if ("".equals(attrName)) { if ("".equals(attrName)) {
Class resolvedType = GenericTypeResolver.resolveReturnType( Class resolvedType = GenericTypeResolver.resolveReturnType(
attributeMethodToInvoke, handler.getClass()); attributeMethodToInvoke, handler.getClass());
attrName = Conventions.getVariableNameForReturnType( attrName = Conventions.getVariableNameForReturnType(
attributeMethodToInvoke, resolvedType, attrValue); attributeMethodToInvoke, resolvedType, attrValue);
} }
implicitModel.addAttribute(attrName, attrValue); if (!implicitModel.containsAttribute(attrName)) {
implicitModel.addAttribute(attrName, attrValue);
}
} }
Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel); Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);
if (debug) { if (debug) {
@ -394,15 +404,15 @@ public class HandlerMethodInvoker {
if (paramName.length() == 0) { if (paramName.length() == 0) {
paramName = getRequiredParameterName(methodParam); paramName = getRequiredParameterName(methodParam);
} }
Object paramValue = null; Object paramValue = webRequest.getFile(paramName);
if (webRequest.getNativeRequest() instanceof MultipartRequest) {
paramValue = ((MultipartRequest) webRequest.getNativeRequest()).getFile(paramName);
}
if (paramValue == null) { if (paramValue == null) {
String[] paramValues = webRequest.getParameterValues(paramName); String[] paramValues = webRequest.getParameterValues(paramName);
if (paramValues != null) { if (paramValues != null && !paramType.isArray()) {
paramValue = (paramValues.length == 1 ? paramValues[0] : paramValues); paramValue = (paramValues.length == 1 ? paramValues[0] : paramValues);
} }
else {
paramValue = paramValues;
}
} }
if (paramValue == null) { if (paramValue == null) {
if (StringUtils.hasText(defaultValue)) { if (StringUtils.hasText(defaultValue)) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2008 the original author or authors. * Copyright 2002-2009 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,7 +19,6 @@ package org.springframework.web.bind.support;
import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.MutablePropertyValues;
import org.springframework.validation.BindException; import org.springframework.validation.BindException;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.WebRequest; import org.springframework.web.context.request.WebRequest;
import org.springframework.web.multipart.MultipartRequest; import org.springframework.web.multipart.MultipartRequest;
@ -100,12 +99,8 @@ public class WebRequestDataBinder extends WebDataBinder {
*/ */
public void bind(WebRequest request) { public void bind(WebRequest request) {
MutablePropertyValues mpvs = new MutablePropertyValues(request.getParameterMap()); MutablePropertyValues mpvs = new MutablePropertyValues(request.getParameterMap());
if (request instanceof NativeWebRequest) { if (request instanceof MultipartRequest) {
Object nativeRequest = ((NativeWebRequest) request).getNativeRequest(); bindMultipartFiles(((MultipartRequest) request).getFileMap(), mpvs);
if (nativeRequest instanceof MultipartRequest) {
MultipartRequest multipartRequest = (MultipartRequest) request;
bindMultipartFiles(multipartRequest.getFileMap(), mpvs);
}
} }
doBind(mpvs); doBind(mpvs);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2008 the original author or authors. * Copyright 2002-2009 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,14 +17,19 @@
package org.springframework.web.context.request; package org.springframework.web.context.request;
import java.security.Principal; import java.security.Principal;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import javax.faces.context.ExternalContext; import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext; import javax.faces.context.FacesContext;
import org.springframework.util.CollectionUtils; import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartRequest;
/** /**
* {@link WebRequest} adapter for a JSF {@link javax.faces.context.FacesContext}. * {@link WebRequest} adapter for a JSF {@link javax.faces.context.FacesContext}.
@ -34,6 +39,9 @@ import org.springframework.util.StringUtils;
*/ */
public class FacesWebRequest extends FacesRequestAttributes implements NativeWebRequest { public class FacesWebRequest extends FacesRequestAttributes implements NativeWebRequest {
private MultipartRequest multipartRequest;
/** /**
* Create a new FacesWebRequest adapter for the given FacesContext. * Create a new FacesWebRequest adapter for the given FacesContext.
* @param facesContext the current FacesContext * @param facesContext the current FacesContext
@ -41,6 +49,9 @@ public class FacesWebRequest extends FacesRequestAttributes implements NativeWeb
*/ */
public FacesWebRequest(FacesContext facesContext) { public FacesWebRequest(FacesContext facesContext) {
super(facesContext); super(facesContext);
if (facesContext.getExternalContext().getRequest() instanceof MultipartRequest) {
this.multipartRequest = (MultipartRequest) facesContext.getExternalContext().getRequest();
}
} }
@ -105,7 +116,6 @@ public class FacesWebRequest extends FacesRequestAttributes implements NativeWeb
return false; return false;
} }
public String getDescription(boolean includeClientInfo) { public String getDescription(boolean includeClientInfo) {
ExternalContext externalContext = getExternalContext(); ExternalContext externalContext = getExternalContext();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@ -123,6 +133,44 @@ public class FacesWebRequest extends FacesRequestAttributes implements NativeWeb
return sb.toString(); return sb.toString();
} }
@SuppressWarnings("unchecked")
public Iterator<String> getFileNames() {
if (this.multipartRequest == null) {
return (Iterator<String>) Collections.EMPTY_SET.iterator();
}
return this.multipartRequest.getFileNames();
}
public MultipartFile getFile(String name) {
if (this.multipartRequest == null) {
return null;
}
return this.multipartRequest.getFile(name);
}
public List<MultipartFile> getFiles(String name) {
if (this.multipartRequest == null) {
return null;
}
return this.multipartRequest.getFiles(name);
}
public Map<String, MultipartFile> getFileMap() {
if (this.multipartRequest == null) {
return Collections.emptyMap();
}
return this.multipartRequest.getFileMap();
}
public MultiValueMap<String, MultipartFile> getMultiFileMap() {
if (this.multipartRequest == null) {
return new LinkedMultiValueMap<String, MultipartFile>();
}
return this.multipartRequest.getMultiFileMap();
}
@Override @Override
public String toString() { public String toString() {
return "FacesWebRequest: " + getDescription(true); return "FacesWebRequest: " + getDescription(true);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2008 the original author or authors. * Copyright 2002-2009 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,8 @@
package org.springframework.web.context.request; package org.springframework.web.context.request;
import org.springframework.web.multipart.MultipartRequest;
/** /**
* Extension of the {@link WebRequest} interface, exposing the * Extension of the {@link WebRequest} interface, exposing the
* native request and response objects in a generic fashion. * native request and response objects in a generic fashion.
@ -26,7 +28,7 @@ package org.springframework.web.context.request;
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 2.5.2 * @since 2.5.2
*/ */
public interface NativeWebRequest extends WebRequest { public interface NativeWebRequest extends WebRequest, MultipartRequest {
/** /**
* Return the underlying native request object, if available. * Return the underlying native request object, if available.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2008 the original author or authors. * Copyright 2002-2009 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,7 +17,9 @@
package org.springframework.web.context.request; package org.springframework.web.context.request;
import java.security.Principal; import java.security.Principal;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -25,8 +27,12 @@ import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartRequest;
/** /**
* {@link WebRequest} adapter for an {@link javax.servlet.http.HttpServletRequest}. * {@link WebRequest} adapter for an {@link javax.servlet.http.HttpServletRequest}.
@ -41,6 +47,8 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
private static final String HEADER_LAST_MODIFIED = "Last-Modified"; private static final String HEADER_LAST_MODIFIED = "Last-Modified";
private MultipartRequest multipartRequest;
private HttpServletResponse response; private HttpServletResponse response;
private boolean notModified = false; private boolean notModified = false;
@ -52,6 +60,9 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
*/ */
public ServletWebRequest(HttpServletRequest request) { public ServletWebRequest(HttpServletRequest request) {
super(request); super(request);
if (request instanceof MultipartRequest) {
this.multipartRequest = (MultipartRequest) request;
}
} }
/** /**
@ -60,7 +71,7 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
* @param response current HTTP response (for automatic last-modified handling) * @param response current HTTP response (for automatic last-modified handling)
*/ */
public ServletWebRequest(HttpServletRequest request, HttpServletResponse response) { public ServletWebRequest(HttpServletRequest request, HttpServletResponse response) {
super(request); this(request);
this.response = response; this.response = response;
} }
@ -133,7 +144,6 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
return getRequest().isSecure(); return getRequest().isSecure();
} }
public boolean checkNotModified(long lastModifiedTimestamp) { public boolean checkNotModified(long lastModifiedTimestamp) {
if (lastModifiedTimestamp >= 0 && !this.notModified && if (lastModifiedTimestamp >= 0 && !this.notModified &&
(this.response == null || !this.response.containsHeader(HEADER_LAST_MODIFIED))) { (this.response == null || !this.response.containsHeader(HEADER_LAST_MODIFIED))) {
@ -155,7 +165,6 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
return this.notModified; return this.notModified;
} }
public String getDescription(boolean includeClientInfo) { public String getDescription(boolean includeClientInfo) {
HttpServletRequest request = getRequest(); HttpServletRequest request = getRequest();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@ -177,6 +186,44 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
return sb.toString(); return sb.toString();
} }
@SuppressWarnings("unchecked")
public Iterator<String> getFileNames() {
if (this.multipartRequest == null) {
return (Iterator<String>) Collections.EMPTY_SET.iterator();
}
return this.multipartRequest.getFileNames();
}
public MultipartFile getFile(String name) {
if (this.multipartRequest == null) {
return null;
}
return this.multipartRequest.getFile(name);
}
public List<MultipartFile> getFiles(String name) {
if (this.multipartRequest == null) {
return null;
}
return this.multipartRequest.getFiles(name);
}
public Map<String, MultipartFile> getFileMap() {
if (this.multipartRequest == null) {
return Collections.emptyMap();
}
return this.multipartRequest.getFileMap();
}
public MultiValueMap<String, MultipartFile> getMultiFileMap() {
if (this.multipartRequest == null) {
return new LinkedMultiValueMap<String, MultipartFile>();
}
return this.multipartRequest.getMultiFileMap();
}
@Override @Override
public String toString() { public String toString() {
return "ServletWebRequest: " + getDescription(true); return "ServletWebRequest: " + getDescription(true);