芋道框架 - 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.**'
相关推荐
kcuwu.1 小时前
Python判断及循环
android·java·python
前进的李工2 小时前
LangChain使用之Model IO(提示词模版之ChatPromptTemplate)
java·前端·人工智能·python·langchain·大模型
Fairy要carry2 小时前
面试-Agent上下文过载、步骤混乱的问题
开发语言·python
ywf12152 小时前
Spring Integration + MQTT
java·后端·spring
liuyao_xianhui2 小时前
优选算法_两数之和_位运算_C++
java·开发语言·数据结构·c++·算法·链表·动态规划
今儿敲了吗2 小时前
python基础学习笔记第五章——容器
笔记·python·学习
李白的粉2 小时前
基于springboot的知识管理系统
java·spring boot·毕业设计·课程设计·知识管理系统·源代码
大傻^2 小时前
Spring AI 2.0 多模型提供商配置:OpenAI、Gemini、Anthropic 与 Ollama 深度集成
java·人工智能·spring·springai
爱丽_2 小时前
JVM 堆参数怎么设:先建立内存基线,再谈性能优化
java·jvm·性能优化