Как установить базовый URL для отдыха при весенней загрузке?


118

Я пытаюсь смешать mvc и отдых в одном проекте весенней загрузки.

Я хочу установить базовый путь для всех остальных контроллеров (например, example.com/api) в одном месте (я не хочу аннотировать каждый контроллер @RequestMapping('api/products'), вместо этого просто @RequestMapping('/products').

Контроллеры MVC должны быть доступны на example.com/whatever

Является ли это возможным?

(Я не использую Spring Data Rest, просто Spring mvc)



server.servlet.contextPath = / api
Дэниел Т. Соброса

версия весенней загрузки 2.1.4.RELEASE, spring.mvc.servlet.path = / api и server.servlet.context-path = / api, оба работают
Праяг Шарма

server.servlet.context-path = / api решение предназначено для ПРИЛОЖЕНИЯ, а не только для REST. Это также верно для сервисов SOAP. Если вы хотите , чтобы Sperate вашего SOAP и REST пути услуги, вы должны использовать @RequestMapping ( 'апи / ...') ... medium.com/@bm.celalkartal/...
bmck

Ответы:


89

С Spring Boot 1.2+ (<2.0) все, что требуется, - это одно свойство в application.properties:

spring.data.rest.basePath=/api

Ссылка для ссылки: https://docs.spring.io/spring-data/rest/docs/current/reference/html/#getting-started.changing-base-uri

Для 2.x используйте

server.servlet.context-path=/api

4
Это точный ответ, который дал торинкор.
Jean-François Beauchef 07

8
Спасибо, но у меня это не работает в версии Spring Boot v1.5.7.RELEASE. Другой ответ server.contextPath = / api сработал
Джей

10
@Suroj Это решение работает только с аннотированными контроллерами RepositoryRestController, а не с RestController ...
Nano

jira.spring.io/browse/DATAREST-1211 В этом билете Jira упоминается, что это «путь spring.data.rest.base для Spring Boot 2.0.0». К сожалению, оба варианта мне не подходят.
Carsten Hagemann

6
для SB 2+ это server.servlet.context-path = / url
vicky

96

Немного поздно, но тот же вопрос привел меня сюда, прежде чем я получил ответ, поэтому я публикую его здесь. Создайте (если у вас его еще нет) application.properties и добавьте

server.contextPath=/api

Итак, в предыдущем примере, если у вас есть RestController, @RequestMapping("/test")вы получите к нему доступ какlocalhost:8080/api/test/{your_rest_method}

источник вопроса: как мне выбрать URL-адрес для моего весеннего загрузочного веб-приложения


19
Как заставить это работать только с RestControllers и получать доступ к обычным контроллерам без "/ api"
Сия Сосибо

@Stoan Я нашел решение, проверьте мой ответ :-)
kravemir

Не делай этого! См. Ответ торинкора.
Стефан

Ответ Thorinkor предназначен специально для Spring Data REST.

8
server.contextPath теперь устарел, используйте вместо этого server.servlet.context-path
DS.

46

Для версии Spring boot framework 2.0.4.RELEASE+. Добавьте эту строку вapplication.properties

server.servlet.context-path=/api

1
Это также влияет на общую папку :-(
Мишель

5
это правильный ответ для Spring boot 2+. spring.data.rest.basePathне работает для Spring boot 2
jackycflau

27

Так как это первое обнаружение проблемы в Google, и я предполагаю, что больше людей будут ее искать. Начиная с Spring Boot 1.4.0 появилась новая опция. Теперь можно определить настраиваемый RequestMappingHandlerMapping, который позволяет определять другой путь для классов, аннотированных с помощью @RestController.

Другая версия с пользовательскими аннотациями, сочетающая @RestController с @RequestMapping, может быть найдена здесь. сообщении блога.

@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();
                        if (AnnotationUtils.findAnnotation(beanType, RestController.class) != 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);
                    }
                };
            }
        };
    }
}

2
В Spring Boot 2.0.0+ работайте напрямую с интерфейса WebMvcRegistrations. WebMvcRegistrationsAdapter был удален в пользу добавления методов по умолчанию в интерфейс.
Кинжал Гилберта Аренаса

27

Я не мог поверить, насколько сложен ответ на этот, казалось бы, простой вопрос. Вот несколько ссылок:

Есть много разных вещей, которые следует учитывать:

  1. Установив server.context-path=/apiв, application.propertiesвы можете настроить префикс для всего (его server.context-path, а не server.contextPath!)
  2. Контроллеры Spring Data, аннотированные @RepositoryRestController, которые предоставляют репозиторий в качестве конечной точки отдыха, будут использовать переменную среды spring.data.rest.base-path в application.properties. Но Плейн @RestControllerэто во внимание не примет. Согласно документации Spring data rest, есть аннотация, @BasePathAwareControllerкоторую вы можете использовать для этого. Но у меня действительно возникают проблемы с Spring-security, когда я пытаюсь защитить такой контроллер. Больше не найдено.

Другой обходной путь - простой трюк. Вы не можете использовать префикс статической String в аннотации, но можете использовать такие выражения:

