Bagaimana cara mengatur url dasar untuk istirahat di musim semi boot?

118

Saya mencoba untuk mencampur MVC dan istirahat dalam satu proyek boot musim semi.

Saya ingin menetapkan jalur dasar untuk semua pengontrol lainnya (mis. Example.com/api) di satu tempat (saya tidak ingin membubuhi keterangan setiap pengontrol dengan @RequestMapping('api/products'), sebagai gantinya, hanya @RequestMapping('/products').

Pengontrol Mvc harus dapat diakses melalui example.com/whatever

Apa itu mungkin?

(Saya tidak menggunakan pegas data rest, hanya pegas mvc)

Teimuraz
sumber
server.servlet.contextPath = / api
Daniel T. Sobrosa
spring boot versi 2.1.4.RELEASE, spring.mvc.servlet.path = / api dan server.servlet.context-path = / api, keduanya berfungsi
Prayag Sharma
server.servlet.context-path = / solusi api adalah untuk APLIKASI, tidak hanya untuk REST. Ini juga berlaku untuk layanan SOAP. Jika Anda ingin memisahkan jalur layanan SOAP dan REST, Anda harus menggunakan @RequestMapping ('api / ...') ... medium.com/@bm.celalkartal/…
bmck

Jawaban:

89

Dengan Spring Boot 1.2+ (<2.0) yang dibutuhkan hanyalah satu properti di application.properties:

spring.data.rest.basePath=/api

tautan ref: https://docs.spring.io/spring-data/rest/docs/current/reference/html/#getting-started.changing-base-uri

Untuk 2.x, gunakan

server.servlet.context-path=/api
Suroj
sumber
4
Ini adalah jawaban yang tepat yang diberikan oleh thorinkor.
Jean-François Beauchef
8
Terima kasih, tapi ini tidak berhasil untuk saya di Spring Boot versi v1.5.7.RELEASE. Server jawaban lainnya.contextPath = / api berfungsi
Jay
10
@Suroj Solusi itu hanya berfungsi dengan pengontrol beranotasi RepositoryRestController, bukan dengan RestController ...
Nano
jira.spring.io/browse/DATAREST-1211 Tiket Jira ini menyebutkannya sebagai "spring.data.rest.base-path for Spring Boot 2.0.0". Sayangnya, keduanya tidak berhasil untuk saya.
Carsten Hagemann
6
untuk SB 2+ itu server.servlet.context-path = / url
vicky
96

Agak terlambat tetapi pertanyaan yang sama membawa saya ke sini sebelum mencapai jawabannya jadi saya mempostingnya di sini. Buat (jika Anda masih belum memilikinya) sebuah application.properties dan tambahkan

server.contextPath=/api

Jadi pada contoh sebelumnya jika Anda memiliki RestController dengan @RequestMapping("/test")Anda akan mengaksesnya sepertilocalhost:8080/api/test/{your_rest_method}

sumber pertanyaan: bagaimana cara memilih url untuk aplikasi web boot musim semi saya

OriolBG
sumber
19
Bagaimana Anda memaksakan ini untuk hanya bekerja dengan RestControllers dan mengakses Pengontrol normal tanpa "/ api"
Siya Sosibo
@Stoan Saya menemukan solusi, periksa jawaban saya :-)
kravemir
Jangan lakukan ini! Lihat jawaban thorinkor.
Stefan
Jawaban Thorinkor khusus untuk Spring Data REST.
8
server.contextPath sekarang tidak digunakan lagi, gunakan server.servlet.context-path
DS.
46

Untuk versi kerangka boot musim semi 2.0.4.RELEASE+. Tambahkan baris ini keapplication.properties

