Просмотр исходного кода

# sql:各表updated_at增加自动刷新触发器并补充文档

yangyi 2 месяцев назад
Родитель
Сommit
2fd32c9f62
2 измененных файлов с 208 добавлено и 2 удалено
  1. 169 0
      README.md
  2. 39 2
      sql/postgersql.sql

+ 169 - 0
README.md

@@ -0,0 +1,169 @@
+# serve_template
+
+在线评测系统(OJ)后端服务模板,基于 Spring Boot 构建,提供统一的认证鉴权、用户管理与通用响应封装,可直接作为后续功能(题目、评测、比赛等)的开发底座。
+
+## 技术栈
+
+| 分类 | 选型 | 版本 |
+| --- | --- | --- |
+| 语言 | Java | 17 |
+| 框架 | Spring Boot | 3.5.13 |
+| 构建工具 | Gradle (Wrapper) | 8.14.4 |
+| 安全 | Spring Security + JWT | - |
+| ORM | MyBatis-Plus | 3.5.15 |
+| 数据库 | PostgreSQL + Druid 连接池 | - |
+| 接口文档 | springdoc-openapi (Swagger UI) | 2.8.16 |
+
+## 已实现功能
+
+- **用户认证**:注册、登录,密码 BCrypt 加密,登录后签发 JWT(有效期 24 小时)
+- **接口鉴权**:基于角色的方法级鉴权(`user` / `coach` / `admin`),未认证、无权限统一 JSON 返回
+- **用户管理**:分页查询、详情查询、新增、编辑、批量删除,以及状态 / 头像 / 密码更新
+- **统一响应**:`Response<T>` 通用响应体 + 全局异常处理(参数校验、业务异常)
+- **请求日志**:基于 `CommonsRequestLoggingFilter` 记录请求入参
+- **接口文档**:Swagger UI 在线调试
+
+## 项目结构
+
+```
+serve_template
+├── sql/postgersql.sql            # 数据库初始化脚本(表结构、索引与触发器)
+├── src/main/java/space/anyi/serve
+│   ├── ServeApplication.java     # 启动类
+│   ├── config                    # SecurityConfig / WebConfig(CORS/日志) / OpenApiConfig
+│   ├── controller                # AuthController(登录注册) / UserController(用户管理)
+│   ├── entity                    # Response(响应体) / PageVo(分页) / auth / user(DTO、VO、实体)
+│   ├── filter                    # JwtAuthenticationFilter(JWT 解析过滤器)
+│   ├── handler                   # GlobalExceptionHandler + security(JWT 工具、异常入口)
+│   ├── mapper                    # MyBatis-Plus Mapper
+│   └── service                   # UserService 接口 + impl 实现
+└── src/main/resources
+    ├── application.yaml          # 应用配置
+    └── mapper/UserMapper.xml     # Mapper XML
+```
+
+## 快速开始
+
+### 1. 环境要求
+
+- JDK 17+
+- PostgreSQL(本地或远程均可)
+
+### 2. 初始化数据库
+
+```bash
+psql -U <postgres用户> -f sql/postgersql.sql
+```
+
+脚本会创建 `oj` 数据库、`dev` schema,以及用户、题目、评测用例、提交记录、分类、比赛等表(含注释与索引)。
+
+### 3. 配置环境变量
+
+`application.yaml` 中数据库连接通过环境变量注入:
+
+| 环境变量 | 说明 | 默认值 |
+| --- | --- | --- |
+| `databaseHost` | 数据库地址 | - |
+| `databaseUsername` | 数据库用户名 | - |
+| `databasePassword` | 数据库密码 | - |
+
+### 4. 启动
+
+```bash
+./gradlew bootRun
+```
+
+服务默认运行在 `http://localhost:8080`。
+
+## 接口文档
+
+启动后访问 Swagger UI:
+
+```
+http://localhost:8080/swagger-ui/index.html
+```
+
+> `auth/login`、`auth/register` 及 Swagger 相关路径无需认证,其余接口需在请求头携带 `Authorization: Bearer <token>`。
+
+## 数据库设计
+
+表均位于 `dev` schema 下:
+
+- `user`:用户(账号、密码、用户名、角色、头像、启用状态、逻辑删除标记)
+- `problem`:题目(标题、描述、时间/内存限制、提交与通过次数、公开状态、难度)
+- `problem_case`:题目样例(展示给用户)
+- `problem_test`:评测用例(后台判题,可隐藏)
+- `submission`:提交记录(代码、语言、判题状态、耗时/内存、得分、用例统计)
+- `category` / `problem_category_rel`:题目类别及多对多关联
+- `contest` / `contest_problem` / `contest_registration`:比赛、比赛题目、比赛报名
+
+各表之间使用逻辑外键(仅记录 ID),便于水平扩展。
+
+### 时间戳自动维护
+
+- **创建时间**:所有表的 `created_at` 由数据库列默认值 `DEFAULT NOW()` 在插入时自动填充。
+- **更新时间**:所有表的 `updated_at` 由 `BEFORE UPDATE` 触发器自动刷新。触发器函数 `set_updated_at()` 将每行更新前的 `updated_at` 置为当前时间,各表对应触发器如下(均在 `sql/postgersql.sql` 中定义):
+
+| 表 | 触发器 |
+| --- | --- |
+| `user` | `trg_user_updated_at` |
+| `problem` | `trg_problem_updated_at` |
+| `problem_case` | `trg_problem_case_updated_at` |
+| `problem_test` | `trg_problem_test_updated_at` |
+| `submission` | `trg_submission_updated_at` |
+| `category` | `trg_category_updated_at` |
+| `problem_category_rel` | `trg_problem_category_rel_updated_at` |
+| `contest` | `trg_contest_updated_at` |
+| `contest_problem` | `trg_contest_problem_updated_at` |
+| `contest_registration` | `trg_contest_registration_updated_at` |
+
+```sql
+-- 触发器函数(定义一次,所有表共用)
+CREATE OR REPLACE FUNCTION set_updated_at()
+RETURNS TRIGGER AS $$
+BEGIN
+    NEW.updated_at = NOW();
+    RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
+
+-- 每个表单独建触发器,例如:
+CREATE TRIGGER trg_user_updated_at
+BEFORE UPDATE ON dev.user
+FOR EACH ROW EXECUTE FUNCTION set_updated_at();
+```
+
+应用层(MyBatis-Plus 实体)无需维护 `created_at` / `updated_at`,插入与更新均由数据库自动处理。
+
+### E-R 图
+
+```mermaid
+erDiagram
+    user ||--o{ problem : "创建(created_by)"
+    user ||--o{ contest : "创建(created_by)"
+    user ||--o{ submission : "提交(user_id)"
+    user ||--o{ contest_registration : "报名(user_id)"
+    problem ||--o{ problem_case : "样例(problem_id)"
+    problem ||--o{ problem_test : "评测用例(problem_id)"
+    problem ||--o{ submission : "提交记录(problem_id)"
+    problem ||--o{ problem_category_rel : "关联(problem_id)"
+    category ||--o{ problem_category_rel : "关联(category_id)"
+    contest ||--o{ submission : "包含(contest_id)"
+    contest ||--o{ contest_problem : "题目(contest_id)"
+    problem ||--o{ contest_problem : "被纳入(problem_id)"
+    contest ||--o{ contest_registration : "报名(contest_id)"
+```
+
+## 主要依赖
+
+| 依赖 | 用途 |
+| --- | --- |
+| spring-boot-starter-web | Web MVC |
+| spring-boot-starter-security | 认证与鉴权 |
+| spring-boot-starter-validation | 参数校验 |
+| mybatis-plus-spring-boot3-starter | ORM |
+| druid-spring-boot-3-starter | 数据库连接池 |
+| postgresql | PostgreSQL 驱动 |
+| jjwt | JWT 生成与解析 |
+| springdoc-openapi-starter-webmvc-ui | Swagger 接口文档 |
+| spring-boot-starter-actuator | 健康检查与监控(端点全量暴露) |

