Как настроить префикс URI по умолчанию для @RestController для всех контроллеров?
Я знаю, что вы можете установить server.contextPath
в application.properties
для изменения корневого контекста.
Кроме того, я могу добавить дополнительный контекст в конфигурацию приложения для Spring Boot, как в следующем примере (в Groovy), чтобы добавить "/api" к сопоставлениям URL-адреса корневого контекста:
@Bean
ServletRegistrationBean dispatcherServlet() {
ServletRegistrationBean reg = new ServletRegistrationBean(new DispatcherServlet(), "/")
reg.name = "dispatcherServlet"
reg.addInitParameter("contextConfigLocation", "")
reg.addUrlMappings("/api/*")
reg.loadOnStartup = 2
reg
}
}
Я пытаюсь создать отдельный базовый URI "/api" специально для вызовов веб-сервисов, которые я могу использовать для обеспечения безопасности и т.д. Однако использование вышеуказанного подхода будет означать, что любой из моих URI, веб-службы или нет, может быть достигнуто с помощью "/" или "/api" и не обеспечивает конкретной сегрегации.
Кто-нибудь знает лучший подход для установки базового пути для всех @RestController
(s) с использованием конфигурации, без необходимости формально префикс каждого контроллера с помощью /api/? Если я вынужден вручную префикс URI для каждого контроллера, можно было бы ошибочно опустить это и обойти мои меры безопасности, специфичные для веб-служб.
Вот ссылка в Qaru на тот же тип вопроса, на который никогда не отвечали полностью:
Spring Загрузка: настройка префикса URL для RestControllers
Ответы
Ответ 1
Кто-то зарегистрировал проблему в Spring MVC Jira и придумал приятное решение, которое я сейчас использую. Идея состоит в том, чтобы использовать язык выражения Spring в префиксе, помещенном в каждый файл RestController, и ссылаться на одно свойство в файле Spring Boot application.properties.
Вот ссылка на проблему: https://jira.spring.io/browse/SPR-13882
Ответ 2
Появилось новое решение для решения этой проблемы, начиная с Spring Boot 1.4.0.RC1 (Подробнее см. https://github.com/spring-projects/spring-boot/issues/5004)
Решение Shahin ASkari отключает части конфигурации Auto, поэтому могут возникнуть другие проблемы.
Следующее решение использует его идею и правильно интегрирует ее в Spring boot. Для моего случая я хотел, чтобы все RestControllers были связаны с базовым путем api, но все равно служат статическому контенту с корневым путем (f.e. angular webapp)
Изменить. Я подвел итог в сообщении в блоге со слегка улучшенной версией. https://mhdevelopment.wordpress.com/2016/10/03/spring-restcontroller-specific-basepath/ p >
@Configuration
public class WebConfig {
@Bean
public WebMvcRegistrationsAdapter webMvcRegistrationsHandlerMapping() {
return new WebMvcRegistrationsAdapter() {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new RequestMappingHandlerMapping() {
private final static String API_BASE_PATH = "api";
@Override
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
Class<?> beanType = method.getDeclaringClass();
RestController restApiController = beanType.getAnnotation(RestController.class);
if (restApiController != null) {
PatternsRequestCondition apiPattern = new PatternsRequestCondition(API_BASE_PATH)
.combine(mapping.getPatternsCondition());
mapping = new RequestMappingInfo(mapping.getName(), apiPattern,
mapping.getMethodsCondition(), mapping.getParamsCondition(),
mapping.getHeadersCondition(), mapping.getConsumesCondition(),
mapping.getProducesCondition(), mapping.getCustomCondition());
}
super.registerHandlerMethod(handler, method, mapping);
}
};
}
};
}
}
Ответ 3
У меня была такая же озабоченность и я не был поклонником опции Spring EL из-за проблем, о которых было документировано, и я хотел, чтобы префикс был жестко контролирован в контроллерах, но я не хотел зависеть от разработчиков, которые делают правильные вещь.
В наши дни может быть лучший способ, но это то, что я сделал. Можете ли вы, ребята, увидеть какие-либо недостатки, я все еще в процессе тестирования каких-либо побочных эффектов.
- Определить пользовательскую аннотацию.
Это позволяет разработчику явно предоставлять типизированные атрибуты, такие как int apiVersion(), String resourceName(). Эти значения позже станут основой префикса.
- Аннотированные контроллеры останова с этой новой аннотацией
- Реализован пользовательский шаблон RequestMappingHandlerMapping
В файле RequestMappingHandlerMapping я мог бы прочитать атрибут пользовательской аннотации и изменить окончательный RequestMappingInfo по мере необходимости. Вот несколько фрагментов кода:
@Configuration
public class MyWebMvcConfigurationSupport extends WebMvcConfigurationSupport {
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
return new MyCustomRequestMappingHandlerMapping();
}
}
И в MyCustomRequestMappingHandlerMapping перезапишите registerHandlerMethod:
private class MyCustomRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
private Logger myLogger = LoggerFactory.getLogger(MyCustomRequestMappingHandlerMapping.class);
public MyCustomRequestMappingHandlerMapping() {
super();
}
@Override
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
// find the class declaring this method
Class<?> beanType = method.getDeclaringClass();
// check for the My rest controller annotation
MyRestController myRestAnnotation = beanType.getAnnotation(MyRestController.class);
if (myRestAnnotation != null) {
// this is a My annotated rest service, lets modify the URL mapping
PatternsRequestCondition oldPattern = mapping.getPatternsCondition();
// create a pattern such as /api/v${apiVersion}/${resourceName}
String urlPattern = String.format("/api/v%d/%s",
myRestAnnotation.apiVersion(),
myRestAnnotation.resourceName());
// create a new condition
PatternsRequestCondition apiPattern =
new PatternsRequestCondition(urlPattern);
// ask our condition to be the core, but import all settinsg from the old
// pattern
PatternsRequestCondition updatedFinalPattern = apiPattern.combine(oldPattern);
myLogger.info("re-writing mapping for {}, myRestAnnotation={}, original={}, final={}",
beanType, myRestAnnotation, oldPattern, updatedFinalPattern);
mapping = new RequestMappingInfo(
mapping.getName(),
updatedFinalPattern,
mapping.getMethodsCondition(),
mapping.getParamsCondition(),
mapping.getHeadersCondition(),
mapping.getConsumesCondition(),
mapping.getProducesCondition(),
mapping.getCustomCondition()
);
}
super.registerHandlerMethod(handler, method, mapping);
}
}
Ответ 4
Немного менее подробное решение, которое не дублирует логику проверки аннотации, а только изменяет путь отображения:
private static final String API_PREFIX = "api";
@Bean
WebMvcRegistrationsAdapter restPrefixAppender() {
return new WebMvcRegistrationsAdapter() {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new RequestMappingHandlerMapping() {
@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo mappingForMethod = super.getMappingForMethod(method, handlerType);
if (mappingForMethod != null) {
return RequestMappingInfo.paths(API_PREFIX).build().combine(mappingForMethod);
} else {
return null;
}
}
};
}
};
}
Побочные эффекты
Контроллер ошибок также будет отображаться в /api/error, что прерывает обработку ошибок (DispatcherServlet будет по-прежнему перенаправлять ошибки в/без префикса!).
Возможным решением является путь пропуска/ошибки при добавлении/api-префикса в вышеприведенный код (еще один "если" ).
Ответ 5
Также вы можете достичь того же результата, настроив WebMVC следующим образом:
@Configuration
public class PluginConfig implements WebMvcConfigurer {
public static final String PREFIX = "/myprefix";
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.addPathPrefix(PREFIX, c -> c.isAnnotationPresent(MyCistomAnnotation.class));
}
}
-
WebMvcConfigurer
в любом классе @Configuration
. - Переопределите метод
configurePathMatch
. - С
PathMatchConfigurer
вы можете сделать много полезных вещей, например добавить префикс для нескольких классов, которые удовлетворяют условиям предиката.