Я создаю контроллер загрузки Spring с массивом @RequestParam. Дело в том, что входные данные будут представлять собой смесь загрузки изображения (нового изображения) и строки (идентификатора существующего изображения) в теле запроса в виде FormData.
Если это новое изображение, мне нужно загрузить его и получить его идентификатор. Если это существующее изображение, я просто использую тот же идентификатор из входных данных.
В контроллере я попробовал использовать
@RequestParam Object[] images
и
if (images[i] instanceof String) {
// Existing Image
} else if (images[i] instanceof MultipartFile) {
// New Image
}
Это работает, если все элементы являются изображениями или всеми элементами или строкой. Но если это смесь того и другого, контроллер захватывает только MultipartFile.
Когда я проверяю вкладку «Сеть» (Браузер), все строки и файлы загружаются нормально.
Может ли кто-нибудь помочь мне с захватом разных типов?
@RequestParam
используется для обработки простых типов данных и, вероятно, не может обрабатывать сложные типы, которые вам нужны, в вашем случае изображение и строку.
Вы можете попробовать использовать @RequestPart
вместо @RequestParam
.
@RequestPart("images") Object[] images
if (images[i] instanceof String) {
// Existing Image
} else if (images[i] instanceof MultipartFile) {
// New Image
}
Это позволит вам обрабатывать несколько типов данных, полученных от клиента.
Классный вопрос, Бро,
Ты прав. Ваш метод только что получил все файлы или все строки, поскольку логика метода resolveName
в org.springframework.web.method.annotation.RequestParamMethodArgumentResolver
. Значения параметров будут игнорироваться, если файлы состоят из нескольких частей:
Object arg = null;
MultipartRequest multipartRequest = request.getNativeRequest(MultipartRequest.class);
if (multipartRequest != null) {
List<MultipartFile> files = multipartRequest.getFiles(name);
if (!files.isEmpty()) {
arg = (files.size() == 1 ? files.get(0) : files);
}
}
if (arg == null) {
String[] paramValues = request.getParameterValues(name);
if (paramValues != null) {
arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
}
}
return arg;
Я только что нашел решение после того, как потратил время на эту статью Пользовательская привязка данных в Spring MVC и несколько интересных классов Spring.
Первым делом создаем разметочную аннотацию @MixMultipartFileAndString
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface MixMultipartFileAndString {
}
Далее мы создаем индивидуальный HandlerMethodArgumentResolver
, который принимает все составные файлы и строку параметров:
public class MixMultipartFileAndStringArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.getParameterAnnotation(MixMultipartFileAndString.class) != null;
}
/**
*
* @param methodParameter the method parameter to resolve. This parameter must
* have previously been passed to {@link #supportsParameter} which must
* have returned {@code true}.
* @param mavContainer the ModelAndViewContainer for the current request
* @param request the current request
* @param binderFactory a factory for creating {@link WebDataBinder} instances
* @return
* @throws Exception
* @see org.springframework.web.method.annotation.RequestParamMethodArgumentResolver#resolveName(String, MethodParameter, NativeWebRequest)
*/
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer mavContainer, NativeWebRequest request, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
String name = methodParameter.getParameterName();
if (servletRequest != null) {
Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, methodParameter, servletRequest);
if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {
return mpArg;
}
}
List<Object> arg = new ArrayList<>();
MultipartRequest multipartRequest = request.getNativeRequest(MultipartRequest.class);
if (multipartRequest != null) {
List<MultipartFile> files = multipartRequest.getFiles(name);
if (!files.isEmpty()) {
arg.addAll(files);
}
}
String[] paramValues = request.getParameterValues(name);
if (paramValues != null) {
Collections.addAll(arg, paramValues);
}
return arg;
}
}
И тогда нам нужно зарегистрироваться:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(
List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add( new MixMultipartFileAndStringArgumentResolver());
}
}
Наконец, используйте его в нашем контроллере:
@PostMapping("/api")
public void uploadOrGetImages(@MixMultipartFileAndString List<Object> images) {
for (Object object: images) {
if (object instanceof MultipartFile) {}
if (object instanceof String) {}
}
}
Надеюсь, поможет.
Попробовал, но получил это исключение. HttpMediaTypeNotSupportedException: тип контента «приложение/октет-поток» не поддерживается