Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
d2cdc5c
refactor(api): switch service result helpers to AjaxResult factories
brickFE Apr 1, 2026
add59c9
refactor(rest): use AjaxResult.success in user list endpoint
brickFE Apr 1, 2026
bf205bc
refactor(rest): adopt AjaxResult.success in core controllers
brickFE Apr 1, 2026
2368e41
refactor(rest): use AjaxResult.failed in upload error paths
brickFE Apr 1, 2026
d199fb1
refactor(api): complete next response normalization batch
brickFE Apr 1, 2026
b37c216
refactor(login): simplify to direct AjaxResult factories
brickFE Apr 1, 2026
eeaca98
docs: add rolling refactor progress tracker
brickFE Apr 1, 2026
d867cd7
refactor(service): extract shared status-to-result builder
brickFE Apr 1, 2026
dde4816
refactor(service): extract shared operation log message builder
brickFE Apr 1, 2026
96f85f9
refactor(service): centralize operation logger construction
brickFE Apr 1, 2026
3971085
refactor(project): start DTO validation migration for add endpoint
brickFE Apr 1, 2026
40c3153
refactor(project): add DTO validation for update endpoint
brickFE Apr 1, 2026
b4dd8d8
refactor(team): migrate add/update to DTO validation
brickFE Apr 1, 2026
03b96c7
refactor(product): migrate add/update to DTO validation
brickFE Apr 1, 2026
979ff4c
refactor(classes): migrate add/update to DTO validation
brickFE Apr 1, 2026
e64fc6b
refactor(role): migrate add/update to DTO validation
brickFE Apr 1, 2026
41363a1
refactor(service): extract shared operation result logging helper
brickFE Apr 1, 2026
0f7c318
feat(security): migrate passwords to bcrypt with legacy upgrade
brickFE Apr 1, 2026
28631bc
feat(auth): add admin permission guard for key write operations
brickFE Apr 1, 2026
bfaa3b0
docs(plan): complete platform upgrade assessment and rollout path
brickFE Apr 1, 2026
b7918e2
feat(auth): extend admin write-guard to project/team/product/classes
brickFE Apr 1, 2026
f6e30eb
docs(readme): rewrite project overview setup and refactor status
brickFE Apr 1, 2026
8991ccd
docs(test): add test runbook and link from README
brickFE Apr 1, 2026
ebffc1d
ci: add github actions test workflow and document it
brickFE Apr 1, 2026
a8143ce
build(test): add unified test gate script and wire CI/docs
brickFE Apr 1, 2026
8fb798a
refactor(login): migrate login check to DTO validation
brickFE Apr 1, 2026
63128dd
chore(test): improve test-gate diagnostics for Maven 403
brickFE Apr 1, 2026
873d85e
feat(validation): add pagination param constraints on REST list endpo…
brickFE Apr 1, 2026
a514d62
test(validation): add pagination query-param validation coverage
brickFE Apr 1, 2026
46e8591
test(validation): add pageSize constraint tests for list endpoints
brickFE Apr 1, 2026
88f7bc3
feat(validation): enforce positive id query params on read/delete end…
brickFE Apr 1, 2026
796a434
feat(validation): enforce positive id for info endpoints and product …
brickFE Apr 1, 2026
baf203e
feat(validation): require non-blank operator on delete endpoints
brickFE Apr 2, 2026
7f508b5
fix(validation): enforce non-blank operator for classes delete
brickFE Apr 2, 2026
6983724
test(validation): cover blank operator on delete endpoints
brickFE Apr 2, 2026
a9dab8a
refactor(classes): rename update handler method
brickFE Apr 2, 2026
d14e472
feat(validation): require non-blank projectId for team allbypid
brickFE Apr 2, 2026
9fd1ee9
fix(validation): map parameter validation failures to 400
brickFE Apr 2, 2026
6a24d45
fix(validation): normalize type-mismatch errors as 400
brickFE Apr 2, 2026
a8a3ee2
fix(security): hide internal exception details in API errors
brickFE Apr 2, 2026
faf08e0
docs(plan): sync refactor progress and upgrade execution roadmap
brickFE Apr 2, 2026
f0083e8
feat(upgrade): add precheck script for Boot/JDK migration
brickFE Apr 2, 2026
060a6a0
ci(upgrade): add readiness precheck job before smoke tests
brickFE Apr 2, 2026
72b4223
ci(upgrade): enforce strict baseline precheck in workflow
brickFE Apr 2, 2026
27ff11b
ci(upgrade): publish precheck report artifact
brickFE Apr 2, 2026
67b216c
ci(upgrade): publish precheck results to job summary
brickFE Apr 2, 2026
d06456c
feat(upgrade): include javax hotspot ranking in precheck report
brickFE Apr 2, 2026
908e856
feat(upgrade): auto-generate execution checklist from precheck
brickFE Apr 2, 2026
e7c5bd9
feat(upgrade): add risk and owner fields to execution checklist
brickFE Apr 2, 2026
2376e97
feat(upgrade): map checklist hotspots to default owners
brickFE Apr 2, 2026
1e46529
ci(upgrade): fail checklist generation on unmapped owners
brickFE Apr 2, 2026
a5dd4cf
feat(upgrade): add javax category breakdown for migration planning
brickFE Apr 2, 2026
46100f4
feat(upgrade): auto-suggest migration batches in checklist
brickFE Apr 2, 2026
4eba3b9
ci(upgrade): validate generated checklist structure
brickFE Apr 2, 2026
340be5e
fix(websocket): correct monitor null checks and add regression test
brickFE Apr 2, 2026
c8ed01f
refactor(websocket): harden monitor scheduling and interval parsing
brickFE Apr 2, 2026
284c643
refactor(role): remove unused servlet request dependency
brickFE Apr 2, 2026
1975a74
refactor(websocket): use logger for monitor push IO failures
brickFE Apr 2, 2026
1fefa5e
refactor(websocket): stop monitor safely on closed session
brickFE Apr 2, 2026
c94322f
fix(websocket): tolerate missing services and documents
brickFE Apr 2, 2026
bf253d5
refactor(websocket): reduce monitor noise and harden payload parsing
brickFE Apr 2, 2026
ff03bbe
feat(upgrade): start spring boot 2.7 and java 11 migration baseline
brickFE Apr 2, 2026
9ec71b9
chore(upgrade): align ci and precheck gates with boot27-jdk11 phase
brickFE Apr 2, 2026
be81abd
feat(upgrade): kick off jdk17 execution phase
brickFE Apr 2, 2026
0fb12e1
chore(build): add maven mirror workflow for real test execution
brickFE Apr 2, 2026
f9afb0e
chore(build): wire aliyun mirror as default maven source
brickFE Apr 2, 2026
1edd63d
feat(upgrade): start boot3 jakarta migration planning stage
brickFE Apr 2, 2026
d67e4a9
feat(upgrade): generate boot3 owner task board in ci
brickFE Apr 2, 2026
640083c
docs(upgrade): freeze boot3 migration batches for task 1
brickFE Apr 2, 2026
c5aee1b
refactor(jakarta): execute batch-a validation namespace migration
brickFE Apr 2, 2026
df8e307
refactor(jakarta): execute batch-b persistence namespace migration
brickFE Apr 2, 2026
b19b49d
refactor(jakarta): execute batch-c protocol namespace migration
brickFE Apr 2, 2026
0b00ece
docs(upgrade): align target section with boot3 baseline
brickFE Apr 2, 2026
5853a62
chore(task1): add batch-freeze guard script and usage docs
brickFE Apr 2, 2026
38ad989
fix(tooling): make boot3 precheck/checklist robust in current env
brickFE Apr 2, 2026
2a2071d
docs(tasks): close precheck task and mark network-blocked gates
brickFE Apr 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions docs/refactor-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# SYTRAVEL 重构路线图(分阶段)