server.servlet.context-path=/api
shellhub.dll
sumber
1
Ini juga memengaruhi folder publik :-(
Michel
5
ini adalah jawaban yang benar untuk Spring boot 2+. spring.data.rest.basePathtidak bekerja untuk Spring boot 2
jackycflau
27

Karena ini adalah serangan Google pertama untuk masalah ini dan saya berasumsi lebih banyak orang akan mencari ini. Ada opsi baru sejak Spring Boot '1.4.0'. Sekarang dimungkinkan untuk menentukan RequestMappingHandlerMapping kustom yang memungkinkan untuk menentukan jalur berbeda untuk kelas yang dianotasi dengan @RestController

Versi berbeda dengan anotasi khusus yang menggabungkan @RestController dengan @RequestMapping dapat ditemukan di entri blog ini

@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
sumber
2
Di Spring Boot 2.0.0+, nonaktifkan antarmuka WebMvcRegistrations secara langsung. WebMvcRegistrationsAdapter telah dihapus untuk mendukung penambahan metode default ke antarmuka.
The Gilbert Arenas Dagger
27

Saya tidak percaya betapa rumitnya jawaban atas pertanyaan yang tampaknya sederhana ini. Berikut beberapa referensinya:

Ada banyak hal berbeda yang perlu dipertimbangkan:

  1. Dengan mengatur server.context-path=/apidi application.propertiesAnda dapat mengkonfigurasi awalan untuk semuanya . (Server.context-pathnya bukan server.contextPath!)
  2. Pengontrol Spring Data yang dianotasi dengan @RepositoryRestController yang mengekspos repositori sebagai endpoint lainnya akan menggunakan variabel lingkungan spring.data.rest.base-pathdi application.properties. Tapi jelas @RestControllertidak akan memperhitungkan ini. Menurut dokumentasi pegas data rest, ada anotasi @BasePathAwareControlleryang dapat Anda gunakan untuk itu. Tetapi saya memiliki masalah sehubungan dengan Spring-security ketika saya mencoba mengamankan pengontrol semacam itu. Itu tidak ditemukan lagi.

Solusi lain adalah trik sederhana. Anda tidak dapat memberi awalan String statis dalam anotasi, tetapi Anda dapat menggunakan ekspresi seperti ini:

@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
sumber
Bagaimana Anda memasukkan Annotation?
Teimuraz
2
meh, maka Anda harus selalu ingat untuk menambahkan awalan ini setiap kali Anda membuat pengontrol baru
The Gilbert Arenas Dagger
13

Untuk Boot 2.0.0+ ini berfungsi untuk saya: server.servlet.context-path = / api

Juan Carlos Vergara Santos
sumber
4
Tampaknya semuanya di bawah / api, tidak hanya pembuat peta @RestController. Tapi Terimakasih. Informasi Anda masih berguna.
eigil
9

Saya menemukan solusi bersih, yang hanya memengaruhi pengontrol istirahat.

@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 akan mendaftarkan dua servlet dispatcher - default dispatcherServletuntuk pengontrol, dan restApidispatcher untuk @RestControllersditentukan di 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 [/]

Contoh 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>

Tapi, Anda tidak terbatas pada :

  • gunakan XmlWebApplicationContext, Anda dapat menggunakan jenis konteks lain yang tersedia, yaitu. AnnotationConfigWebApplicationContext, GenericWebApplicationContext, GroovyWebApplicationContext, ...
  • mendefinisikan jsonMessageConverter, messageConverterskacang dalam konteks istirahat, mereka dapat didefinisikan dalam konteks induk
kravemir.dll
sumber
Apakah mungkin melakukan ini secara terprogram tanpa menggunakan xml?
Arian
@Arian_Arian Ya. Itu mungkin untuk melakukannya secara terprogram. Ada banyak cara untuk mengatur konteks pegas. Dalam contoh, saya telah menunjukkan cara membuat konteks anak untuk penanganan REST API. Pelajari saja cara mengatur konteks dalam Java, lalu gabungkan pengetahuan tersebut dengan pengetahuan dalam jawaban ini. Itu disebut pemrograman.
kravemir
7

Anda dapat membuat anotasi khusus untuk pengontrol Anda:

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

Gunakan ini sebagai ganti @RestController biasa pada kelas pengontrol Anda dan anotasi metode dengan @RequestMapping.

Baru saja diuji - berfungsi di Spring 4.2!

Ilya Novoseltsev
sumber
Terima kasih. Saya sudah mencoba ini. Tapi sekarang saya harus menganotasi setiap metode dengan @RequestMapping ("/ products"), @RequestMapping ("/ products / {id}"). Sebaliknya, saya perlu memberi anotasi Pengontrol dengan @RequestMapping ("/ products") dan metode dengan @RequestMapping, @RequestMapping ("/: id"). Dan pengontrol produk harus dapat diakses di api / produk (misalnya, setel awalan api di satu tempat)
Teimuraz
2
Dalam hal ini, tidak, tidak ada solusi di luar kotak, AFAIK. Anda dapat mencoba menerapkannya sendiri RequestMappingHandlerMapping. Spring Data REST memiliki mapper yang mirip dengan yang Anda butuhkan - BasePathAwareHandlerMapping.
Ilya Novoseltsev
@moreo, apakah Anda menemukan solusi yang tepat? Saya akan senang jika Anda dapat mempostingnya sebagai tanggapan. Saya memiliki persyaratan yang sama di sini.
fischermatte
@fischermatte, Tidak, saya tidak menemukan apa yang saya inginkan, saya menempatkan @RequestMapping ("/ api / products") atau @RequestMapping ("/ api / users") sebelum setiap kelas pengontrol dan kemudian, sebelum metode hanya @ RequestMapping ("/ {id}"). Tapi saya rasa ini bukan masalah besar, jika saya ingin mengubah "api" menjadi sesuatu, saya hanya akan mengubahnya di awal setiap kelas.
Teimuraz
@IlyaNovoseltsev Ada solusinya, lihat jawaban saya :-)
kravemir
7

Saya mungkin agak terlambat, TAPI ... Saya yakin ini adalah solusi terbaik. Siapkan di application.yml Anda (atau file konfigurasi analogis):

spring:
    data:
        rest:
            basePath: /api

Seperti yang saya ingat, itu saja - semua repositori Anda akan ditampilkan di bawah URI ini.

