Как мне настроить путь отображения @Controller?

Я строю внутреннюю библиотеку, которая должна автоматически добавить несколько контроллеров в приложение Spring MVC. Эти контроллеры все @RestController с несколькими методами-обработчиками, аннотированными @RequestMapping, Поскольку это библиотека, я хочу, чтобы пользователи могли указывать корневой путь, в котором библиотека должна предоставлять все эти контроллеры. Иллюстрация:

// given that I have a controller like this:
@RestController
@RequestMapping("/admin") 
class AdminController {
  @RequestMapping("/users")
  UsersDto allUsers() { ... }
}

// it will be exposed at `http://localhost/admin/users`

Чего я хочу добиться, так это сделать /admin часть настраивается. Например, если пользователь говорит в application.properties:

super.admin.path=/top/secret/location/here

я хочу AdminControllerобработчики будут доступны на http://localhost/top/secret/location/hereи так allUsers() У обработчика должен быть полный путь:

http://localhost/top/secret/location/here/users

Как мне этого добиться? Похоже, довольно распространенная задача, но мне не удалось найти простое решение, которое работает.

Мое нахождение #1

Есть SimpleUrlHandlerMapping механизм, который, кажется, именно то, что я хочу:

@Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
    SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping();
    simpleUrlHandlerMapping.setOrder(Integer.MAX_VALUE - 2);
    simpleUrlHandlerMapping.setUrlMap(Collections.singletonMap("/ANY_CUSTOM_VALUE_HERE/*", "adminController"));
    return simpleUrlHandlerMapping;
}

Но это продолжает говорить

Конфигурация DispatcherServlet должна включать в себя HandlerAdapter, который поддерживает этот обработчик

Моя находка № 2

Есть проект Spring Boot Admin, который имеет именно эту функцию - вы можете настроить, где они должны выставлять все свои конечные точки. Похоже, они реализовали эту функциональность с нуля в PrefixHandlerMapping. Как они это используют:

...
@Bean
public PrefixHandlerMapping prefixHandlerMappingNotificationFilterController() {
    PrefixHandlerMapping prefixHandlerMapping = new PrefixHandlerMapping(notificationFilterController());
    prefixHandlerMapping.setPrefix(adminServerProperties.getContextPath());
    return prefixHandlerMapping;
}
...

1 ответ

Решение

В дополнение к @M. Решение Deinum, вы можете использовать паттерны путей с заполнителями. В документации Spring говорится:

Шаблоны в @RequestMapping поддержка аннотаций ${…​} заполнители для локальных свойств и / или системных свойств и переменных среды. Это может быть полезно в тех случаях, когда путь, на который отображается контроллер, может потребоваться настроить с помощью конфигурации.

Так что в вашем случае ваш контроллер будет выглядеть так:

@RestController
@RequestMapping("/${super.admin.path:admin}") 
class AdminController {
  // Same as before
}

Предыдущий контроллер будет использовать super.admin.path локальное / системное свойство или значение переменной среды в качестве префикса или admin если они не предоставлены. Если вы используете Spring Boot, добавив следующее application.properties:

super.admin.path=whatever

Вы можете настроить этот префикс.

Другие вопросы по тегам