feat(extapi): 新增外部接口清单注解扫描与展示导出
新增 @ExternalApi/@ExternalCall 方法级注解,启动时扫描生成内存注册表。 提供 /sys/extApi/list 展示、exportXls(AutoPoi) 与 exportMarkdown 导出; 给 TaskApiController.countTaskforporter 打 @ExternalApi 示范并补菜单 SQL。
This commit is contained in:
+32
@@ -0,0 +1,32 @@
|
||||
package org.jeecg.common.aspect.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 对外提供的接口(供外部系统调用)
|
||||
* <p>标注在 Controller 方法上;接口地址与 HTTP 方法由框架从 @RequestMapping 自动推导。
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface ExternalApi {
|
||||
|
||||
/** 接口名称/用途 */
|
||||
String name();
|
||||
|
||||
/** 调用方系统(谁在调我) */
|
||||
String caller() default "";
|
||||
|
||||
/** 认证机制 */
|
||||
ExternalApiAuthType auth() default ExternalApiAuthType.NONE;
|
||||
|
||||
/** 数据范围说明(返回/涉及什么数据) */
|
||||
String dataScope() default "";
|
||||
|
||||
/** 备注 */
|
||||
String remark() default "";
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package org.jeecg.common.aspect.annotation;
|
||||
|
||||
/**
|
||||
* 外部接口认证机制
|
||||
*/
|
||||
public enum ExternalApiAuthType {
|
||||
/** 无需认证(裸调用) */
|
||||
NONE,
|
||||
/** 共享密钥签名(X-Sign / X-TIMESTAMP) */
|
||||
SIGN,
|
||||
/** JWT 登录态 */
|
||||
JWT
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package org.jeecg.common.aspect.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 调用外部系统的接口(本系统调用其他系统)
|
||||
* <p>标注在发起出站调用的方法上(Service、客户端等)。
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface ExternalCall {
|
||||
|
||||
/** 用途 */
|
||||
String name();
|
||||
|
||||
/** 被调用的外部系统 */
|
||||
String system();
|
||||
|
||||
/** 被调接口地址 */
|
||||
String url();
|
||||
|
||||
/** HTTP 方法 */
|
||||
String httpMethod() default "GET";
|
||||
|
||||
/** 对方要求的认证机制 */
|
||||
ExternalApiAuthType auth() default ExternalApiAuthType.NONE;
|
||||
|
||||
/** 交互的数据范围说明 */
|
||||
String dataScope() default "";
|
||||
|
||||
/** 备注 */
|
||||
String remark() default "";
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.jeecg.config.extapi;
|
||||
|
||||
import org.jeecg.config.extapi.model.ExternalApiInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 外部接口清单内存注册表
|
||||
* <p>启动时由 {@link ExternalApiScanner} 填充,运行时只读。
|
||||
*/
|
||||
public class ExternalApiRegistry {
|
||||
|
||||
private static final List<ExternalApiInfo> REGISTRY = new ArrayList<>();
|
||||
|
||||
private ExternalApiRegistry() {
|
||||
}
|
||||
|
||||
public static synchronized void set(List<ExternalApiInfo> list) {
|
||||
REGISTRY.clear();
|
||||
if (list != null) {
|
||||
REGISTRY.addAll(list);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<ExternalApiInfo> get() {
|
||||
return Collections.unmodifiableList(REGISTRY);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
package org.jeecg.config.extapi;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.common.aspect.annotation.ExternalApi;
|
||||
import org.jeecg.common.aspect.annotation.ExternalApiAuthType;
|
||||
import org.jeecg.common.aspect.annotation.ExternalCall;
|
||||
import org.jeecg.config.extapi.model.ExternalApiInfo;
|
||||
import org.jeecg.config.extapi.model.ExternalApiType;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 外部接口清单扫描器
|
||||
* <p>启动时扫描两类注解生成内存注册表:
|
||||
* <ul>
|
||||
* <li>@ExternalApi:扫描 Controller 方法(接口地址由 @RequestMapping 推导)</li>
|
||||
* <li>@ExternalCall:扫描全部 Spring Bean 方法(出站调用,地址取自注解)</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ExternalApiScanner implements InitializingBean {
|
||||
|
||||
private final RequestMappingHandlerMapping requestMappingHandlerMapping;
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
public ExternalApiScanner(RequestMappingHandlerMapping requestMappingHandlerMapping,
|
||||
ApplicationContext applicationContext) {
|
||||
this.requestMappingHandlerMapping = requestMappingHandlerMapping;
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
long start = System.currentTimeMillis();
|
||||
List<ExternalApiInfo> list = new ArrayList<>();
|
||||
scanExposeApis(list);
|
||||
scanCallApis(list);
|
||||
ExternalApiRegistry.set(list);
|
||||
long cost = System.currentTimeMillis() - start;
|
||||
log.info("【外部接口清单-扫描器】初始化完成, 对外提供 {} 条, 对外调用 {} 条, 耗时 {} 毫秒",
|
||||
list.stream().filter(i -> ExternalApiType.EXPOSE.name().equals(i.getType())).count(),
|
||||
list.stream().filter(i -> ExternalApiType.CALL.name().equals(i.getType())).count(),
|
||||
cost);
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描对外提供接口(Controller 方法)
|
||||
*/
|
||||
private void scanExposeApis(List<ExternalApiInfo> list) {
|
||||
Set<Class<?>> controllers = requestMappingHandlerMapping.getHandlerMethods().values().stream()
|
||||
.map(HandlerMethod::getBeanType)
|
||||
.collect(java.util.stream.Collectors.toSet());
|
||||
for (Class<?> controller : controllers) {
|
||||
RequestMapping base = controller.getAnnotation(RequestMapping.class);
|
||||
String[] baseUrl = Objects.nonNull(base) ? base.value() : new String[]{};
|
||||
for (Method method : controller.getDeclaredMethods()) {
|
||||
ExternalApi ann = method.getAnnotation(ExternalApi.class);
|
||||
if (ann == null) {
|
||||
continue;
|
||||
}
|
||||
RequestMappingInfo info = resolveRequestMapping(method);
|
||||
if (info == null) {
|
||||
log.warn("【外部接口清单-扫描器】@ExternalApi 方法未找到 HTTP 映射, 跳过, method: {}.{}",
|
||||
controller.getSimpleName(), method.getName());
|
||||
continue;
|
||||
}
|
||||
for (String url : rebuildUrl(baseUrl, info.uris)) {
|
||||
ExternalApiInfo item = new ExternalApiInfo();
|
||||
item.setType(ExternalApiType.EXPOSE.name());
|
||||
item.setName(ann.name());
|
||||
item.setUrl(url);
|
||||
item.setHttpMethod(info.httpMethod);
|
||||
item.setCallerSystem(ann.caller());
|
||||
item.setTargetSystem("本系统");
|
||||
item.setDataFlow("外部系统→本系统(请求入站);本系统→外部系统(数据出站)");
|
||||
item.setDataScope(ann.dataScope());
|
||||
item.setAuth(authLabel(ann.auth()));
|
||||
item.setSource(controller.getName() + "#" + method.getName());
|
||||
item.setRemark(ann.remark());
|
||||
list.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描对外调用接口(全部 Spring Bean 方法)
|
||||
*/
|
||||
private void scanCallApis(List<ExternalApiInfo> list) {
|
||||
Set<String> visited = new HashSet<>();
|
||||
String[] beanNames = applicationContext.getBeanDefinitionNames();
|
||||
for (String beanName : beanNames) {
|
||||
Class<?> type = applicationContext.getType(beanName);
|
||||
if (type == null || type.getName().startsWith("org.springframework")
|
||||
|| type.getName().startsWith("org.apache")
|
||||
|| type.getName().startsWith("java.")
|
||||
|| type.getName().startsWith("lombok")) {
|
||||
continue;
|
||||
}
|
||||
Class<?> target = type.getName().contains("$$") && type.getSuperclass() != null
|
||||
? type.getSuperclass() : type;
|
||||
for (Method method : target.getDeclaredMethods()) {
|
||||
ExternalCall ann = method.getAnnotation(ExternalCall.class);
|
||||
if (ann == null) {
|
||||
continue;
|
||||
}
|
||||
String key = target.getName() + "#" + method.getName();
|
||||
if (!visited.add(key)) {
|
||||
continue;
|
||||
}
|
||||
ExternalApiInfo item = new ExternalApiInfo();
|
||||
item.setType(ExternalApiType.CALL.name());
|
||||
item.setName(ann.name());
|
||||
item.setUrl(ann.url());
|
||||
item.setHttpMethod(ann.httpMethod());
|
||||
item.setCallerSystem("本系统");
|
||||
item.setTargetSystem(ann.system());
|
||||
item.setDataFlow("本系统→外部系统(数据出站)");
|
||||
item.setDataScope(ann.dataScope());
|
||||
item.setAuth(authLabel(ann.auth()));
|
||||
item.setSource(target.getName() + "#" + method.getName());
|
||||
item.setRemark(ann.remark());
|
||||
list.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从方法的 HTTP 映射注解解析 URL 与 HTTP 方法
|
||||
*/
|
||||
private RequestMappingInfo resolveRequestMapping(Method method) {
|
||||
RequestMapping rm = method.getAnnotation(RequestMapping.class);
|
||||
if (rm != null) {
|
||||
return new RequestMappingInfo(rm.value(), rm.method().length > 0 ? rm.method()[0].name() : "ALL");
|
||||
}
|
||||
GetMapping get = method.getAnnotation(GetMapping.class);
|
||||
if (get != null) {
|
||||
return new RequestMappingInfo(get.value(), "GET");
|
||||
}
|
||||
PostMapping post = method.getAnnotation(PostMapping.class);
|
||||
if (post != null) {
|
||||
return new RequestMappingInfo(post.value(), "POST");
|
||||
}
|
||||
PutMapping put = method.getAnnotation(PutMapping.class);
|
||||
if (put != null) {
|
||||
return new RequestMappingInfo(put.value(), "PUT");
|
||||
}
|
||||
DeleteMapping del = method.getAnnotation(DeleteMapping.class);
|
||||
if (del != null) {
|
||||
return new RequestMappingInfo(del.value(), "DELETE");
|
||||
}
|
||||
PatchMapping patch = method.getAnnotation(PatchMapping.class);
|
||||
if (patch != null) {
|
||||
return new RequestMappingInfo(patch.value(), "PATCH");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<String> rebuildUrl(String[] bases, String[] uris) {
|
||||
List<String> urls = new ArrayList<>();
|
||||
if (bases.length > 0) {
|
||||
for (String base : bases) {
|
||||
for (String uri : uris) {
|
||||
urls.add(prefix(base) + prefix(uri.replaceAll("\\{.*?}", "*")));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (String uri : uris) {
|
||||
urls.add(prefix(uri.replaceAll("\\{.*?}", "*")));
|
||||
}
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
private String prefix(String seg) {
|
||||
return seg.startsWith("/") ? seg : "/" + seg;
|
||||
}
|
||||
|
||||
private String authLabel(ExternalApiAuthType auth) {
|
||||
switch (auth) {
|
||||
case SIGN:
|
||||
return "签名";
|
||||
case JWT:
|
||||
return "JWT";
|
||||
default:
|
||||
return "无";
|
||||
}
|
||||
}
|
||||
|
||||
private static class RequestMappingInfo {
|
||||
private final String[] uris;
|
||||
private final String httpMethod;
|
||||
|
||||
private RequestMappingInfo(String[] uris, String httpMethod) {
|
||||
this.uris = uris;
|
||||
this.httpMethod = httpMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.jeecg.config.extapi.model;
|
||||
|
||||
import lombok.Data;
|
||||
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||
|
||||
/**
|
||||
* 外部接口清单条目
|
||||
*/
|
||||
@Data
|
||||
public class ExternalApiInfo {
|
||||
|
||||
/** 方向类型(对外提供 / 对外调用) */
|
||||
@Excel(name = "方向", width = 12)
|
||||
private String type;
|
||||
|
||||
/** 接口名称/用途 */
|
||||
@Excel(name = "接口名称", width = 28)
|
||||
private String name;
|
||||
|
||||
/** 接口地址 */
|
||||
@Excel(name = "接口地址", width = 50)
|
||||
private String url;
|
||||
|
||||
/** HTTP 方法 */
|
||||
@Excel(name = "HTTP方法", width = 10)
|
||||
private String httpMethod;
|
||||
|
||||
/** 调用方系统(谁在调) */
|
||||
@Excel(name = "调用方系统", width = 20)
|
||||
private String callerSystem;
|
||||
|
||||
/** 被调系统(调谁) */
|
||||
@Excel(name = "被调系统", width = 20)
|
||||
private String targetSystem;
|
||||
|
||||
/** 数据流向 */
|
||||
@Excel(name = "数据流向", width = 45)
|
||||
private String dataFlow;
|
||||
|
||||
/** 数据范围 */
|
||||
@Excel(name = "数据范围", width = 45)
|
||||
private String dataScope;
|
||||
|
||||
/** 认证机制 */
|
||||
@Excel(name = "认证机制", width = 12)
|
||||
private String auth;
|
||||
|
||||
/** 代码位置(类#方法) */
|
||||
@Excel(name = "代码位置", width = 70)
|
||||
private String source;
|
||||
|
||||
/** 备注 */
|
||||
@Excel(name = "备注", width = 30)
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.jeecg.config.extapi.model;
|
||||
|
||||
/**
|
||||
* 外部接口方向类型
|
||||
*/
|
||||
public enum ExternalApiType {
|
||||
/** 对外提供(外部系统调用本系统) */
|
||||
EXPOSE,
|
||||
/** 对外调用(本系统调用外部系统) */
|
||||
CALL
|
||||
}
|
||||
+3
@@ -4,6 +4,8 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.aspect.annotation.ExternalApi;
|
||||
import org.jeecg.common.aspect.annotation.ExternalApiAuthType;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.jeecg.openapi.service.ITaskApi;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -32,6 +34,7 @@ public class TaskApiController {
|
||||
* <p>调用方(门户)通过 username 参数传入 sys_user.username(登录账号)。
|
||||
*/
|
||||
@Operation(summary = "门户查询待办数", description = "门户查询待办数")
|
||||
@ExternalApi(name = "门户查询待办数", caller = "门户系统", auth = ExternalApiAuthType.NONE, dataScope = "仅返回待办数量,不涉及业务明细")
|
||||
@GetMapping("/countTaskforporter")
|
||||
public Result<Long> countTaskforporter(HttpServletRequest request) {
|
||||
String username = request.getParameter("username");
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
package org.jeecg.modules.system.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.system.vo.LoginUser;
|
||||
import org.jeecg.config.extapi.ExternalApiRegistry;
|
||||
import org.jeecg.config.extapi.model.ExternalApiInfo;
|
||||
import org.jeecg.config.extapi.model.ExternalApiType;
|
||||
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
|
||||
import org.jeecgframework.poi.excel.entity.ExportParams;
|
||||
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 外部接口清单(对外提供 / 对外调用)展示与导出
|
||||
* <p>数据来自 {@link ExternalApiRegistry} 内存注册表(启动时由注解扫描生成)。
|
||||
*/
|
||||
@Tag(name = "外部接口清单")
|
||||
@RestController
|
||||
@RequestMapping("/sys/extApi")
|
||||
@Slf4j
|
||||
public class ExternalApiController {
|
||||
|
||||
private static final DateTimeFormatter FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@Operation(summary = "外部接口清单列表")
|
||||
@GetMapping("/list")
|
||||
public Result<List<ExternalApiInfo>> list() {
|
||||
return Result.OK(ExternalApiRegistry.get());
|
||||
}
|
||||
|
||||
@Operation(summary = "导出外部接口清单Excel")
|
||||
@GetMapping("/exportXls")
|
||||
public ModelAndView exportXls(HttpServletRequest request) {
|
||||
// AutoPoi 导出时会 remove 已处理行(多sheet分页),必须传可变集合
|
||||
List<ExternalApiInfo> data = new ArrayList<>(ExternalApiRegistry.get());
|
||||
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
|
||||
String title = "外部接口清单";
|
||||
mv.addObject(NormalExcelConstants.FILE_NAME, title);
|
||||
mv.addObject(NormalExcelConstants.CLASS, ExternalApiInfo.class);
|
||||
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||
ExportParams exportParams = new ExportParams(title + "报表", "导出人:" + (sysUser == null ? "" : sysUser.getRealname()), title);
|
||||
mv.addObject(NormalExcelConstants.PARAMS, exportParams);
|
||||
mv.addObject(NormalExcelConstants.DATA_LIST, data);
|
||||
return mv;
|
||||
}
|
||||
|
||||
@Operation(summary = "导出外部接口清单Markdown")
|
||||
@GetMapping("/exportMarkdown")
|
||||
public void exportMarkdown(HttpServletResponse response) throws IOException {
|
||||
String content = buildMarkdown();
|
||||
String fileName = URLEncoder.encode("外部接口清单.md", StandardCharsets.UTF_8.name()).replaceAll("\\+", "%20");
|
||||
response.setContentType("text/markdown;charset=UTF-8");
|
||||
response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + fileName);
|
||||
OutputStream os = response.getOutputStream();
|
||||
os.write(content.getBytes(StandardCharsets.UTF_8));
|
||||
os.flush();
|
||||
os.close();
|
||||
}
|
||||
|
||||
private String buildMarkdown() {
|
||||
List<ExternalApiInfo> all = ExternalApiRegistry.get();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("# 应用系统外部接口清单\n\n");
|
||||
sb.append("> 生成时间:" + LocalDateTime.now().format(FMT) + " | 认证机制:无=裸调用 / 签名=X-Sign / JWT=登录态\n\n");
|
||||
sb.append("## 一、对外提供的接口(外部系统调用本系统)\n\n");
|
||||
sb.append(tableHeader());
|
||||
all.stream().filter(i -> ExternalApiType.EXPOSE.name().equals(i.getType())).forEach(i -> sb.append(tableRow(i)));
|
||||
sb.append("\n## 二、对外调用的接口(本系统调用外部系统)\n\n");
|
||||
sb.append(tableHeader());
|
||||
all.stream().filter(i -> ExternalApiType.CALL.name().equals(i.getType())).forEach(i -> sb.append(tableRow(i)));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String tableHeader() {
|
||||
return "| 接口名称 | 地址 | HTTP方法 | 调用方系统 | 被调系统 | 数据流向 | 数据范围 | 认证机制 | 代码位置 | 备注 |\n"
|
||||
+ "|---|---|---|---|---|---|---|---|---|---|\n";
|
||||
}
|
||||
|
||||
private String tableRow(ExternalApiInfo i) {
|
||||
return String.join(" | ",
|
||||
cell(i.getName()),
|
||||
cell(i.getUrl()),
|
||||
cell(i.getHttpMethod()),
|
||||
cell(i.getCallerSystem()),
|
||||
cell(i.getTargetSystem()),
|
||||
cell(i.getDataFlow()),
|
||||
cell(i.getDataScope()),
|
||||
cell(i.getAuth()),
|
||||
cell(i.getSource()),
|
||||
cell(i.getRemark())) + "\n";
|
||||
}
|
||||
|
||||
private String cell(String v) {
|
||||
return StringUtils.hasText(v) ? v.replace("|", "\\|").replace("\n", " ") : " ";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
-- ============================================
|
||||
-- 外部接口清单 菜单 + 角色授权(幂等)
|
||||
-- 页面: src/views/super/apiList/index.vue
|
||||
-- 后端: /sys/extApi/* (ExternalApiController)
|
||||
-- ============================================
|
||||
|
||||
SET @menu_id = REPLACE(UUID(), '-', '');
|
||||
|
||||
INSERT INTO sys_permission
|
||||
(id, parent_id, name, url, component, is_route, component_name, redirect,
|
||||
menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf,
|
||||
keep_alive, hidden, hide_tab, description, create_by, create_time,
|
||||
update_by, update_time, del_flag, rule_flag, status, internal_or_external)
|
||||
SELECT
|
||||
@menu_id, '', '外部接口清单', '/super/apiList', 'super/apiList/index', 1, NULL, NULL,
|
||||
1, NULL, 1, 100.00, 0, NULL, 1,
|
||||
0, 0, 0, '应用系统间接口清单(对外提供/对外调用),注解自动采集', 'admin', NOW(),
|
||||
'admin', NOW(), 0, 0, 1, 0
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (SELECT 1 FROM sys_permission WHERE name = '外部接口清单' AND url = '/super/apiList');
|
||||
|
||||
-- 授权给 admin 角色
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids)
|
||||
SELECT REPLACE(UUID(), '-', ''), 'f6817f48af4fb3af11b9e8bf182f618b', @menu_id, NULL
|
||||
FROM DUAL
|
||||
WHERE EXISTS (SELECT 1 FROM sys_permission WHERE id = @menu_id)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM sys_role_permission r
|
||||
WHERE r.role_id = 'f6817f48af4fb3af11b9e8bf182f618b' AND r.permission_id = @menu_id
|
||||
);
|
||||
Reference in New Issue
Block a user