我正在尝试将我的一组RESTful终结点(依赖于 Jersey 2 JAX-RS实现)插入运行在顶部的第三方 Spring MVC Web应用程序中的是 Tomcat 9。
不允许我修改web.xml
,也不能在容器启动时使用我的插件,因此annotation-based configuration也不可行。这意味着我不能直接部署 Jersey 的ServletContainer
。
我 am 所允许的是插入 Spring MVC ,即
- 创建自定义的部分 Spring 应用程序上下文和
- 实现自定义
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
}
}
除了文件上传方案(即HTTP POST
和Content-Type: multipart/form-data
)之外,上述方法都可以正常工作。
Spring 检测到此类请求并将常规HttpServletRequest
转换为MultipartHttpServletRequest
,读出并耗尽其输入流(mark()
/ reset()
不支持)。该Web应用程序具有一个自定义MultipartResolver
,该自定义不能以任何方式影响
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
这意味着 Jersey 收到包含空请求正文的多部分HTTP POST
,抛出MIMEParsingException
并以HTTP 400 Bad Request
进行响应。
据我了解,多部分分辨率只能全局禁用,不能在每个控制器的基础上禁用(1,2,3)。
问题:
- 解决
MultipartResolver
从而使 Jersey 收到未修改的请求的最佳方法是什么? - 或者,您可以推荐一个API来重新构造请求主体(即与
MultipartResolver
所做的相反,并将新的HttpServletRequest
馈送到 Jersey )吗?当然,这可以手工完成,但是我宁愿依赖现有的库。