From 5052fea9efbdb128d853903b6b4a08c76832d7e6 Mon Sep 17 00:00:00 2001
From: QAIU <736226400@qq.com>
Date: Thu, 6 Feb 2025 16:52:06 +0800
Subject: [PATCH] =?UTF-8?q?MySQL=E6=94=AF=E6=8C=81,=20=E5=85=B6=E4=BB=96?=
=?UTF-8?q?=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
core-database/pom.xml | 6 +
.../main/java/cn/qaiu/db/ddl/Constraint.java | 2 +-
.../java/cn/qaiu/db/ddl/CreateDatabase.java | 67 ++++++++++
.../java/cn/qaiu/db/pool/JDBCPoolInit.java | 27 +++-
.../main/java/cn/qaiu/db/pool/JDBCType.java | 47 ++++++-
.../main/java/cn/qaiu/db/pool/JDBCUtil.java | 18 ---
note.txt | 10 +-
.../main/java/cn/qaiu/parser/impl/UcTool.java | 122 ++++++++++++++++++
.../cn/qaiu/lz/common/cache/CacheManager.java | 87 ++++++++++---
.../qaiu/lz/web/model/ApiStatisticsInfo.java | 4 +-
.../cn/qaiu/lz/web/model/CacheLinkInfo.java | 2 +-
.../lz/web/service/impl/DbServiceImpl.java | 12 +-
web-service/src/main/resources/app-dev.yml | 15 +--
.../src/main/resources/http-tools/pan-uc.http | 108 ++++++++++++++++
14 files changed, 465 insertions(+), 62 deletions(-)
create mode 100644 core-database/src/main/java/cn/qaiu/db/ddl/CreateDatabase.java
delete mode 100644 core-database/src/main/java/cn/qaiu/db/pool/JDBCUtil.java
create mode 100644 parser/src/main/java/cn/qaiu/parser/impl/UcTool.java
diff --git a/core-database/pom.xml b/core-database/pom.xml
index 9c15186..507a6a3 100644
--- a/core-database/pom.xml
+++ b/core-database/pom.xml
@@ -59,6 +59,12 @@
vertx-jdbc-client
${vertx.version}
+
+ com.mysql
+ mysql-connector-j
+ 9.2.0
+
+
diff --git a/core-database/src/main/java/cn/qaiu/db/ddl/Constraint.java b/core-database/src/main/java/cn/qaiu/db/ddl/Constraint.java
index 3b234bf..cfcad14 100644
--- a/core-database/src/main/java/cn/qaiu/db/ddl/Constraint.java
+++ b/core-database/src/main/java/cn/qaiu/db/ddl/Constraint.java
@@ -32,7 +32,7 @@ public @interface Constraint {
*/
String defaultValue() default "";
/**
- * 默认值是否是函数
+ * 默认值是否是函数 like value=NOW()
* @return false 不是函数
*/
boolean defaultValueIsFunction() default false;
diff --git a/core-database/src/main/java/cn/qaiu/db/ddl/CreateDatabase.java b/core-database/src/main/java/cn/qaiu/db/ddl/CreateDatabase.java
new file mode 100644
index 0000000..6749c15
--- /dev/null
+++ b/core-database/src/main/java/cn/qaiu/db/ddl/CreateDatabase.java
@@ -0,0 +1,67 @@
+package cn.qaiu.db.ddl;
+
+import cn.qaiu.db.pool.JDBCPoolInit;
+import io.vertx.core.json.JsonObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class CreateDatabase {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(JDBCPoolInit.class);
+
+ /**
+ * 解析数据库URL,获取数据库名
+ * @param url 数据库URL
+ * @return 数据库名
+ */
+ public static String getDatabaseName(String url) {
+ // 正则表达式匹配数据库名
+ String regex = "jdbc:mysql://[^/]+/(\\w+)(\\?.*)?";
+ Pattern pattern = Pattern.compile(regex);
+ Matcher matcher = pattern.matcher(url);
+
+ if (matcher.find()) {
+ return matcher.group(1);
+ } else {
+ throw new IllegalArgumentException("Invalid database URL: " + url);
+ }
+ }
+
+ /**
+ * 使用JDBC原生方法创建数据库
+ * @param url 数据库连接URL
+ * @param user 数据库用户名
+ * @param password 数据库密码
+ */
+ public static void createDatabase(String url, String user, String password) {
+ String dbName = getDatabaseName(url);
+ LOGGER.info(">>>>>>>>>>> 创建数据库:'{}' <<<<<<<<<<<< ", dbName);
+
+ // 去掉数据库名,构建不带数据库名的URL
+ String baseUrl = url.substring(0, url.lastIndexOf("/") + 1) + "?characterEncoding=UTF-8&useUnicode=true";
+
+ try (Connection conn = DriverManager.getConnection(baseUrl, user, password);
+ Statement stmt = conn.createStatement()) {
+ // 创建数据库
+ stmt.executeUpdate("CREATE DATABASE IF NOT EXISTS " + dbName + " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
+ LOGGER.info(">>>>>>>>>>> 数据库'{}'创建成功 <<<<<<<<<<<<", dbName);
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void createDatabase(JsonObject dbConfig) {
+ createDatabase(
+ dbConfig.getString("jdbcUrl"),
+ dbConfig.getString("username"),
+ dbConfig.getString("password")
+ );
+ }
+}
diff --git a/core-database/src/main/java/cn/qaiu/db/pool/JDBCPoolInit.java b/core-database/src/main/java/cn/qaiu/db/pool/JDBCPoolInit.java
index 2fdbcb9..602eee3 100644
--- a/core-database/src/main/java/cn/qaiu/db/pool/JDBCPoolInit.java
+++ b/core-database/src/main/java/cn/qaiu/db/pool/JDBCPoolInit.java
@@ -1,13 +1,18 @@
package cn.qaiu.db.pool;
import cn.qaiu.db.ddl.CreateTable;
+import cn.qaiu.db.ddl.CreateDatabase;
import cn.qaiu.vx.core.util.VertxHolder;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.jdbcclient.JDBCPool;
+import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
/**
* 初始化JDBC
*
Create date 2021/8/10 12:04
@@ -17,18 +22,32 @@ import org.slf4j.LoggerFactory;
public class JDBCPoolInit {
private static final Logger LOGGER = LoggerFactory.getLogger(JDBCPoolInit.class);
+
+ private static final String providerClass = io.vertx.ext.jdbc.spi.impl.HikariCPDataSourceProvider.class.getName();
+
private JDBCPool pool = null;
JsonObject dbConfig;
Vertx vertx = VertxHolder.getVertxInstance();
String url;
+
private final JDBCType type;
private static JDBCPoolInit instance;
+ public JDBCType getType() {
+ return type;
+ }
+
public JDBCPoolInit(Builder builder) {
this.dbConfig = builder.dbConfig;
this.url = builder.url;
- this.type = builder.type;
+ this.type = JDBCType.getJDBCTypeByURL(builder.url);
+ if (StringUtils.isBlank(builder.dbConfig.getString("provider_class"))) {
+ builder.dbConfig.put("provider_class", providerClass);
+ }
+ if (StringUtils.isBlank(builder.dbConfig.getString("driverClassName"))) {
+ builder.dbConfig.put("driverClassName", this.type.getDriverClassName());
+ }
}
public static Builder builder() {
@@ -42,12 +61,10 @@ public class JDBCPoolInit {
public static class Builder {
private JsonObject dbConfig;
private String url;
- private JDBCType type;
public Builder config(JsonObject dbConfig) {
this.dbConfig = dbConfig;
this.url = dbConfig.getString("jdbcUrl");
- this.type = JDBCUtil.getJDBCType(dbConfig.getString("driverClassName"));
return this;
}
@@ -59,7 +76,6 @@ public class JDBCPoolInit {
}
}
-
/**
* init h2db
* 这个方法只允许调用一次
@@ -72,6 +88,9 @@ public class JDBCPoolInit {
// 初始化数据库连接
// 初始化连接池
+ if (type == JDBCType.MySQL) {
+ CreateDatabase.createDatabase(dbConfig);
+ }
pool = JDBCPool.pool(vertx, dbConfig);
CreateTable.createTable(pool, type);
LOGGER.info("数据库连接初始化: URL=" + url);
diff --git a/core-database/src/main/java/cn/qaiu/db/pool/JDBCType.java b/core-database/src/main/java/cn/qaiu/db/pool/JDBCType.java
index 7cccb3e..5430b9b 100644
--- a/core-database/src/main/java/cn/qaiu/db/pool/JDBCType.java
+++ b/core-database/src/main/java/cn/qaiu/db/pool/JDBCType.java
@@ -1,9 +1,52 @@
package cn.qaiu.db.pool;
+import org.apache.commons.lang3.StringUtils;
+
/**
* @author QAIU
- * @date 2023/10/10 14:06
+ * @since 2023/10/10 14:06
*/
public enum JDBCType {
- MySQL, H2DB
+ // 添加驱动类型字段
+ MySQL("com.mysql.cj.jdbc.Driver", "jdbc:mysql:"),
+ H2DB("org.h2.Driver", "jdbc:h2:");
+
+ private final String driverClassName; // 驱动类名
+ private final String urlPrefix; // JDBC URL 前缀
+
+ // 构造函数
+ JDBCType(String driverClassName, String urlPrefix) {
+ this.driverClassName = driverClassName;
+ this.urlPrefix = urlPrefix;
+ }
+
+ // 获取驱动类名
+ public String getDriverClassName() {
+ return driverClassName;
+ }
+
+ // 获取 JDBC URL 前缀
+ public String getUrlPrefix() {
+ return urlPrefix;
+ }
+
+ // 根据驱动类名获取 JDBC 类型
+ public static JDBCType getJDBCType(String driverClassName) {
+ for (JDBCType jdbcType : values()) {
+ if (jdbcType.getDriverClassName().equalsIgnoreCase(driverClassName)) {
+ return jdbcType;
+ }
+ }
+ throw new RuntimeException("不支持的SQL驱动类型: " + driverClassName);
+ }
+
+ // 根据 JDBC URL 获取 JDBC 类型
+ public static JDBCType getJDBCTypeByURL(String jdbcURL) {
+ for (JDBCType jdbcType : values()) {
+ if (StringUtils.startsWithIgnoreCase(jdbcURL, jdbcType.getUrlPrefix())) {
+ return jdbcType;
+ }
+ }
+ throw new RuntimeException("不支持的SQL驱动类型: " + jdbcURL);
+ }
}
diff --git a/core-database/src/main/java/cn/qaiu/db/pool/JDBCUtil.java b/core-database/src/main/java/cn/qaiu/db/pool/JDBCUtil.java
deleted file mode 100644
index 8f25366..0000000
--- a/core-database/src/main/java/cn/qaiu/db/pool/JDBCUtil.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package cn.qaiu.db.pool;
-
-/**
- * @author QAIU
- * @date 2023/10/10 14:05
- */
-public class JDBCUtil {
- public static JDBCType getJDBCType(String deviceName) {
- switch (deviceName) {
- case "com.mysql.cj.jdbc.Driver":
- case "com.mysql.jdbc.Driver":
- return JDBCType.MySQL;
- case "org.h2.Driver":
- return JDBCType.H2DB;
- }
- throw new RuntimeException("不支持的SQL驱动类型: " + deviceName);
- }
-}
diff --git a/note.txt b/note.txt
index d4cc93b..38691b7 100644
--- a/note.txt
+++ b/note.txt
@@ -60,7 +60,15 @@ jwt鉴权用户
文件信息: 文件/文件夹, 文件数量, 文件大小, 文件类型; 链接信息: 解析次数, 缓存次数等)
微服务设计:
-
+TODO
+
+后台管理:
+ 菜单:
+ 网盘管理: token配置, 启用/禁用
+ 短链管理: 短链列表, 新增, 删除
+ 解析统计: 下载次数统计, 下载流量统计, 详细解析列表
+ 状态监视: 服务请求并发数; 来源IP列表: 拉黑, 限制次数; Nginx
+ 系统配置: 管理员账户, 系统参数: 域名配置, 预览URL,
diff --git a/parser/src/main/java/cn/qaiu/parser/impl/UcTool.java b/parser/src/main/java/cn/qaiu/parser/impl/UcTool.java
new file mode 100644
index 0000000..7e2527b
--- /dev/null
+++ b/parser/src/main/java/cn/qaiu/parser/impl/UcTool.java
@@ -0,0 +1,122 @@
+package cn.qaiu.parser.impl;
+
+import cn.qaiu.entity.ShareLinkInfo;
+import cn.qaiu.parser.PanBase;
+import io.vertx.core.Future;
+import io.vertx.core.json.JsonArray;
+import io.vertx.core.json.JsonObject;
+import io.vertx.uritemplate.UriTemplate;
+
+/**
+ * UC网盘解析
+ */
+public class UcTool extends PanBase {
+ private static final String API_URL_PREFIX = "https://pc-api.uc.cn/1/clouddrive/";
+
+ public static final String SHARE_URL_PREFIX = "https://fast.uc.cn/s/";
+
+ private static final String FIRST_REQUEST_URL = API_URL_PREFIX + "share/sharepage/token?entry=ft&fr=pc&pr" +
+ "=UCBrowser";
+
+ private static final String SECOND_REQUEST_URL = API_URL_PREFIX + "transfer_share/detail?pwd_id={pwd_id}&passcode" +
+ "={passcode}&stoken={stoken}";
+
+ private static final String THIRD_REQUEST_URL = API_URL_PREFIX + "file/download?entry=ft&fr=pc&pr=UCBrowser";
+
+ public UcTool(ShareLinkInfo shareLinkInfo) {
+ super(shareLinkInfo);
+ }
+
+ public Future parse() {
+ var dataKey = shareLinkInfo.getShareKey();
+ var passcode = shareLinkInfo.getSharePassword();
+
+ var jsonObject = JsonObject.of("share_for_transfer", true);
+ jsonObject.put("pwd_id", dataKey);
+ jsonObject.put("passcode", passcode);
+ // 第一次请求 获取文件信息
+ client.postAbs(FIRST_REQUEST_URL).sendJsonObject(jsonObject).onSuccess(res -> {
+ log.debug("第一阶段 {}", res.body());
+ var resJson = res.bodyAsJsonObject();
+ if (resJson.getInteger("code") != 0) {
+ fail(FIRST_REQUEST_URL + " 返回异常: " + resJson);
+ return;
+ }
+ var stoken = resJson.getJsonObject("data").getString("stoken");
+ // 第二次请求
+ client.getAbs(UriTemplate.of(SECOND_REQUEST_URL))
+ .setTemplateParam("pwd_id", dataKey)
+ .setTemplateParam("passcode", passcode)
+ .setTemplateParam("stoken", stoken)
+ .send().onSuccess(res2 -> {
+ log.debug("第二阶段 {}", res2.body());
+ JsonObject resJson2 = res2.bodyAsJsonObject();
+ if (resJson2.getInteger("code") != 0) {
+ fail(FIRST_REQUEST_URL + " 返回异常: " + resJson2);
+ return;
+ }
+ // 文件信息
+ var info = resJson2.getJsonObject("data").getJsonArray("list").getJsonObject(0);
+ // 第二次请求
+ var bodyJson = JsonObject.of()
+ .put("fids", JsonArray.of(info.getString("fid")))
+ .put("pwd_id", dataKey)
+ .put("stoken", stoken)
+ .put("fids_token", JsonArray.of(info.getString("share_fid_token")));
+ client.postAbs(THIRD_REQUEST_URL).sendJsonObject(bodyJson)
+ .onSuccess(res3 -> {
+ log.debug("第三阶段 {}", res3.body());
+ var resJson3 = res3.bodyAsJsonObject();
+ if (resJson3.getInteger("code") != 0) {
+ fail(FIRST_REQUEST_URL + " 返回异常: " + resJson2);
+ return;
+ }
+ promise.complete(resJson3.getJsonArray("data").getJsonObject(0).getString("download_url"));
+ }).onFailure(handleFail(THIRD_REQUEST_URL));
+
+ }).onFailure(handleFail(SECOND_REQUEST_URL));
+ }
+ ).onFailure(handleFail(FIRST_REQUEST_URL));
+ return promise.future();
+ }
+
+ public static void main(String[] args) {
+
+ // https://dl-uf-zb.pds.uc.cn/l3PNAKfz/64623447/
+ // 646b0de6e9f13000c9b14ba182b805312795a82a/
+ // 646b0de6717e1bfa5bb44dd2a456f103c5177850?
+ // Expires=1737784900&OSSAccessKeyId=LTAI5tJJpWQEfrcKHnd1LqsZ&
+ // Signature=oBVV3anhv3tBKanHUcEIsktkB%2BM%3D&x-oss-traffic-limit=503316480
+ // &response-content-disposition=attachment%3B%20filename%3DC%2523%2520Shell%2520%2528C%2523%2520Offline%2520Compiler%2529_2.5.16.apks
+ // %3Bfilename%2A%3Dutf-8%27%27C%2523%2520Shell%2520%2528C%2523%2520Offline%2520Compiler%2529_2.5.16.apks
+
+ //eyJ4OmF1IjoiLSIsIng6dWQiOiI0LU4tNS0wLTYtTi0zLWZ0LTAtMi1OLU4iLCJ4OnNwIjoiMTAwIiwieDp0b2tlbiI6IjQtZjY0ZmMxMDFjZmQxZGVkNTRkMGM0NmMzYzliMzkyOWYtNS03LTE1MzYxMS1kYWNiMzY2NWJiYWE0ZjVlOWQzNzgwMGVjNjQwMzE2MC0wLTAtMC0wLTQ5YzUzNTE3OGIxOTY0YzhjYzUwYzRlMDk5MTZmYWRhIiwieDp0dGwiOiIxMDgwMCJ9
+ //eyJjYWxsYmFja0JvZHlUeXBlIjoiYXBwbGljYXRpb24vanNvbiIsImNhbGxiYWNrU3RhZ2UiOiJiZWZvcmUtZXhlY3V0ZSIsImNhbGxiYWNrRmFpbHVyZUFjdGlvbiI6Imlnbm9yZSIsImNhbGxiYWNrVXJsIjoiaHR0cHM6Ly9hdXRoLWNkbi51Yy5jbi9vdXRlci9vc3MvY2hlY2twbGF5IiwiY2FsbGJhY2tCb2R5Ijoie1wiaG9zdFwiOiR7aHR0cEhlYWRlci5ob3N0fSxcInNpemVcIjoke3NpemV9LFwicmFuZ2VcIjoke2h0dHBIZWFkZXIucmFuZ2V9LFwicmVmZXJlclwiOiR7aHR0cEhlYWRlci5yZWZlcmVyfSxcImNvb2tpZVwiOiR7aHR0cEhlYWRlci5jb29raWV9LFwibWV0aG9kXCI6JHtodHRwSGVhZGVyLm1ldGhvZH0sXCJpcFwiOiR7Y2xpZW50SXB9LFwicG9ydFwiOiR7Y2xpZW50UG9ydH0sXCJvYmplY3RcIjoke29iamVjdH0sXCJzcFwiOiR7eDpzcH0sXCJ1ZFwiOiR7eDp1ZH0sXCJ0b2tlblwiOiR7eDp0b2tlbn0sXCJhdVwiOiR7eDphdX0sXCJ0dGxcIjoke3g6dHRsfSxcImR0X3NwXCI6JHt4OmR0X3NwfSxcImhzcFwiOiR7eDpoc3B9LFwiY2xpZW50X3Rva2VuXCI6JHtxdWVyeVN0cmluZy5jbGllbnRfdG9rZW59fSJ9
+ //callback-var {"x:au":"-","x:ud":"4-N-5-0-6-N-3-ft-0-2-N-N","x:sp":"100","x:token":"4-f64fc101cfd1ded54d0c46c3c9b3929f-5-7-153611-dacb3665bbaa4f5e9d37800ec6403160-0-0-0-0-49c535178b1964c8cc50c4e09916fada","x:ttl":"10800"}
+ //callback {"callbackBodyType":"application/json","callbackStage":"before-execute","callbackFailureAction":"ignore","callbackUrl":"https://auth-cdn.uc.cn/outer/oss/checkplay","callbackBody":"{\"host\":${httpHeader.host},\"size\":${size},\"range\":${httpHeader.range},\"referer\":${httpHeader.referer},\"cookie\":${httpHeader.cookie},\"method\":${httpHeader.method},\"ip\":${clientIp},\"port\":${clientPort},\"object\":${object},\"sp\":${x:sp},\"ud\":${x:ud},\"token\":${x:token},\"au\":${x:au},\"ttl\":${x:ttl},\"dt_sp\":${x:dt_sp},\"hsp\":${x:hsp},\"client_token\":${queryString.client_token}}"}
+
+ /*
+ // callback-var
+{
+ "x:au": "-",
+ "x:ud": "4-N-5-0-6-N-3-ft-0-2-N-N",
+ "x:sp": "100",
+ "x:token": "4-f64fc101cfd1ded54d0c46c3c9b3929f-5-7-153611-dacb3665bbaa4f5e9d37800ec6403160-0-0-0-0-49c535178b1964c8cc50c4e09916fada",
+ "x:ttl": "10800"
+}
+
+// callback
+{
+ "callbackBodyType": "application/json",
+ "callbackStage": "before-execute",
+ "callbackFailureAction": "ignore",
+ "callbackUrl": "https://auth-cdn.uc.cn/outer/oss/checkplay",
+ "callbackBody": "{\"host\":${httpHeader.host},\"size\":${size},\"range\":${httpHeader.range},\"referer\":${httpHeader.referer},\"cookie\":${httpHeader.cookie},\"method\":${httpHeader.method},\"ip\":${clientIp},\"port\":${clientPort},\"object\":${object},\"sp\":${x:sp},\"ud\":${x:ud},\"token\":${x:token},\"au\":${x:au},\"ttl\":${x:ttl},\"dt_sp\":${x:dt_sp},\"hsp\":${x:hsp},\"client_token\":${queryString.client_token}}"
+}
+ */
+
+ new UcTool(ShareLinkInfo.newBuilder().shareUrl("https://fast.uc.cn/s/33197dd53ace4").shareKey("33197dd53ace4").build()).parse().onSuccess(
+ System.out::println
+ );
+ }
+}
diff --git a/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java b/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java
index cbc4800..8d8564f 100644
--- a/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java
+++ b/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java
@@ -1,6 +1,7 @@
package cn.qaiu.lz.common.cache;
import cn.qaiu.db.pool.JDBCPoolInit;
+import cn.qaiu.db.pool.JDBCType;
import cn.qaiu.lz.web.model.CacheLinkInfo;
import io.vertx.core.Future;
import io.vertx.core.Promise;
@@ -8,13 +9,17 @@ import io.vertx.core.json.JsonObject;
import io.vertx.jdbcclient.JDBCPool;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.templates.SqlTemplate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
public class CacheManager {
private final JDBCPool jdbcPool = JDBCPoolInit.instance().getPool();
+ private final JDBCType jdbcType = JDBCPoolInit.instance().getType();
+ private static final Logger LOGGER = LoggerFactory.getLogger(CacheManager.class);
public Future get(String cacheKey) {
String sql = "SELECT share_key as shareKey, direct_link as directLink, expiration FROM cache_link_info WHERE share_key = #{share_key}";
@@ -33,16 +38,31 @@ public class CacheManager {
cacheHit = new CacheLinkInfo(JsonObject.of("cacheHit", false, "shareKey", cacheKey));
}
promise.complete(cacheHit);
- }).onFailure(Throwable::printStackTrace);
+ }).onFailure(e->{
+ promise.fail(e);
+ LOGGER.error("cache get:", e);
+ });
return promise.future();
}
// 插入或更新缓存数据
public Future cacheShareLink(CacheLinkInfo cacheLinkInfo) {
- String sql = "MERGE INTO cache_link_info (share_key, direct_link, expiration) " +
- "KEY (share_key) " +
- "VALUES (#{shareKey}, #{directLink}, #{expiration})";
+ String sql;
+ if (jdbcType == JDBCType.MySQL) {
+ sql = """
+ INSERT INTO cache_link_info (share_key, direct_link, expiration)
+ VALUES (#{shareKey}, #{directLink}, #{expiration})
+ ON DUPLICATE KEY UPDATE
+ direct_link = VALUES(direct_link),
+ expiration = VALUES(expiration);
+ """;
+ } else { // 运行H2
+ sql = "MERGE INTO cache_link_info (share_key, direct_link, expiration) " +
+ "KEY (share_key) " +
+ "VALUES (#{shareKey}, #{directLink}, #{expiration})";
+ }
+
// 直接传递 CacheLinkInfo 实体类
return SqlTemplate.forUpdate(jdbcPool, sql)
@@ -55,11 +75,23 @@ public class CacheManager {
public Future updateTotalByField(String shareKey, CacheTotalField field) {
Promise promise = Promise.promise();
String fieldLower = field.name().toLowerCase();
- String sql = """
+ String sql;
+ if (jdbcType == JDBCType.MySQL) { // 假设你有一个标识当前数据库类型的布尔变量
+ sql = """
+ INSERT INTO `api_statistics_info` (`pan_type`, `share_key`, `{field}`, `update_ts`)
+ VALUES (#{panType}, #{shareKey}, #{total}, #{ts})
+ ON DUPLICATE KEY UPDATE
+ `pan_type` = VALUES(`pan_type`),
+ `{field}` = VALUES(`{field}`),
+ `update_ts` = VALUES(`update_ts`);
+ """.replace("{field}", fieldLower);
+ } else { // 运行H2
+ sql = """
MERGE INTO `api_statistics_info` (`pan_type`, `share_key`, `{field}`, `update_ts`)
KEY (`share_key`)
VALUES (#{panType}, #{shareKey}, #{total}, #{ts})
""".replace("{field}", fieldLower);
+ }
getShareKeyTotal(shareKey, fieldLower).onSuccess(total -> {
Integer newTotal = (total == null ? 0 : total) + 1;
@@ -71,7 +103,10 @@ public class CacheManager {
put("ts", System.currentTimeMillis());
}})
.onSuccess(res -> promise.complete(res.rowCount()))
- .onFailure(Throwable::printStackTrace);
+ .onFailure(e->{
+ promise.fail(e);
+ LOGGER.error("updateTotalByField: ", e);
+ });
});
return promise.future();
}
@@ -84,10 +119,12 @@ public class CacheManager {
public Future getShareKeyTotal(String shareKey, String name) {
String sql = """
- select `share_key`, sum({total_name}) sum_num
- from `api_statistics_info`
- group by `share_key` having `share_key` = #{shareKey};
+ SELECT `share_key`, SUM({total_name}) AS sum_num
+ FROM `api_statistics_info`
+ WHERE `share_key` = #{shareKey}
+ GROUP BY `share_key`;
""".replace("{total_name}", name);
+
Promise promise = Promise.promise();
Map paramMap = new HashMap<>();
paramMap.put("shareKey", shareKey);
@@ -98,16 +135,21 @@ public class CacheManager {
Integer total = res.iterator().hasNext() ?
res.iterator().next().getInteger("sum_num") : null;
promise.complete(total);
+ }).onFailure(e->{
+ promise.fail(e);
+ LOGGER.error("getShareKeyTotal: ", e);
});
return promise.future();
}
public Future