芋道框架 - API 前缀区分机制

问题背景

在芋道框架中,门户端和管理后台的 Controller 可能有相同的 @RequestMapping,例如都是 /zhiping/news/page,但实际访问路径却不同:

  • 管理后台:/admin-api/zhiping/news/page
  • 门户端:/app-api/zhiping/news/page

这是如何实现的?

核心机制

芋道框架通过 Controller 所在包路径 自动为接口添加不同的 URL 前缀。

1. 配置类 WebProperties.java

java 复制代码
@ConfigurationProperties(prefix = "yudao.web")
@Data
public class WebProperties {

    // 门户端 API 配置
    private Api appApi = new Api("/app-api", "**.controller.app.**");

    // 管理后台 API 配置
    private Api adminApi = new Api("/admin-api", "**.controller.admin.**");

    @Data
    public static class Api {
        /** URL 前缀 */
        private String prefix;
        /** Controller 所在包的 Ant 路径规则 */
        private String controller;
    }
}

2. 自动配置类 YudaoWebAutoConfiguration.java

java 复制代码
@Bean
public WebMvcRegistrations webMvcRegistrations(WebProperties webProperties) {
    return new WebMvcRegistrations() {
        @Override
        public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
            RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping();
            // 核心:设置路径前缀映射
            mapping.setPathPrefixes(buildPathPrefixes(webProperties));
            return mapping;
        }

        private Map<String, Predicate<Class<?>>> buildPathPrefixes(WebProperties webProperties) {
            Map<String, Predicate<Class<?>>> pathPrefixes = new LinkedHashMap<>();
            // 根据包路径匹配,自动添加前缀
            putPathPrefix(pathPrefixes, webProperties.getAdminApi());
            putPathPrefix(pathPrefixes, webProperties.getAppApi());
            return pathPrefixes;
        }

        private void putPathPrefix(Map<String, Predicate<Class<?>>> pathPrefixes,
                                   WebProperties.Api api, AntPathMatcher matcher) {
            pathPrefixes.put(api.getPrefix(),  // 前缀:/admin-api 或 /app-api
                clazz -> clazz.isAnnotationPresent(RestController.class)
                    && matcher.match(api.getController(), clazz.getPackage().getName()));
                    // 匹配:**.controller.admin.** 或 **.controller.app.**
        }
    };
}

目录结构规范

复制代码
yudao-module-zhiping/src/main/java/cn/iocoder/yudao/module/zhiping/controller/
├── admin/                          # 管理后台 Controller
│   └── news/
│       └── NewsController.java     # → /admin-api/zhiping/news/**
└── app/                            # 门户端 Controller
    └── news/
        └── AppNewsController.java  # → /app-api/zhiping/news/**

示例对比

管理后台 Controller

java 复制代码
// 包路径:cn.iocoder.yudao.module.zhiping.controller.admin.news
@RestController
@RequestMapping("/zhiping/news")
public class NewsController {
    // 实际 URL:/admin-api/zhiping/news/page
    @GetMapping("/page")
    public CommonResult<PageResult<NewsRespVO>> getPage(...) { }
}

门户端 Controller

java 复制代码
// 包路径:cn.iocoder.yudao.module.zhiping.controller.app.news
@RestController
@RequestMapping("/zhiping/news")
public class AppNewsController {
    // 实际 URL:/app-api/zhiping/news/page
    @GetMapping("/page")
    public CommonResult<PageResult<AppNewsRespVO>> getPage(...) { }
}

为什么要这样设计?

优点 说明
安全性 Nginx 只需转发 /admin-api/*/app-api/*,避免内部接口泄露
权限隔离 /admin-api 需要登录且有一定权限,/app-api 可以配置为 @PermitAll 允许匿名访问
代码复用 同一个模块可以同时提供管理端和门户端接口,复用 Service 层代码
Swagger 分组 可按前缀分组展示 API 文档

常见问题

Q1: 为什么我的接口没有前缀?

A: 检查 Controller 所在包路径是否正确:

  • 管理后台:必须包含 controller.admin
  • 门户端:必须包含 controller.app

Q2: 如何配置不需要前缀的接口?

A: 放在 controller 包下但不包含 adminapp 子包即可(不推荐)。

Q3: 前端请求应该用什么路径?

A:

  • 管理后台前端:/admin-api/模块/功能/操作
  • 门户前端:/app-api/模块/功能/操作

扩展:自定义前缀

如需修改默认前缀,在 application.yaml 中配置:

yaml 复制代码
yudao:
  web:
    admin-api:
      prefix: /admin-api
      controller: '**.controller.admin.**'
    app-api:
      prefix: /app-api
      controller: '**.controller.app.**'
相关推荐
2401_8920709812 小时前
【Linux C++ 日志系统实战】LogFile 日志文件管理核心:滚动策略、线程安全与方法全解析
linux·c++·日志系统·日志滚动
云烟成雨TD12 小时前
Spring AI Alibaba 1.x 系列【6】ReactAgent 同步执行 & 流式执行
java·人工智能·spring
Csvn12 小时前
🌟 LangChain 30 天保姆级教程 · Day 13|OutputParser 进阶!让 AI 输出自动转为结构化对象,并支持自动重试!
python·langchain
lwx91485212 小时前
Linux-Shell算术运算
linux·运维·服务器
于慨12 小时前
Lambda 表达式、方法引用(Method Reference)语法
java·前端·servlet
swg32132112 小时前
Spring Boot 3.X Oauth2 认证服务与资源服务
java·spring boot·后端
somi712 小时前
ARM-驱动-02-Linux 内核开发环境搭建与编译
linux·运维·arm开发
gelald12 小时前
SpringBoot - 自动配置原理
java·spring boot·后端
殷紫川12 小时前
深入理解 AQS:从架构到实现,解锁 Java 并发编程的核心密钥
java
一轮弯弯的明月12 小时前
贝尔数求集合划分方案总数
java·笔记·蓝桥杯·学习心得