@RestController
public class PingController {

  /**
   * Simple is alive test
   * @return <pre>{"Hello":"World"}</pre>
   */
  @RequestMapping("${spring.data.rest.base-path}/_ping")
  public String isAlive() {
    return "{\"Hello\":\"World\"}";
  }
}

Как бы вы поместили в аннотацию?
Теймураз

2
да, тогда вы всегда должны не забывать добавлять этот префикс каждый раз, когда создаете новый контроллер
Кинжал Гилберта Аренаса

13

Для Boot 2.0.0+ это работает для меня: server.servlet.context-path = / api


4
Кажется, что это поместило все в / api, а не только картографы @RestController. Но все равно спасибо. Ваша информация по-прежнему полезна.
eigil 05

9

Нашел чистое решение, которое затрагивает только остальные контроллеры.

@SpringBootApplication
public class WebApp extends SpringBootServletInitializer {

    @Autowired
    private ApplicationContext context;

    @Bean
    public ServletRegistrationBean restApi() {
        XmlWebApplicationContext applicationContext = new XmlWebApplicationContext();
        applicationContext.setParent(context);
        applicationContext.setConfigLocation("classpath:/META-INF/rest.xml");

        DispatcherServlet dispatcherServlet = new DispatcherServlet();
        dispatcherServlet.setApplicationContext(applicationContext);

        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet, "/rest/*");
        servletRegistrationBean.setName("restApi");

        return servletRegistrationBean;
    }

    static public void main(String[] args) throws Exception {
        SpringApplication.run(WebApp.class,args);
    }
}

Spring boot зарегистрирует два сервлета диспетчера - по умолчанию dispatcherServletдля контроллеров и restApiдиспетчер для @RestControllersопределенных в rest.xml:

