[英]How to declare Servlet on root path without overriding Spring MVC Controllers
我有在/api
上映射了REST API的Spring Boot應用程序。 我需要在/
上定義其他servlet。 我希望所有與/api
匹配的請求均由REST API處理,所有其他請求均由servlet處理。 這個怎么做?
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
@RestController
@RequestMapping("/api")
public class ApiController {
@GetMapping
public String get() {
return "api";
}
}
@Bean
public ServletRegistrationBean customServletBean() {
return new ServletRegistrationBean<>(new HttpServlet() {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.getWriter().println("custom");
}
}, "/*");
}
}
在上面的代碼中,我想要這樣的東西:
curl http://localhost:8080/api/
> api⏎
curl http://localhost:8080/custom/
> custom
我嘗試使用過濾器重定向請求,但所有請求都轉到自定義servlet:
@Bean
public FilterRegistrationBean apiResolverFilter() {
final FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter((req, response, chain) -> {
HttpServletRequest request = (HttpServletRequest) req;
String path = request.getRequestURI().substring(request.getContextPath().length());
if (path.startsWith("/api/")) {
request.getRequestDispatcher(path).forward(request, response);
} else {
chain.doFilter(request, response);
}
});
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
該項目可在github上找到: https : //github.com/mariuszs/nestedweb
將servlet映射到根路徑時,您將覆蓋DispatcherServlet
的映射,默認情況下,該映射被映射到/
。
基本上可以嘗試3種解決方案
DispatcherServlet
映射到/api
並修改控制器中的映射 ServletForwardingController
將請求轉發到已配置但未映射的Servlet
ServletWrappingController
包裝Servlet
實例 數字2和3幾乎相同,不同之處在於,使用選項3,Spring還將管理Servlet
實例,而使用選項2,則Servlet容器將管理Servlet
。
DispatcherServlet
映射到/api
如果所有控制器都映射在/api
,則選項1是一個選項,如果不是,則這不是一個選項。 在application.properties
,將spring.mvc.servlet.path
設置為/api
。 然后,您將像在問題中一樣配置其他Servlet
。
ServletForwardingController
Spring提供了一個ServletForwardingController
,它將在給定Servlet
名稱的情況下在ServletContext
查找一個Servlet
並將請求轉發給它。 您仍然必須注冊Servlet
但阻止其被映射。
接下來,您將需要一個SimpleUrlHandlerMapping
來將URL映射到此控制器,或將其設置為默認處理程序(基本上是全部捕獲)。
@Bean
public ServletForwardingController forwarder() {
ServletForwardingController controller = new ServletForwardingController();
controller.setServletName("my-servlet");
return controller;
}
@Bean
public CustomServlet customServlet() {
return new CustomServlet();
}
@Bean
public ServletRegistrationBean customServletRegistration() {
ServletRegistrationBean registration = new ServletRegistrationBean(customServlet(), false);
registration.setServletName("customServlet");
return registration;
}
@Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setDefaultHandler(forwarder());
mapping.setOrder(LOWEST_PRECEDENCE - 2);
return mapping;
}
ServletWrappingController
Spring提供了一個ServletWrappingController
,它將在內部創建和配置Servlet
實例。 它充當Servlet
到Spring Controller
的適配器。 在這種情況下,您不必注冊CustomServlet
,因此配置ServletForwardingController
稍微容易ServletForwardingController
。
接下來,您將需要一個SimpleUrlHandlerMapping
來將URL映射到此控制器,或將其設置為默認處理程序(基本上是全部捕獲)。
@Bean
public ServletWrappingController wrapper() {
ServletWrappingController controller = new ServletWrappingController ();
controller.setServletName("my-servlet");
controller.setServletClass(CustomerServlet.class);
return controller;
}
@Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setDefaultHandler(wrapper());
mapping.setOrder(LOWEST_PRECEDENCE - 2);
return mapping;
}
根據您的體系結構和url結構,您可能需要選擇選項1或選項3。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.