初始化前端目录
This commit is contained in:
@@ -14,12 +14,12 @@ public class AuthInterceptor implements HandlerInterceptor {
|
||||
public boolean preHandle(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
Object handler) throws Exception {
|
||||
// HttpSession session = request.getSession();
|
||||
// ApiUser apiUser = (ApiUser) session.getAttribute("Authorization");
|
||||
// if (apiUser == null) {
|
||||
// response.sendRedirect(request.getContextPath() + "/login");
|
||||
// return false;
|
||||
// }
|
||||
HttpSession session = request.getSession();
|
||||
ApiUser apiUser = (ApiUser) session.getAttribute("userInfo");
|
||||
if (apiUser == null) {
|
||||
response.sendRedirect(request.getContextPath() + "/login");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
package com.mini.capi.config;
|
||||
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.resource.PathResourceResolver;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
@@ -13,35 +19,51 @@ public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
private final AuthInterceptor authInterceptor;
|
||||
|
||||
// @Override
|
||||
// public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
// registry.addResourceHandler("/cApi/**")
|
||||
// .addResourceLocations("classpath:/static/")
|
||||
// .setCachePeriod(0);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// @Override
|
||||
// public void addViewControllers(ViewControllerRegistry registry) {
|
||||
// registry.addViewController("/cApi/**")
|
||||
// .setViewName("forward:/cApi/index.html");
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/login").setViewName("forward:/index.html");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("/**")
|
||||
.addResourceLocations("classpath:/static/")
|
||||
.resourceChain(true)
|
||||
.addResolver(new PathResourceResolver() {
|
||||
@Override
|
||||
protected Resource getResource(String resourcePath, Resource location) throws IOException {
|
||||
Resource requested = super.getResource(resourcePath, location);
|
||||
// 文件存在就返回,不存在返回 index.html
|
||||
return requested != null ? requested : new ClassPathResource("/static/index.html");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(authInterceptor)
|
||||
.addPathPatterns("/**") // 需要拦截的路径
|
||||
.excludePathPatterns( // 排除的路径
|
||||
.addPathPatterns("/**") // 拦截所有请求
|
||||
.excludePathPatterns(
|
||||
// ① 排除 Vue 静态资源(匹配 static 目录下所有 js/css/img 等)
|
||||
"/js/**",
|
||||
"/css/**",
|
||||
"/img/**",
|
||||
"/favicon.ico",
|
||||
"/index.html", // 排除首页(Vue 入口)
|
||||
"/assets/**", // 若 Vue 打包后有 assets 目录,需排除
|
||||
"/resource/**", // 若有其他静态资源目录,需排除
|
||||
"/cApi/index/**",
|
||||
|
||||
"/login",
|
||||
"/index.html",
|
||||
"/assets/**",
|
||||
"/resource/**",
|
||||
"/swagger-ui/**",
|
||||
"/v3/api-docs/**",
|
||||
"/Sys/jobs/**",
|
||||
"/Sys/login/**", // 你的登录接口(原 /Sys/login/** 缺少 /cApi 前缀,修复)
|
||||
"/Sys/jobs/**", // 原路径补充 /cApi 前缀
|
||||
"/Sys/hosts/**",
|
||||
"/Sys/dbs/**",
|
||||
"/Sys/login/**"
|
||||
|
||||
"/cApi/swagger-ui/**",
|
||||
"/cApi/v3/api-docs/**"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.mini.capi.job;
|
||||
|
||||
|
||||
import com.mini.capi.model.ApiResult;
|
||||
import com.mini.capi.sys.service.DbService;
|
||||
import com.mini.capi.sys.service.DockerService;
|
||||
import com.mini.capi.utils.*;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/Sys/jobs")
|
||||
public class taskEnable {
|
||||
|
||||
|
||||
@Resource
|
||||
private DockerService dockerService;
|
||||
|
||||
@Resource
|
||||
private DbService dbService;
|
||||
|
||||
|
||||
/**
|
||||
* 获取容器主机的磁盘使用情况
|
||||
*/
|
||||
@GetMapping("/getTaskDockerDiskInfo")
|
||||
public ApiResult<?> jobHostDisk(String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return dockerService.jobHostDisk();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 运行全部任务数据同步
|
||||
*/
|
||||
@GetMapping("/getTaskSyncDbInfo")
|
||||
public ApiResult<?> jobSyncAllTask(String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return dbService.jobSyncAllTask();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.mini.capi.model;
|
||||
|
||||
import com.mini.capi.biz.domain.SyncTablesView;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ApiResult<T> implements Serializable {
|
||||
@@ -37,6 +39,7 @@ public class ApiResult<T> implements Serializable {
|
||||
this.result = data;
|
||||
}
|
||||
|
||||
|
||||
/* ---------------- 静态工厂方法 ---------------- */
|
||||
|
||||
/**
|
||||
|
||||
124
src/main/java/com/mini/capi/sys/Api/apiController.java
Normal file
124
src/main/java/com/mini/capi/sys/Api/apiController.java
Normal file
@@ -0,0 +1,124 @@
|
||||
package com.mini.capi.sys.Api;
|
||||
|
||||
import com.mini.capi.model.ApiResult;
|
||||
import com.mini.capi.model.TabResult;
|
||||
import com.mini.capi.sys.service.DbService;
|
||||
import com.mini.capi.sys.service.DockerService;
|
||||
import com.mini.capi.sys.service.HostService;
|
||||
import com.mini.capi.utils.vToken;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/Sys/api")
|
||||
public class apiController {
|
||||
|
||||
|
||||
@Resource
|
||||
private DbService dbService;
|
||||
|
||||
@Resource
|
||||
private HostService hostService;
|
||||
|
||||
|
||||
@Resource
|
||||
private DockerService dockerService;
|
||||
|
||||
|
||||
/**
|
||||
* 获取MySQL的当前连接下的所有数据表
|
||||
*/
|
||||
@GetMapping("/getApiSourceTables")
|
||||
public ApiResult<List<TabResult>> listSourceTables(String token, String dbId) {
|
||||
// 1. 验证token有效性
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return dbService.listSourceTables(dbId);
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/getApiInfo")
|
||||
public ApiResult<List<HostService.SnapshotDTO>> getApiInfo(String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return hostService.getApiInfo();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取容器列表
|
||||
*/
|
||||
@GetMapping("/getApiDockerInfo")
|
||||
public ApiResult<?> getDockerInfo(String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return hostService.getDockerInfo();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 启动容器
|
||||
*/
|
||||
@GetMapping("/getApiStartDockerInfo")
|
||||
public ApiResult<?> startDockerInfo(String id, String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return hostService.startDockerInfo(id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 停止容器
|
||||
*/
|
||||
@GetMapping("/getApiStopDockerInfo")
|
||||
public ApiResult<?> stopDockerInfo(String id, String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return hostService.stopDockerInfo(id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取容器主机的磁盘使用情况
|
||||
*/
|
||||
@GetMapping("/getTaskDockerDiskInfo")
|
||||
public ApiResult<?> jobHostDisk(String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return dockerService.jobHostDisk();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 运行全部任务数据同步
|
||||
*/
|
||||
@GetMapping("/getTaskSyncDbInfo")
|
||||
public ApiResult<?> jobSyncAllTask(String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return dbService.jobSyncAllTask();
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行单个任务
|
||||
*/
|
||||
@GetMapping("/getTaskSyncDbByInfo")
|
||||
public ApiResult<?> jobSyncOneTask(String token, String taskId) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return dbService.jobSyncOneTask(taskId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +1,32 @@
|
||||
package com.mini.capi.sys.controller;
|
||||
package com.mini.capi.sys.App;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.mini.capi.biz.domain.DbConfig;
|
||||
import com.mini.capi.biz.domain.SyncTablesView;
|
||||
import com.mini.capi.biz.domain.SyncTask;
|
||||
import com.mini.capi.biz.service.DbConfigService;
|
||||
import com.mini.capi.biz.service.SyncTablesViewService;
|
||||
import com.mini.capi.biz.service.SyncTaskService;
|
||||
import com.mini.capi.config.DataSourceConfig;
|
||||
import com.mini.capi.model.ApiResult;
|
||||
import com.mini.capi.sys.domain.SelectOption;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.Data;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Controller
|
||||
@RestController
|
||||
@RequestMapping("/Sys/data")
|
||||
public class dataController {
|
||||
|
||||
|
||||
@@ -26,12 +35,11 @@ public class dataController {
|
||||
|
||||
|
||||
@Resource
|
||||
private DbConfigService dbConfigService;
|
||||
private DbConfigService configService;
|
||||
|
||||
@GetMapping("/Sys/data/list")
|
||||
public String listPage() {
|
||||
return "views/data/list";
|
||||
}
|
||||
|
||||
@Resource
|
||||
private SyncTablesViewService tablesViewService;
|
||||
|
||||
|
||||
@Data
|
||||
@@ -73,6 +81,28 @@ public class dataController {
|
||||
}
|
||||
|
||||
|
||||
@Data
|
||||
static class TableInfo implements Serializable {
|
||||
private TabDetail tabDetail;
|
||||
private List<TabColumns> tabColumns;
|
||||
private long pkCnt;
|
||||
private long idxCnt;
|
||||
private long colCnt;
|
||||
private String ddlSql;
|
||||
private String selectSql;
|
||||
|
||||
public TableInfo(TabDetail tabDetail, List<TabColumns> tabColumns, long pkCnt, long idxCnt, long colCnt, String ddlSql, String selectSql) {
|
||||
this.tabDetail = tabDetail;
|
||||
this.tabColumns = tabColumns;
|
||||
this.pkCnt = pkCnt;
|
||||
this.idxCnt = idxCnt;
|
||||
this.colCnt = colCnt;
|
||||
this.ddlSql = ddlSql;
|
||||
this.selectSql = selectSql;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String buildSelect(List<TabColumns> columns, TabDetail table) {
|
||||
if (columns == null || columns.isEmpty() || table == null) {
|
||||
return "-- no columns or table info";
|
||||
@@ -160,18 +190,78 @@ public class dataController {
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/Sys/data/getTableDetail")
|
||||
public String getTableDetail(String taskId, Model model) {
|
||||
SyncTask task = syncTaskService.getById(taskId);
|
||||
DbConfig dbConfig = dbConfigService.getById(task.getSourceDbId());
|
||||
List<TabDetail> data;
|
||||
List<TabColumns> columns;
|
||||
/**
|
||||
* 获取数据配置表
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/getDbList")
|
||||
public ApiResult<List<SelectOption>> getDbList() {
|
||||
try {
|
||||
JdbcTemplate jdbcTemplate = DataSourceConfig.createJdbcTemplate(dbConfig);
|
||||
// 补充参数传递
|
||||
String querySql = "SELECT CREATE_TIME,TABLE_NAME,TABLE_COMMENT,MAX_DATA_LENGTH,UPDATE_TIME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?";
|
||||
List<DbConfig> configs = configService.list();
|
||||
List<SelectOption> selectOptions = configs.stream()
|
||||
.map(config -> new SelectOption(
|
||||
config.getDbId(), // 下拉框value(绑定值)
|
||||
config.getDbName(), // 下拉框label(显示文本)
|
||||
false // 【关键注释】说明禁用原因(如:所有数据库默认禁用选择,需申请后启用)
|
||||
))
|
||||
.collect(Collectors.toList());
|
||||
return ApiResult.success(selectOptions);
|
||||
} catch (Exception e) {
|
||||
return ApiResult.error(401, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据字段表
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/getTableList")
|
||||
public ApiResult<List<SyncTablesView>> getTableList(String dbId, String targetTable) {
|
||||
try {
|
||||
List<SyncTablesView> tablesViews = tablesViewService.list(
|
||||
new QueryWrapper<SyncTablesView>()
|
||||
.eq(StringUtils.hasText(dbId), "db_id", dbId)
|
||||
.and(StringUtils.hasText(targetTable),
|
||||
w -> w.like("target_table", targetTable)
|
||||
.or()
|
||||
.like("task_name", targetTable))
|
||||
.orderByDesc("create_time")
|
||||
);
|
||||
return ApiResult.success(tablesViews);
|
||||
} catch (Exception e) {
|
||||
return ApiResult.error(401, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据表属性
|
||||
*
|
||||
* @param taskId
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/Sys/data/getTableDetail")
|
||||
public ApiResult<TableInfo> getTableDetail(String taskId) {
|
||||
// 获取基础数据
|
||||
SyncTask task = syncTaskService.getById(taskId);
|
||||
DbConfig dbConfig = configService.getById(task.getSourceDbId());
|
||||
JdbcTemplate jdbcTemplate;
|
||||
try {
|
||||
// 统一创建JdbcTemplate,避免重复初始化
|
||||
jdbcTemplate = DataSourceConfig.createJdbcTemplate(dbConfig);
|
||||
} catch (Exception e) {
|
||||
return ApiResult.error(401, e.getMessage());
|
||||
}
|
||||
|
||||
// 查询表基本信息
|
||||
List<TabDetail> data;
|
||||
try {
|
||||
String tableQuerySql = "SELECT CREATE_TIME,TABLE_NAME,TABLE_COMMENT,MAX_DATA_LENGTH,UPDATE_TIME " +
|
||||
"FROM information_schema.TABLES " +
|
||||
"WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?";
|
||||
data = jdbcTemplate.query(
|
||||
querySql,
|
||||
tableQuerySql,
|
||||
(rs, rowNum) -> new TabDetail(
|
||||
rs.getString("CREATE_TIME"),
|
||||
dbConfig.getDbName(),
|
||||
@@ -185,16 +275,17 @@ public class dataController {
|
||||
);
|
||||
data.sort(Comparator.comparing(TabDetail::getTableName));
|
||||
} catch (Exception e) {
|
||||
data = Collections.emptyList();
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
return ApiResult.error(401, e.getMessage());
|
||||
}
|
||||
// 查询表列信息
|
||||
List<TabColumns> columns;
|
||||
try {
|
||||
JdbcTemplate jdbcTemplate = DataSourceConfig.createJdbcTemplate(dbConfig);
|
||||
// 补充参数传递
|
||||
String querySql = "SELECT TABLE_NAME,ORDINAL_POSITION,COLUMN_NAME,COLUMN_TYPE,COLUMN_COMMENT,COLUMN_KEY FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?";
|
||||
String columnQuerySql = "SELECT TABLE_NAME,ORDINAL_POSITION,COLUMN_NAME,COLUMN_TYPE,COLUMN_COMMENT,COLUMN_KEY " +
|
||||
"FROM information_schema.COLUMNS " +
|
||||
"WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?";
|
||||
columns = jdbcTemplate.query(
|
||||
querySql,
|
||||
columnQuerySql,
|
||||
(rs, rowNum) -> new TabColumns(
|
||||
rs.getString("TABLE_NAME"),
|
||||
rs.getInt("ORDINAL_POSITION"),
|
||||
@@ -208,26 +299,29 @@ public class dataController {
|
||||
);
|
||||
columns.sort(Comparator.comparing(TabColumns::getSort));
|
||||
} catch (Exception e) {
|
||||
columns = Collections.emptyList();
|
||||
System.out.println(e.getMessage());
|
||||
return ApiResult.error(401, e.getMessage());
|
||||
}
|
||||
// 在查询完表结构后
|
||||
|
||||
// 计算表结构统计信息
|
||||
long primaryKeyCnt = columns.stream()
|
||||
.filter(c -> "PRI".equalsIgnoreCase(c.getKeyType()))
|
||||
.count();
|
||||
long indexCnt = columns.stream()
|
||||
.filter(c -> !"PRI".equalsIgnoreCase(c.getKeyType()) && !c.getKeyType().isBlank())
|
||||
.count()
|
||||
+ 1; // 主键索引也算 1 个
|
||||
.count() + 1; // 包含主键索引
|
||||
long colCnt = columns.size();
|
||||
model.addAttribute("pkCnt", primaryKeyCnt);
|
||||
model.addAttribute("idxCnt", indexCnt);
|
||||
model.addAttribute("colCnt", colCnt);
|
||||
model.addAttribute("data", data);
|
||||
model.addAttribute("columns", columns);
|
||||
model.addAttribute("ddlSql", buildDDL(columns, data.get(0)));
|
||||
model.addAttribute("selectSql", buildSelect(columns, data.get(0)));
|
||||
return "views/data/detail";
|
||||
|
||||
// 构建返回结果
|
||||
TableInfo tableInfo = new TableInfo(
|
||||
data.get(0),
|
||||
columns,
|
||||
primaryKeyCnt,
|
||||
indexCnt,
|
||||
colCnt,
|
||||
buildDDL(columns, data.get(0)),
|
||||
buildSelect(columns, data.get(0))
|
||||
);
|
||||
return ApiResult.success(tableInfo);
|
||||
}
|
||||
|
||||
|
||||
9
src/main/java/com/mini/capi/sys/App/hostController.java
Normal file
9
src/main/java/com/mini/capi/sys/App/hostController.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package com.mini.capi.sys.App;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/Sys/hosts")
|
||||
public class hostController {
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.mini.capi.sys.pageController;
|
||||
package com.mini.capi.sys.App;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.mini.capi.biz.domain.ApiMenus;
|
||||
@@ -10,6 +10,7 @@ import com.mini.capi.biz.service.ApiUserService;
|
||||
import com.mini.capi.model.ApiResult;
|
||||
import com.mini.capi.model.auth.Result;
|
||||
import com.mini.capi.sys.domain.ModuleMenuDTO;
|
||||
import com.mini.capi.utils.KeyUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import lombok.Data;
|
||||
@@ -20,10 +21,9 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/Sys/login")
|
||||
public class loginPageController {
|
||||
public class loginController {
|
||||
|
||||
|
||||
@Resource
|
||||
@@ -58,11 +58,14 @@ public class loginPageController {
|
||||
*/
|
||||
private String uname;
|
||||
|
||||
private String token;
|
||||
|
||||
// 构造方法(从实体类转换)
|
||||
public ApiUserDTO(ApiUser apiUser) {
|
||||
public ApiUserDTO(ApiUser apiUser, String token) {
|
||||
this.userId = apiUser.getUserId();
|
||||
this.username = apiUser.getApiUser();
|
||||
this.uname = apiUser.getUname();
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,14 +94,25 @@ public class loginPageController {
|
||||
// 可记录登录失败日志,用于后续风控
|
||||
return Result.error(102, "账户或密码错误");
|
||||
}
|
||||
session.setAttribute("token", apiUser);
|
||||
ApiUserDTO userDTO = new ApiUserDTO(apiUser);
|
||||
session.setAttribute("userInfo", apiUser);
|
||||
ApiUserDTO userDTO = new ApiUserDTO(apiUser, KeyUtil.ObjKey(32, 0));
|
||||
return Result.success("登录成功", userDTO);
|
||||
} catch (Exception e) {
|
||||
return Result.error(103, "登录失败,请稍后重试");
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/userLogout")
|
||||
public Result loginOut(HttpSession session) {
|
||||
try {
|
||||
session.removeAttribute("userInfo"); // 只清 token
|
||||
session.invalidate();
|
||||
return Result.error(200, "退出成功");
|
||||
} catch (Exception e) {
|
||||
return Result.error(500, "退出失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/getModules")
|
||||
public ApiResult<List<ModuleMenuDTO>> getModules() {
|
||||
@@ -1,31 +1,40 @@
|
||||
package com.mini.capi.sys.controller;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest; // 注意这里
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.boot.web.servlet.error.ErrorController;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Controller
|
||||
public class CustomErrorController implements ErrorController {
|
||||
|
||||
@RequestMapping("/error")
|
||||
public ResponseEntity<Map<String, Object>> handleError(HttpServletRequest request) {
|
||||
public Object handleError(HttpServletRequest request) {
|
||||
String uri = request.getRequestURI();
|
||||
|
||||
// 1. 前端路由:统一转发到 index.html
|
||||
if (uri.startsWith("/cApi/index/")) {
|
||||
return "forward:/index.html";
|
||||
}
|
||||
|
||||
// 2. 其他 404:返回 JSON
|
||||
HttpStatus status = getStatus(request);
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("status", status.value());
|
||||
body.put("error", status.getReasonPhrase());
|
||||
body.put("message", "访问的资源不存在");
|
||||
body.put("path", request.getRequestURI());
|
||||
return ResponseEntity.status(status).body(body);
|
||||
return ResponseEntity
|
||||
.status(status)
|
||||
.body(Map.of(
|
||||
"status", status.value(),
|
||||
"error", status.getReasonPhrase(),
|
||||
"message", "访问的资源不存在",
|
||||
"path", uri
|
||||
));
|
||||
}
|
||||
|
||||
private HttpStatus getStatus(HttpServletRequest request) {
|
||||
Integer code = (Integer) request.getAttribute("jakarta.servlet.error.status_code");
|
||||
return (code != null) ? HttpStatus.valueOf(code) : HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
return code != null ? HttpStatus.valueOf(code) : HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.mini.capi.sys.controller;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
@Controller
|
||||
public class hostController {
|
||||
|
||||
|
||||
/**
|
||||
* 主机登录
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/Sys/app/host")
|
||||
public String listPage() {
|
||||
return "views/ssh/index";
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.mini.capi.sys.controller;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
@Controller
|
||||
public class loginController {
|
||||
|
||||
@GetMapping("/login")
|
||||
public String loginPage() {
|
||||
return "forward:/index.html";
|
||||
}
|
||||
|
||||
//
|
||||
// /**
|
||||
// * 退出登录:清空 session 并返回到退出成功页面
|
||||
// */
|
||||
// @GetMapping("/userLogout")
|
||||
// public String logout(HttpSession session) {
|
||||
// session.invalidate();
|
||||
// return "index";
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 主页
|
||||
// */
|
||||
// @GetMapping("/welcome")
|
||||
// public String welcomePage() {
|
||||
// return "views/demo";
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 系统首页-控制台
|
||||
// */
|
||||
// @GetMapping("/home")
|
||||
// public String homePage() {
|
||||
// return "views/home";
|
||||
// }
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.mini.capi.sys.controller;
|
||||
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
@Controller
|
||||
public class sysController {
|
||||
|
||||
|
||||
@GetMapping("/Sys/sys/icon")
|
||||
public String getIcon() {
|
||||
return "views/icon";
|
||||
}
|
||||
}
|
||||
28
src/main/java/com/mini/capi/sys/domain/SelectOption.java
Normal file
28
src/main/java/com/mini/capi/sys/domain/SelectOption.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package com.mini.capi.sys.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class SelectOption implements Serializable {
|
||||
|
||||
|
||||
private String value;
|
||||
|
||||
|
||||
private String label;
|
||||
|
||||
private boolean disabled;
|
||||
|
||||
public SelectOption() {
|
||||
}
|
||||
|
||||
// 全参构造函数
|
||||
public SelectOption(String value, String label, boolean disabled) {
|
||||
this.value = value;
|
||||
this.label = label;
|
||||
this.disabled = disabled;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.mini.capi.sys.pageController;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.mini.capi.biz.domain.DbConfig;
|
||||
import com.mini.capi.biz.domain.SyncTablesView;
|
||||
import com.mini.capi.biz.service.DbConfigService;
|
||||
import com.mini.capi.biz.service.SyncTablesViewService;
|
||||
import jakarta.annotation.Resource;
|
||||
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 java.util.List;
|
||||
|
||||
@RestController // ← 关键
|
||||
@RequestMapping("/Sys/data")
|
||||
public class dataPageController {
|
||||
|
||||
|
||||
@Resource
|
||||
private DbConfigService configService;
|
||||
|
||||
|
||||
@Resource
|
||||
private SyncTablesViewService tablesViewService;
|
||||
|
||||
|
||||
@GetMapping("/getDbList")
|
||||
public List<DbConfig> getDbList() {
|
||||
return configService.list();
|
||||
}
|
||||
|
||||
@GetMapping("/getTableList")
|
||||
public List<SyncTablesView> getTableList(String dbId, String targetTable) {
|
||||
return tablesViewService.list(
|
||||
new QueryWrapper<SyncTablesView>()
|
||||
.eq(StringUtils.hasText(dbId), "db_id", dbId)
|
||||
.and(StringUtils.hasText(targetTable),
|
||||
w -> w.like("target_table", targetTable)
|
||||
.or()
|
||||
.like("task_name", targetTable))
|
||||
.orderByDesc("create_time")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.mini.capi.sys.pageController;
|
||||
|
||||
import com.mini.capi.model.ApiResult;
|
||||
import com.mini.capi.model.TabResult;
|
||||
import com.mini.capi.sys.service.DbService;
|
||||
import com.mini.capi.utils.vToken;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/Sys/dbs")
|
||||
public class dbPageController {
|
||||
|
||||
|
||||
@Resource
|
||||
private DbService dbService;
|
||||
|
||||
/**
|
||||
* 获取MySQL的当前连接下的所有数据表
|
||||
*/
|
||||
@GetMapping("/getApiSourceTables")
|
||||
public ApiResult<List<TabResult>> listSourceTables(String token, String dbId) {
|
||||
// 1. 验证token有效性
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return dbService.listSourceTables(dbId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 运行单个任务
|
||||
*/
|
||||
@GetMapping("/getTaskSyncDbByInfo")
|
||||
public ApiResult<?> jobSyncOneTask(String token, String taskId) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return dbService.jobSyncOneTask(taskId);
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package com.mini.capi.sys.pageController;
|
||||
|
||||
|
||||
import com.mini.capi.model.ApiResult;
|
||||
import com.mini.capi.sys.service.HostService;
|
||||
import com.mini.capi.utils.vToken;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/Sys/hosts")
|
||||
public class hostPageController {
|
||||
|
||||
|
||||
@Resource
|
||||
private HostService hostService;
|
||||
|
||||
|
||||
@GetMapping("/getApiInfo")
|
||||
public ApiResult<List<HostService.SnapshotDTO>> getApiInfo(String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return hostService.getApiInfo();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取容器列表
|
||||
*/
|
||||
@GetMapping("/getApiDockerInfo")
|
||||
public ApiResult<?> getDockerInfo(String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return hostService.getDockerInfo();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 启动容器
|
||||
*/
|
||||
@GetMapping("/getApiStartDockerInfo")
|
||||
public ApiResult<?> startDockerInfo(String id, String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return hostService.startDockerInfo(id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 停止容器
|
||||
*/
|
||||
@GetMapping("/getApiStopDockerInfo")
|
||||
public ApiResult<?> stopDockerInfo(String id, String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return hostService.stopDockerInfo(id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
81
src/main/java/com/mini/capi/utils/AESUtil.java
Normal file
81
src/main/java/com/mini/capi/utils/AESUtil.java
Normal file
@@ -0,0 +1,81 @@
|
||||
package com.mini.capi.utils;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.apache.commons.net.util.Base64;
|
||||
|
||||
public class AESUtil {
|
||||
public static String key = "AD42F6697B035B7580E4FEF93BE20BAD";
|
||||
private static String charset = "utf-8";
|
||||
// 偏移量
|
||||
private static int offset = 16;
|
||||
private static String transformation = "AES/CBC/PKCS5Padding";
|
||||
private static String algorithm = "AES";
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param content
|
||||
* @return
|
||||
*/
|
||||
public static String encrypt(String content) {
|
||||
return encrypt(content, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密
|
||||
*
|
||||
* @param content
|
||||
* @return
|
||||
*/
|
||||
public static String decrypt(String content) {
|
||||
return decrypt(content, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param content 需要加密的内容
|
||||
* @param key 加密密码
|
||||
* @return
|
||||
*/
|
||||
public static String encrypt(String content, String key) {
|
||||
try {
|
||||
SecretKeySpec skey = new SecretKeySpec(key.getBytes(), algorithm);
|
||||
IvParameterSpec iv = new IvParameterSpec(key.getBytes(), 0, offset);
|
||||
Cipher cipher = Cipher.getInstance(transformation);
|
||||
byte[] byteContent = content.getBytes(charset);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, skey, iv);// 初始化
|
||||
byte[] result = cipher.doFinal(byteContent);
|
||||
return new Base64().encodeToString(result).replaceAll("[\\s*\t\n\r]", ""); // 加密
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* AES(256)解密
|
||||
*
|
||||
* @param content 待解密内容
|
||||
* @param key 解密密钥
|
||||
* @return 解密之后
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String decrypt(String content, String key) {
|
||||
try {
|
||||
|
||||
SecretKeySpec skey = new SecretKeySpec(key.getBytes(), algorithm);
|
||||
IvParameterSpec iv = new IvParameterSpec(key.getBytes(charset), 0, offset);
|
||||
Cipher cipher = Cipher.getInstance(transformation);
|
||||
cipher.init(Cipher.DECRYPT_MODE, skey, iv);// 初始化
|
||||
byte[] result = cipher.doFinal(new Base64().decode(content));
|
||||
return new String(result).replaceAll("[\\s*\t\n\r]", ""); // 解密
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
48
src/main/java/com/mini/capi/utils/KeyUtil.java
Normal file
48
src/main/java/com/mini/capi/utils/KeyUtil.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package com.mini.capi.utils;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class KeyUtil {
|
||||
|
||||
public static String ObjKey(int length, int type) {
|
||||
Random random = new Random();
|
||||
StringBuffer key = new StringBuffer();
|
||||
if (type == 1) {
|
||||
String str = "0123456789";
|
||||
for (int i = 0; i < length; ++i) {
|
||||
//从62个的数字或字母中选择
|
||||
int number = random.nextInt(10);
|
||||
//将产生的数字通过length次承载到key中
|
||||
key.append(str.charAt(number));
|
||||
}
|
||||
return key.toString();
|
||||
} else if (type == 2) {
|
||||
String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
for (int i = 0; i < length; ++i) {
|
||||
//从62个的数字或字母中选择
|
||||
int number = random.nextInt(36);
|
||||
//将产生的数字通过length次承载到key中
|
||||
key.append(str.charAt(number));
|
||||
}
|
||||
return key.toString();
|
||||
} else if (type == 3) {
|
||||
String str = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
for (int i = 0; i < length; ++i) {
|
||||
//从62个的数字或字母中选择
|
||||
int number = random.nextInt(36);
|
||||
//将产生的数字通过length次承载到key中
|
||||
key.append(str.charAt(number));
|
||||
}
|
||||
return key.toString();
|
||||
} else {
|
||||
String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
for (int i = 0; i < length; ++i) {
|
||||
//从62个的数字或字母中选择
|
||||
int number = random.nextInt(62);
|
||||
//将产生的数字通过length次承载到key中
|
||||
key.append(str.charAt(number));
|
||||
}
|
||||
return key.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user