芋道框架 - 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.**'
相关推荐
Sirius.z1 天前
第R6周:LSTM实现糖尿病探索与预测
python
名字还没想好☜1 天前
Python f-string 进阶:数字格式化、对齐填充、调试 = 号与嵌套表达式
开发语言·数据库·python·字符串格式化·f-string
ltl1 天前
内核追踪:ftrace、kprobe、uprobe、tracepoint 生产实战
linux
·薯条大王1 天前
经济实惠玩云服务器|一台云服务器多人共用,子账号配置教程
java·linux·运维·服务器·汇编·c++·python
Dxy12393102161 天前
Python 如何使用 MySQL 的事务
python·mysql
ZJH__GO1 天前
网络编程v4pro--实现聊天室文件传输功能
java·服务器·网络·计算机网络
小小、码农1 天前
Linux进程控制:从fork到exec,手写一个简易Shell
linux·运维·服务器
程序员黑豆1 天前
Windows 系统 Java 环境变量配置全攻略:解决“不是内部或外部命令”
java·前端·ai编程
命运之光1 天前
【C语言完整代码】就诊信息管理系统
java·c语言·开发语言
凤山老林1 天前
Spring Boot @Async 线上实战:从默认配置到生产级线程池治理
java·spring boot·后端