告别硬编码!Spring Boot 优雅实现 Controller 路径前缀统一管理

背景

最近我需要把几个独立的项目合并到一个项目中,每个项目都有自己的路径前缀。

最初的想法是在每个模块中定义一个路径前缀常量:

java 复制代码
public static final String PREFIX = "/api/user";

@RestController
@RequestMapping(PREFIX + "/profile")
public class UserProfileController {
    // ...
}

这种方式虽然能用,但总感觉不够优雅。既然 Spring 会扫描所有的 Controller,并将类和方法上的 @RequestMapping 进行合并,那必然有办法统一添加路径前缀。

功夫不负有心人,发现了 WebMvcConfigurer 这个宝藏。

解决方案

通过实现 WebMvcConfigurer 接口的 configurePathMatch 方法,可以优雅地为指定的 Controller 添加统一前缀。

基础用法

java 复制代码
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        // 为所有 @RestController 添加 /api 前缀
        configurer.addPathPrefix("/api",
            c -> c.isAnnotationPresent(RestController.class));
    }
}

这样,所有带有 @RestController 注解的类,其路径都会自动加上 /api 前缀。

按包名区分前缀

如果需要为不同模块添加不同的前缀,可以根据包名来区分:

java 复制代码
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.addPathPrefix("/api/user",
            c -> c.getPackageName().startsWith("com.example.user"));

        configurer.addPathPrefix("/api/order",
            c -> c.getPackageName().startsWith("com.example.order"));

        configurer.addPathPrefix("/api/product",
            c -> c.getPackageName().startsWith("com.example.product"));
    }
}

自定义注解方式

更灵活的做法是定义自己的注解:

java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@RestController
public @interface UserApi {
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@RestController
public @interface OrderApi {
}

然后在配置中使用:

java 复制代码
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.addPathPrefix("/api/user",
            c -> c.isAnnotationPresent(UserApi.class));

        configurer.addPathPrefix("/api/order",
            c -> c.isAnnotationPresent(OrderApi.class));
    }
}

Controller 中使用:

java 复制代码
@UserApi
@RequestMapping("/profile")
public class UserProfileController {

    @GetMapping("/{id}")
    public User getProfile(@PathVariable Long id) {
        // 实际路径: GET /api/user/profile/{id}
        return userService.findById(id);
    }
}

原理简析

PathMatchConfigurer.addPathPrefix() 方法接收两个参数:

  • prefix: 要添加的路径前缀
  • predicate: 一个 Predicate<Class<?>> 用于判断哪些 Controller 需要添加前缀

Spring MVC 在初始化时会遍历所有的 Controller,对于满足条件的 Controller,会将前缀与原有的 @RequestMapping 路径进行拼接。

注意事项

  1. Spring Boot 版本: 此方法在 Spring Boot 2.x 以上版本中均可使用
  2. 多个前缀匹配: 如果一个 Controller 同时满足多个前缀条件,会按配置顺序应用第一个匹配的前缀
  3. Swagger/OpenAPI: 使用此方式添加的前缀,Swagger 文档会自动识别,无需额外配置

总结

相比在每个 Controller 上手动拼接路径前缀,使用 WebMvcConfigurer.configurePathMatch() 的方式更加优雅:

  • 前缀配置集中管理
  • Controller 代码更简洁
  • 模块划分更清晰
  • 后期维护更方便
相关推荐
IvanCodes4 小时前
Python 数据处理(十三):JSON、CSV 与数据序列化
开发语言·python
Patrick在香港5 小时前
Claude 工具调用返回空:8 次失败里只有 1 次状态码不对,其余全带 200
爬虫·python·api·claude·香港
Web3&Basketball5 小时前
CRM Agent 后训练实战:3 倍更少错误
python·架构·大模型·agent·推理
Rain的Java大神之路6 小时前
如何快速上传10G文件
java·spring boot·redis·后端·mysql·spring cloud·面试
AIFQuant6 小时前
ETF行情API接入踩坑记:从报错到跑通的七个问题
python·金融·区块链·etf·基金
十二同学啊6 小时前
向量数据库:从核心原理到 RAG 与 Java 实战
数据库
蓝速科技7 小时前
会议室门牌公告通知发布选型与落地指南丨蓝速科技
大数据·运维·数据库·人工智能·科技
GPU实战笔记7 小时前
云端 Python 开发:JupyterLab 还是 VS Code Remote-SSH?
python·vs code·jupyterlab·remote-ssh·远程开发
狗狗狗狗狗乐啊8 小时前
搭一个 AI 对话工作台 AChat:从 0 到可用的完整记录(一)
python·react.js·ai编程
白猫不黑8 小时前
Python实现简易Web弱口令爆破与防护方案
python·web安全·计算机·网络安全·黑客·信息安全·渗透测试