+ 39 - 2
sql/postgersql.sql

@@ -49,6 +49,8 @@ COMMENT ON COLUMN dev.user.updated_at IS '更新时间';
 
 -- 创建索引
 CREATE INDEX idx_user_role ON dev.user(role);
+CREATE INDEX idx_user_enable ON dev.user(enable);
+CREATE INDEX idx_user_delete_flag ON dev.user(delete_flag);
 
 -- 自动刷新 updated_at 的触发器函数
 CREATE OR REPLACE FUNCTION set_updated_at()
@@ -63,8 +65,6 @@ $$ LANGUAGE plpgsql;
 CREATE TRIGGER trg_user_updated_at
 BEFORE UPDATE ON dev.user
 FOR EACH ROW EXECUTE FUNCTION set_updated_at();
-CREATE INDEX idx_user_enable ON dev.user(enable);
-CREATE INDEX idx_user_delete_flag ON dev.user(delete_flag);
 
 -- 题目表
 DROP TABLE IF EXISTS dev.problem;
@@ -318,3 +318,40 @@ COMMENT ON INDEX idx_contest_problem_contest_id IS '比赛题目比赛ID索引';
 COMMENT ON INDEX idx_contest_problem_problem_id IS '比赛题目题目ID索引';
 COMMENT ON INDEX idx_contest_registration_contest_id IS '比赛报名比赛ID索引';
 COMMENT ON INDEX idx_contest_registration_user_id IS '比赛报名用户ID索引';
+
+-- 各表 updated_at 自动刷新触发器(函数 set_updated_at() 定义见上文)
+CREATE TRIGGER trg_problem_updated_at
+BEFORE UPDATE ON dev.problem
+FOR EACH ROW EXECUTE FUNCTION set_updated_at();
+
+CREATE TRIGGER trg_problem_case_updated_at
+BEFORE UPDATE ON dev.problem_case
+FOR EACH ROW EXECUTE FUNCTION set_updated_at();
+
+CREATE TRIGGER trg_problem_test_updated_at
+BEFORE UPDATE ON dev.problem_test
+FOR EACH ROW EXECUTE FUNCTION set_updated_at();
+
+CREATE TRIGGER trg_submission_updated_at
+BEFORE UPDATE ON dev.submission
+FOR EACH ROW EXECUTE FUNCTION set_updated_at();
+
+CREATE TRIGGER trg_category_updated_at
+BEFORE UPDATE ON dev.category
+FOR EACH ROW EXECUTE FUNCTION set_updated_at();
+
+CREATE TRIGGER trg_problem_category_rel_updated_at
+BEFORE UPDATE ON dev.problem_category_rel
+FOR EACH ROW EXECUTE FUNCTION set_updated_at();
+
+CREATE TRIGGER trg_contest_updated_at
+BEFORE UPDATE ON dev.contest
+FOR EACH ROW EXECUTE FUNCTION set_updated_at();
+
+CREATE TRIGGER trg_contest_problem_updated_at
+BEFORE UPDATE ON dev.contest_problem
+FOR EACH ROW EXECUTE FUNCTION set_updated_at();
+
+CREATE TRIGGER trg_contest_registration_updated_at
+BEFORE UPDATE ON dev.contest_registration
+FOR EACH ROW EXECUTE FUNCTION set_updated_at();