簡體   English   中英

如何在根路徑上聲明Servlet而不覆蓋Spring MVC控制器

[英]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種解決方案

  1. DispatcherServlet映射到/api並修改控制器中的映射
  2. 使用ServletForwardingController將請求轉發到已配置但未映射的Servlet
  3. 使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM