feat(interactive): add participatory verification lab for debugging and repair validation

This commit is contained in:
likingcode
2026-03-10 09:35:04 +08:00
parent 76a243b2de
commit 4bfb2fa250
5 changed files with 260 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
package com.example.scaffold.controller;
import com.example.scaffold.mapper.ProductMapper;
import com.example.scaffold.service.UserService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.Instant;
import java.util.LinkedHashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/verify")
public class VerificationController {
private final JdbcTemplate jdbcTemplate;
private final UserService userService;
private final ProductMapper productMapper;
@Value("${spring.profiles.active:learn}")
private String activeProfile;
@Value("${auth.type:none}")
private String authType;
@Value("${spring.datasource.url:unknown}")
private String datasourceUrl;
public VerificationController(JdbcTemplate jdbcTemplate, UserService userService, ProductMapper productMapper) {
this.jdbcTemplate = jdbcTemplate;
this.userService = userService;
this.productMapper = productMapper;
}
@GetMapping("/overview")
public Map<String, Object> overview() {
Map<String, Object> result = new LinkedHashMap<>();
result.put("timestamp", Instant.now().toString());
result.put("profile", activeProfile);
result.put("authType", authType);
result.put("datasourceUrl", datasourceUrl);
result.put("checks", Map.of(
"database", checkDatabase(),
"users", checkUsers(),
"products", checkProducts(),
"h2Console", checkH2ConsoleHint(),
"auth", checkAuthMode()
));
return result;
}
@GetMapping("/database")
public Map<String, Object> checkDatabase() {
Map<String, Object> r = new LinkedHashMap<>();
try {
Integer one = jdbcTemplate.queryForObject("SELECT 1", Integer.class);
r.put("ok", one != null && one == 1);
r.put("message", "数据库连接正常SELECT 1 返回成功");
} catch (Exception e) {
r.put("ok", false);
r.put("message", "数据库连接失败: " + e.getMessage());
}
r.put("hint", "如果这里失败,优先检查 DataSource、H2 文件锁或 profile 配置");
return r;
}
@GetMapping("/users")
public Map<String, Object> checkUsers() {
Map<String, Object> r = new LinkedHashMap<>();
try {
long count = userService.count();
r.put("ok", true);
r.put("count", count);
r.put("message", "用户服务可用");
} catch (Exception e) {
r.put("ok", false);
r.put("message", "用户服务异常: " + e.getMessage());
}
r.put("hint", "如果用户接口异常,说明 Service / JPA / 数据源链路可能有问题");
return r;
}
@GetMapping("/products")
public Map<String, Object> checkProducts() {
Map<String, Object> r = new LinkedHashMap<>();
try {
int size = productMapper.findAll().size();
r.put("ok", true);
r.put("count", size);
r.put("message", "MyBatis 产品查询可用");
} catch (Exception e) {
r.put("ok", false);
r.put("message", "MyBatis 查询异常: " + e.getMessage());
}
r.put("hint", "如果这里失败但 users 正常,优先排查 Mapper / SQL / MyBatis 配置");
return r;
}
@GetMapping("/h2")
public Map<String, Object> checkH2ConsoleHint() {
Map<String, Object> r = new LinkedHashMap<>();
r.put("ok", true);
r.put("consolePath", "/h2-console");
r.put("expectedJdbc", datasourceUrl);
r.put("message", "H2 控制台入口已暴露;若跳转异常,优先检查 X-Forwarded-Proto / forward-headers 配置");
return r;
}
@GetMapping("/auth")
public Map<String, Object> checkAuthMode() {
Map<String, Object> r = new LinkedHashMap<>();
r.put("ok", true);
r.put("authType", authType);
r.put("profile", activeProfile);
r.put("message", switch (authType) {
case "jwt" -> "当前是 JWT 模式,更适合验证 token / 401 / 403 链路";
case "satoken" -> "当前是 Sa-Token 模式,可测试登录态与会话行为";
default -> "当前是 none 模式,适合先学 Spring 核心功能";
});
return r;
}
}