网上的文章五花八门,不写SpringBoot的版本号,导致代码拿来主义不好使了。

本文采用的版本

SpringBoot 2.7.7Java 1.8

目录

    • 1、默认访问路径
    • 2、整个项目增加路由前缀
    • 3、通过注解方式增加路由前缀
    • 4、按照目录结构/包名添加前缀
    • 总结
    • 参考文章

1、默认访问路径

package com.example.demo.controller.api;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/api")public class AppIndexController {@GetMapping("/index")public String index() {return "app";}}

访问地址:http://localhost:8080/api/index

2、整个项目增加路由前缀

application.yml

server:servlet:context-path: /prefix

访问地址:http://localhost:8080/prefix/api/index

注意:该方案会将所有的路由都增加一个前缀

3、通过注解方式增加路由前缀

注解

package com.example.demo.annotation;import org.springframework.core.annotation.AliasFor;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RestController;import java.lang.annotation.*;/** * controller层统一使用该注解 */@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@RestControllerpublic @interface ApiRestController {/** * Alias for {@link Controller#value}. */@AliasFor(annotation = Controller.class)String value() default "";}

配置

package com.example.demo.config;import com.example.demo.annotation.ApiRestController;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/** * 配置统一的后台接口访问路径的前缀 */@Configurationpublic class CustomWebMvcConfig implements WebMvcConfigurer {@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {configurer.addPathPrefix("/api", c -> c.isAnnotationPresent(ApiRestController.class));}}

使用注解

package com.example.demo.controller.api;import com.example.demo.annotation.ApiRestController;import org.springframework.web.bind.annotation.GetMapping;@ApiRestController// @RestController// @RequestMapping("/api")public class AppIndexController {@GetMapping("/index")public String index() {return "app";}}

访问地址:http://localhost:8080/api/index

4、按照目录结构/包名添加前缀

没有成功,可能是版本的问题

按照网上的实现方式

// 核心代码RequestMappingInfo.paths(prefix).build().combine(mappingInfo);

会报错

Neither PathPatterns nor String patterns condition

2023年6月9日补充

感谢评论区的大佬 @孤独和弦 帮助,补充第四种方式

思路:

将原有路由的所有路径取出,手动拼接前缀,再和原有路由配置合并

项目结构

$ tree -I target -I test.├── pom.xml└── src└── main├── java│ └── com│ └── example│ └── demo│ ├── Application.java│ ├── config│ │ ├── AutoPrefixConfiguration.java│ │ └── AutoPrefixUrlMapping.java│ └── controller│ └── v1│ └── IndexController.java└── resources├── application.yml├── static└── templates

配置 application.yml

# 需要添加路径前缀的包名api-package: com.example.demo.controller

AutoPrefixUrlMapping.java

package com.example.demo.config;import org.springframework.beans.factory.annotation.Value;import org.springframework.web.servlet.mvc.method.RequestMappingInfo;import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;import java.lang.reflect.Method;import java.util.Objects;/** * 自动补全路由前缀处理类 */public class AutoPrefixUrlMapping extends RequestMappingHandlerMapping {/** * 读取基础包配置 */@Value("${api-package}")private String bathApiPackagePath;/** * 重写方法路由获取 * * @param method * @param handlerType * @return */@Overrideprotected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {RequestMappingInfo mappingInfo = super.getMappingForMethod(method, handlerType);if (Objects.nonNull(mappingInfo)) {String prefix = this.getPrefix(handlerType);if (prefix != null) {String[] paths = mappingInfo.getPatternValues().stream().map(path -> prefix + path).toArray(String[]::new);return mappingInfo.mutate().paths(paths).build();}}return mappingInfo;}/** * 获取方法路由前缀 * * @param handleType * @return */private String getPrefix(Class<?> handleType) {String packageName = handleType.getPackage().getName();// 如果包含指定的包则返回前缀if (packageName.startsWith(this.bathApiPackagePath)) {return packageName.substring(this.bathApiPackagePath.length()).replace(".", "/");} else {return null;}}}

AutoPrefixConfiguration.java

package com.example.demo.config;import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;import org.springframework.stereotype.Component;import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;/** * 自动补全路由前缀配置类 */@Componentpublic class AutoPrefixConfiguration implements WebMvcRegistrations {@Overridepublic RequestMappingHandlerMapping getRequestMappingHandlerMapping() {return new AutoPrefixUrlMapping();}}

控制器

package com.example.demo.controller.v1;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/api")public class IndexController {@GetMapping("/index")public String index() {return "Hello";}}

访问路径:http://localhost:8080/v1/api/index

总结

方 式适用范围
RequestMapping/PostMapping/GetMapping单个方法 或 单个类(多个方法)
自定义注解多个控制器(可以不同目录)
目录 / 包名 前缀多个控制器(同目录)
配置 context-path全局前缀

包名前缀只能是符合java包名规范的才可以,比如中划线就不行,需要修改代码自定义做映射

参考文章

  • SpringBoot2.x 给Controller的RequestMapping添加统一前缀
  • SpringBoot – 根据目录结构自动生成路由前缀