Как объявить сервлет в корневом пути без переопределения контроллеров Spring MVC - PullRequest
0 голосов
/ 19 марта 2019

У меня есть приложение Spring Boot с REST API, отображенным на /api. Мне нужно определить дополнительный сервлет на /. Я хочу, чтобы все запросы, соответствующие /api, обрабатывались REST API, а все остальные запросы - сервлетом. Как это сделать?

@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

Я пытался с фильтром перенаправить запросы, но все запросы переходят на пользовательский сервлет:

@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

1 Ответ

1 голос
/ 25 марта 2019

При отображении сервлета в корневой путь вы переопределяете отображение для DispatcherServlet, которое по умолчанию отображается на /.

Есть в основном 3 решения, которые вы можете попробовать

  1. Сопоставьте DispatcherServlet с /api и измените сопоставления в ваших контроллерах
  2. Используйте ServletForwardingController для пересылки запроса на настроенный, но не сопоставленный Servlet
  3. Используйте ServletWrappingController, чтобы обернуть Servlet экземпляр

Числа 2 и 3 почти одинаковы, с той разницей, что с опцией 3 Spring также управляет экземпляром Servlet, тогда как с опцией 2 контейнер сервлетов управляет Servlet.

Отображение DispatcherServlet на /api

Опция 1 может быть опцией, если все ваши контроллеры сопоставлены с /api, если это не так, это не опция. В вашем application.properties вы должны установить spring.mvc.servlet.path на /api. Затем вы настроите другой Servlet, как вы сделали в своем вопросе.

Используйте ServletForwardingController

Spring предоставляет ServletForwardingController, который будет искать Servlet в ServletContext с заданным именем сервлета и перенаправлять запрос на него. Вам все равно придется зарегистрировать 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 к пружине Controller. Вам не нужно регистрировать CustomServlet в этом случае и, следовательно, немного проще настроить тогда 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...