1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.web.servlet.mvc.method.annotation;
18
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.List;
22 import javax.servlet.http.HttpServletRequest;
23 import javax.servlet.http.Part;
24
25 import org.springframework.core.GenericCollectionTypeResolver;
26 import org.springframework.core.MethodParameter;
27 import org.springframework.http.HttpInputMessage;
28 import org.springframework.http.converter.HttpMessageConverter;
29 import org.springframework.util.Assert;
30 import org.springframework.validation.BindingResult;
31 import org.springframework.web.bind.MethodArgumentNotValidException;
32 import org.springframework.web.bind.WebDataBinder;
33 import org.springframework.web.bind.annotation.RequestBody;
34 import org.springframework.web.bind.annotation.RequestParam;
35 import org.springframework.web.bind.annotation.RequestPart;
36 import org.springframework.web.bind.support.WebDataBinderFactory;
37 import org.springframework.web.context.request.NativeWebRequest;
38 import org.springframework.web.method.support.ModelAndViewContainer;
39 import org.springframework.web.multipart.MultipartException;
40 import org.springframework.web.multipart.MultipartFile;
41 import org.springframework.web.multipart.MultipartHttpServletRequest;
42 import org.springframework.web.multipart.MultipartResolver;
43 import org.springframework.web.multipart.support.MissingServletRequestPartException;
44 import org.springframework.web.multipart.support.RequestPartServletServerHttpRequest;
45 import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
46 import org.springframework.web.util.WebUtils;
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 public class RequestPartMethodArgumentResolver extends AbstractMessageConverterMethodArgumentResolver {
74
75 public RequestPartMethodArgumentResolver(List<HttpMessageConverter<?>> messageConverters) {
76 super(messageConverters);
77 }
78
79
80
81
82
83
84
85
86
87
88 @Override
89 public boolean supportsParameter(MethodParameter parameter) {
90 if (parameter.hasParameterAnnotation(RequestPart.class)) {
91 return true;
92 }
93 else {
94 if (parameter.hasParameterAnnotation(RequestParam.class)){
95 return false;
96 }
97 else if (MultipartFile.class.equals(parameter.getParameterType())) {
98 return true;
99 }
100 else if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName())) {
101 return true;
102 }
103 else {
104 return false;
105 }
106 }
107 }
108
109 @Override
110 public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
111 NativeWebRequest request, WebDataBinderFactory binderFactory) throws Exception {
112
113 HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
114 assertIsMultipartRequest(servletRequest);
115
116 MultipartHttpServletRequest multipartRequest =
117 WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class);
118
119 String partName = getPartName(parameter);
120 Object arg;
121
122 if (MultipartFile.class.equals(parameter.getParameterType())) {
123 Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
124 arg = multipartRequest.getFile(partName);
125 }
126 else if (isMultipartFileCollection(parameter)) {
127 Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
128 arg = multipartRequest.getFiles(partName);
129 }
130 else if (isMultipartFileArray(parameter)) {
131 Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
132 List<MultipartFile> files = multipartRequest.getFiles(partName);
133 arg = files.toArray(new MultipartFile[files.size()]);
134 }
135 else if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName())) {
136 assertIsMultipartRequest(servletRequest);
137 arg = servletRequest.getPart(partName);
138 }
139 else if (isPartCollection(parameter)) {
140 assertIsMultipartRequest(servletRequest);
141 arg = new ArrayList<Object>(servletRequest.getParts());
142 }
143 else if (isPartArray(parameter)) {
144 assertIsMultipartRequest(servletRequest);
145 arg = RequestPartResolver.resolvePart(servletRequest);
146 }
147 else {
148 try {
149 HttpInputMessage inputMessage = new RequestPartServletServerHttpRequest(servletRequest, partName);
150 arg = readWithMessageConverters(inputMessage, parameter, parameter.getParameterType());
151 WebDataBinder binder = binderFactory.createBinder(request, arg, partName);
152 if (arg != null) {
153 validateIfApplicable(binder, parameter);
154 if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
155 throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
156 }
157 }
158 mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + partName, binder.getBindingResult());
159 }
160 catch (MissingServletRequestPartException ex) {
161
162 arg = null;
163 }
164 }
165
166 RequestPart ann = parameter.getParameterAnnotation(RequestPart.class);
167 boolean isRequired = (ann == null || ann.required());
168
169 if (arg == null && isRequired) {
170 throw new MissingServletRequestPartException(partName);
171 }
172
173 return arg;
174 }
175
176 private static void assertIsMultipartRequest(HttpServletRequest request) {
177 String contentType = request.getContentType();
178 if (contentType == null || !contentType.toLowerCase().startsWith("multipart/")) {
179 throw new MultipartException("The current request is not a multipart request");
180 }
181 }
182
183 private String getPartName(MethodParameter methodParam) {
184 RequestPart ann = methodParam.getParameterAnnotation(RequestPart.class);
185 String partName = (ann != null ? ann.value() : "");
186 if (partName.length() == 0) {
187 partName = methodParam.getParameterName();
188 if (partName == null) {
189 throw new IllegalArgumentException("Request part name for argument type [" +
190 methodParam.getNestedParameterType().getName() +
191 "] not specified, and parameter name information not found in class file either.");
192 }
193 }
194 return partName;
195 }
196
197 private boolean isMultipartFileCollection(MethodParameter methodParam) {
198 Class<?> collectionType = getCollectionParameterType(methodParam);
199 return MultipartFile.class.equals(collectionType);
200 }
201
202 private boolean isMultipartFileArray(MethodParameter methodParam) {
203 Class<?> paramType = methodParam.getNestedParameterType().getComponentType();
204 return MultipartFile.class.equals(paramType);
205 }
206
207 private boolean isPartCollection(MethodParameter methodParam) {
208 Class<?> collectionType = getCollectionParameterType(methodParam);
209 return (collectionType != null && "javax.servlet.http.Part".equals(collectionType.getName()));
210 }
211
212 private boolean isPartArray(MethodParameter methodParam) {
213 Class<?> paramType = methodParam.getNestedParameterType().getComponentType();
214 return (paramType != null && "javax.servlet.http.Part".equals(paramType.getName()));
215 }
216
217 private Class<?> getCollectionParameterType(MethodParameter methodParam) {
218 Class<?> paramType = methodParam.getNestedParameterType();
219 if (Collection.class.equals(paramType) || List.class.isAssignableFrom(paramType)){
220 Class<?> valueType = GenericCollectionTypeResolver.getCollectionParameterType(methodParam);
221 if (valueType != null) {
222 return valueType;
223 }
224 }
225 return null;
226 }
227
228
229
230
231
232 private static class RequestPartResolver {
233
234 public static Object resolvePart(HttpServletRequest servletRequest) throws Exception {
235 Collection<Part> parts = servletRequest.getParts();
236 return parts.toArray(new Part[parts.size()]);
237 }
238 }
239
240 }