项目架构
Asone 是面向广告投放与渠道运营的一体化后台系统,由一个 Spring Boot 单体多模块后端、一个 UmiJS Max 前端、一个 XXL-JOB 调度中心组成,整体以 Docker 镜像交付,由 Nginx / OpenResty 统一反向代理。
整体拓扑
业务容器只绑定 127.0.0.1,不直接对外暴露端口;对外访问统一经过 OpenResty 的站点配置与证书。
运行时按层次自上而下依赖:
- 1使用者运营与管理员浏览器、开放 API 调用方
- 2接入层OpenResty 反向代理、HTTPS 证书、前端静态资源
- 3接口层asone-front 页面与后端 /api 控制器
- 4领域层advertisement · channel-report · iaa 业务模块
- 5内核层asone-server-system:鉴权、审批、通知、导出、通用配置
- 6基础设施MySQL、Redis、OSS、SMTP、XXL-JOB、渠道开放 API
后端:单体多模块
后端是一个进程、多个 Maven 模块。除 asone-server-boot 外,其它模块都不是可独立部署的服务。
| 模块 | 根包 | 职责 |
|---|---|---|
asone-server-system | com.qianxunclub.asone | 共享内核:登录鉴权、管理员 / 角色 / 菜单、审批、通知、导出、文件、系统配置、操作日志、第三方身份登录;同时提供全局配置与通用工具 |
asone-module-advertisement | com.qianxunclub.asone.advertisement | 广告主、渠道、产品、广告计划、点击日志、数据报表等广告投放分析能力 |
asone-module-channel-report | com.qianxunclub.asone.channelreport | 各渠道(Ad Manager、IDG、Adsentri、Alldata、泽耀等)日报 / 国家 / 单元 / 明细报表同步与查询 |
asone-module-iaa | com.qianxunclub.asone.iaa | IAA 客户、产品、ROAS 等变现数据分析 |
asone-server-boot | com.qianxunclub.asone | 唯一启动模块:启动类 AsoneServerApplication、全局 application.yml、logback.xml |
依赖方向:
三条硬约束:
- 业务模块之间不互相依赖,需要跨域复用的能力一律下沉到
asone-server-system。 - 新模块必须同时登记到父 POM 的
<modules>与<dependencyManagement>,并由asone-server-boot显式依赖,否则不会被启动。 - 每个模块自带
application-<模块后缀>.yml,通过asone-server-boot/src/main/resources/application.yml的spring.profiles.include装配(当前为system、channel-report)。
请求处理链路
一次前端请求在后端的流转路径固定,新增接口不需要自己写包装与异常处理:
要点:
GlobalResponseBodyAdvice会把业务对象包成Result;已是Result的返回值原样透传,两种写法都能工作,新接口优先直接返回业务对象。/v3/api-docs、/swagger-ui、/actuator、SSE、StreamingResponseBody一律透传不包装。- 错误码集中在
asone-server-system的constants/ResponseCodeEnum,业务异常抛configuration/BizException,不要在 Controller 里自己拼错误响应。 - 写操作统一加
@OperationLog(summaryTemplate用 SpEL 生成可读日志);需要被 API Key 调用的接口显式加@ApiKeyAllowed。
鉴权与授权模型
- 认证:Spring Security
SecurityFilterChain(@EnableWebSecurity+@EnableMethodSecurity),JWT 使用 HS512 多kid密钥集,口令散列走DelegatingPasswordEncoder("bcrypt")(cost 12)。 - 授权:接口侧用
hasAuthority('资源:动作'),读用xxx:read,写用xxx:manage并叠加@authenticationType.isSession(authentication),把写操作限制在真人会话内。 - 资源与菜单:
system_resource表驱动,role_scope决定该资源可否分配给普通角色(BUSINESS可分配,SYSTEM仅系统 / 超级管理员),沿菜单层级向下继承。 - 第三方身份登录(飞书 / 钉钉 / 企业微信 / OIDC / SAML)在
asone-server-system的identity包,配置方法见平台文档站的《第三方账号登录》。
数据访问
- MyBatis-Plus 3.5(
mybatis-plus-spring-boot4-starter+mybatis-plus-jsqlparser),依赖版本由父 POM import 的mybatis-plus-bom统一管理。 - Mapper 接口逐个标注
@Mapper(项目不使用@MapperScan),extends BaseMapper<T>;Service 继承 MyBatis-Plus 的ServiceImpl<M, E>。 - XML 放各模块
src/main/resources/mapper/,由 starter 默认扫描,YAML 中没有覆盖mapper-locations。 - 分页统一用
Page/IPage,插件配置在asone-server-system/.../configuration/MybatisPlusConfiguration.java:PaginationInnerInterceptor(DbType.MYSQL)+BlockAttackInnerInterceptor(拦截无 where 的全表更新删除)。 - 连接池 Druid;SQL 日志本地通过 p6spy 开关控制(
decorator.datasource.p6spy.enable-logging)。 - 没有自动迁移工具:表结构唯一来源是开发者文档站随附的 全量 DDL,由人工执行,详见数据库。
异步与调度
- Tomcat / MVC 运行在虚拟线程上(
spring.threads.virtual.enabled=true),异步请求不超时(spring.mvc.async.request-timeout=-1),由各自的SseEmitter控制生命周期。 - 定时任务全部走 XXL-JOB:执行器由
XxlJobExecutorConfiguration按xxl.job.executor.enabled条件装配,@XxlJobhandler 放在业务模块的task/包,任务参数通过XxlJobHelper.getJobParam()读取。本地 Profile 默认关闭执行器注册。 - 大批量导出走异步导出任务:业务模块实现
ExportTaskHandler,由asone-server-system的ExportTaskScheduler驱动,前端通过全局 Model 轮询进度。状态流转见图表语法的导出任务示例。
前端架构
- 框架:UmiJS Max(
@umijs/max4.7)+ React 19 + antd 6 + ProComponents,构建已启用utoopack。 - 路由:配置式,
config/routes.ts汇总展开config/routes/{advRoutes,iaaRoutes,systemRoutes,channelReportRoutes,approvalRoutes}.ts,按业务域一个文件。 - 菜单与权限:菜单可见性由后台「菜单管理」中的资源记录决定(
path必须与路由一致),路由过滤走src/access.ts的normalRouteFilter,按钮级判断走hasPermission/hasAnyPermission。 - 接口层:
src/services/asone-server/<域>/<controller>.ts,由pnpm openapi从后端/v3/api-docs/asone-server生成;页面只调用 service 函数,不直接发请求。 - 全局约定:
src/globalRequestConfig.ts处理ResponseStructure {success, code, message, data}、登录失效跳转、限流验证码与X-Locale请求头;src/app.tsx提供getInitialState(当前管理员、菜单与权限集合)。 - 国际化:
src/locales/{zh-CN,en-US},新增页面必须两侧同时补文案,pnpm i18n-check校验缺失。
多环境与配置装配
| 文件 | 作用 |
|---|---|
asone-server-boot/src/main/resources/application.yml | 端口 8001、profiles.include、虚拟线程、优雅停机、i18n basename、数据源 / Redis / 邮件、xxl.job.*、actuator |
asone-server-boot/src/main/resources/application-local.yml | 本地覆盖:立即停机、本地 MySQL、开启 p6spy SQL 日志、关闭 Sentry、关闭执行器注册 |
asone-server-system/src/main/resources/application-system.yml | security.permit-all-paths 等系统域配置 |
asone-module-channel-report/src/main/resources/application-channel-report.yml | channel-api.request-interval-millis 与各渠道 *-report.* 配置 |
asone-front/config/config.ts + config/proxy.ts | 前端构建与插件配置,按 UMI_ENV 选择代理 |
生产环境以 SPRING_PROFILES_ACTIVE=production 由镜像注入,密钥类配置应通过环境变量或部署平台外部配置提供,不落仓库。
