# 资金服务平台 (FundPlatform) - 开发规范 > **文档版本**: v1.2 > **创建日期**: 2026-02-20 > **更新日期**: 2026-02-23 > **适用范围**: 本项目所有开发人员 --- ## 一、项目概述 资金服务平台是一套完整的公司项目资金管理解决方案,采用微服务架构,实现应收账款和项目支出的全流程跟踪与管理。 ### 1.1 技术栈 | 层级 | 技术选型 | |------|----------| | **应用框架** | Spring Boot 3.2 + Spring Cloud Alibaba | | **服务注册** | Nacos 3.x | | **数据库** | MySQL 8.0 | | **缓存** | Redis 7.x | | **ORM框架** | MyBatis-Plus 3.5 | | **API网关** | Spring Cloud Gateway | | **前端框架** | Vue 3 + TypeScript + Element Plus | | **移动端** | Vue 3 + Vite 5 + Vant 4 | ### 1.2 模块划分 | 模块 | 端口 | 说明 | |------|------|------| | fund-gateway | 8000 | API网关 | | fund-sys | 8100 | 系统管理服务 | | fund-cust | 8110 | 客户管理服务 | | fund-proj | 8120 | 项目管理服务 | | fund-req | 8130 | 需求工单服务 | | fund-exp | 8140 | 支出管理服务 | | fund-receipt | 8150 | 收款管理服务 | | fund-file | 8600 | 文件服务 | | fund-report | 8700 | 报表服务 | | fund-admin | 3000 | 管理后台前端 | | fund-mobile | - | 移动端H5 | --- ## 二、项目结构规范 ### 2.1 后端模块结构 ``` fund-xxx/ ├── src/main/java/com/fundplatform/xxx/ │ ├── XxxApplication.java # 启动类 │ ├── config/ # 配置类 │ ├── controller/ # 控制器层 │ ├── service/ # 服务层 │ │ └── impl/ # 服务实现 │ ├── mapper/ # MyBatis Mapper │ ├── entity/ # 实体类 │ ├── dto/ # 数据传输对象 │ ├── vo/ # 视图对象 │ └── enums/ # 枚举类 ├── src/main/resources/ │ ├── application.yml # 主配置 │ ├── application-docker.yml # Docker配置 │ └── logback-spring.xml # 日志配置 └── pom.xml ``` ### 2.2 公共模块 (fund-common) ``` fund-common/ ├── src/main/java/com/fundplatform/common/ │ ├── auth/ # 认证相关 │ ├── cache/ # 缓存服务 │ ├── config/ # 通用配置 │ ├── context/ # 上下文管理 │ ├── core/ # 核心类(Result, PageResult等) │ ├── exception/ # 异常处理 │ ├── feign/ # Feign拦截器 │ ├── loadbalancer/ # 负载均衡 │ ├── mybatis/ # MyBatis配置 │ ├── nacos/ # Nacos配置 │ └── web/ # Web拦截器 ``` ### 2.3 启动类配置 所有业务服务必须配置 `scanBasePackages`: ```java @SpringBootApplication(scanBasePackages = {"com.fundplatform.xxx", "com.fundplatform.common"}) @EnableDiscoveryClient public class XxxApplication { public static void main(String[] args) { SpringApplication.run(XxxApplication.class, args); } } ``` **注意**: Gateway 作为 WebFlux 应用,**不扫描** `fund-common` 的任何包,避免 Servlet 依赖冲突。 --- ## 三、命名规范 ### 3.1 包命名 - 全部小写 - 格式:`com.fundplatform.{模块名}.{层级}` ``` com.fundplatform.cust.controller com.fundplatform.cust.service com.fundplatform.cust.service.impl com.fundplatform.cust.mapper com.fundplatform.cust.entity com.fundplatform.cust.dto com.fundplatform.cust.vo ``` ### 3.2 类命名 | 类型 | 命名规则 | 示例 | |------|----------|------| | 实体类 | 名词,PascalCase | `Customer`, `Project` | | Controller | 名词 + Controller | `CustomerController` | | Service接口 | 名词 + Service | `CustomerService` | | Service实现 | 名词 + ServiceImpl | `CustomerServiceImpl` | | Mapper | 名词 + Mapper | `CustomerMapper` | | DTO | 动作 + 名词 + DTO | `CustomerCreateDTO`, `CustomerUpdateDTO` | | VO | 名词 + VO | `CustomerVO`, `ProjectVO` | | 配置类 | 功能 + Config | `RedisConfig`, `MybatisConfig` | ### 3.3 方法命名 | 操作 | Service方法 | Controller方法 | |------|-------------|----------------| | 创建 | `createXxx()` | `createXxx()` | | 更新 | `updateXxx()` | `updateXxx()` | | 删除 | `deleteXxx()` | `deleteXxx()` | | 查询单个 | `getXxxById()` | `getXxx()` | | 分页查询 | `pageXxxs()` | `pageXxxs()` | | 列表查询 | `listXxxs()` | `listXxxs()` | ### 3.4 数据库命名 - 表名:小写,下划线分隔,如 `customer`, `project_member` - 字段名:小写,下划线分隔,如 `customer_name`, `created_time` - 索引名:`idx_表名_字段名`,如 `idx_customer_status` - 主键:`表名_id`,如 `customer_id` --- ## 四、数据库设计规范 ### 4.1 必备字段 所有业务表必须包含以下审计字段: ```sql created_by BIGINT NOT NULL COMMENT '创建人ID', created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', updated_by BIGINT NOT NULL COMMENT '更新人ID', updated_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)' ``` ### 4.2 多租户字段 支持多租户的表必须包含: ```sql tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT '租户ID' ``` ### 4.3 主键策略 - 使用雪花算法(Snowflake)生成分布式ID - MyBatis-Plus配置:`@TableId(type = IdType.ASSIGN_ID)` ### 4.4 逻辑删除 - 统一使用 `deleted` 字段 - 0 = 未删除,1 = 已删除 - MyBatis-Plus配置:`@TableLogic` --- ## 五、API设计规范 ### 5.1 URL规范 ``` # 基础格式 /{模块}/api/v1/{资源}/{动作} # 示例 POST /sys/api/v1/auth/login # 登录 GET /cust/api/v1/customer/{id} # 查询客户 POST /cust/api/v1/customer # 创建客户 PUT /cust/api/v1/customer/{id} # 更新客户 DELETE /cust/api/v1/customer/{id} # 删除客户 GET /cust/api/v1/customer/page # 分页查询 ``` ### 5.2 HTTP方法 | 方法 | 用途 | 示例 | |------|------|------| | GET | 查询 | 查询客户列表、详情 | | POST | 创建 | 新增客户 | | PUT | 更新 | 修改客户信息 | | DELETE | 删除 | 删除客户 | ### 5.3 响应格式 统一使用 `Result` 包装: ```json { "code": 200, "message": "success", "data": { ... }, "success": true } ``` 错误响应: ```json { "code": 400, "message": "参数错误:客户名称不能为空", "data": null, "success": false } ``` ### 5.4 分页格式 ```json { "code": 200, "message": "success", "data": { "pageNum": 1, "pageSize": 10, "total": 100, "list": [ ... ] }, "success": true } ``` ### 5.5 状态码规范 | 状态码 | 说明 | |--------|------| | 200 | 成功 | | 400 | 参数错误 | | 401 | 未授权/Token无效 | | 403 | 权限不足 | | 404 | 资源不存在 | | 500 | 服务器内部错误 | --- ## 六、多租户规范 ### 6.1 租户ID传递 1. **前端请求**:Header 传递 `X-Tenant-Id` 2. **Gateway**:`TenantGatewayFilter` 提取并透传 3. **后端服务**:`TenantContextHolder` 存储到 ThreadLocal 4. **MyBatis拦截器**:自动注入 `tenant_id` 条件 ### 6.2 租户隔离 ```java // 自动注入 tenant_id @TableField(fill = FieldFill.INSERT) private Long tenantId; // MyBatis-Plus 元数据填充 public class TenantMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, "tenantId", Long.class, TenantContextHolder.getTenantId()); } } ``` ### 6.3 租户上下文 ```java // 获取当前租户ID Long tenantId = TenantContextHolder.getTenantId(); // 设置租户ID(通常由拦截器自动设置) TenantContextHolder.setTenantId(tenantId); // 清除上下文(请求结束时) TenantContextHolder.clear(); ``` --- ## 七、链路追踪规范 ### 7.1 TraceId 和 SpanId - **TraceId**:全链路唯一标识,32位UUID - **SpanId**:服务节点标识,16位UUID ### 7.2 日志格式 ``` %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId:-}][%X{spanId:-}] %-5level %logger{50} - %msg%n ``` 日志示例: ``` 2026-02-20 18:10:25.240 [http-nio-8100-exec-1] [a1b2c3d4e5f6...][1234567890abcdef] INFO c.f.c.controller.CustomerController - 查询客户列表 ``` ### 7.3 HTTP Header 透传 | Header | 说明 | |--------|------| | `X-Trace-Id` | 全链路追踪ID | | `X-Span-Id` | 当前服务SpanID | | `X-Source-Service` | 来源服务名 | | `X-Request-Time` | 请求发起时间戳 | | `X-Tenant-Id` | 租户ID | | `X-User-Id` | 用户ID | | `X-Username` | 用户名 | ### 7.4 响应头返回 API响应必须返回追踪信息: ``` X-Trace-Id: a1b2c3d4e5f67890a1b2c3d4e5f67890 X-Span-Id: 1234567890abcdef ``` --- ## 八、Token认证规范 ### 8.1 Token机制 采用 **UUID + Redis** 方案(非JWT): ```java // 生成Token String token = tokenService.generateToken(userId, username, tenantId); // Token存储到Redis Key: auth:token:{token} Value: TokenInfo(userId, username, tenantId, expireTime) TTL: 24小时 ``` ### 8.2 请求认证 ``` Authorization: Bearer {token} ``` ### 8.3 白名单路径 以下路径无需Token验证: ``` /sys/api/v1/auth/login /sys/api/v1/sys/health ``` --- ## 九、日志规范 ### 9.1 日志级别 | 级别 | 使用场景 | |------|----------| | ERROR | 异常、错误、需要立即处理的问题 | | WARN | 警告、潜在问题 | | INFO | 关键业务流程、重要操作 | | DEBUG | 调试信息、详细流程 | ### 9.2 日志文件 ``` logs/ ├── fund-xxx.log # 主日志 ├── fund-xxx/ │ ├── info.log # INFO级别日志 │ ├── error.log # ERROR级别日志 │ └── aop.log # API请求日志 ``` ### 9.3 API请求日志 通过AOP记录所有API请求: ```java @Around("execution(* com.fundplatform..controller..*(..))") public Object logApiRequest(ProceedingJoinPoint joinPoint) { // 记录:请求方法、参数、响应时间、结果状态 } ``` --- ## 十、异常处理规范 ### 10.1 统一异常处理 ```java @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(BusinessException.class) public Result handleBusinessException(BusinessException e) { return Result.error(e.getCode(), e.getMessage()); } @ExceptionHandler(Exception.class) public Result handleException(Exception e) { log.error("系统异常", e); return Result.error(500, "系统异常,请稍后重试"); } } ``` ### 10.2 业务异常 ```java public class BusinessException extends RuntimeException { private final int code; public BusinessException(String message) { super(message); this.code = 400; } public BusinessException(int code, String message) { super(message); this.code = code; } } ``` ### 10.3 异常使用 ```java // 参数校验 if (customerName == null || customerName.isEmpty()) { throw new BusinessException("客户名称不能为空"); } // 业务校验 Customer customer = customerMapper.selectById(id); if (customer == null) { throw new BusinessException(404, "客户不存在"); } ``` --- ## 十一、Git提交规范 ### 11.1 分支命名 ``` master # 主分支 develop # 开发分支 feature/xxx # 功能分支 bugfix/xxx # Bug修复分支 hotfix/xxx # 紧急修复分支 ``` ### 11.2 提交信息格式 ``` : ``` **type 类型**: | 类型 | 说明 | |------|------| | feat | 新功能 | | fix | Bug修复 | | docs | 文档更新 | | style | 代码格式调整 | | refactor | 重构 | | test | 测试相关 | | chore | 构建/工具相关 | **示例**: ``` feat: 新增客户管理分页查询接口 - 支持按客户名称模糊查询 - 支持按状态筛选 - 分页参数校验 ``` ``` fix: 修复Gateway路由配置错误 fund-cust 路由路径配置错误,修正为 /cust/** ``` --- ## 十二、代码规范 ### 12.1 Controller层 ```java @RestController @RequestMapping("/api/v1/customer") @RequiredArgsConstructor public class CustomerController { private final CustomerService customerService; @PostMapping public Result createCustomer(@Valid @RequestBody CustomerCreateDTO dto) { Long id = customerService.createCustomer(dto); return Result.success(id); } @GetMapping("/page") public Result> pageCustomers( @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize, @RequestParam(required = false) String keyword) { Page page = customerService.pageCustomers(pageNum, pageSize, keyword); return Result.success(PageResult.of(page)); } } ``` ### 12.2 Service层 ```java @Service @RequiredArgsConstructor public class CustomerServiceImpl implements CustomerService { private final CustomerMapper customerMapper; @Override @Transactional(rollbackFor = Exception.class) public Long createCustomer(CustomerCreateDTO dto) { // 1. 参数校验 // 2. 业务逻辑 // 3. 数据持久化 // 4. 返回结果 } } ``` ### 12.3 DTO/VO规范 ```java @Data public class CustomerCreateDTO { @NotBlank(message = "客户名称不能为空") @Size(max = 200, message = "客户名称最长200字符") private String customerName; @NotBlank(message = "联系人不能为空") private String contact; @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确") private String phone; } ``` --- ## 十三、配置规范 ### 13.1 配置文件分离架构 项目采用**统一配置 + 个性化配置**分离架构: ``` fundplatform/ ├── scripts/ │ └── env.properties # 统一配置(所有服务共用) ├── fund-sys/src/main/resources/ │ └── service.properties # 个性化配置(每服务独立) ├── fund-gateway/src/main/resources/ │ └── service.properties └── ...其他服务 ``` #### 13.1.1 统一配置 (env.properties) **位置**: `scripts/env.properties` **用途**: 所有服务共用的公共配置 **打包后**: `conf/env.properties` ```properties # ============================================ # 环境变量配置文件(所有服务共用) # ============================================ # Nacos配置 NACOS_SERVER_ADDR=localhost:8848 NACOS_NAMESPACE=fund-platform NACOS_GROUP=DEFAULT_GROUP NACOS_USERNAME=nacos NACOS_PASSWORD=nacos # Redis配置 REDIS_HOST=localhost REDIS_PORT=6379 REDIS_PASSWORD=zjf@123456 REDIS_DATABASE=0 REDIS_TIMEOUT=10000 REDIS_POOL_MAX_ACTIVE=8 REDIS_POOL_MAX_WAIT=-1 REDIS_POOL_MAX_IDLE=8 REDIS_POOL_MIN_IDLE=0 # Hikari连接池配置 HIKARI_MINIMUM_IDLE=5 HIKARI_CONNECTION_TIMEOUT=30000 # Sentinel配置(Gateway使用) SENTINEL_DASHBOARD=localhost:8080 SENTINEL_PORT=8719 # 网关限流配置 GATEWAY_RATE_LIMIT_REPLENISH_RATE=100 GATEWAY_RATE_LIMIT_BURST_CAPACITY=200 # 腾讯云COS配置(文件服务使用) COS_ENABLED=true COS_SECRET_ID=your-secret-id COS_SECRET_KEY=your-secret-key COS_BUCKET=your-bucket COS_REGION=ap-beijing # 文件上传配置 FILE_UPLOAD_MAX_SIZE=50MB FILE_UPLOAD_MAX_REQUEST_SIZE=100MB FILE_STORAGE_PATH=./uploads # 日志配置 LOG_PATH=/datacfs/applogs LOG_LEVEL_ROOT=INFO LOG_LEVEL_APP=DEBUG LOG_PATTERN=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId:-}][%X{spanId:-}] %-5level %logger{50} - %msg%n # 多租户路由配置 TENANT_ROUTING_ENABLED=true TENANT_HEADER=X-Tenant-Id DEFAULT_TENANT_ID=1 ``` #### 13.1.2 个性化配置 (service.properties) **位置**: 各服务 `src/main/resources/service.properties` **用途**: 服务独立的个性化配置 **打包后**: `conf/service.properties` ```properties # ============================================ # 服务个性化配置 # 此文件随服务打包,每个服务独立配置 # ============================================ # 服务名称 APP_NAME=fund-sys # 实例名称(多租户场景使用,默认与APP_NAME相同) # 多租户示例:fund-sys-shared, fund-sys-vip001 INSTANCE_NAME=${APP_NAME} # 租户标识(多租户场景使用,用于Nacos元数据路由) # 空值=共享实例,有值=VIP专属实例 TENANT_ID= # 服务端口(可覆盖application.yml中的配置) # SERVER_PORT=8100 ``` #### 13.1.3 配置加载顺序 启动脚本按以下顺序加载配置(后加载覆盖先加载): ```bash # 1. 加载统一配置 load_properties "${APP_HOME}/conf/env.properties" # 2. 加载个性化配置(覆盖同名参数) load_properties "${APP_HOME}/conf/service.properties" ``` ### 13.2 打包目录结构 使用Maven Assembly打包后的目录结构: ``` fund-sys/ # 服务根目录 ├── bin/ # 脚本目录 │ ├── start.sh # 启动脚本 │ ├── stop.sh # 停止脚本 │ ├── restart.sh # 重启脚本 │ └── status.sh # 状态查看脚本 ├── lib/ # 依赖JAR目录 │ └── fund-sys.jar # 服务JAR包 └── conf/ # 配置文件目录 ├── env.properties # 统一配置 ├── service.properties # 个性化配置 ├── application.yml # 主配置 ├── bootstrap.yml # 启动配置 └── logback-spring.xml # 日志配置 ``` ### 13.3 日志配置集中化 日志管理统一由 `logback-spring.xml` 控制,从环境变量读取配置: ```xml ``` **application.yml 中不再配置 logging 节点**,完全由 logback-spring.xml 管理。 ### 13.4 多租户部署配置 #### 13.4.1 共享实例配置 ```properties # service.properties APP_NAME=fund-sys INSTANCE_NAME=fund-sys TENANT_ID= # 空值表示共享实例 ``` #### 13.4.2 VIP专属实例配置 ```properties # service.properties APP_NAME=fund-sys INSTANCE_NAME=fund-sys-vip001 # 实例名称带租户标识 TENANT_ID=vip001 # 租户ID用于Nacos路由 ``` #### 13.4.3 多实例部署目录 ``` /opt/fundplatform/deploy/ ├── fund-sys/ # 共享实例 │ ├── bin/ │ ├── lib/ │ └── conf/ │ └── service.properties # INSTANCE_NAME=fund-sys, TENANT_ID= ├── fund-sys-vip001/ # VIP实例1 │ ├── bin/ │ ├── lib/ │ └── conf/ │ └── service.properties # INSTANCE_NAME=fund-sys-vip001, TENANT_ID=vip001 └── fund-sys-vip002/ # VIP实例2 └── ... ``` ### 13.5 Redis配置 所有服务统一使用 **database 0**: ```yaml spring: data: redis: host: localhost port: 6379 password: zjf@123456 database: 0 ``` ### 13.2 Nacos配置 ```yaml spring: cloud: nacos: discovery: server-addr: localhost:8848 namespace: fund-platform group: DEFAULT_GROUP username: nacos password: nacos ``` ### 13.3 日志配置 ```xml ./logs/${APP_NAME}/info.log ./logs/${APP_NAME}/info-%d{yyyy-MM-dd}.%i.log 100MB 30 ``` --- ## 十四、常见问题处理 ### 14.1 Bean名称冲突 多模块配置类避免冲突: ```java // 错误:多个模块都有 RedisConfig @Configuration public class RedisConfig { } // 正确:添加模块前缀 @Configuration public class GatewayRedisConfig { } // Gateway专用 ``` ### 14.2 WebFlux与Servlet冲突 Gateway作为WebFlux应用,不能使用Servlet API: ```java // 错误:Gateway中使用Servlet API public class TokenAuthFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response) { } } // 正确:Gateway使用WebFlux public class TokenAuthFilter implements GlobalFilter { public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { } } ``` ### 14.3 Nacos服务发现失败 确保pom.xml包含依赖: ```xml com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery ``` --- ## 十五、附录 ### 15.1 环境变量汇总 #### 统一配置变量 (env.properties) | 变量名 | 说明 | 默认值 | |--------|------|--------| | `NACOS_SERVER_ADDR` | Nacos服务地址 | localhost:8848 | | `NACOS_NAMESPACE` | Nacos命名空间 | fund-platform | | `NACOS_GROUP` | Nacos分组 | DEFAULT_GROUP | | `NACOS_USERNAME` | Nacos用户名 | nacos | | `NACOS_PASSWORD` | Nacos密码 | nacos | | `REDIS_HOST` | Redis地址 | localhost | | `REDIS_PORT` | Redis端口 | 6379 | | `REDIS_PASSWORD` | Redis密码 | zjf@123456 | | `REDIS_DATABASE` | Redis数据库 | 0 | | `LOG_PATH` | 日志路径 | /datacfs/applogs | | `LOG_LEVEL_ROOT` | 根日志级别 | INFO | | `LOG_LEVEL_APP` | 应用日志级别 | DEBUG | | `TENANT_ROUTING_ENABLED` | 多租户路由开关 | true | | `DEFAULT_TENANT_ID` | 默认租户ID | 1 | #### 个性化配置变量 (service.properties) | 变量名 | 说明 | 备注 | |--------|------|--------| | `APP_NAME` | 服务名称 | 对应JAR文件名 | | `INSTANCE_NAME` | 实例名称 | 多租户场景区分实例 | | `TENANT_ID` | 租户标识 | 空值=共享实例,有值=VIP实例 | | `SERVER_PORT` | 服务端口 | 可选,覆盖application.yml | ### 15.2 前端部署路径 前端项目采用 **Nginx 子路径部署** 模式: | 前端项目 | 部署路径 | 访问地址 | 说明 | |----------|----------|----------|------| | fund-admin | `/fadmin/` | `http://host/fadmin/` | 管理后台 | | fund-mobile | `/fmobile/` | `http://host/fmobile/` | 移动端H5 | | API网关 | `/fund/` | `http://host/fund/` | 后端API统一前缀 | **开发环境访问地址**: | 服务 | 地址 | |------|------| | 管理后台 | http://localhost:3000 | | 移动端H5 | http://localhost:8080 | | API网关 | http://localhost:8000 | | Nacos控制台 | http://localhost:8048/nacos | ### 15.3 默认账号 | 系统 | 用户名 | 密码 | |------|--------|------| | Nacos | nacos | nacos | | 管理后台 | admin | 123456 | --- **文档结束**