> 目标:在不中断业务功能的前提下,把项目从“可运行”升级为“可维护、可测试、可演进”。

## 0. 现状快照

- 后端基于 Spring Boot 1.5.9 + Java 8,技术栈较旧。
- Controller/Service 层存在大量重复样板代码(分页、参数校验、日志结果组装)。
- 密码处理为 Base64 编码(非加密),存在明显安全风险。
- 前端为传统 jQuery + 多版本脚本混用,静态资源结构分散。
- 自动化测试非常薄弱(当前仅见基础启动测试)。

## 1. 重构原则

1. **先建立安全网,再动核心逻辑**:优先补测试与观测能力。
2. **小步快跑,保持可回滚**:每个阶段可独立上线。
3. **功能不变优先**:先做结构重组,再做行为变更。
4. **风险前置**:安全问题(密码、鉴权、输入校验)优先。

## 2. 阶段计划

## 阶段 A:基线与可观测(1~2 周)

- 建立“重构基线”:
- 固定本地开发环境(JDK/Maven/MySQL 版本、初始化脚本)。
- 增加健康检查与关键日志字段。
- 测试补齐(最少可用):
- 为核心 Service(用户、项目、团队、产品)补充单元测试。
- 为 REST 接口增加 MockMvc 集成测试(覆盖增删改查主流程)。
- 输出:
- 测试可执行文档。
- 第一版覆盖率报告(可先设 20% 目标)。

