Como definir o url básico para descanso na bota primavera

118

Estou tentando misturar mvc e descanso em um único projeto de inicialização de mola.

Quero definir o caminho base para todos os controladores de resto (por exemplo, example.com/api) em um único lugar (não quero anotar cada controlador @RequestMapping('api/products'), em vez disso, apenas @RequestMapping('/products').

Os controladores Mvc devem ser acessados ​​por example.com/whatever

É possível?

(Eu não uso o descanso de dados da primavera, apenas o mvc da primavera)

Teimuraz
fonte
server.servlet.contextPath = / api
Daniel T. Sobrosa
spring boot versão 2.1.4.RELEASE, spring.mvc.servlet.path = / api e server.servlet.context-path = / api, ambos funcionam
Prayag Sharma
A solução server.servlet.context-path = / api é para APLICATIVO, não apenas para REST. É válido também para serviços SOAP. Se você quiser separar o caminho dos serviços SOAP e REST, deve usar @RequestMapping ('api / ...') ... medium.com/@bm.celalkartal/…
bmck

Respostas:

89

Com Spring Boot 1.2+ (<2.0), tudo o que é necessário é uma única propriedade em application.properties:

spring.data.rest.basePath=/api

link de referência: https://docs.spring.io/spring-data/rest/docs/current/reference/html/#getting-started.changing-base-uri

Para 2.x, use

server.servlet.context-path=/api
Suroj
fonte
4
Esta é a resposta exata que Thorinkor deu.
Jean-François Beauchef
8
Obrigado, mas isso não funciona para mim no Spring Boot versão v1.5.7.RELEASE. A outra resposta server.contextPath = / api funcionou
Jay
10
@Suroj Essa solução funciona apenas com controladores anotados RepositoryRestController, não com RestController ...
Nano
jira.spring.io/browse/DATAREST-1211 Este tíquete Jira menciona ser "spring.data.rest.base-path for Spring Boot 2.0.0". Infelizmente, ambos não funcionam para mim.
Carsten Hagemann
6
para SB 2+ é server.servlet.context-path = / url
vicky
95

Um pouco tarde, mas a mesma pergunta me trouxe aqui antes de chegar a resposta, então eu a posto aqui. Crie (se ainda não tiver) um application.properties e adicione

server.contextPath=/api

Então, no exemplo anterior, se você tiver um RestController com @RequestMapping("/test")você irá acessá-lo comolocalhost:8080/api/test/{your_rest_method}

fonte da pergunta: como faço para escolher o url para meu webapp de boot do Spring

OriolBG
fonte
19
Como você aplica isso para funcionar apenas com RestControllers e acessar os controladores normais sem o "/ api"
Siya Sosibo
@Stoan Eu encontrei a solução, verifique minha resposta :-)
kravemir
Não faça isso! Veja a resposta de Thorinkor.
Stefan,
A resposta de Thorinkor é especificamente para Spring Data REST.
8
server.contextPath agora está obsoleto, use server.servlet.context-path em vez
DS.
46

Para a versão do framework de boot de primavera 2.0.4.RELEASE+. Adicione esta linha aapplication.properties

server.servlet.context-path=/api
shellhub
fonte
1
Isso também afeta a pasta pública :-(
Michel,
5
esta é a resposta correta para o Spring boot 2+. spring.data.rest.basePathnão funciona para o Spring boot 2
jackycflau
27

Uma vez que esta é a primeira resposta do Google para o problema e presumo que mais pessoas pesquisarão por isso. Existe uma nova opção desde o Spring Boot '1.4.0'. Agora é possível definir um RequestMappingHandlerMapping personalizado que permite definir um caminho diferente para as classes anotadas com @RestController

Uma versão diferente com anotações personalizadas que combina @RestController com @RequestMapping pode ser encontrada nesta postagem do blog

@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);
                    }
                };
            }
        };
    }
}
mh-dev
fonte
2
No Spring Boot 2.0.0+, trabalhe diretamente na interface WebMvcRegistrations. WebMvcRegistrationsAdapter foi removido em favor da adição de métodos padrão à interface.
The Gilbert Arenas Dagger
27

Eu não conseguia acreditar como a resposta a esta pergunta aparentemente simples é complicada. Aqui estão algumas referências:

