Java:SpringBoot给Controller添加统一路由前缀
网上的文章五花八门,不写SpringBoot的版本号,导致代码拿来主义不好使了。
本文采用的版本
SpringBoot 2.7.7
Java 1.8
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
@RestController
public @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;
/**
* 配置统一的后台接口访问路径的前缀
*/
@Configuration
public class CustomWebMvcConfig implements WebMvcConfigurer {
@Override
public 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
*/
@Override
protected 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;
/**
* 自动补全路由前缀配置类
*/
@Component
public class AutoPrefixConfiguration implements WebMvcRegistrations {
@Override
public 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包名规范的才可以,比如中划线就不行,需要修改代码自定义做映射
参考文章
摘抄自网络,便于检索查找。