# 艾灸椅管理后台 — 框架规范说明 > 本文档供 AI 写代码时遵循,描述框架封装位置和编码规范。 --- ## 一、项目结构 ``` openspec/ ├── backend/ 后端 Spring Boot 项目 └── frontend/ 前端 Vue3 项目 ``` --- ## 二、后端框架规范 ### 技术栈 - Java 1.8 + Spring Boot 2.7.18 - MyBatis Plus 3.5.3 - Redis(Spring Data Redis + Lettuce) - JWT(jjwt 0.9.1)+ FastJSON 1.2.83 ### 包结构 ``` com.aijiuyi.admin/ ├── AijiuyiAdminApplication.java 启动类 ├── common/ │ ├── annotation/ │ │ ├── Log.java 操作日志注解 │ │ └── NoAuth.java 免鉴权注解 │ ├── aspect/ │ │ └── LogAspect.java 日志 AOP 切面(拦截所有 Controller) │ ├── config/ │ │ ├── AsyncConfig.java 异步线程池配置 │ │ ├── AuthProperties.java 鉴权白名单配置属性 │ │ ├── MybatisPlusConfig.java MP 分页插件 │ │ ├── RedisConfig.java Redis 序列化配置 │ │ └── WebMvcConfig.java 拦截器 + 跨域配置 │ ├── constant/ │ │ └── ResultCode.java ★ 所有错误码和错误信息集中定义 │ ├── context/ │ │ └── RequestContext.java ThreadLocal(requestId/userId/userName) │ ├── entity/ │ │ ├── Result.java 统一接口返回对象 │ │ └── SysLog.java 操作日志实体 │ ├── enums/ │ │ └── OperationType.java 操作类型枚举(查询/新增/更新/删除/其他) │ ├── exception/ │ │ ├── BusinessException.java 业务异常类 │ │ └── GlobalExceptionHandler.java 全局异常处理器 │ ├── handler/ │ │ └── MyMetaObjectHandler.java MP 时间自动填充 │ ├── interceptor/ │ │ └── TokenInterceptor.java Token 鉴权拦截器 │ ├── service/ │ │ ├── SysLogService.java 日志 Service 接口 │ │ └── impl/SysLogServiceImpl.java 日志 Service 实现(异步保存) │ └── util/ │ ├── IpUtil.java IP 获取工具 │ ├── LogUtil.java ★ 统一日志工具(自动携带 requestId) │ ├── RedisUtil.java ★ Redis 统一操作工具 │ └── TokenUtil.java JWT Token 工具 ├── controller/ Controller 层(业务) │ ├── dto/ 请求参数 DTO │ └── AuthController.java 示例:认证接口 ├── entity/ 业务实体类 │ └── SysUser.java ├── mapper/ MyBatis Plus Mapper │ ├── SysLogMapper.java │ └── SysUserMapper.java └── service/ 业务 Service ├── SysUserService.java └── impl/SysUserServiceImpl.java ``` ### 配置文件 | 文件 | 说明 | |------|------| | `application.yml` | 共享配置:端口、Jackson、MyBatis Plus、鉴权白名单 | | `application-dev.yml` | 开发环境:DB、Redis、日志(DEBUG级别,打印SQL) | | `application-prod.yml` | 生产环境:DB、Redis、日志(INFO级别,不打印SQL) | 切换环境:修改 `application.yml` 中的 `spring.profiles.active` --- ### 规范一览 #### 1. 统一返回格式 所有 Controller 必须返回 `Result`,禁止直接返回业务对象。 ```java // ✅ 正确 return Result.success(data); return Result.error(ResultCode.USER_NOT_FOUND); // ❌ 错误 return user; ``` #### 2. 错误码管理 **所有错误码和错误信息必须在 `ResultCode.java` 中定义**,禁止在其他地方硬编码。 ```java // 在 ResultCode.java 新增 MY_ERROR(2001, "自定义错误信息"), // 在业务代码中使用 throw new BusinessException(ResultCode.MY_ERROR); ``` #### 3. 日志记录 使用 `LogUtil` 工具类,**禁止直接用 `@Slf4j` 或 `LoggerFactory`**(否则 requestId 不自动注入)。 ```java // ✅ 正确(自动带 requestId) LogUtil.info(MyService.class, "处理完成: userId={}", userId); LogUtil.error(MyService.class, "保存失败", e); // ❌ 错误 log.info("处理完成"); ``` #### 4. Controller 接口日志注解 所有 Controller 方法上都应添加 `@Log` 注解,明确接口说明和操作类型。 ```java @GetMapping("/list") @Log(value = "查询用户列表", module = "用户管理", operationType = OperationType.QUERY) public Result> list() { ... } ``` #### 5. 免鉴权接口 两种方式,推荐用注解(`@NoAuth`),也可在 `application.yml` 的 `auth.white-list` 中配置。 ```java // 方式一:注解(推荐,精确到方法) @PostMapping("/login") @NoAuth public Result login(...) { ... } // 方式二:配置文件(适合整批免鉴权路径) # application.yml auth: white-list: - /api/auth/login ``` #### 6. 数据库操作 **只能用 MyBatis Plus**,禁止手写 SQL(简单查询);复杂查询写在 `mapper/` 目录对应的 XML 文件中。 ```java // ✅ 简单查询用 Lambda userMapper.selectOne( new LambdaQueryWrapper() .eq(SysUser::getUsername, username) ); // ✅ 也可用 ServiceImpl 提供的 lambdaQuery SysUser user = lambdaQuery().eq(SysUser::getUsername, username).one(); // ✅ 复杂查询写 XML(放 resources/mapper/XxxMapper.xml) ``` #### 7. 实体类规范 ```java @Data @TableName("表名") public class XxxEntity { @TableId(type = IdType.AUTO) private Long id; // 逻辑删除字段 @TableLogic private Integer deleted; // 自动填充时间 @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; } ``` #### 8. 获取当前用户 在 Service/Controller 中通过 `RequestContext` 获取当前登录用户,无需额外传参。 ```java Long userId = RequestContext.getUserId(); String userName = RequestContext.getUserName(); String requestId = RequestContext.getRequestId(); ``` #### 9. Redis 操作 统一使用 `RedisUtil`,禁止直接注入 `RedisTemplate`。 ```java @Autowired private RedisUtil redisUtil; redisUtil.set("key", value, 3600); // 设置1小时过期 redisUtil.get("key"); // 获取 redisUtil.del("key"); // 删除 redisUtil.expire("key", 7200); // 修改过期时间 ``` #### 10. 注释规范 **所有方法(包括私有方法)必须有中文注释**,格式参考: ```java /** * 根据用户名查询用户信息 * * @param username 用户名 * @return 用户对象,不存在返回 null */ public SysUser findByUsername(String username) { ... } ``` --- ## 三、前端框架规范 ### 技术栈 - Vue 3 + Vite + Composition API - Element Plus(中文语言包) - Vue Router 4 - Pinia(状态管理) - Axios(HTTP 请求封装) - XLSX/SheetJS(Excel 纯前端处理) - Sass(CSS 预处理器) ### 目录结构 ``` frontend/src/ ├── api/ │ ├── index.js API 统一导出入口 │ └── auth.js 认证模块 API(示例) │ └── xxx.js 新业务模块 API(按模块建文件) ├── components/ │ ├── ExcelImport.vue Excel 导入组件 │ └── ExcelExport.vue Excel 导出按钮组件 ├── layout/ │ └── index.vue 主布局(侧边栏 + 顶栏 + 内容区) ├── router/ │ └── index.js 路由配置(含登录守卫) ├── store/ │ └── user.js 用户状态 Store(Pinia) ├── utils/ │ ├── excel.js Excel 导入导出工具函数 │ ├── request.js Axios 封装(自动 Token + 统一错误处理) │ └── storage.js localStorage 封装(Token/用户信息) └── views/ ├── login/index.vue 登录页 ├── dashboard/index.vue 控制台 └── 404.vue 404 页面 ``` --- ### 规范一览 #### 1. API 请求规范 每个业务模块创建独立的 API 文件,在 `api/index.js` 统一导出。 ```javascript // 新建 src/api/user.js import request from '@/utils/request' export function getUserList(params) { return request.get('/user/list', { params }) } // 在 api/index.js 追加 export * as userApi from './user' // 页面中使用 import { userApi } from '@/api' const res = await userApi.getUserList({ page: 1, size: 10 }) ``` #### 2. 路由配置规范 需要登录的页面都放在 Layout 的 `children` 下,`meta.requiresAuth = true`(默认)。 不需要登录的页面配置 `meta: { requiresAuth: false }`。 ```javascript // router/index.js 中添加子路由 { path: 'user', name: 'User', component: () => import('@/views/user/index.vue'), meta: { requiresAuth: true, title: '用户管理', icon: 'User' } } ``` `meta.icon` 的值是 Element Plus 图标名(会自动显示在左侧菜单)。 #### 3. Excel 导出使用 ```vue ``` #### 4. Excel 导入使用 ```vue // handleImport 接收解析后的数组,执行业务逻辑(如调用后端接口批量保存) async function handleImport(data) { await userApi.batchImport(data) } ``` #### 5. 用户状态获取 ```javascript import { useUserStore } from '@/store/user' const userStore = useUserStore() userStore.nickname // 用户昵称 userStore.username // 用户名 userStore.avatar // 头像 userStore.isLoggedIn // 是否已登录 await userStore.logout() // 退出登录 ``` --- ## 四、数据库 ### 连接信息 ``` url: jdbc:mysql://localhost:3306/aijiuyi_admin 账号: root 密码: root 字符集: utf8mb4 ``` ### 初始化 执行 `backend/src/main/resources/sql/init.sql`,创建所有表结构和初始数据。 **默认管理员账号:** - 用户名:`admin` - 密码:`admin123` --- ## 五、Redis ``` 地址: localhost:6379 密码: 无(如有密码,在 application-dev.yml 的 spring.redis.password 中配置) 数据库: 0 ``` --- ## 六、启动说明 ### 后端 ```bash cd backend mvn spring-boot:run # 或用 IDE 运行 AijiuyiAdminApplication.java # 服务地址:http://localhost:8080/api ``` ### 前端 ```bash cd frontend nvm use 22 # 切换到 Node.js 22 npm run dev # 开发服务器:http://localhost:3000 npm run build # 构建生产包 ``` --- ## 七、请求流程说明 ``` HTTP 请求 ↓ TokenInterceptor(生成 requestId,写入 ThreadLocal + MDC) ↓ Token 验证(白名单/NoAuth 注解跳过) ↓ Controller 方法 ↓ LogAspect(AOP 环绕,记录请求参数/结果/耗时) ↓ Service → Mapper(所有日志自动带 requestId,含 SQL 日志) ↓ 返回 Result ↓ LogAspect 异步保存操作日志到 sys_log 表 ↓ TokenInterceptor afterCompletion(清理 ThreadLocal + MDC) ``` 所有涉及数据库删除都是软删除