Existem muitas coisas diferentes a serem consideradas:

  1. Ao definir server.context-path=/apiem, application.propertiesvocê pode configurar um prefixo para tudo . (Seu server.context-path não server.contextPath!)
  2. Controladores Spring Data anotados com @RepositoryRestController que expõem um repositório como ponto final de descanso usarão a variável de ambiente spring.data.rest.base-pathem application.properties. Mas o plain @RestControllernão vai levar isso em conta. De acordo com a documentação do Spring Data Rest, há uma anotação @BasePathAwareControllerque você pode usar para isso. Mas eu tenho problemas em conexão com o Spring-security quando tento proteger esse controlador. Não foi mais encontrado.

Outra solução alternativa é um truque simples. Você não pode prefixar uma String estática em uma anotação, mas pode usar expressões como esta:

@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\"}";
  }
}
Robert
fonte
Como você colocaria no Annotation?
Teimuraz
2
meh, então você sempre deve se lembrar de adicionar este prefixo cada vez que criar um novo controlador
The Gilbert Arenas Dagger
13

Para Boot 2.0.0+ isso funciona para mim: server.servlet.context-path = / api

Juan Carlos Vergara Santos
fonte
4
Ao que parece, isso colocava tudo em / api, não apenas os mapeadores @RestController. Mas obrigado mesmo assim. Suas informações ainda são úteis.
oito de
9

Eu encontrei uma solução limpa, que afeta apenas os controladores de descanso.

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

O Spring boot registrará dois servlets dispatcher - padrão dispatcherServletpara controladores e restApidispatcher para @RestControllersdefinidos em 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 [/]

O exemplo 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>

Mas você não está limitado a :

  • usar XmlWebApplicationContext, você pode usar qualquer outro tipo de contexto disponível, ou seja, AnnotationConfigWebApplicationContext, GenericWebApplicationContext, GroovyWebApplicationContext, ...
  • definir jsonMessageConverter, messageConvertersfeijão no contexto de repouso, eles podem ser definidos no contexto pai
kravemir
fonte
É possível fazer isso programaticamente sem usar o xml?
Arian
@ArianHosseinzadeh Sim. É possível fazer isso de forma programática. Existem muitas maneiras de configurar o contexto da primavera. No exemplo, mostrei como criar contexto filho para manipulação da API REST. Apenas aprenda como configurar o contexto em Java e, em seguida, combine esse conhecimento com o conhecimento nesta resposta. Isso se chama programação.
kravemir
7

Você pode criar uma anotação personalizada para seus controladores:

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

Use-o em vez do @RestController usual em suas classes de controlador e anote métodos com @RequestMapping.

Acabei de testar - funciona no Spring 4.2!

Ilya Novoseltsev
fonte
Obrigado. Eu tentei isso. Mas agora eu tenho que anotar cada método com @RequestMapping ("/ products"), @RequestMapping ("/ products / {id}"). Em vez disso, preciso anotar o controlador com @RequestMapping ("/ products") e métodos com @RequestMapping, @RequestMapping ("/: id"). E o controlador de produtos deve estar acessível em api / products (por exemplo, definir o prefixo api em um único lugar)
Teimuraz
2
Nesse caso, não, não há solução fora da caixa, AFAIK. Você pode tentar implementar o seu próprio RequestMappingHandlerMapping. Spring Data REST tem um mapeador semelhante ao que você precisa - BasePathAwareHandlerMapping.
Ilya Novoseltsev,
@moreo, você encontrou uma solução adequada? Eu ficaria feliz se você pudesse postar como uma resposta. eu tenho o mesmo requisito aqui.
fischermatte
@fischermatte, Não, não encontrei exatamente o que queria, coloco @RequestMapping ("/ api / products") ou @RequestMapping ("/ api / users") antes de cada classe de controlador e, em seguida, antes do método apenas outro @ RequestMapping ("/ {id}"). Mas eu não acho que isso seja um grande problema, se eu quiser mudar "api" para alguma coisa, vou mudá-la apenas no início de cada aula.
Teimuraz
@IlyaNovoseltsev Há uma solução, veja minha resposta :-)
kravemir
7

Posso chegar um pouco tarde, MAS ... acredito que seja a melhor solução. Configure-o em seu application.yml (ou arquivo de configuração analógico):

spring:
    data:
        rest:
            basePath: /api

Como posso me lembrar, é isso - todos os seus repositórios serão expostos abaixo deste URI.