## 阶段 B:后端分层与公共能力抽取(2~3 周)

- 引入 DTO + 校验:
- 请求对象从 `JSON` 动态取值改为强类型 DTO。
- 使用参数校验注解替代手写判空。
- 统一异常与返回:
- 引入全局异常处理(`@ControllerAdvice`)。
- 统一错误码、错误消息、日志追踪 ID。
- 抽取可复用模块:
- 分页查询模板。
- 操作日志记录模板(替代每个 Service 手动拼装结果)。
- 输出:
- 至少一个模块(建议 user)完成“端到端新结构示范”。

## 阶段 C:安全整改(并行推进,1~2 周)

- 密码体系升级:
- 由 Base64 改为 BCrypt/Argon2。
- 登录验证改为哈希比对。
- 增加“渐进迁移策略”(老密码首次登录后自动升级)。
- 基础安全:
- 补充接口鉴权与角色控制。
- 统一输入过滤,避免注入/越权。
- 输出:
- 安全基线清单 + 验收用例。

## 阶段 D:数据层与领域模型治理(2 周)

- Repository 命名与查询规范统一。
- 领域对象瘦身:实体不承载表现层逻辑(如 `toMap`)。
- 引入 MapStruct/手写 Mapper(Entity ↔ DTO)。
- 关键表加索引与唯一约束复核。

## 阶段 E:前端治理(2~4 周)

- 静态资源整理:
- 清理重复/多版本 jQuery 与历史插件。
- 按模块归档 JS/CSS。
- 前端接口层统一:
- 封装请求方法、统一错误提示。
- 去除页面脚本中的重复逻辑。
- 视情况选择:
- 轻量化继续维护 jQuery 架构;或逐步迁移到 Vue/React(按业务价值评估)。

## 阶段 F:平台升级(3~6 周,独立里程碑)

- Spring Boot 1.5.x 升级到 2.7.x(再评估到 3.x)。
- JDK 8 升级到 17 LTS。
- 依赖升级并修复兼容性问题。
- 完成后再启用更高版本框架特性(如新版安全配置)。

## 3. 每一轮迭代的执行模板

每个模块都按以下顺序推进:

1. 画出现状调用链(Rest → Service → Repository)。
2. 写回归测试,锁定当前行为。
3. 引入 DTO + 参数校验。
4. 抽离公共逻辑(日志、分页、异常处理)。
5. 保持接口兼容并灰度验证。
6. 合并后监控 1~2 天再进行下一模块。

## 4. 第一批优先重构清单(建议按这个顺序)

1. **用户模块(SYUserRest/SYUserService)**:风险最高(密码、权限、输入)。
2. **登录模块(SYLoginRest/SYLoginService)**:与安全改造联动。
3. **项目/团队/产品模块**:模板化改造,提取共性。
4. **日志模块**:统一审计模型与查询能力。

## 5. 验收标准(DoD)

- 功能回归:核心接口回归通过率 100%。
- 测试覆盖:核心业务包覆盖率达到阶段目标(20%→40%→60%)。
- 安全:不再存在明文/可逆密码存储。
- 可维护性:单个 Service 类平均行数明显下降,重复代码减少。
- 文档:模块设计说明与接口说明同步更新。

## 6. 我们下一步怎么做

建议从 **阶段 A + 用户模块** 开始,第一迭代只做三件事:

1. 为用户模块补单测与接口测试。
2. 把 `JSON` 入参改为 `UserCreateRequest/UserUpdateRequest`。
3. 落地全局异常处理和统一错误响应。

完成后你确认效果,我们再进入第二迭代(密码与鉴权改造)。
8 changes: 8 additions & 0 deletions src/main/java/com/sy/travel/common/AjaxResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ public AjaxResult(int code, String msg, T data) {
this.data = data;
}

public static <T> AjaxResult<T> success(T data) {
return new AjaxResult<T>(200, ApiMessages.SUCCESS, data);
}

public static <T> AjaxResult<T> failed(int code, T data) {
return new AjaxResult<T>(code, ApiMessages.FAILED, data);
}

public int getCode() {
return code;
}
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/sy/travel/common/ApiMessages.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.sy.travel.common;

