วิธีตั้งค่า url ฐานสำหรับการพักในสปริงบูต?


118

ฉันกำลังพยายามผสม mvc และพักในโครงการสปริงบูตเดียว

ฉันต้องการกำหนดเส้นทางฐานสำหรับตัวควบคุมส่วนที่เหลือทั้งหมด (เช่น example.com/api) ในที่เดียว (ฉันไม่ต้องการใส่คำอธิบายประกอบแต่ละตัวควบคุมด้วย@RequestMapping('api/products')เพียงแค่@RequestMapping('/products').

ตัวควบคุม Mvc ควรเข้าถึงได้โดย example.com/whatever

เป็นไปได้ไหม?

(ฉันไม่ใช้สปริงข้อมูลเหลือแค่สปริง mvc)



server.servlet.contextPath = / api
Daniel T. Sobrosa

spring boot เวอร์ชัน 2.1.4.RELEASE, spring.mvc.servlet.path = / api และ server.servlet.context-path = / api ทั้งสองงาน
Prayag Sharma

โซลูชัน server.servlet.context-path = / api ใช้สำหรับ APPLICATION ไม่ใช่สำหรับ 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
นี่คือคำตอบที่แน่นอนที่ thorinkor ให้มา
Jean-François Beauchef

8
ขอบคุณ แต่นี่ใช้ไม่ได้สำหรับฉันใน Spring Boot เวอร์ชัน v1.5.7.RELEASE server.contextPath คำตอบอื่น ๆ = / API ทำงาน
เจ

10
@Suroj โซลูชันนั้นใช้ได้เฉพาะกับ RepositoryRestController ตัวควบคุมที่มีคำอธิบายประกอบไม่ใช่กับ RestController ...
Nano

jira.spring.io/browse/DATAREST-1211 Jira Ticket นี้ระบุว่าเป็น "spring.data.rest.base-path สำหรับ 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 สำหรับเว็บแอป spring boot ได้อย่างไร


19
คุณจะบังคับใช้สิ่งนี้ได้อย่างไรเพื่อให้ทำงานกับ RestControllers และเข้าถึง Controllers ปกติโดยไม่มี "/ api" ได้อย่างไร
Siya Sosibo

@Stoan ฉันพบวิธีแก้ปัญหาตรวจสอบคำตอบของฉัน :-)
kravemir

อย่าทำแบบนี้! ดูคำตอบของ thorinkor
Stefan

คำตอบของ 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ไม่ทำงานกับ 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 ถูกลบออกเพื่อเพิ่มวิธีการเริ่มต้นให้กับอินเทอร์เฟซ
The Gilbert Arenas Dagger

27

ฉันไม่อยากจะเชื่อเลยว่าคำตอบของคำถามง่ายๆที่ดูเหมือนจะซับซ้อนแค่ไหน นี่คือข้อมูลอ้างอิงบางส่วน:

มีหลายสิ่งที่แตกต่างกันที่ต้องพิจารณา:

  1. โดยการตั้งค่าserver.context-path=/apiในapplication.propertiesคุณสามารถกำหนดค่าคำนำหน้าสำหรับทุกสิ่ง (server.context-path ไม่ใช่ server.contextPath!)
  2. Spring Data controllers ที่ใส่คำอธิบายประกอบด้วย @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\"}";
  }
}

คุณจะใส่คำอธิบายประกอบอย่างไร?
Teimuraz

2
ฉันแล้วคุณต้องจำไว้เสมอว่าต้องเพิ่มคำนำหน้านี้ทุกครั้งที่คุณสร้างคอนโทรลเลอร์ใหม่
The Gilbert Arenas Dagger

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

Spring boot จะลงทะเบียนสอง servlets ตัวเลือกจ่าย - ค่าเริ่มต้น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
Arian

@ArianHosseinzadeh ค่ะ เป็นไปได้ที่จะทำแบบเป็นโปรแกรม มีหลายวิธีในการตั้งค่าบริบทสปริง ในตัวอย่างฉันได้แสดงวิธีสร้างบริบทลูกสำหรับการจัดการ REST API เพียงเรียนรู้วิธีตั้งค่าบริบทภายใน Java จากนั้นรวมความรู้ดังกล่าวเข้ากับความรู้ในคำตอบนี้ นั่นเรียกว่าการเขียนโปรแกรม
kravemir

7

คุณสามารถสร้างคำอธิบายประกอบแบบกำหนดเองสำหรับคอนโทรลเลอร์ของคุณ:

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

ใช้แทน @RestController ตามปกติในคลาสคอนโทรลเลอร์ของคุณและใส่คำอธิบายประกอบวิธีด้วย @RequestMapping

เพิ่งทดสอบ - ใช้งานได้ใน Spring 4.2!


ขอบคุณ. ฉันได้ลองสิ่งนี้แล้ว แต่ตอนนี้ฉันต้องใส่คำอธิบายประกอบแต่ละวิธีด้วย @RequestMapping ("/ products"), @RequestMapping ("/ products / {id}") ฉันต้องการคำอธิบายประกอบ Controller ที่มี @RequestMapping ("/ products") และวิธีการที่มี @RequestMapping, @RequestMapping ("/: id") แทน และตัวควบคุมผลิตภัณฑ์ควรเข้าถึงได้ที่ API / ผลิตภัณฑ์ (เช่นตั้งค่าคำนำหน้า api ในที่เดียว)
Teimuraz

