SPR-8483 Add support for @RequestPart annotated method parameters
This commit is contained in:
@@ -35,7 +35,7 @@ import java.lang.annotation.Target;
|
||||
* @see RequestParam
|
||||
* @see RequestHeader
|
||||
* @see org.springframework.web.bind.annotation.RequestMapping
|
||||
* @see org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
|
||||
* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter
|
||||
* @see org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter
|
||||
*/
|
||||
@Target(ElementType.PARAMETER)
|
||||
|
||||
@@ -12,7 +12,7 @@ import java.lang.annotation.Target;
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see RequestMapping
|
||||
* @see org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
|
||||
* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter
|
||||
* @since 3.0
|
||||
*/
|
||||
@Target(ElementType.PARAMETER)
|
||||
|
||||
@@ -29,7 +29,7 @@ import java.lang.annotation.Target;
|
||||
* @author Arjen Poutsma
|
||||
* @see RequestHeader
|
||||
* @see ResponseBody
|
||||
* @see org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
|
||||
* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter
|
||||
* @since 3.0
|
||||
*/
|
||||
@Target(ElementType.PARAMETER)
|
||||
|
||||
@@ -31,7 +31,7 @@ import java.lang.annotation.Target;
|
||||
* @see RequestMapping
|
||||
* @see RequestParam
|
||||
* @see CookieValue
|
||||
* @see org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
|
||||
* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter
|
||||
* @see org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter
|
||||
*/
|
||||
@Target(ElementType.PARAMETER)
|
||||
|
||||
@@ -95,6 +95,11 @@ import java.lang.annotation.Target;
|
||||
* converted to the declared method argument type using
|
||||
* {@linkplain org.springframework.http.converter.HttpMessageConverter message
|
||||
* converters}. Such parameters may optionally be annotated with {@code @Valid}.
|
||||
* <li>{@link RequestPart @RequestPart} annotated parameters for access to the content
|
||||
* of a part of "multipart/form-data" request. The request part stream will be
|
||||
* converted to the declared method argument type using
|
||||
* {@linkplain org.springframework.http.converter.HttpMessageConverter message
|
||||
* converters}. Such parameters may optionally be annotated with {@code @Valid}.
|
||||
* <li>{@link org.springframework.http.HttpEntity HttpEntity<?>} parameters
|
||||
* for access to the Servlet request HTTP headers and contents. The request stream will be
|
||||
* converted to the entity body using
|
||||
|
||||
@@ -33,7 +33,7 @@ import java.lang.annotation.Target;
|
||||
* @see RequestMapping
|
||||
* @see RequestHeader
|
||||
* @see CookieValue
|
||||
* @see org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
|
||||
* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter
|
||||
* @see org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter
|
||||
*/
|
||||
@Target(ElementType.PARAMETER)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Arjen Poutsma
|
||||
* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
|
||||
* @since 3.1
|
||||
*/
|
||||
@Target(ElementType.PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RequestPart {
|
||||
|
||||
/**
|
||||
* The name of the part in the "multipart/form-data" request to bind to.
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
}
|
||||
@@ -60,7 +60,7 @@ public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueMet
|
||||
@Override
|
||||
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest)
|
||||
throws Exception {
|
||||
// There is no name to be resolved
|
||||
// No name to resolve
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
||||
if (binder.getTarget() != null) {
|
||||
bindRequestParameters(binder, request);
|
||||
|
||||
if (isValidationApplicable(binder, parameter)) {
|
||||
if (isValidationApplicable(binder.getTarget(), parameter)) {
|
||||
binder.validate();
|
||||
}
|
||||
|
||||
@@ -148,12 +148,12 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to validate the model attribute inside the given data binder instance.
|
||||
* @param binder the data binder containing the validation candidate
|
||||
* Whether to validate the given model attribute argument value.
|
||||
* @param argumentValue the validation candidate
|
||||
* @param parameter the method argument declaring the validation candidate
|
||||
* @return {@code true} if validation should be applied, {@code false} otherwise.
|
||||
*/
|
||||
protected boolean isValidationApplicable(WebDataBinder binder, MethodParameter parameter) {
|
||||
protected boolean isValidationApplicable(Object argumentValue, MethodParameter parameter) {
|
||||
Annotation[] annotations = parameter.getParameterAnnotations();
|
||||
for (Annotation annot : annotations) {
|
||||
if ("Valid".equals(annot.annotationType().getSimpleName())) {
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.multipart;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ServerHttpRequest} implementation that is based on a part of a {@link MultipartHttpServletRequest}.
|
||||
* The part is accessed as {@link MultipartFile} and adapted to the ServerHttpRequest contract.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class RequestPartServletServerHttpRequest implements ServerHttpRequest {
|
||||
|
||||
private final MultipartHttpServletRequest request;
|
||||
|
||||
private final MultipartFile multipartFile;
|
||||
|
||||
private HttpHeaders headers;
|
||||
|
||||
/**
|
||||
* Creates a new {@link RequestPartServletServerHttpRequest} instance.
|
||||
*
|
||||
* @param request the multipart request.
|
||||
* @param name the name of the part to adapt to the {@link ServerHttpRequest} contract.
|
||||
*/
|
||||
public RequestPartServletServerHttpRequest(MultipartHttpServletRequest request, String name) {
|
||||
this.request = request;
|
||||
this.multipartFile = request.getFile(name);
|
||||
Assert.notNull(multipartFile, "Request part named '" + name + "' not found. " +
|
||||
"Available request part names: " + request.getMultiFileMap().keySet());
|
||||
|
||||
}
|
||||
|
||||
public HttpMethod getMethod() {
|
||||
return HttpMethod.valueOf(this.request.getMethod());
|
||||
}
|
||||
|
||||
public URI getURI() {
|
||||
try {
|
||||
return new URI(this.request.getScheme(), null, this.request.getServerName(),
|
||||
this.request.getServerPort(), this.request.getRequestURI(),
|
||||
this.request.getQueryString(), null);
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new IllegalStateException("Could not get HttpServletRequest URI: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the headers associated with the part of the multi-part request associated with this instance.
|
||||
* If the underlying implementation supports access to headers, then all headers are returned.
|
||||
* Otherwise, the returned headers will have a 'Content-Type' header in the very least.
|
||||
*/
|
||||
public HttpHeaders getHeaders() {
|
||||
if (this.headers == null) {
|
||||
this.headers = new HttpHeaders();
|
||||
Iterator<String> iterator = this.multipartFile.getHeaderNames();
|
||||
while (iterator.hasNext()) {
|
||||
String name = iterator.next();
|
||||
String[] values = this.multipartFile.getHeaders(name);
|
||||
for (String value : values) {
|
||||
this.headers.add(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.headers;
|
||||
}
|
||||
|
||||
public InputStream getBody() throws IOException {
|
||||
return this.multipartFile.getInputStream();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.multipart;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.mock.web.MockMultipartHttpServletRequest;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
/**
|
||||
* Test fixture for {@link RequestPartServletServerHttpRequest} unit tests.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class RequestPartServletServerHttpRequestTests {
|
||||
|
||||
private RequestPartServletServerHttpRequest request;
|
||||
|
||||
private MockMultipartHttpServletRequest mockRequest;
|
||||
|
||||
private MockMultipartFile mockFile;
|
||||
|
||||
@Before
|
||||
public void create() throws Exception {
|
||||
mockFile = new MockMultipartFile("part", "", "application/json" ,"Part Content".getBytes("UTF-8"));
|
||||
mockRequest = new MockMultipartHttpServletRequest();
|
||||
mockRequest.addFile(mockFile);
|
||||
request = new RequestPartServletServerHttpRequest(mockRequest, "part");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMethod() throws Exception {
|
||||
mockRequest.setMethod("POST");
|
||||
assertEquals("Invalid method", HttpMethod.POST, request.getMethod());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getURI() throws Exception {
|
||||
URI uri = new URI("http://example.com/path?query");
|
||||
mockRequest.setServerName(uri.getHost());
|
||||
mockRequest.setServerPort(uri.getPort());
|
||||
mockRequest.setRequestURI(uri.getPath());
|
||||
mockRequest.setQueryString(uri.getQuery());
|
||||
assertEquals("Invalid uri", uri, request.getURI());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getContentType() throws Exception {
|
||||
HttpHeaders headers = request.getHeaders();
|
||||
assertNotNull("No HttpHeaders returned", headers);
|
||||
|
||||
MediaType expected = MediaType.parseMediaType(mockFile.getContentType());
|
||||
MediaType actual = headers.getContentType();
|
||||
assertEquals("Invalid content type returned", expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBody() throws Exception {
|
||||
byte[] result = FileCopyUtils.copyToByteArray(request.getBody());
|
||||
assertArrayEquals("Invalid content returned", mockFile.getBytes(), result);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user