web-dev-qa-db-fra.com

Comment définir l'URL de base pour le repos dans les bottes de printemps?

J'essaie de mélanger du MVC et de rester dans un seul projet de bottes de printemps.

Je veux définir le chemin de base pour tous les contrôleurs de repos (par exemple, exemple.com/api)au même endroit (je ne veux pas annoter chaque contrôleur avec @RequestMapping('api/products'), mais plutôt @RequestMapping('/products').

Les contrôleurs MVC doivent être accessibles à example.com/whats

C'est possible?

(Je n'utilise pas le reste des données de printemps, juste le printemps mvc)

68
Teimuraz

Avec Spring Boot 1.2+, une seule propriété dans application.properties suffit:

spring.data.rest.basePath=/api

lien de référence: https://docs.spring.io/spring-data/rest/docs/current/reference/html/#getting-started.changing-base-uri

33
Suroj

Un peu en retard mais la même question m’a amené ici avant d’arriver à la réponse, je la poste donc ici . Créez (si vous ne l’avez pas encore) un application.properties et ajoutez

server.contextPath=/api

Ainsi, dans l'exemple précédent, si vous avez un RestController avec @RequestMapping("/test"), vous y accéderez comme localhost:8080/api/test/{your_rest_method}.

source de question: comment puis-je choisir l'URL pour mon webapp de démarrage de printemps

83
OriolBG

Je ne pouvais pas croire à quel point la réponse à cette question apparemment simple était compliquée. Voici quelques références:

Il y a beaucoup de choses différentes à considérer: 

  1. En définissantserver.context-path=/api dans application.properties, vous pouvez configurer un préfixe pour everything. (Son chemin.context-chemin n'est pas server.contextPath!)
  2. Les contrôleurs de données Spring annotés avec @RepositoryRestController qui exposent un référentiel en tant que noeud final repos utiliseront la variable d'environnement spring.data.rest.base-path dans application.properties. Mais @RestController ne tiendra pas compte de cela. Selon la documentation des données restantes spring , vous pouvez utiliser une annotation @BasePathAwareController pour cela. Mais j’ai des problèmes avec Spring-security lorsque j’essaie de sécuriser un tel contrôleur. Il n'est plus trouvé.

Une autre solution est un truc simple. Vous ne pouvez pas préfixer une chaîne statique dans une annotation, mais vous pouvez utiliser des expressions telles que:

@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\"}";
  }
}
21
Robert

Comme c'est le premier coup Google pour le problème et je suppose que plus de gens le rechercheront. Il y a une nouvelle option depuis Spring Boot '1.4.0' . Il est maintenant possible de définir un RequestMappingHandlerMapping personnalisé permettant de définir un chemin différent pour les classes annotées avec @RestController

Une version différente avec des annotations personnalisées combinant @RestController avec @RequestMapping est disponible à cet emplacement blog post

@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);
                    }
                };
            }
        };
    }
}
21
mh-dev

Pour la version du cadre de démarrage printanier 2.0.4.RELEASE+. Ajouter cette ligne à application.properties

server.servlet.context-path=/api
20
shellhub

Pour Boot 2.0.0+, cela fonctionne pour moi: server.servlet.context-path =/api

J'ai trouvé une solution propre, qui ne concerne que les contrôleurs de repos. 

@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 va enregistrer deux servlets de répartiteur - dispatcherServlet par défaut pour les contrôleurs et restApi dispatcher pour @RestControllers défini dans 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 [/]

L'exemple 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>

Mais vous êtes pas limité à:

  • utiliser XmlWebApplicationContext, vous pouvez utiliser tout autre type de contexte disponible, c'est-à-dire. AnnotationConfigWebApplicationContext, GenericWebApplicationContext, GroovyWebApplicationContext, ...
  • définir les beans jsonMessageConverter, messageConverters dans un contexte de repos, ils peuvent être définis dans un contexte parent
7
kravemir

Je pourrais être un peu en retard, MAIS ... Je pense que c'est la meilleure solution. Configurez-le dans votre application.yml (ou votre fichier de configuration analogique):

spring:
    data:
        rest:
            basePath: /api

Si je me souviens bien, tous vos dépôts seront exposés sous cet URI.

7
thorinkor

Vous pouvez créer une annotation personnalisée pour vos contrôleurs:

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

Utilisez-le à la place de @RestController habituel sur vos classes de contrôleur et annotez les méthodes avec @RequestMapping.

Vient de tester - fonctionne au printemps 4.2!

5
Ilya Novoseltsev

Vous pouvez créer une classe de base avec des annotations @RequestMapping("rest") et étendre toutes les autres classes avec cette classe de base.

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

Désormais, toutes les classes qui étendent cette classe de base seront accessibles à rest/**.

4
Saket Mehta

Avec spring-boot 2.x, vous pouvez configurer dans application.properties:

spring.mvc.servlet.path=/api
1
Bulgar Sadykov

serveur.contextPath travaillé =/chemin

0
Pravin

Données par printemps REST docs , si vous utilisez application.properties , utilisez cette propriété pour définir votre chemin de base:

spring.data.rest.basePath=/api

Mais notez que Spring utilisereliure détendue , cette variante peut donc être utilisée:

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

... ou celui-ci si vous préférez:

spring.data.rest.base_path=/api

Si vous utilisez application.yml , vous utiliseriez des deux points pour les séparateurs de clé:

spring:
  data:
    rest:
      basePath: /api

(Pour référence, un ticket associé a été créé en mars 2018 pour clarifier la documentation.)

0
J Woodchuck

Cette solution s'applique si:

  1. Vous voulez préfixer RestController mais pas Controller.
  2. Vous n'utilisez pas 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);
        }
    }
    

    }

Ceci est similaire à solution posté par mh-dev, mais je pense que c'est un peu plus propre et que cela devrait être supporté par toute version de Spring Boot 1.4.0+, y compris 2.0.0+.