001/* 002 * Copyright 2002-2019 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.multipart.support; 018 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.List; 022 023import javax.servlet.http.HttpServletRequest; 024import javax.servlet.http.Part; 025 026import org.springframework.core.MethodParameter; 027import org.springframework.core.ResolvableType; 028import org.springframework.lang.Nullable; 029import org.springframework.web.context.request.NativeWebRequest; 030import org.springframework.web.multipart.MultipartFile; 031import org.springframework.web.multipart.MultipartHttpServletRequest; 032import org.springframework.web.multipart.MultipartRequest; 033import org.springframework.web.util.WebUtils; 034 035/** 036 * A common delegate for {@code HandlerMethodArgumentResolver} implementations 037 * which need to resolve {@link MultipartFile} and {@link Part} arguments. 038 * 039 * @author Juergen Hoeller 040 * @since 4.3 041 */ 042public final class MultipartResolutionDelegate { 043 044 /** 045 * Indicates an unresolvable value. 046 */ 047 public static final Object UNRESOLVABLE = new Object(); 048 049 050 private MultipartResolutionDelegate() { 051 } 052 053 054 @Nullable 055 public static MultipartRequest resolveMultipartRequest(NativeWebRequest webRequest) { 056 MultipartRequest multipartRequest = webRequest.getNativeRequest(MultipartRequest.class); 057 if (multipartRequest != null) { 058 return multipartRequest; 059 } 060 HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); 061 if (servletRequest != null && isMultipartContent(servletRequest)) { 062 return new StandardMultipartHttpServletRequest(servletRequest); 063 } 064 return null; 065 } 066 067 public static boolean isMultipartRequest(HttpServletRequest request) { 068 return (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null || 069 isMultipartContent(request)); 070 } 071 072 private static boolean isMultipartContent(HttpServletRequest request) { 073 String contentType = request.getContentType(); 074 return (contentType != null && contentType.toLowerCase().startsWith("multipart/")); 075 } 076 077 static MultipartHttpServletRequest asMultipartHttpServletRequest(HttpServletRequest request) { 078 MultipartHttpServletRequest unwrapped = WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class); 079 if (unwrapped != null) { 080 return unwrapped; 081 } 082 return new StandardMultipartHttpServletRequest(request); 083 } 084 085 086 public static boolean isMultipartArgument(MethodParameter parameter) { 087 Class<?> paramType = parameter.getNestedParameterType(); 088 return (MultipartFile.class == paramType || 089 isMultipartFileCollection(parameter) || isMultipartFileArray(parameter) || 090 (Part.class == paramType || isPartCollection(parameter) || isPartArray(parameter))); 091 } 092 093 @Nullable 094 public static Object resolveMultipartArgument(String name, MethodParameter parameter, HttpServletRequest request) 095 throws Exception { 096 097 MultipartHttpServletRequest multipartRequest = 098 WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class); 099 boolean isMultipart = (multipartRequest != null || isMultipartContent(request)); 100 101 if (MultipartFile.class == parameter.getNestedParameterType()) { 102 if (multipartRequest == null && isMultipart) { 103 multipartRequest = new StandardMultipartHttpServletRequest(request); 104 } 105 return (multipartRequest != null ? multipartRequest.getFile(name) : null); 106 } 107 else if (isMultipartFileCollection(parameter)) { 108 if (multipartRequest == null && isMultipart) { 109 multipartRequest = new StandardMultipartHttpServletRequest(request); 110 } 111 return (multipartRequest != null ? multipartRequest.getFiles(name) : null); 112 } 113 else if (isMultipartFileArray(parameter)) { 114 if (multipartRequest == null && isMultipart) { 115 multipartRequest = new StandardMultipartHttpServletRequest(request); 116 } 117 if (multipartRequest != null) { 118 List<MultipartFile> multipartFiles = multipartRequest.getFiles(name); 119 return multipartFiles.toArray(new MultipartFile[0]); 120 } 121 else { 122 return null; 123 } 124 } 125 else if (Part.class == parameter.getNestedParameterType()) { 126 return (isMultipart ? request.getPart(name): null); 127 } 128 else if (isPartCollection(parameter)) { 129 return (isMultipart ? resolvePartList(request, name) : null); 130 } 131 else if (isPartArray(parameter)) { 132 return (isMultipart ? resolvePartList(request, name).toArray(new Part[0]) : null); 133 } 134 else { 135 return UNRESOLVABLE; 136 } 137 } 138 139 private static boolean isMultipartFileCollection(MethodParameter methodParam) { 140 return (MultipartFile.class == getCollectionParameterType(methodParam)); 141 } 142 143 private static boolean isMultipartFileArray(MethodParameter methodParam) { 144 return (MultipartFile.class == methodParam.getNestedParameterType().getComponentType()); 145 } 146 147 private static boolean isPartCollection(MethodParameter methodParam) { 148 return (Part.class == getCollectionParameterType(methodParam)); 149 } 150 151 private static boolean isPartArray(MethodParameter methodParam) { 152 return (Part.class == methodParam.getNestedParameterType().getComponentType()); 153 } 154 155 @Nullable 156 private static Class<?> getCollectionParameterType(MethodParameter methodParam) { 157 Class<?> paramType = methodParam.getNestedParameterType(); 158 if (Collection.class == paramType || List.class.isAssignableFrom(paramType)){ 159 Class<?> valueType = ResolvableType.forMethodParameter(methodParam).asCollection().resolveGeneric(); 160 if (valueType != null) { 161 return valueType; 162 } 163 } 164 return null; 165 } 166 167 private static List<Part> resolvePartList(HttpServletRequest request, String name) throws Exception { 168 Collection<Part> parts = request.getParts(); 169 List<Part> result = new ArrayList<>(parts.size()); 170 for (Part part : parts) { 171 if (part.getName().equals(name)) { 172 result.add(part); 173 } 174 } 175 return result; 176 } 177 178}