2016-06-07 09:06:16.205  INFO 17270 --- [           main] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'restApi' to [/rest/*]
2016-06-07 09:06:16.206  INFO 17270 --- [           main] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]

Пример rest.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
  http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <context:component-scan base-package="org.example.web.rest"/>
    <mvc:annotation-driven/>

    <!-- Configure to plugin JSON as request and response in method handler -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="jsonMessageConverter"/>
            </list>
        </property>
    </bean>

    <!-- Configure bean to convert JSON to POJO and vice versa -->
    <bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
    </bean>
</beans>

Но вы не ограничены :

  • use XmlWebApplicationContext, вы можете использовать любой другой доступный тип контекста, т.е. AnnotationConfigWebApplicationContext, GenericWebApplicationContext, GroovyWebApplicationContext, ...
  • определить jsonMessageConverter, messageConvertersbeans в контексте отдыха, они могут быть определены в родительском контексте

Можно ли сделать это программно без использования xml?
Ариан

@ArianHosseinzadeh Да. Это можно сделать программно. Есть много способов настроить контекст Spring. В этом примере я показал, как создать дочерний контекст для обработки REST API. Просто узнайте, как настроить контекст в Java, а затем объедините эти знания со знаниями в этом ответе. Это называется программированием.
Кравемир

7

Вы можете создать собственную аннотацию для своих контроллеров:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@RestController
@RequestMapping("/test")
public @interface MyRestController {
}

Используйте его вместо обычного @RestController в ваших классах контроллера и аннотируйте методы с помощью @RequestMapping.

Только что протестировал - работает в Spring 4.2!


Спасибо. Я пробовал это. Но теперь я должен аннотировать каждый метод с помощью @RequestMapping ("/ products"), @RequestMapping ("/ products / {id}"). Вместо этого мне нужно аннотировать Контроллер с помощью @RequestMapping ("/ products") и методов с помощью @RequestMapping, @RequestMapping ("/: id"). И контроллер продуктов должен быть доступен в api / products (например, установить префикс api в одном месте)
Теймураз

2
В таком случае нет, готового решения нет, AFAIK. Вы можете попробовать реализовать свой собственный RequestMappingHandlerMapping. Spring Data REST имеет сопоставитель, похожий на то, что вам нужно - BasePathAwareHandlerMapping.
Илья Новосельцев

@moreo, ты нашел подходящее решение? Буду рад, если вы разместите его в качестве ответа. У меня здесь то же самое требование.
fischermatte

@fischermatte, нет, я не нашел именно то, что хотел, я помещаю @RequestMapping ("/ api / products") или @RequestMapping ("/ api / users") перед каждым классом контроллера, а затем перед методом просто еще один @ RequestMapping ( "/ {ID}"). Но я не думаю, что это большая проблема, если я хочу что-то изменить "api", я просто изменю его в начале каждого класса.
Теймураз

@IlyaNovoseltsev Есть решение, см. Мой ответ :-)
kravemir 07

7

Я могу немного опоздать, НО ... Я считаю, что это лучшее решение. Настройте его в своем application.yml (или аналогичном файле конфигурации):

spring:
    data:
        rest:
            basePath: /api

Насколько я помню, это все - все ваши репозитории будут отображаться под этим URI.


Не могли бы вы немного объяснить это или указать на соответствующую документацию?
Дмитрий Сердюк

1
Соответствующие документы находятся по адресу docs.spring.io/spring-data/rest/docs/current/reference/html/… .
Брюс Сальвински

11
переменная environemnt spring.data.rest.base-path влияет только на spring-data-rest и spring-hateoas. Обычный @RestController по-прежнему будет находиться в корне!
Роберт

4
@thorinkor на основе того, что вы говорите, что в большинстве случаев люди будут создавать репозитории Spring Data REST? И ОП ясно говорит, что у него есть диспетчеры отдыха ...
Жан-Франсуа Бошф,

1
Я думаю, это будет работать, только если вы используете SpringDataRest.
Jaumzera 06

6

Попробуйте использовать PathMatchConfigurer (Spring Boot 2.x):

@Configuration
public class WebMvcConfig implements WebMvcConfigurer  {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.addPathPrefix("api", HandlerTypePredicate.forAnnotation(RestController.class));
    }
}

1
Спасибо, это именно то, что я искал! Это позволяет вам установить элемент контекстного пути для всех RestController, настроенных с помощью этого WebMvcConfig, аналогично тому, что делает spring.data.rest.base-path.
Buurman

Ваш ответ - место на @HaraldWendel: +1: Вы могли бы улучшить его еще немного, расширив его немного, например, объяснив, что именно делает ваш код (как я пытался сделать в своем комментарии) и / или, возможно, ссылку на некоторый javadoc или документация, описывающая это использование.
Buurman

Это единственное решение, которое сработало для меня, поскольку я использую интерфейсы контроллеров
Анатолий Якимчук

4

Вы можете создать базовый класс с @RequestMapping("rest")аннотациями и расширить все остальные классы этим базовым классом.

@RequestMapping("rest")
public abstract class BaseController {}

Теперь все классы, расширяющие этот базовый класс, будут доступны по адресу rest/**.


3
Это неправильный ответ, пользователь имеет в виду аннотацию контроллера. Если вы расширяете абстрактный класс с помощью аннотации RequestMapping, и новый класс также имеет RequestMapping, последний будет переопределять первый, он не будет объединять два.
Массимо

Знаете ли вы, что аннотации не наследуются в Java, если она не унаследовала мета-аннотацию? Проверьте это: stackoverflow.com/a/21409651 . И @RequestMapping, похоже, этого не имеет: docs.spring.io/spring-framework/docs/current/javadoc-api/org/…
Mashrur

3

Для тех, кто использует конфигурацию YAML (application.yaml).

Примечание : это работает только дляSpring Boot 2.x.x

server:
  servlet:
    contextPath: /api

Если вы все еще используете Spring Boot 1.x

server:
  contextPath: /api


1

server.servlet.context-path=/apiбыло бы решением, я думаю. У меня была такая же проблема, и это помогло мне решить. Я использовал server.context-path. Однако это казалось устаревшим, и я обнаружил, чтоserver.servlet.context-path теперь решает проблему. Еще один обходной путь, который я нашел, - это добавление базового тега к моим страницам внешнего интерфейса (H5). Надеюсь, это кому-то поможет.

ура


0

Это решение применимо, если:

  1. Вы хотите префикс, RestControllerно неController .
  2. Вы не используете Spring Data Rest.

    @Configuration
    public class WebConfig extends WebMvcConfigurationSupport {
    
    @Override
    protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
        return new ApiAwareRequestMappingHandlerMapping();
    }
    
    private static class ApiAwareRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
    
        private static final String API_PATH_PREFIX = "api";
    
        @Override
        protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
            Class<?> beanType = method.getDeclaringClass();
            if (AnnotationUtils.findAnnotation(beanType, RestController.class) != null) {
                PatternsRequestCondition apiPattern = new PatternsRequestCondition(API_PATH_PREFIX)
                        .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);
        }
    }

    }

Это похоже на решение, опубликованное mh-dev, но я думаю, что оно немного чище и должно поддерживаться в любой версии Spring Boot 1.4.0+, включая 2.0.0+.


Если я использую Pageable в своем RestControler, api / something не дает мне Основной или конструктор по умолчанию не найден для интерфейса org.springframework.data.domain.Pageable
К. Аюб

0

Per Spring Data REST документации , при использовании application.properties , использовать это свойство , чтобы установить базовый путь:

spring.data.rest.basePath=/api

Но обратите внимание, что Spring использует ослабленную привязку , поэтому можно использовать этот вариант:

spring.data.rest.base-path=/api

... или этот, если вы предпочитаете:

spring.data.rest.base_path=/api

Если вы используете application.yml , вы должны использовать двоеточия для разделителей ключей:

spring:
  data:
    rest:
      basePath: /api

(Для справки, в марте 2018 года был создан соответствующий тикет, чтобы прояснить документы.)



0

Вы можете создать собственную аннотацию для своих контроллеров:

Используйте его вместо обычного @RestController в ваших классах контроллера и аннотируйте методы с помощью @RequestMapping.

Прекрасно работает в Spring 4.2!

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.