public interface ApiMessages {
String SUCCESS = "success";
String FAILED = "failed";
}
8 changes: 8 additions & 0 deletions src/main/java/com/sy/travel/common/Commons.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,15 @@ public class Commons {
public final static String USER_DELETE = "删除用户";
public final static String USER_DELETE_FAILED = "删除用户失败";
public final static String USER_UPDATE = "修改用户";
@Deprecated
public final static String USER_UPDATE_NOT_FOUNT ="该用户不存在";
public final static String USER_UPDATE_NOT_FOUND ="该用户不存在";
@Deprecated
public final static String USER_UPDTE_PWD = "修改超级管理员密码";
public final static String USER_UPDATE_PWD = "修改超级管理员密码";
public final static String USER_UPDATE_PWD_NOT_PERMISSION = "只有超级管理员才有修改密码的权限";
public final static String USER_NOT_LOGIN = "用户未登录";
public final static String USER_ADMIN_OLD_PASSWORD_EMPTY = "超级管理员原密码不能为空";
public final static String USER_ADMIN_OLD_PASSWORD_ERROR = "超级管理员原密码输入错误";
public final static String USER_ADMIN_NEW_PASSWORD_EMPTY = "超级管理员新密码不能为空";
}
6 changes: 6 additions & 0 deletions src/main/java/com/sy/travel/common/ErrorCodes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.sy.travel.common;

public interface ErrorCodes {
String VALIDATION_ERROR = "VALIDATION_ERROR";
String INTERNAL_ERROR = "INTERNAL_ERROR";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.sy.travel.dto.user;

import javax.validation.constraints.NotBlank;

public class UserAdminPwdUpdateRequest {
@NotBlank(message = "operator不能为空")
private String operator;
@NotBlank(message = "password不能为空")
private String password;
@NotBlank(message = "newPwd不能为空")
private String newPwd;

public String getOperator() {
return operator;
}

public void setOperator(String operator) {
this.operator = operator;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public String getNewPwd() {
return newPwd;
}

public void setNewPwd(String newPwd) {
this.newPwd = newPwd;
}
}
57 changes: 57 additions & 0 deletions src/main/java/com/sy/travel/dto/user/UserCreateRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.sy.travel.dto.user;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;

public class UserCreateRequest {
@NotBlank(message = "operator不能为空")
private String operator;
@NotBlank(message = "username不能为空")
private String username;
@NotBlank(message = "password不能为空")
private String password;
@NotBlank(message = "permission不能为空")
@Pattern(regexp = "^[0-5]$", message = "permission取值范围为0-5")
private String permission;
private String remark;

public String getOperator() {
return operator;
}

public void setOperator(String operator) {
this.operator = operator;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public String getPermission() {
return permission;
}

public void setPermission(String permission) {
this.permission = permission;
}

public String getRemark() {
return remark;
}

public void setRemark(String remark) {
this.remark = remark;
}
}
56 changes: 56 additions & 0 deletions src/main/java/com/sy/travel/dto/user/UserUpdateRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.sy.travel.dto.user;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;

public class UserUpdateRequest {
@NotBlank(message = "operator不能为空")
private String operator;
@NotNull(message = "id不能为空")
private Integer id;
private String password;
@Pattern(regexp = "^[0-5]$", message = "permission取值范围为0-5")
private String permission;
private String remark;

public String getOperator() {
return operator;
}

public void setOperator(String operator) {
this.operator = operator;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public String getPermission() {
return permission;
}

public void setPermission(String permission) {
this.permission = permission;
}

public String getRemark() {
return remark;
}

public void setRemark(String remark) {
this.remark = remark;
}
}
33 changes: 33 additions & 0 deletions src/main/java/com/sy/travel/handler/GlobalExceptionHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.sy.travel.handler;

import java.util.stream.Collectors;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import com.sy.travel.common.AjaxResult;
import com.sy.travel.common.ErrorCodes;

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public AjaxResult<String> handleValidation(MethodArgumentNotValidException ex) {
String message = ex.getBindingResult().getFieldErrors().stream().map(fieldError -> fieldError.getDefaultMessage())
.collect(Collectors.joining(";"));
return new AjaxResult<String>(400, ErrorCodes.VALIDATION_ERROR, message);
}

@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
Comment on lines +41 to +43
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Don't map all framework exceptions to HTTP 500

The catch-all @ExceptionHandler(Exception.class) now forces every uncaught exception to return 500, including client-input errors that Spring normally reports as 400 (for example malformed JSON as HttpMessageNotReadableException or bad query-parameter coercion). This makes invalid requests look like server faults, which can break client error handling and distort monitoring/alerting; add specific handlers for these request-binding exceptions (or let Spring handle them) instead of routing them through the generic 500 path.

Useful? React with 👍 / 👎.

public AjaxResult<String> handleUnexpected(Exception ex) {
return new AjaxResult<String>(500, ErrorCodes.INTERNAL_ERROR, ex.getMessage());
}
}
Loading