Можно ли определить конечную точку в контроллере с помощью RequestBody и RequestPart?

Мне нужно создать единую конечную точку, которая принимает RequestBody ИЛИ RequestPart.

Если запрос содержит RequestPart, он выполнит некоторую логику для обработки MultipartFile, в противном случае он обработает объект, переданный в RequestBody.

Я проверил Как отправить весной @Requestbody и @Requestpart вместе, но он отличается от моего вопроса, потому что я не хочу одновременно отправлять и RequestBody, и RequestPart.

Я определил свою точку входа как:

@RequestMapping(value="/xyz/api/{endPoint}", method= RequestMethod.POST)
public void endPointPost(
        @PathVariable String endPoint,
        HttpServletRequest request,
        HttpServletResponse response,
        @RequestBody(required=false) Object body,
        @RequestPart(required=false) MultipartFile uploadFile) throws Exception {

Если запрос содержит только RequestBody, он работает правильно, например:

{"body":{"companyCD":"myTest"}}

Однако при отправке многостраничного запроса происходит сбой со следующей ошибкой:

2019-10-18 00:50:43,440 DEBUG [http-nio-8080-exec-8] org.springframework.web.servlet.handler.AbstractHandlerMapping: Mapped to public void com.monoplus.mcd.rest.GenericController.endPointPost(java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse,java.lang.Object,org.springframework.web.multipart.MultipartFile) throws java.lang.Exception
2019-10-18 00:50:43,440 INFO  [http-nio-8080-exec-8] com.monoplus.mcd.rest.ServletControllerInterceptor: ServletControllerInterceptor - preHandle
2019-10-18 00:50:43,442 DEBUG [http-nio-8080-exec-8] org.springframework.web.method.support.InvocableHandlerMethod: Could not resolve parameter [3] in public void com.monoplus.mcd.rest.GenericController.endPointPost(java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse,java.lang.Object,org.springframework.web.multipart.MultipartFile) throws java.lang.Exception: Content type 'multipart/form-data;boundary=----WebKitFormBoundaryG1Xr4xtC2rNYWuCd;charset=UTF-8' not supported
2019-10-18 00:50:43,446 DEBUG [http-nio-8080-exec-8] org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver: Using @ExceptionHandler public final org.springframework.http.ResponseEntity<java.lang.Object> org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler.handleException(java.lang.Exception,org.springframework.web.context.request.WebRequest) throws java.lang.Exception
2019-10-18 00:50:43,481 DEBUG [http-nio-8080-exec-8] org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor: No match for [text/html, application/xhtml+xml, image/webp, image/apng, application/signed-exchange;v=b3, application/xml;q=0.9, */*;q=0.8], supported: []
2019-10-18 00:50:43,482 DEBUG [http-nio-8080-exec-8] org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver: Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'multipart/form-data;boundary=----WebKitFormBoundaryG1Xr4xtC2rNYWuCd;charset=UTF-8' not supported]
2019-10-18 00:50:43,483 INFO  [http-nio-8080-exec-8] com.monoplus.mcd.rest.ServletControllerInterceptor: ServletControllerInterceptor - afterCompletion - org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryResponseWrapper@6c9a1e05
2019-10-18 00:50:43,484 DEBUG [http-nio-8080-exec-8] org.springframework.web.servlet.FrameworkServlet: Completed 415 UNSUPPORTED_MEDIA_TYPE

Обратите внимание, что Could not resolve parameter [3]... относится к параметру RequestBody.

Это мой многостраничный запрос:

  • Заголовок
Host: localhost:88
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------262541039624932
Content-Length: 1401
Connection: keep-alive
Referer: http://localhost:88/appl/html/master/FileImport.html
Cookie: JSESSIONID=3f052417-1702-48b6-b7c2-cac5609ef525; SESSION=M2YwNTI0MTctMTcwMi00OGI2LWI3YzItY2FjNTYwOWVmNTI1
Upgrade-Insecure-Requests: 1
Pragma: no-cache
Cache-Control: no-cache
  • Тело
-----------------------------262541039624932
Content-Disposition: form-data; name="uploadFile"; filename="testFile.txt"
Content-Type: text/plain


1 - File content

-----------------------------262541039624932
Content-Disposition: form-data; name="_ns"


-----------------------------262541039624932
Content-Disposition: form-data; name="_qt"

false
-----------------------------262541039624932
Content-Disposition: form-data; name="_body"

{"USER_NAME":""}
-----------------------------262541039624932--

Любая помощь приветствуется.

Спасибо


person saavedrah    schedule 17.10.2019    source источник


Ответы (2)


Я думаю об этом вопросе с точки зрения RESTful, а не обязательно Spring. Если вы 1) пытаетесь создать или отредактировать (опубликовать или разместить) ресурс или 2) пытаетесь загрузить файл; Разве это не должны быть два разных пути URI?

person Chris Savory    schedule 17.10.2019
comment
Я вроде как согласен, но есть две вещи: во-первых, это спецификации, а во-вторых, поскольку конечная точка определяется с помощью PathVariable, сервлет примет решение, куда отправить запрос. В этом случае мне просто нужна одна точка входа вместо нескольких RestController. - person saavedrah; 18.10.2019

Благодаря предложению Криса я смог решить свой вопрос, я определил другую точку входа для многостраничного контента.

    @RequestMapping(value="/xyz/api/{endPoint}", method= RequestMethod.POST, consumes = {"multipart/form-data"})
    public void multiPartEndPointPost(
            @PathVariable String endPoint,
            HttpServletRequest request,
            HttpServletResponse response
    ) throws Exception {

        this.doSomeStuff(endPoint, request, response);
    }

Важная часть - это consumes = {"multipart/form-data"}, тогда я могу использовать Apache Commons FileUpload для загрузки файлов.

Ответ для [ person saavedrah    schedule 18.10.2019