Як встановити базовий URL для відпочинку у весняному завантаженні?


118

Я намагаюся змішати mvc та відпочинок в одному проекті весняного завантаження.

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

Mvc-контролери повинні бути доступними через example.com/wever

Це можливо?

(Я не використовую дані для весняних даних, просто весняний mvc)



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

версія весняного завантаження 2.1.4.RELEASE, spring.mvc.servlet.path = / api та server.servlet.context-path = / api, обидві роботи
Prayag Sharma

server.servlet.context-path = / api рішення призначено для ЗАСТОСУВАННЯ, а не лише для REST. Він дійсний і для служб SOAP. Якщо ви хочете спрямувати свій шлях до SOAP та REST, вам слід скористатися @RequestMapping ('api / ...') ... 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
Це точна відповідь, яку дав торинкор.
Жан-Франсуа Бошоф

8
Дякую, але це не працює для мене у версії Spring Boot v1.5.7.RELEASE. Інший сервер відповідей.contextPath = / api працював
Jay

10
@Suroj Це рішення працює лише з контрольованими контролерами RepositoryRestController, а не з RestController ...
Нано,

jira.spring.io/browse/DATAREST-1211 Цей Білет Джира згадує, що це "spring.data.rest.base-path для весняного завантаження 2.0.0". На жаль, обидва не працюють для мене.
Карстен Хагеман

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"
Siya Sosibo

@Stoan Я знайшов рішення, перевір мою відповідь :-)
kravemir

Не робіть цього! Дивіться відповідь торінора.
Стефан

Відповідь Thorinkor спеціально для Spring Data REST.

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

46

Для версії рамки для весняного завантаження 2.0.4.RELEASE+. Додайте цей рядок доapplication.properties

server.servlet.context-path=/api

1
Це також впливає на загальнодоступну папку :-(
Michel

5
це правильна відповідь для Spring boot 2+. spring.data.rest.basePathне працює для весняного завантаження 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 not server.contextPath!)
  2. Веб-контролери даних, помічені за допомогою @RepositoryRestController, які виставляють сховище як кінцева точка спокою, використовуватимуть змінну середовища spring.data.rest.base-pathв application.properties. Але звичайна @RestControllerне враховує це. Відповідно до весняної документації щодо відпочинку даних є примітка, @BasePathAwareControllerяку ви можете використовувати для цього. Але у мене є проблеми у зв’язку із Spring-security, коли я намагаюся захистити такий контролер. Він більше не знайдений.

Ще одне вирішення - проста хитрість. Ви не можете перефіксувати статичний рядок в примітці, але ви можете використовувати такі вирази:

@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

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);
    }
}

Весняний завантажувач зареєструє два серветки диспетчера - за замовчуванням 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>

Але ви не обмежуєтесь :

  • використання XmlWebApplicationContext, ви можете використовувати будь-який інший доступний тип контексту, тобто AnnotationConfigWebApplicationContext, GenericWebApplicationContext, GroovyWebApplicationContext, ...
  • визначте jsonMessageConverter, messageConvertersквасоля в контексті спокою, вони можуть бути визначені в батьківському контексті

Чи можливо це зробити програмно без використання xml?
Аріан

@ArianHosseinzadeh Так. Це можна зробити програмно. Існує багато способів налаштування весняного контексту. У прикладі я показав, як створити дочірній контекст для обробки REST API. Просто дізнайтеся, як налаштувати контекст у Java, а потім поєднайте такі знання зі знаннями у цій відповіді. Це називається програмуванням.
kravemir

7

Ви можете створити власну примітку для своїх контролерів:

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

Використовуйте його замість звичного @RestController на класах контролерів та коментуйте методи за допомогою @RequestMapping.

Щойно перевірена - працює навесні 4.2!


Дякую. Я спробував це. Але тепер я повинен коментувати кожен метод за допомогою @RequestMapping ("/ products"), @RequestMapping ("/ products / {id}"). Натомість мені потрібен анотаційний контролер з @RequestMapping ("/ products") та методи з @RequestMapping, @RequestMapping ("/: id"). І контролер продуктів повинен бути доступним для api / products (наприклад, встановити префікс api в одному місці)
Teimuraz

2
У такому випадку, ні, рішення не існує, AFAIK. Ви можете спробувати реалізувати свій власний RequestMappingHandlerMapping. Spring Data REST має картограф, подібний до того, що вам потрібно - BasePathAwareHandlerMapping.
Ілля Новосельцев

@moreo, ти знайшов правильне рішення? Я буду радий, якщо ви можете опублікувати це як відповідь. я маю ту саму вимогу.
fischermatte

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

@IlyaNovoseltsev Є рішення, дивіться мою відповідь :-)
kravemir

7

Я можу трохи запізнитися, АЛЕ ... Я вважаю, що це найкраще рішення. Встановіть його у application.yml (або аналогічному конфігураційному файлі):

spring:
    data:
        rest:
            basePath: /api

Як я пам'ятаю, це все - всі ваші сховища будуть відкриті під цим URI.


Чи можете ви пояснити це трохи або вказати на документацію, що підлягає відновленню?
Дмитро Сердюк

1
Відповідні документи знаходяться на docs.spring.io/spring-data/rest/docs/current/reference/html/… .
bruce szalwinski

11
змінна навколишнє середовище spring.data.rest.base-path впливає лише на весну-відпочинок та весну-гетеоа. Простий @RestController все одно буде сидіти біля кореня!
Роберт

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

1
Я думаю, що це спрацює лише в тому випадку, якщо ви використовуєте SpringDataRest.
Jaumzera

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
Дякую, саме це я шукав! Це дозволяє встановити елемент контуру контексту для всіх RestControllers, налаштованих через цей WebMvcConfig, подібно до того, що робить spring.data.rest.base-path-path.
Бурман

Ваша відповідь є місцем на @HaraldWendel: +1: Ви можете ще більше попрацювати над цим, трохи розширивши його, як пояснити, що саме робить ваш код (як я намагався зробити у своєму коментарі) та / або, можливо, посилання на деякий javadoc або документація, яка описує це використання.
Бурман

Це єдине рішення, яке працювало для мене, коли я використовую інтерфейси контролера
Анатолій Якимчук

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 / щось дає мені Не знайдено основного конструктора або конструктора за замовчуванням для інтерфейсу org.springframework.data.domain.Pageable
K. Ayoub

0

Документи REST Data REST , якщо ви використовуєте application.properties , використовуйте це властивість для встановлення базового шляху:

spring.data.rest.basePath=/api

Але зауважте, що Весна використовує розслаблене зв’язування , тому цей варіант можна використовувати:

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

... або цей, якщо ви віддаєте перевагу:

spring.data.rest.base_path=/api

Якщо ви використовуєте application.yml , ви б використовували колонки для розділювачів ключів:

spring:
  data:
    rest:
      basePath: /api

(Для довідки, відповідний квиток був створений у березні 2018 року для уточнення документів.)



0

Ви можете створити власну примітку для своїх контролерів:

Використовуйте його замість звичного @RestController на класах контролерів та коментуйте методи за допомогою @RequestMapping.

Добре працює навесні 4.2!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.