Делегирование обработки HTTP-запроса от контроллера Spring MVC на Jersey 2 - PullRequest
3 голосов
/ 07 ноября 2019

Я пытаюсь подключить мой набор конечных точек RESTful (которые зависят от реализации Jersey 2 JAX-RS) от стороннего Spring MVC веб-приложения, работающего поверх Tomcat 9.

Мне не разрешено изменять web.xml, и мой плагин недоступен при запуске контейнера, поэтому конфигурация на основе аннотаций не разрешенавариант, либо. Это означает, что я не могу развернуть Джерси ServletContainer напрямую.

То, что я am разрешено, подключается к SpringMVC , а именно

  1. создание пользовательского частичного Spring контекста приложения и
  2. реализация пользовательского Controller, поэтому янаписали эту наивную реализацию, которая на самом деле близка к стандартному ServletWrappingController:
package com.example

import org.glassfish.jersey.server.ResourceConfig
import org.glassfish.jersey.servlet.ServletContainer
import org.springframework.web.servlet.ModelAndView
import org.springframework.web.servlet.mvc.AbstractController
import java.io.IOException
import java.util.Collections
import java.util.Enumeration
import javax.servlet.ServletConfig
import javax.servlet.ServletContext
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

class JerseyServletInitializer(servletContext: ServletContext,
                               componentClasses: List<Class<*>>,
                               components: List<Any>): AbstractController() {
    private val servletContainer: ServletContainer

    init {
        val resourceConfig = ResourceConfig()
            .apply {
                // Register org.glassfish.jersey.media.multipart.MultiPartFeature
                componentClasses.forEach { clazz ->
                    register(clazz)
                }
                // Register REST endpoints
                components.forEach { component ->
                    register(component)
                }
            }

        // Provide a dummy ServletConfig
        val servletConfig = object : ServletConfig {
            override fun getInitParameter(name: String): String? = null

            override fun getInitParameterNames(): Enumeration<String> = emptyList<String>().let {
                Collections.enumeration(it)
            }

            override fun getServletName(): String = ServletContainer::class.java.name

            override fun getServletContext(): ServletContext = servletContext
        }

        // Create and initialize Jersey's ServletContainer
        servletContainer = ServletContainer(resourceConfig).apply {
            init(servletConfig)
        }

        setSupportedMethods("GET", "POST", "PUT", "OPTIONS")
    }

    @Throws(IOException::class)
    override fun handleRequestInternal(request: HttpServletRequest,
                                       response: HttpServletResponse): ModelAndView? {
        // Delegate all HTTP requests to Jersey
        servletContainer.service(request, response)
        return null
    }
}

Вышеприведенное работает отлично, за исключением сценария загрузки файла (т. е. * 1040)* with Content-Type: multipart/form-data).

Spring обнаруживает такие запросы и преобразует обычный HttpServletRequest в MultipartHttpServletRequest, считывая и исчерпывая его входной поток (mark() / reset() не поддерживаются). В веб-приложении есть пользовательский MultipartResolver, на который я никак не могу повлиять:

  <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>

Это означает, что Джерси получает составную часть HTTP POST спустое тело запроса, выбрасывает MIMEParsingException и отвечает HTTP 400 Bad Request.

Насколько я понимаю, многочастное разрешение может быть отключено только глобально, а не для каждого контроллерабазис ( 1 , 2 , 3 ).

Вопросы:

  1. Каков наилучший способ работы с MultipartResolver, чтобы Джерси получал неизмененный запрос?
  2. В качестве альтернативы, вы можете порекомендовать API для пересоздания тела запроса (то есть делает ли обратное тому, что делает MultipartResolver и кормит нового HttpServletRequest на Джерси )? Это, конечно, можно сделать вручную, но я бы предпочел использовать существующие библиотеки.
...