diff --git a/src/main/java/com/yxtech/ossyn/App.java b/src/main/java/com/yxtech/ossyn/App.java index ca5887d..0348f7e 100644 --- a/src/main/java/com/yxtech/ossyn/App.java +++ b/src/main/java/com/yxtech/ossyn/App.java @@ -21,149 +21,4 @@ public class App { public static void main(String[] args) { Solon.start(App.class, args); } - - -// private static final String BASE_URL = "http://api.dev.xjyt.petrochina/oauth/choerodon/login"; // 替换为实际域名 -// private static final String PUBLIC_KEY = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJL0JkqsUoK6kt3JyogsgqNp9VDGDp+t3ZAGMbVoMPdHNT2nfiIVh9ZMNHF7g2XiAa8O8AQWyh2PjMR0NiUSVQMCAwEAAQ=="; -// -// /** -// * RSA 加密密码 -// */ -// public static String encryptPassword(String password) throws Exception { -// byte[] keyBytes = Base64.getDecoder().decode(PUBLIC_KEY); -// X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); -// PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(keySpec); -// -// Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); -// cipher.init(Cipher.ENCRYPT_MODE, publicKey); -// byte[] encrypted = cipher.doFinal(password.getBytes("UTF-8")); -// return Base64.getEncoder().encodeToString(encrypted); -// } -// -// /** -// * 登录,返回 Cookie(后续请求需携带) -// */ -// public static String login(String username, String password) throws Exception { -// String encryptedPassword = encryptPassword(password); -// -// // 构建 form 表单体 -// String formBody = "username=" + java.net.URLEncoder.encode(username, "UTF-8") -// + "&password=" + java.net.URLEncoder.encode(encryptedPassword, "UTF-8"); -// -// // 打印等效的 curl 命令(Windows 格式) -// System.out.println("curl \"" + BASE_URL + "\" ^"); -// System.out.println(" -H \"Origin: http://api.dev.xjyt.petrochina\" ^"); -// System.out.println(" -H \"Content-Type: application/x-www-form-urlencoded\" ^"); -// System.out.println(" -H \"User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36\" ^"); -// System.out.println(" -H \"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\" ^"); -// System.out.println(" -H \"Referer: http://api.dev.xjyt.petrochina/oauth/choerodon/login\" ^"); -// System.out.println(" -H \"Accept-Language: zh-CN,zh;q=0.9\" ^"); -// System.out.println(" -H \"Cookie: SESSION=M2MwYTZjM2ItNzk4Ni00NTM0LWJlYzYtZDAwMDA5Zjc2ZTE1; route=289a995e776d44c58b544d574adb34a0; _hatt=26a898962c71fb9c70f01348ee9e32bb\" ^"); -// System.out.println(" --data-raw \"" + formBody + "\""); -// -// HttpClient client = HttpClient.newBuilder() -// .followRedirects(HttpClient.Redirect.NEVER) -// .build(); -// -// HttpRequest request = HttpRequest.newBuilder() -// .uri(URI.create(BASE_URL)) -// .header("Origin", "http://api.dev.xjyt.petrochina") -// .header("Content-Type", "application/x-www-form-urlencoded") -// .header("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36") -// .header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9") -// .header("Referer", "http://api.dev.xjyt.petrochina/oauth/choerodon/login") -// .header("Accept-Language", "zh-CN,zh;q=0.9") -// .header("Cookie", "SESSION=M2MwYTZjM2ItNzk4Ni00NTM0LWJlYzYtZDAwMDA5Zjc2ZTE1; route=289a995e776d44c58b544d574adb34a0; _hatt=26a898962c71fb9c70f01348ee9e32bb") -// .POST(HttpRequest.BodyPublishers.ofString(formBody)) -// .build(); -// -// HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); -// -// System.out.println("状态码: " + response.statusCode()); -// System.out.println("响应体: " + response.body()); -// -// // 登录成功后服务器返回 302,Set-Cookie 中携带新 Session -// String cookie = response.headers().firstValue("Set-Cookie").orElse(null); -// System.out.println("Cookie: " + cookie); -// -// return cookie; -// } -// -// /** -// * OAuth 授权,返回重定向地址(含 access_token) -// */ -// public static String authorize(String cookie) throws Exception { -// String url = "http://api.dev.xjyt.petrochina/oauth/oauth/authorize" + -// "?response_type=token&client_id=choerodon&state=&redirect_uri=" + -// java.net.URLEncoder.encode("http://dev.xjyt.petrochina/#/devops/resource" + -// "?activeKey=instance&category=AGILE&id=748209321615708160" + -// "&name=%E5%85%A5%E5%BA%B7%E7%AE%A1%E7%90%86%E5%B9%B3%E5%8F%B0" + -// "&organizationId=1&type=project&redirectFlag", "UTF-8"); -// -// // 打印等效的 curl 命令(Windows 格式) -// System.out.println("curl -v \"" + url + "\" ^"); -// System.out.println(" -H \"User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36\" ^"); -// System.out.println(" -H \"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8\" ^"); -// System.out.println(" -H \"Referer: http://dev.xjyt.petrochina/\" ^"); -// System.out.println(" -H \"Accept-Language: zh-CN,zh;q=0.9\" ^"); -// System.out.println(" -H \"Cookie: " + cookie + "\" ^"); -// System.out.println(" -L"); -// -// HttpClient client = HttpClient.newBuilder() -// .followRedirects(HttpClient.Redirect.NEVER) -// .build(); -// -// HttpRequest request = HttpRequest.newBuilder() -// .uri(URI.create(url)) -// .header("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36") -// .header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9") -// .header("Referer", "http://dev.xjyt.petrochina/") -// .header("Accept-Language", "zh-CN,zh;q=0.9") -// .header("Cookie", cookie) -// .GET() -// .build(); -// -// HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); -// -// System.out.println("authorize 状态码: " + response.statusCode()); -// System.out.println("authorize 响应体: " + response.body()); -// -// // 授权成功返回 302,Location 中含 access_token -// String location = response.headers().firstValue("Location").orElse(null); -// System.out.println("Location: " + location); -// -// return location; -// } -// -// public static void main(String[] args) throws Exception { -// String cookie = login("jy-lianlonggang", "UserPwdLlgA@123!"); -// System.out.println("登录成功,Cookie: " + cookie); -// -// if (cookie != null) { -// String location = authorize(cookie); -// System.out.println("授权跳转地址: " + location); -// -// String token = extractToken(location); -// System.out.println("access_token: " + token); -// } -// } -// -// /** -// * 从 Location URL 的 fragment(# 后)中提取 access_token -// */ -// public static String extractToken(String location) { -// if (location == null) return null; -// int hashIdx = location.indexOf('#'); -// if (hashIdx < 0) return null; -// String fragment = location.substring(hashIdx + 1); -// // fragment 格式:/path?key=val&access_token=xxx&... -// int queryIdx = fragment.indexOf('?'); -// String query = queryIdx >= 0 ? fragment.substring(queryIdx + 1) : fragment; -// for (String param : query.split("&")) { -// if (param.startsWith("access_token=")) { -// return param.substring("access_token=".length()); -// } -// } -// return null; -// } } diff --git a/src/main/java/com/yxtech/ossyn/service/HarborService.java b/src/main/java/com/yxtech/ossyn/service/HarborService.java index 2b8fcbd..42c2bc0 100644 --- a/src/main/java/com/yxtech/ossyn/service/HarborService.java +++ b/src/main/java/com/yxtech/ossyn/service/HarborService.java @@ -13,6 +13,7 @@ import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; +import java.io.File; import java.security.cert.X509Certificate; import java.util.Base64; import javax.net.ssl.SSLContext; @@ -111,26 +112,27 @@ public class HarborService { * @param tag 目标 tag */ public String pushImage(String tarRelPath, String repoName, String tag) throws Exception { - String tarAbsPath = skopeoConfig.getImagesPath().replace("\\", "/") + "/" + tarRelPath; - String dest = harborConfig.getUrl().replace("https://", "") - .replace("http://", ""); - dest = harborConfig.getUrl().startsWith("https") ? dest : dest; - String destImage = "docker://" + dest.replace("https://", "").replace("http://", "") - + "/" + harborConfig.getProject() + "/" + repoName + ":" + tag; - // 修正:直接拼完整 harbor host + // tarAbsPath 使用系统原生路径分隔符,供 File 对象使用 + String tarAbsPath = skopeoConfig.getImagesPath() + File.separator + tarRelPath.replace("/", File.separator); + File tarFile = new File(tarAbsPath); + // skopeo 在 Windows 下无法处理带盘符的绝对路径,改用工作目录+文件名相对路径规避 + String tarFileName = tarFile.getName(); + File workDir = tarFile.getParentFile(); + String harborHost = harborConfig.getUrl().replaceFirst("https?://", ""); - destImage = "docker://" + harborHost + "/" + harborConfig.getProject() + "/" + repoName + ":" + tag; + String destImage = "docker://" + harborHost + "/" + harborConfig.getProject() + "/" + repoName + ":" + tag; String[] cmd = { skopeoConfig.getExePath(), "copy", "--dest-creds", harborConfig.getUsername() + ":" + harborConfig.getPassword(), "--dest-tls-verify=false", - "docker-archive:" + tarAbsPath, + "docker-archive:" + tarFileName, destImage }; - log.info("[Harbor] skopeo push: {} -> {}", tarAbsPath, destImage); + log.info("[Harbor] skopeo push: workDir={} cmd={}", workDir.getAbsolutePath(), String.join(" ", cmd)); Process process = new ProcessBuilder(cmd) + .directory(workDir) // 工作目录设为 tar 所在目录 .redirectErrorStream(true) .start(); String output = new String(process.getInputStream().readAllBytes()); diff --git a/src/main/java/com/yxtech/ossyn/service/OssSyncService.java b/src/main/java/com/yxtech/ossyn/service/OssSyncService.java index 956632a..c3f1e63 100644 --- a/src/main/java/com/yxtech/ossyn/service/OssSyncService.java +++ b/src/main/java/com/yxtech/ossyn/service/OssSyncService.java @@ -171,6 +171,10 @@ public class OssSyncService { for (Map row : rows) { String bizId = row.get("id"); String filePath = row.get("filePath"); + // 已回写的 OSS 路径包含 @/jkgl 关键字,跳过避免重复处理 + if (filePath != null && filePath.contains("@/jkgl")) { + continue; + } QhOssFileLog existing = ossFileLogMapper.selectOne(new LambdaQueryWrapper() .eq(QhOssFileLog::getBizTabName, mapping.getTableName()) .eq(QhOssFileLog::getBizTabId, bizId) @@ -272,17 +276,26 @@ public class OssSyncService { * 回写已上传成功(状态=1)的记录到业务表 */ private int writeBack(SyncTask task) { + // 先取有效映射,再按表名范围查日志,避免加载无效表的数据 + List mappings = bizFileMappingMapper.selectList( + new LambdaQueryWrapper() + .eq(BizFileMappingEntity::getEnabled, BizFileMappingEntity.ENABLED_YES)); + if (mappings == null || mappings.isEmpty()) { + log.warn("[OssSyncService] 无有效的业务表映射配置,跳过回写"); + return 0; + } + List validTableNames = mappings.stream() + .map(BizFileMappingEntity::getTableName).toList(); List uploaded = ossFileLogMapper.selectList( new LambdaQueryWrapper() - .eq(QhOssFileLog::getBizHandleStatus, QhOssFileLog.STATUS_UPLOADED)); + .eq(QhOssFileLog::getBizHandleStatus, QhOssFileLog.STATUS_UPLOADED) + .in(QhOssFileLog::getBizTabName, validTableNames)); syncTaskMapper.update(null, new LambdaUpdateWrapper() .eq(SyncTask::getId, task.getId()) .set(SyncTask::getTotal, uploaded.size()) .set(SyncTask::getSuccess, 0) .set(SyncTask::getFail, 0) .set(SyncTask::getUpdateTime, LocalDateTime.now())); - // 从数据库读取所有映射配置(回写不限有效/无效,按表名匹配) - List mappings = bizFileMappingMapper.selectList(null); int success = 0; for (QhOssFileLog record : uploaded) { String dbName = mappings.stream() diff --git a/src/main/resources/app.yml b/src/main/resources/app.yml index bae2f9a..a8f4849 100644 --- a/src/main/resources/app.yml +++ b/src/main/resources/app.yml @@ -1,5 +1,7 @@ server.port: 8080 -server.request-maxBodySize: 1073741824 +server.request.maxBodySize: 1073741824 +server.request.maxFileSize: 1073741824 +server.request.maxRequestSize: 1073741824 solon.config.load: - "app-env.yml" #可以是环境相关的