SPR-8532 Upgrade org.springframework.web.servlet to Servlet 3.0 (as provided dependency) and add support for javax.servlet.Part parameter

This commit is contained in:
Rossen Stoyanchev
2011-07-18 12:06:11 +00:00
parent f874ed9790
commit b8c723d080
26 changed files with 962 additions and 197 deletions

View File

@@ -22,9 +22,15 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.http.converter.HttpMessageConverter;
/**
* Annotation which indicates that a method parameter should be bound to the web request body. Supported for annotated
* handler methods in Servlet environments.
* Annotation indicating a method parameter should be bound to the body of the web request.
* The body of the request is passed through an {@link HttpMessageConverter} to resolve the
* method argument depending on the content type of the request. Optionally, automatic
* validation can be applied by annotating the argument with {@code @Valid}.
*
* <p>Supported for annotated handler methods in Servlet environments.
*
* @author Arjen Poutsma
* @see RequestHeader

View File

@@ -16,20 +16,44 @@
package org.springframework.web.bind.annotation;
import java.beans.PropertyEditor;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartResolver;
/**
* Annotation that indicates a method parameter should be bound to the content of a part of a "multipart/form-data" request.
* Supported for annotated handler methods in Servlet environments.
*
* Annotation that can be used to associate the part of a "multipart/form-data" request
* with a method argument. Supported method argument types include {@link MultipartFile}
* in conjunction with Spring's {@link MultipartResolver} abstraction,
* {@code javax.servlet.http.Part} in conjunction with Servlet 3.0 multipart requests,
* or otherwise for any other method argument, the content of the part is passed through an
* {@link HttpMessageConverter} taking into consideration the 'Content-Type' header
* of the request part. This is analogous to what @{@link RequestBody} does to resolve
* an argument based on the content of a non-multipart regular request.
*
* <p>Note that @{@link RequestParam} annotation can also be used to associate the
* part of a "multipart/form-data" request with a method argument supporting the same
* method argument types. The main difference is that when the method argument is not a
* String, @{@link RequestParam} relies on type conversion via a registered
* {@link Converter} or {@link PropertyEditor} while @{@link RequestPart} relies
* on {@link HttpMessageConverter}s taking into consideration the 'Content-Type' header
* of the request part. @{@link RequestParam} is likely to be used with name-value form
* fields while @{@link RequestPart} is likely to be used with parts containing more
* complex content (e.g. JSON, XML).
*
* @author Rossen Stoyanchev
* @author Arjen Poutsma
* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
* @since 3.1
*
* @see RequestParam
* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@@ -41,4 +65,12 @@ public @interface RequestPart {
*/
String value() default "";
/**
* Whether the part is required.
* <p>Default is <code>true</code>, leading to an exception thrown in case
* of the part missing in the request. Switch this to <code>false</code>
* if you prefer a <code>null</value> in case of the part missing.
*/
boolean required() default true;
}

View File

@@ -21,6 +21,7 @@ import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
@@ -33,19 +34,25 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ValueConstants;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartRequest;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.util.WebUtils;
/**
* Resolves method arguments annotated with @{@link RequestParam}.
* Resolves method arguments annotated with @{@link RequestParam}, arguments of
* type {@link MultipartFile} in conjunction with Spring's {@link MultipartResolver}
* abstraction, and arguments of type {@code javax.servlet.http.Part} in conjunction
* with Servlet 3.0 multipart requests. This resolver can also be created in default
* resolution mode in which simple types (int, long, etc.) not annotated
* with @{@link RequestParam} are also treated as request parameters with the
* parameter name derived from the argument name.
*
* <p>If the method parameter type is {@link Map}, the request parameter name is resolved and then converted
* to a {@link Map} via type conversion assuming a suitable {@link PropertyEditor} or {@link Converter} is
* registered. Alternatively, see {@link RequestParamMapMethodArgumentResolver} for access to all request
* parameters in a {@link Map}.
*
* <p>If this class is created with default resolution mode on, simple types not annotated
* with @{@link RequestParam} are also treated as request parameters with the parameter name based
* on the method argument name. See the class constructor for more details.
* <p>If the method parameter type is {@link Map}, the request parameter name is used to
* resolve the request parameter String value. The value is then converted to a {@link Map}
* via type conversion assuming a suitable {@link Converter} or {@link PropertyEditor} has
* been registered. If a request parameter name is not specified with a {@link Map} method
* parameter type, the {@link RequestParamMapMethodArgumentResolver} is used instead
* providing access to all request parameters in the form of a map.
*
* <p>A {@link WebDataBinder} is invoked to apply type conversion to resolved request header values that
* don't yet match the method parameter type.
@@ -72,6 +79,18 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod
this.useDefaultResolution = useDefaultResolution;
}
/**
* Supports the following:
* <ul>
* <li>@RequestParam method arguments. This excludes the case where a parameter is of type
* {@link Map} and the annotation does not specify a request parameter name. See
* {@link RequestParamMapMethodArgumentResolver} instead for such parameters.
* <li>Arguments of type {@link MultipartFile} even if not annotated.
* <li>Arguments of type {@code javax.servlet.http.Part} even if not annotated.
* </ul>
*
* <p>In default resolution mode, simple type arguments not annotated with @RequestParam are also supported.
*/
public boolean supportsParameter(MethodParameter parameter) {
Class<?> paramType = parameter.getParameterType();
RequestParam requestParamAnnot = parameter.getParameterAnnotation(RequestParam.class);
@@ -81,6 +100,12 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod
}
return true;
}
else if (MultipartFile.class.equals(paramType)) {
return true;
}
else if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName())) {
return true;
}
else if (this.useDefaultResolution) {
return BeanUtils.isSimpleProperty(paramType);
}
@@ -99,14 +124,22 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod
@Override
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {
MultipartRequest multipartRequest = webRequest.getNativeRequest(MultipartRequest.class);
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
MultipartHttpServletRequest multipartRequest =
WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class);
if (multipartRequest != null) {
List<MultipartFile> files = multipartRequest.getFiles(name);
if (!files.isEmpty()) {
return (files.size() == 1 ? files.get(0) : files);
}
}
if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName())) {
return servletRequest.getPart(name);
}
String[] paramValues = webRequest.getParameterValues(name);
if (paramValues != null) {
return paramValues.length == 1 ? paramValues[0] : paramValues;