Thorinkor
fonte
Você pode explicar isso um pouco ou apontar para uma documentação relevante?
Dmitry Serdiuk
1
Os documentos relevantes estão em docs.spring.io/spring-data/rest/docs/current/reference/html/… .
bruce szalwinski
11
a variável de ambiente spring.data.rest.base-path afeta apenas spring-data-rest e spring-hateoas. O @RestController simples ainda ficará na raiz!
Robert
4
@thorinkor com base no que você está dizendo que na maioria dos casos as pessoas construirão repositórios REST do Spring Data? E o OP está dizendo claramente que ele tem controladores de descanso ...
Jean-François Beauchef
1
Acho que só funcionará se você estiver usando SpringDataRest.
Jaumzera
6

Tente usar um PathMatchConfigurer (Spring Boot 2.x):

@Configuration
public class WebMvcConfig implements WebMvcConfigurer  {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.addPathPrefix("api", HandlerTypePredicate.forAnnotation(RestController.class));
    }
}
Harald Wendel
fonte
1
Obrigado, isso era exatamente o que eu estava procurando! Isso permite que você defina um elemento de caminho de contexto para todos os RestControllers configurados por meio deste WebMvcConfig, semelhante ao que spring.data.rest.base-path faz.
Buurman
Sua resposta está correta em @HaraldWendel: +1: Você poderia melhorar um pouco mais expandindo-o um pouco, como explicar o que seu código faz exatamente (como tentei fazer em meu comentário) e / ou talvez link para algum javadoc ou documentação que descreve esse uso.
Buurman
Esta é a única solução que funcionou para mim, pois estou usando interfaces de controlador
Anatoly Yakimchuk
4

Você pode criar uma classe base com @RequestMapping("rest")anotações e estender todas as outras classes com esta classe base.

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

Agora, todas as classes que estendem esta classe base estarão acessíveis em rest/**.

Saket Mehta
fonte
3
Esta não é a resposta correta, o usuário está se referindo à anotação do Controlador. Se você estender uma classe abstrata com uma anotação RequestMapping, e a nova classe também tiver um RequestMapping, este último substituirá o primeiro, não concatenará os dois.
Massimo
Você está ciente de que as anotações não são herdadas em java, a menos que tenha herdado uma metanotação? Verifique isto: stackoverflow.com/a/21409651 . E @RequestMapping não parece ter isso: docs.spring.io/spring-framework/docs/current/javadoc-api/org/…
Mashrur
3

Para quem usa a configuração YAML (application.yaml).

Nota : isso funciona apenas paraSpring Boot 2.x.x

server:
  servlet:
    contextPath: /api

Se você ainda está usando Spring Boot 1.x

server:
  contextPath: /api
Prasanth Rajendran
fonte
1

Com o spring-boot 2.x você pode configurar em application.properties:

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

server.servlet.context-path=/apiseria a solução, eu acho. Eu tive o mesmo problema e isso me resolveu. Eu usei server.context-path. No entanto, parecia estar obsoleto e descobri que server.servlet.context-pathagora resolve o problema. Outra solução alternativa que encontrei foi adicionar uma tag base às minhas páginas de front end (H5). Eu espero que isto ajude alguém lá fora.

Felicidades

Rahul Talreja
fonte
0

Esta solução se aplica se:

  1. Você quer prefixar, RestControllermas não Controller.
  2. Você não está usando 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);
        }
    }

    }

Isso é semelhante à solução postada por mh-dev, mas acho que é um pouco mais limpo e deve ser compatível com qualquer versão do Spring Boot 1.4.0+, incluindo 2.0.0+.

Adaga Gilbert Arenas
fonte
Se eu estiver usando Pageable em meu RestControler, api / something fornece nenhum construtor primário ou padrão encontrado para interface org.springframework.data.domain.Pageable
K. Ayoub
0

De acordo com os documentos REST do Spring Data , se estiver usando application.properties , use esta propriedade para definir seu caminho base:

spring.data.rest.basePath=/api

Mas observe que o Spring usa ligação relaxada , então esta variação pode ser usada:

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

... ou este se preferir:

spring.data.rest.base_path=/api

Se usar application.yml , você usaria dois pontos para separadores de chave:

spring:
  data:
    rest:
      basePath: /api

(Para referência, um tíquete relacionado foi criado em março de 2018 para esclarecer os documentos.)

J Woodchuck
fonte
0

funcionou server.contextPath = / path

Pravin
fonte
0

Você pode criar uma anotação personalizada para seus controladores:

Use-o em vez do @RestController usual em suas classes de controlador e anote métodos com @RequestMapping.

Funciona bem no Spring 4.2!

Prerit Neema
fonte