diff --git a/pom.xml b/pom.xml
index 4c11879..f928a8c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,6 +23,19 @@
UTF-8
+
+
+
+
+ com.yunhai.platform
+ yh-platform-dependencies
+ 1.0.0-SNAPSHOT
+ pom
+ import
+
+
+
+
@@ -77,6 +90,19 @@
lombok
true
+
+
+ com.yunhai.platform
+ yh-api-std
+
+
+
+ org.springdoc
+ springdoc-openapi-ui
+ 1.7.0
+
@@ -95,4 +121,14 @@
+
+
+
+ nexus-public
+ bsch/nexus public
+ http://nexus.yunhaixingtong.com/repository/maven-public/
+ true
+ true
+
+
diff --git a/src/main/java/com/yunhai/platform/gateway/admin/InternalAdminController.java b/src/main/java/com/yunhai/platform/gateway/admin/InternalAdminController.java
index 68a4782..fa1e6ee 100644
--- a/src/main/java/com/yunhai/platform/gateway/admin/InternalAdminController.java
+++ b/src/main/java/com/yunhai/platform/gateway/admin/InternalAdminController.java
@@ -1,5 +1,6 @@
package com.yunhai.platform.gateway.admin;
+import com.yunhai.platform.apistd.ApiResponse;
import com.yunhai.platform.gateway.entity.OpenApiLog;
import com.yunhai.platform.gateway.entity.OpenApiRoute;
import com.yunhai.platform.gateway.entity.OpenApiTarget;
@@ -7,12 +8,18 @@ import com.yunhai.platform.gateway.repository.OpenApiLogRepository;
import com.yunhai.platform.gateway.repository.OpenApiRouteRepository;
import com.yunhai.platform.gateway.repository.OpenApiTargetRepository;
import com.yunhai.platform.gateway.route.RouteRegistry;
+import com.yunhai.platform.utils.exception.ErrorCode;
+import com.yunhai.platform.utils.model.BasePageResult;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
import org.springframework.http.MediaType;
import org.springframework.util.StreamUtils;
+import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
@@ -24,24 +31,27 @@ import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
-import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 网关治理小页后端(/api/internal/admin/**,D5 最小治理面):路由/目标地址的查询与行内编辑、
- * 台账倒序查询;写操作落库后立即热重载注册表(routes→reload / targets→reloadTargets),
+ * 台账分页查询;写操作落库后立即热重载注册表(routes→reload / targets→reloadTargets),
* 无须重启网关。与 {@code RouteRefreshController} 同前缀,被 RoutingFilter 旁路(不进 oapi 链)。
*
+ * 响应契约:成功响应由 {@code yh-api-std} 的 {@code ApiResponseAdvice} 统一包成
+ * {@code {code:0, msg:"", data:...}}(与 notice/userbase 一致);非法入参走 {@link #badRequest}
+ * 返回 HTTP 200 + {@code {code:2, msg:...}}(平台规范:业务错误不改 HTTP 状态码)。
+ *
* 收网前提示:本前缀当前宿主端口可达(10013 未绑 127.0.0.1),页面用于 observe 期
* 治理与排障;T0.2 端口收网随下次重新部署自然收紧(届时仅容器网内可达)。
* 值域白名单与 {@code docs/sql/01_schema.sql} 注释对齐:visibility∈{INTERNAL,EXTERNAL}、
- * authMode∈{SIGNED,ANONYMOUS}、cacheScope∈{CALLER,GLOBAL};非法值 400 且不落库。
+ * authMode∈{SIGNED,ANONYMOUS}、cacheScope∈{CALLER,GLOBAL};非法值返回 code=2 且不落库。
*/
+@Tag(name = "GatewayAdmin", description = "网关治理:路由旋钮 / 目标地址 / 访问台账")
@RestController
@RequestMapping("/api/internal/admin")
public class InternalAdminController {
@@ -71,28 +81,29 @@ public class InternalAdminController {
this.routeRegistry = routeRegistry;
}
- /** 治理小页本体(classpath:/static/admin.html,N03 产出) */
+ /** 治理小页本体(classpath:/static/admin.html,N03 产出);返回 String 故不被信封包装 */
+ @Operation(operationId = "GatewayAdmin.page", summary = "治理小页(内置 HTML)")
@GetMapping(value = "/page", produces = MediaType.TEXT_HTML_VALUE)
public String page() throws IOException {
return StreamUtils.copyToString(
new ClassPathResource("static/admin.html").getInputStream(), StandardCharsets.UTF_8);
}
- /** 路由表(治理对象全量,含禁用行;排序稳定便于表格展示) */
+ /** 路由表分页(治理对象全量含禁用行;targetCode+pathPattern 稳定排序) */
+ @Operation(operationId = "GatewayAdmin.routes", summary = "路由注册表分页")
@GetMapping("/routes")
- public List routes() {
- List all = routeRepo.findAll();
- all.sort((a, b) -> {
- int c = a.getTargetCode().compareTo(b.getTargetCode());
- return c != 0 ? c : a.getPathPattern().compareTo(b.getPathPattern());
- });
- return all;
+ public BasePageResult routes(
+ @RequestParam(value = "pageIndex", required = false, defaultValue = "1") Integer pageIndex,
+ @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize) {
+ Sort sort = Sort.by("targetCode").and(Sort.by("pathPattern"));
+ return toResult(routeRepo.findAll(pageRequest(pageIndex, pageSize, sort)));
}
/**
* 行内编辑路由治理旋钮。只接受治理字段(不可改 target/pattern/method——那是路由身份,
* 改动应走 SQL 迁移评审);enabled 可整体停用一行。成功后热重载并返回加载数。
*/
+ @Operation(operationId = "GatewayAdmin.updateRoute", summary = "编辑路由治理旋钮")
@PutMapping("/routes/{id}")
public Map updateRoute(@PathVariable("id") Long id,
@RequestBody Map body) {
@@ -148,15 +159,17 @@ public class InternalAdminController {
return out;
}
- /** 目标地址表全量 */
+ /** 目标地址表分页 */
+ @Operation(operationId = "GatewayAdmin.targets", summary = "目标地址分页")
@GetMapping("/targets")
- public List targets() {
- List all = targetRepo.findAll();
- all.sort((a, b) -> a.getTargetCode().compareTo(b.getTargetCode()));
- return all;
+ public BasePageResult targets(
+ @RequestParam(value = "pageIndex", required = false, defaultValue = "1") Integer pageIndex,
+ @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize) {
+ return toResult(targetRepo.findAll(pageRequest(pageIndex, pageSize, Sort.by("targetCode"))));
}
/** 行内编辑目标地址/启停;成功后热重载 target 快照(禁用/空白行按无行回落 yml 由 TargetRouter 承担) */
+ @Operation(operationId = "GatewayAdmin.updateTarget", summary = "编辑目标地址/启停")
@PutMapping("/targets/{id}")
public Map updateTarget(@PathVariable("id") Long id,
@RequestBody Map body) {
@@ -181,32 +194,61 @@ public class InternalAdminController {
return out;
}
- /** 台账倒序查询(limit 默认 50 上限 500;targetCode/callerAppKey 可空) */
+ /**
+ * 台账倒序分页查询。{@code pageSize} 优先、上限 500;兼容旧 {@code limit} 参数
+ * (未传 pageSize 时以 limit 作 pageSize)。targetCode/callerAppKey 可空=不过滤。
+ */
+ @Operation(operationId = "GatewayAdmin.logs", summary = "访问台账分页")
@GetMapping("/logs")
- public Map logs(@RequestParam(value = "limit", required = false) Integer limit,
- @RequestParam(value = "targetCode", required = false) String targetCode,
- @RequestParam(value = "callerAppKey", required = false) String callerAppKey) {
- int size = limit == null || limit < 1 ? 50 : Math.min(limit, 500);
- Page page = logRepo.pageLatest(emptyToNull(targetCode), emptyToNull(callerAppKey),
- PageRequest.of(0, size));
- Map out = new LinkedHashMap<>();
- out.put("total", page.getTotalElements());
- out.put("rows", new ArrayList<>(page.getContent()));
- return out;
+ public BasePageResult logs(
+ @RequestParam(value = "pageIndex", required = false, defaultValue = "1") Integer pageIndex,
+ @RequestParam(value = "pageSize", required = false) Integer pageSize,
+ @RequestParam(value = "limit", required = false) Integer limit,
+ @RequestParam(value = "targetCode", required = false) String targetCode,
+ @RequestParam(value = "callerAppKey", required = false) String callerAppKey) {
+ int size = resolvePageSize(pageSize, limit);
+ int page = normalizePageIndex(pageIndex);
+ Page result = logRepo.pageLatest(emptyToNull(targetCode), emptyToNull(callerAppKey),
+ PageRequest.of(page - 1, size));
+ return toResult(result);
}
/**
- * 值域/参数错误 → 400 + JSON 错误体(页面 alert 展示)。本类抛出的 IllegalArgumentException
+ * 值域/参数错误 → HTTP 200 + {@code {code:2, msg}}(平台规范:业务错误不改 HTTP 状态码,
+ * 与 notice/userbase 的 GlobalExceptionHandler 行为一致)。本类抛出的 IllegalArgumentException
* 全是"调用方传值非法",缺省会被 Spring 映射成 500,误导排障方向——故在类内显式收敛。
*/
- @org.springframework.web.bind.annotation.ExceptionHandler(IllegalArgumentException.class)
- @org.springframework.web.bind.annotation.ResponseStatus(
- org.springframework.http.HttpStatus.BAD_REQUEST)
- public Map badRequest(IllegalArgumentException e) {
- Map out = new LinkedHashMap<>();
- out.put("code", 1);
- out.put("msg", e.getMessage());
- return out;
+ @ExceptionHandler(IllegalArgumentException.class)
+ public ApiResponse