thorinkor
sumber
Bisakah Anda menjelaskan ini sedikit atau menunjuk ke dokumentasi yang relevan?
Dmitry Serdiuk
1
Dokumen yang relevan ada di docs.spring.io/spring-data/rest/docs/current/reference/html/… .
bruce szalwinski
11
variabel environment spring.data.rest.base-path hanya mempengaruhi spring-data-rest dan spring-hateoas. @RestController biasa akan tetap berada di root!
Robert
4
@thorinkor berdasarkan apa yang Anda katakan bahwa dalam kebanyakan kasus orang akan membangun repositori REST Data Musim Semi? Dan OP dengan jelas mengatakan dia memiliki pengontrol istirahat ...
Jean-François Beauchef
1
Saya pikir ini hanya akan berfungsi jika Anda menggunakan SpringDataRest.
Jaumzera
6

Coba gunakan 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
sumber
1
Terima kasih, inilah yang saya cari! Ini memungkinkan Anda menyetel elemen jalur konteks untuk semua RestControllers yang dikonfigurasi melalui WebMvcConfig ini, mirip dengan yang dilakukan spring.data.rest.base-path.
Buurman
Jawaban Anda tepat di @HaraldWendel: +1: Anda dapat meningkatkannya lagi dengan sedikit mengembangkannya, seperti menjelaskan apa yang sebenarnya dilakukan kode Anda (seperti yang saya coba lakukan dalam komentar saya) dan / atau mungkin menautkan ke beberapa javadoc atau dokumentasi yang menjelaskan penggunaan ini.
Buurman
Ini adalah satu-satunya solusi yang berhasil untuk saya karena saya menggunakan antarmuka pengontrol
Anatoly Yakimchuk
4

Anda dapat membuat kelas dasar dengan @RequestMapping("rest")penjelasan dan memperluas semua kelas lainnya dengan kelas dasar ini.

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

Sekarang semua kelas yang memperluas kelas dasar ini dapat diakses di rest/**.

Saket Mehta
sumber
3
Ini bukan jawaban yang benar, pengguna mengacu pada penjelasan Pengontrol. Jika Anda memperluas kelas abstrak dengan anotasi RequestMapping, dan kelas baru memiliki RequestMapping juga, yang terakhir ini akan menimpa yang pertama, itu tidak akan menggabungkan keduanya.
Massimo
Tahukah Anda bahwa anotasi tidak diwariskan di java kecuali jika ia mewarisi anotasi meta? Periksa ini: stackoverflow.com/a/21409651 . Dan @RequestMapping tampaknya tidak memiliki itu: docs.spring.io/spring-framework/docs/current/javadoc-api/org/…
Mashrur
3

Bagi mereka yang menggunakan konfigurasi YAML (application.yaml).

Catatan : ini hanya berfungsi untukSpring Boot 2.x.x

server:
  servlet:
    contextPath: /api

Jika Anda masih menggunakan Spring Boot 1.x

server:
  contextPath: /api
Prasanth Rajendran
sumber
1

Dengan spring-boot 2.x Anda dapat mengonfigurasi di application.properties:

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

server.servlet.context-path=/apiakan menjadi solusi yang saya kira. Saya memiliki masalah yang sama dan ini membuat saya terselesaikan. Saya menggunakan server.context-path. Namun, itu sepertinya sudah usang dan saya menemukan itu server.servlet.context-pathmenyelesaikan masalah sekarang. Solusi lain yang saya temukan adalah menambahkan tag dasar ke halaman ujung depan (H5) saya. Saya harap ini membantu seseorang di luar sana.

Bersulang

Rahul Talreja
sumber
0

Solusi ini berlaku jika:

  1. Anda ingin memberi awalan RestControllertetapi tidak Controller.
  2. Anda tidak menggunakan 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);
        }
    }

    }

Ini mirip dengan solusi yang diposting oleh mh-dev, tetapi menurut saya ini sedikit lebih bersih dan ini harus didukung pada versi apa pun dari Spring Boot 1.4.0+, termasuk 2.0.0+.

Belati Arena Gilbert
sumber
Jika saya menggunakan Pageable di RestControler saya, api / sesuatu memberi saya Tidak ada konstruktor utama atau default yang ditemukan untuk antarmuka org.springframework.data.domain.Pageable
K. Ayoub
0

Per dokumen REST Data Musim Semi , jika menggunakan application.properties , gunakan properti ini untuk menyetel jalur dasar Anda:

spring.data.rest.basePath=/api

Tetapi perhatikan bahwa Spring menggunakan ikatan santai , sehingga variasi ini dapat digunakan:

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

... atau yang ini jika Anda lebih suka:

spring.data.rest.base_path=/api

Jika menggunakan application.yml , Anda akan menggunakan titik dua untuk pemisah kunci:

spring:
  data:
    rest:
      basePath: /api

(Sebagai referensi, tiket terkait dibuat pada Maret 2018 untuk mengklarifikasi dokumen.)

J Woodchuck
sumber
0

server yang berfungsi.contextPath = / jalur

Pravin
sumber
0

Anda dapat membuat anotasi khusus untuk pengontrol Anda:

Gunakan ini sebagai ganti @RestController biasa pada kelas pengontrol Anda dan anotasi metode dengan @RequestMapping.

Berfungsi dengan baik di Spring 4.2!

Neema Prerit
sumber