2
ในกรณีนั้นไม่ไม่มีทางออกนอกกรอบ AFAIK RequestMappingHandlerMappingคุณสามารถลองการดำเนินการของคุณเอง ฤดูใบไม้ผลิข้อมูลส่วนที่เหลือมี mapper คล้ายกับสิ่งที่คุณต้องการ BasePathAwareHandlerMapping-
Ilya Novoseltsev

@moreo คุณพบวิธีแก้ปัญหาที่เหมาะสมแล้วหรือยัง? ฉันยินดีถ้าคุณสามารถโพสต์เป็นคำตอบได้ ฉันมีข้อกำหนดเดียวกันที่นี่
fischermatte

@fischermatte ไม่ฉันไม่พบสิ่งที่ต้องการฉันวาง @RequestMapping ("/ api / products") หรือ @RequestMapping ("/ api / users") ก่อนคลาสคอนโทรลเลอร์แต่ละคลาสก่อนที่จะใช้วิธีอื่น @ RequestMapping ( "/ {รหัส}") แต่ฉันไม่คิดว่านี่เป็นปัญหาใหญ่ถ้าฉันต้องการเปลี่ยน "api" เป็นบางอย่างฉันจะเปลี่ยนมันในตอนเริ่มต้นของแต่ละคลาส
Teimuraz

@IlyaNovoseltsev มีวิธีแก้ไขดูคำตอบของฉัน :-)
kravemir

7

ฉันอาจจะสายไปหน่อย แต่ ... ฉันเชื่อว่ามันเป็นทางออกที่ดีที่สุด ตั้งค่าใน application.yml ของคุณ (หรือไฟล์ config แบบอะนาล็อก):

spring:
    data:
        rest:
            basePath: /api

อย่างที่ฉันจำได้นั่นคือที่เก็บทั้งหมดของคุณจะถูกเปิดเผยภายใต้ URI นี้


คุณช่วยอธิบายเรื่องนี้เล็กน้อยหรือชี้ไปที่เอกสารที่เกี่ยวข้องได้ไหม
Dmitry Serdiuk

1
เอกสารที่เกี่ยวข้องที่มีความdocs.spring.io/spring-data/rest/docs/current/reference/html/...
bruce szalwinski

11
ตัวแปรสภาพแวดล้อม spring.data.rest.base-path มีผลเฉพาะกับสปริงข้อมูลพักและสปริงเกลียดชัง Plain @RestController จะยังคงนั่งอยู่ที่รูท!
Robert

4
@thorinkor จากสิ่งที่คุณพูดว่าในกรณีส่วนใหญ่ผู้คนจะสร้างที่เก็บข้อมูล Spring Data REST? และ OP ก็บอกชัดเจนว่าเขามีตัวควบคุมส่วนที่เหลือ ...
Jean-François Beauchef

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 ทำ
Buurman

คำตอบของคุณอยู่ที่ @HaraldWendel: +1: คุณสามารถปรับปรุงเพิ่มเติมได้โดยการขยายความเล็กน้อยเช่นอธิบายว่าโค้ดของคุณทำอะไรได้บ้าง (ตามที่ฉันพยายามทำในความคิดเห็นของฉัน) และ / หรืออาจจะเชื่อมโยงไปยัง javadoc หรือเอกสารประกอบที่อธิบายการใช้งานนี้
Buurman

นี่เป็นทางออกเดียวที่ใช้ได้ผลสำหรับฉันเพราะฉันใช้อินเทอร์เฟซคอนโทรลเลอร์
Anatoly Yakimchuk

4

คุณสามารถสร้างคลาสพื้นฐานพร้อม@RequestMapping("rest")คำอธิบายประกอบและขยายคลาสอื่น ๆ ทั้งหมดของคุณด้วยคลาสพื้นฐานนี้

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

rest/**ตอนนี้ทุกชั้นที่ขยายชั้นฐานนี้จะสามารถเข้าถึงได้


3
นี่ไม่ใช่คำตอบที่ถูกต้องผู้ใช้อ้างถึงคำอธิบายประกอบของคอนโทรลเลอร์ หากคุณขยายคลาสนามธรรมด้วยคำอธิบายประกอบ RequestMapping และคลาสใหม่ก็มี RequestMapping เช่นกันสุดท้ายนี้จะแทนที่คลาสแรกมันจะไม่เชื่อมทั้งสองเข้าด้วยกัน
Massimo

คุณทราบหรือไม่ว่าคำอธิบายประกอบจะไม่ได้รับการสืบทอดใน java เว้นแต่จะได้รับการสืบทอดคำอธิบายประกอบเมตา ตรวจสอบเรื่องนี้: stackoverflow.com/a/21409651 และดูเหมือนว่า@RequestMapping
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 หน้าได้
K. Ayoub

0

ต่อเอกสาร 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!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.