mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2025-12-17 12:53:02 +00:00
remove yarn.lock
This commit is contained in:
@@ -64,6 +64,12 @@
|
|||||||
<artifactId>mysql-connector-j</artifactId>
|
<artifactId>mysql-connector-j</artifactId>
|
||||||
<version>9.2.0</version>
|
<version>9.2.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- PG驱动-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<version>42.7.3</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ public @interface Constraint {
|
|||||||
boolean notNull() default false;
|
boolean notNull() default false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 唯一键约束 TODO 待实现
|
|
||||||
* @return 唯一键约束
|
* @return 唯一键约束
|
||||||
*/
|
*/
|
||||||
String uniqueKey() default "";
|
String uniqueKey() default "";
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import io.vertx.codegen.format.LowerCamelCase;
|
|||||||
import io.vertx.codegen.format.SnakeCase;
|
import io.vertx.codegen.format.SnakeCase;
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
import io.vertx.core.Promise;
|
import io.vertx.core.Promise;
|
||||||
import io.vertx.jdbcclient.JDBCPool;
|
import io.vertx.sqlclient.Pool;
|
||||||
import io.vertx.sqlclient.templates.annotations.Column;
|
import io.vertx.sqlclient.templates.annotations.Column;
|
||||||
import io.vertx.sqlclient.templates.annotations.RowMapped;
|
import io.vertx.sqlclient.templates.annotations.RowMapped;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@@ -24,164 +24,312 @@ import java.util.*;
|
|||||||
* @author <a href="https://qaiu.top">QAIU</a>
|
* @author <a href="https://qaiu.top">QAIU</a>
|
||||||
*/
|
*/
|
||||||
public class CreateTable {
|
public class CreateTable {
|
||||||
public static Map<Class<?>, String> javaProperty2SqlColumnMap = new HashMap<>();
|
public static Map<Class<?>, String> javaProperty2SqlColumnMap = new HashMap<>() {{
|
||||||
|
// Java类型到SQL类型的映射
|
||||||
|
put(Integer.class, "INT");
|
||||||
|
put(Short.class, "SMALLINT");
|
||||||
|
put(Byte.class, "TINYINT");
|
||||||
|
put(Long.class, "BIGINT");
|
||||||
|
put(java.math.BigDecimal.class, "DECIMAL");
|
||||||
|
put(Double.class, "DOUBLE");
|
||||||
|
put(Float.class, "REAL");
|
||||||
|
put(Boolean.class, "BOOLEAN");
|
||||||
|
put(String.class, "VARCHAR");
|
||||||
|
put(Date.class, "TIMESTAMP");
|
||||||
|
put(java.time.LocalDateTime.class, "TIMESTAMP");
|
||||||
|
put(java.sql.Timestamp.class, "TIMESTAMP");
|
||||||
|
put(java.sql.Date.class, "DATE");
|
||||||
|
put(java.sql.Time.class, "TIME");
|
||||||
|
|
||||||
|
// 基本数据类型
|
||||||
|
put(int.class, "INT");
|
||||||
|
put(short.class, "SMALLINT");
|
||||||
|
put(byte.class, "TINYINT");
|
||||||
|
put(long.class, "BIGINT");
|
||||||
|
put(double.class, "DOUBLE");
|
||||||
|
put(float.class, "REAL");
|
||||||
|
put(boolean.class, "BOOLEAN");
|
||||||
|
}};
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(CreateTable.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(CreateTable.class);
|
||||||
|
public static String UNIQUE_PREFIX = "idx_";
|
||||||
static {
|
|
||||||
javaProperty2SqlColumnMap.put(Integer.class, "INT");
|
|
||||||
javaProperty2SqlColumnMap.put(Short.class, "SMALLINT");
|
|
||||||
javaProperty2SqlColumnMap.put(Byte.class, "TINYINT");
|
|
||||||
javaProperty2SqlColumnMap.put(Long.class, "BIGINT");
|
|
||||||
javaProperty2SqlColumnMap.put(java.math.BigDecimal.class, "DECIMAL");
|
|
||||||
javaProperty2SqlColumnMap.put(Double.class, "DOUBLE");
|
|
||||||
javaProperty2SqlColumnMap.put(Float.class, "REAL");
|
|
||||||
javaProperty2SqlColumnMap.put(Boolean.class, "BOOLEAN");
|
|
||||||
javaProperty2SqlColumnMap.put(String.class, "VARCHAR");
|
|
||||||
javaProperty2SqlColumnMap.put(java.util.Date.class, "TIMESTAMP");
|
|
||||||
javaProperty2SqlColumnMap.put(java.time.LocalDateTime.class, "TIMESTAMP");
|
|
||||||
javaProperty2SqlColumnMap.put(java.sql.Timestamp.class, "TIMESTAMP");
|
|
||||||
javaProperty2SqlColumnMap.put(java.sql.Date.class, "DATE");
|
|
||||||
javaProperty2SqlColumnMap.put(java.sql.Time.class, "TIME");
|
|
||||||
|
|
||||||
javaProperty2SqlColumnMap.put(int.class, "INT");
|
|
||||||
javaProperty2SqlColumnMap.put(short.class, "SMALLINT");
|
|
||||||
javaProperty2SqlColumnMap.put(byte.class, "TINYINT");
|
|
||||||
javaProperty2SqlColumnMap.put(long.class, "BIGINT");
|
|
||||||
javaProperty2SqlColumnMap.put(double.class, "DOUBLE");
|
|
||||||
javaProperty2SqlColumnMap.put(float.class, "REAL");
|
|
||||||
javaProperty2SqlColumnMap.put(boolean.class, "BOOLEAN");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Case getCase(Class<?> clz) {
|
private static Case getCase(Class<?> clz) {
|
||||||
switch (clz.getName()) {
|
return switch (clz.getName()) {
|
||||||
case "io.vertx.codegen.format.CamelCase":
|
case "io.vertx.codegen.format.CamelCase" -> CamelCase.INSTANCE;
|
||||||
return CamelCase.INSTANCE;
|
case "io.vertx.codegen.format.SnakeCase" -> SnakeCase.INSTANCE;
|
||||||
case "io.vertx.codegen.format.SnakeCase":
|
case "io.vertx.codegen.format.LowerCamelCase" -> LowerCamelCase.INSTANCE;
|
||||||
return SnakeCase.INSTANCE;
|
default -> throw new UnsupportedOperationException();
|
||||||
case "io.vertx.codegen.format.LowerCamelCase":
|
};
|
||||||
return LowerCamelCase.INSTANCE;
|
}
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException();
|
public static List<String> getCreateTableSQL(Class<?> clz, JDBCType type) {
|
||||||
|
// 获取表名和主键
|
||||||
|
TableInfo tableInfo = extractTableInfo(clz, type);
|
||||||
|
|
||||||
|
// 构建表的SQL语句
|
||||||
|
List<String> sqlList = new ArrayList<>();
|
||||||
|
StringBuilder sb = new StringBuilder(50);
|
||||||
|
sb.append("CREATE TABLE IF NOT EXISTS ")
|
||||||
|
.append(tableInfo.quotationMarks).append(tableInfo.tableName).append(tableInfo.quotationMarks)
|
||||||
|
.append(" ( \r\n ");
|
||||||
|
|
||||||
|
// 处理字段并生成列定义
|
||||||
|
List<String> indexSQLs = new ArrayList<>();
|
||||||
|
processFields(clz, tableInfo, sb, indexSQLs);
|
||||||
|
|
||||||
|
// 去掉最后一个逗号并添加表尾部信息
|
||||||
|
String tableSQL = sb.substring(0, sb.lastIndexOf(",")) + tableInfo.endStr;
|
||||||
|
sqlList.add(tableSQL);
|
||||||
|
|
||||||
|
// 添加索引SQL
|
||||||
|
sqlList.addAll(indexSQLs);
|
||||||
|
|
||||||
|
return sqlList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 修改extractTableInfo方法,处理没有Table注解时默认使用id字段作为主键
|
||||||
|
private static TableInfo extractTableInfo(Class<?> clz, JDBCType type) {
|
||||||
|
String quotationMarks;
|
||||||
|
String endStr;
|
||||||
|
if (type == JDBCType.MySQL) {
|
||||||
|
quotationMarks = "`";
|
||||||
|
endStr = ")ENGINE=InnoDB DEFAULT CHARSET=utf8;";
|
||||||
|
} else {
|
||||||
|
quotationMarks = "\"";
|
||||||
|
endStr = ");";
|
||||||
|
}
|
||||||
|
|
||||||
|
String primaryKey = null;
|
||||||
|
String tableName = null;
|
||||||
|
Case caseFormat = SnakeCase.INSTANCE;
|
||||||
|
|
||||||
|
// 判断类上是否有RowMapped注解
|
||||||
|
if (clz.isAnnotationPresent(RowMapped.class)) {
|
||||||
|
RowMapped annotation = clz.getAnnotation(RowMapped.class);
|
||||||
|
caseFormat = getCase(annotation.formatter());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断类上是否有Table注解
|
||||||
|
if (clz.isAnnotationPresent(Table.class)) {
|
||||||
|
Table annotation = clz.getAnnotation(Table.class);
|
||||||
|
tableName = StringUtils.isNotEmpty(annotation.value())
|
||||||
|
? annotation.value()
|
||||||
|
: LowerCamelCase.INSTANCE.to(caseFormat, clz.getSimpleName());
|
||||||
|
primaryKey = annotation.keyFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果表名仍为null,使用类名转下划线命名作为表名
|
||||||
|
if (StringUtils.isEmpty(tableName)) {
|
||||||
|
tableName = LowerCamelCase.INSTANCE.to(SnakeCase.INSTANCE, clz.getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果主键为空,默认使用id字段作为主键
|
||||||
|
if (StringUtils.isEmpty(primaryKey)) {
|
||||||
|
try {
|
||||||
|
clz.getDeclaredField("id");
|
||||||
|
primaryKey = "id";
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
// 如果没有id字段,不设置主键
|
||||||
|
primaryKey = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TableInfo(tableName, quotationMarks, endStr, primaryKey, caseFormat, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改processFields方法,处理索引
|
||||||
|
private static void processFields(Class<?> clz, TableInfo tableInfo, StringBuilder sb, List<String> indexSQLs) {
|
||||||
|
Field[] fields = clz.getDeclaredFields();
|
||||||
|
for (Field field : fields) {
|
||||||
|
// 跳过无效字段
|
||||||
|
if (isIgnoredField(field)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取字段名和SQL类型
|
||||||
|
String column = LowerCamelCase.INSTANCE.to(tableInfo.caseFormat, field.getName());
|
||||||
|
String sqlType = javaProperty2SqlColumnMap.get(field.getType());
|
||||||
|
|
||||||
|
// 处理字段注解
|
||||||
|
column = processColumnAnnotation(field, column);
|
||||||
|
int[] decimalSize = {22, 2};
|
||||||
|
int varcharSize = 255;
|
||||||
|
if (field.isAnnotationPresent(Length.class)) {
|
||||||
|
Length length = field.getAnnotation(Length.class);
|
||||||
|
decimalSize = length.decimalSize();
|
||||||
|
varcharSize = length.varcharSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建列定义
|
||||||
|
sb.append(tableInfo.quotationMarks).append(column).append(tableInfo.quotationMarks)
|
||||||
|
.append(" ").append(sqlType);
|
||||||
|
appendTypeLength(sqlType, sb, decimalSize, varcharSize);
|
||||||
|
appendConstraints(field, sb, tableInfo);
|
||||||
|
appendPrimaryKey(tableInfo.primaryKey, column, sb);
|
||||||
|
|
||||||
|
// 添加索引
|
||||||
|
appendIndex(tableInfo, indexSQLs, field);
|
||||||
|
|
||||||
|
sb.append(",\n ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getCreateTableSQL(Class<?> clz, JDBCType type) {
|
// 判断是否忽略字段
|
||||||
String quotationMarks = type == JDBCType.H2DB ? "\"" : "`";
|
private static boolean isIgnoredField(Field field) {
|
||||||
String endStr = type == JDBCType.H2DB ? ");" : ")ENGINE=InnoDB DEFAULT CHARSET=utf8;";
|
return field.getName().equals("serialVersionUID")
|
||||||
// 判断类上是否有次注解
|
|| StringUtils.isEmpty(javaProperty2SqlColumnMap.get(field.getType()))
|
||||||
String primaryKey = null; // 主键
|
|| field.isAnnotationPresent(TableGenIgnore.class);
|
||||||
String tableName = null; // 表名
|
}
|
||||||
Case caseFormat = SnakeCase.INSTANCE;
|
|
||||||
if (clz.isAnnotationPresent(RowMapped.class)) {
|
|
||||||
RowMapped annotation = clz.getAnnotation(RowMapped.class);
|
|
||||||
Class<? extends Case> formatter = annotation.formatter();
|
|
||||||
caseFormat = getCase(formatter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clz.isAnnotationPresent(Table.class)) {
|
// 处理Column注解
|
||||||
// 获取类上的注解
|
private static String processColumnAnnotation(Field field, String column) {
|
||||||
Table annotation = clz.getAnnotation(Table.class);
|
if (field.isAnnotationPresent(Column.class)) {
|
||||||
// 输出注解上的类名
|
Column columnAnnotation = field.getAnnotation(Column.class);
|
||||||
String tableNameAnnotation = annotation.value();
|
if (StringUtils.isNotBlank(columnAnnotation.name())) {
|
||||||
if (StringUtils.isNotEmpty(tableNameAnnotation)) {
|
column = columnAnnotation.name();
|
||||||
tableName = tableNameAnnotation;
|
|
||||||
} else {
|
|
||||||
tableName = LowerCamelCase.INSTANCE.to(caseFormat, clz.getSimpleName());
|
|
||||||
}
|
}
|
||||||
primaryKey = annotation.keyFields();
|
|
||||||
}
|
}
|
||||||
Field[] fields = clz.getDeclaredFields();
|
return column;
|
||||||
String column;
|
}
|
||||||
int[] decimalSize = {22, 2};
|
|
||||||
int varcharSize = 255;
|
// 添加类型长度
|
||||||
StringBuilder sb = new StringBuilder(50);
|
private static void appendTypeLength(String sqlType, StringBuilder sb, int[] decimalSize, int varcharSize) {
|
||||||
sb.append("CREATE TABLE IF NOT EXISTS ").append(quotationMarks).append(tableName).append(quotationMarks).append(" ( \r\n ");
|
if ("DECIMAL".equals(sqlType)) {
|
||||||
boolean firstId = true;
|
sb.append("(").append(decimalSize[0]).append(",").append(decimalSize[1]).append(")");
|
||||||
for (Field f : fields) {
|
} else if ("VARCHAR".equals(sqlType)) {
|
||||||
Class<?> paramType = f.getType();
|
sb.append("(").append(varcharSize).append(")");
|
||||||
String sqlType = javaProperty2SqlColumnMap.get(paramType);
|
}
|
||||||
if (f.getName().equals("serialVersionUID") || StringUtils.isEmpty(sqlType) || f.isAnnotationPresent(TableGenIgnore.class)) {
|
}
|
||||||
continue;
|
|
||||||
|
// 添加约束
|
||||||
|
private static void appendConstraints(Field field, StringBuilder sb, TableInfo tableInfo) {
|
||||||
|
JDBCType type = tableInfo.dbType;
|
||||||
|
|
||||||
|
if (field.isAnnotationPresent(Constraint.class)) {
|
||||||
|
Constraint constraint = field.getAnnotation(Constraint.class);
|
||||||
|
if (constraint.notNull()) {
|
||||||
|
sb.append(" NOT NULL");
|
||||||
}
|
}
|
||||||
column = LowerCamelCase.INSTANCE.to(caseFormat, f.getName());
|
String apostrophe = constraint.defaultValueIsFunction() ? "" : "'";
|
||||||
if (f.isAnnotationPresent(Column.class)) {
|
if (StringUtils.isNotEmpty(constraint.defaultValue())) {
|
||||||
Column columnAnnotation = f.getAnnotation(Column.class);
|
sb.append(" DEFAULT ").append(apostrophe).append(constraint.defaultValue()).append(apostrophe);
|
||||||
//输出注解属性
|
|
||||||
if (StringUtils.isNotBlank(columnAnnotation.name())) {
|
|
||||||
column = columnAnnotation.name();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (f.isAnnotationPresent(Length.class)) {
|
if (constraint.autoIncrement()) {
|
||||||
Length fieldAnnotation = f.getAnnotation(Length.class);
|
if (type == JDBCType.PostgreSQL) {
|
||||||
decimalSize = fieldAnnotation.decimalSize();
|
// 需要移除字段类型(最后一个单词)
|
||||||
varcharSize = fieldAnnotation.varcharSize();
|
if (field.getType().equals(Integer.class)) {
|
||||||
}
|
sb.delete(sb.lastIndexOf(" "), sb.length());
|
||||||
sb.append(quotationMarks).append(column).append(quotationMarks);
|
sb.append(" SERIAL");
|
||||||
sb.append(" ").append(sqlType);
|
} else if (field.getType().equals(Long.class)) {
|
||||||
// 添加类型长度
|
sb.delete(sb.lastIndexOf(" "), sb.length());
|
||||||
if (sqlType.equals("DECIMAL")) {
|
sb.append(" BIGSERIAL");
|
||||||
sb.append("(").append(decimalSize[0]).append(",").append(decimalSize[1]).append(")");
|
}
|
||||||
}
|
} else if (field.getType().equals(Integer.class) || field.getType().equals(Long.class)) {
|
||||||
if (sqlType.equals("VARCHAR")) {
|
|
||||||
sb.append("(").append(varcharSize).append(")");
|
|
||||||
}
|
|
||||||
if (f.isAnnotationPresent(Constraint.class)) {
|
|
||||||
Constraint constraintAnnotation = f.getAnnotation(Constraint.class);
|
|
||||||
if (constraintAnnotation.notNull()) {
|
|
||||||
//非空约束
|
|
||||||
sb.append(" NOT NULL");
|
|
||||||
}
|
|
||||||
String apostrophe = constraintAnnotation.defaultValueIsFunction() ? "" : "'";
|
|
||||||
if (StringUtils.isNotEmpty(constraintAnnotation.defaultValue())) {
|
|
||||||
//默认值约束
|
|
||||||
sb.append(" DEFAULT ").append(apostrophe).append(constraintAnnotation.defaultValue()).append(apostrophe);
|
|
||||||
}
|
|
||||||
if (constraintAnnotation.autoIncrement() && paramType.equals(Integer.class) || paramType.equals(Long.class)) {
|
|
||||||
////自增
|
|
||||||
sb.append(" AUTO_INCREMENT");
|
sb.append(" AUTO_INCREMENT");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (StringUtils.isEmpty(primaryKey)) {
|
}
|
||||||
if (firstId) {//类型转换
|
}
|
||||||
sb.append(" PRIMARY KEY");
|
|
||||||
firstId = false;
|
// 添加主键
|
||||||
}
|
private static void appendPrimaryKey(String primaryKey, String column, StringBuilder sb) {
|
||||||
} else {
|
if (StringUtils.isEmpty(primaryKey)) {
|
||||||
if (primaryKey.equals(column.toLowerCase())) {
|
return;
|
||||||
sb.append(" PRIMARY KEY");
|
}
|
||||||
|
if (primaryKey.equalsIgnoreCase(column)) {
|
||||||
|
sb.append(" PRIMARY KEY");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void appendIndex(TableInfo tableInfo, List<String> indexSQLs, Field field) {
|
||||||
|
if (!field.isAnnotationPresent(Constraint.class)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Constraint constraint = field.getAnnotation(Constraint.class);
|
||||||
|
if (StringUtils.isEmpty(constraint.uniqueKey())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String indexName = UNIQUE_PREFIX + tableInfo.tableName + "_" + constraint.uniqueKey();
|
||||||
|
String columnName = field.getName();
|
||||||
|
|
||||||
|
// 检查是否已有相同索引名称的索引
|
||||||
|
Optional<String> existingIndex = indexSQLs.stream()
|
||||||
|
.filter(sql -> sql.contains(tableInfo.quotationMarks + indexName + tableInfo.quotationMarks))
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (existingIndex.isPresent()) {
|
||||||
|
// 如果存在相同索引名称,追加字段到索引定义中
|
||||||
|
String updatedIndex = existingIndex.get().replaceFirst(
|
||||||
|
"\\(([^)]+)\\)", // 匹配索引字段列表
|
||||||
|
"($1, " + tableInfo.quotationMarks + columnName + tableInfo.quotationMarks + ")"
|
||||||
|
);
|
||||||
|
indexSQLs.remove(existingIndex.get());
|
||||||
|
indexSQLs.add(updatedIndex);
|
||||||
|
} else {
|
||||||
|
// 如果不存在相同索引名称,创建新的索引
|
||||||
|
String indexSQL = String.format(
|
||||||
|
"CREATE UNIQUE INDEX %s %s%s%s ON %s%s%s (%s%s%s);",
|
||||||
|
tableInfo.dbType == JDBCType.MySQL ? "" : "IF NOT EXISTS",
|
||||||
|
tableInfo.quotationMarks, indexName, tableInfo.quotationMarks,
|
||||||
|
tableInfo.quotationMarks, tableInfo.tableName, tableInfo.quotationMarks,
|
||||||
|
tableInfo.quotationMarks, columnName, tableInfo.quotationMarks
|
||||||
|
);
|
||||||
|
indexSQLs.add(indexSQL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表信息类
|
||||||
|
private record TableInfo(
|
||||||
|
String tableName, // 表名
|
||||||
|
String quotationMarks, // 引号或反引号
|
||||||
|
String endStr, // 表尾部信息
|
||||||
|
String primaryKey, // 主键字段
|
||||||
|
Case caseFormat, // 命名格式
|
||||||
|
JDBCType dbType // 数据库类型
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Future<Void> createTable(Pool pool, JDBCType type) {
|
||||||
|
Promise<Void> promise = Promise.promise();
|
||||||
|
Set<Class<?>> tableClasses = ReflectionUtil.getReflections().getTypesAnnotatedWith(Table.class);
|
||||||
|
|
||||||
|
if (tableClasses.isEmpty()) {
|
||||||
|
LOGGER.warn("Table model class not found");
|
||||||
|
promise.complete();
|
||||||
|
return promise.future();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Future<Object>> futures = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Class<?> clazz : tableClasses) {
|
||||||
|
List<String> sqlList = getCreateTableSQL(clazz, type);
|
||||||
|
LOGGER.info("Class `{}` auto-generate table", clazz.getName());
|
||||||
|
|
||||||
|
for (String sql : sqlList) {
|
||||||
|
try {
|
||||||
|
pool.query(sql).execute().toCompletionStage().toCompletableFuture().join();
|
||||||
|
futures.add(Future.succeededFuture());
|
||||||
|
LOGGER.debug("Executed SQL:\n{}", sql);
|
||||||
|
} catch (Exception e) {
|
||||||
|
String message = e.getMessage();
|
||||||
|
if (message != null && message.contains("Duplicate key name")) {
|
||||||
|
LOGGER.warn("Ignoring duplicate key error: {}", message);
|
||||||
|
futures.add(Future.succeededFuture());
|
||||||
|
} else {
|
||||||
|
LOGGER.error("SQL Error: {}\nSQL: {}", message, sql);
|
||||||
|
futures.add(Future.failedFuture(e));
|
||||||
|
throw new RuntimeException(e); // Stop execution for other exceptions
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb.append(",\n ");
|
|
||||||
}
|
}
|
||||||
String sql = sb.toString();
|
|
||||||
//去掉最后一个逗号
|
|
||||||
int lastIndex = sql.lastIndexOf(",");
|
|
||||||
sql = sql.substring(0, lastIndex) + sql.substring(lastIndex + 1);
|
|
||||||
return sql.substring(0, sql.length() - 1) + endStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Future<Void> createTable(JDBCPool pool, JDBCType type) {
|
|
||||||
Set<Class<?>> tableClassList = ReflectionUtil.getReflections().getTypesAnnotatedWith(Table.class);
|
|
||||||
if (tableClassList.isEmpty()) LOGGER.info("Table model class not fount");
|
|
||||||
List<Future<Object>> futures = new ArrayList<>();
|
|
||||||
tableClassList.forEach(clazz -> {
|
|
||||||
String createTableSQL = getCreateTableSQL(clazz, type);
|
|
||||||
Future<Object> future = pool.query(createTableSQL).execute().compose(rs -> {
|
|
||||||
LOGGER.info("table auto generate:\n" + createTableSQL);
|
|
||||||
return Future.succeededFuture();
|
|
||||||
}).onFailure(e -> {
|
|
||||||
LOGGER.error(e.getMessage() + " SQL: \n" + createTableSQL);
|
|
||||||
});
|
|
||||||
futures.add(future);
|
|
||||||
});
|
|
||||||
|
|
||||||
Promise<Void> promise = Promise.promise();
|
|
||||||
Future.all(futures).onSuccess(r -> {
|
|
||||||
LOGGER.info("create table success");
|
|
||||||
promise.complete();
|
|
||||||
}).onFailure(promise::fail);
|
|
||||||
|
|
||||||
|
Future.all(futures).onSuccess(r -> promise.complete()).onFailure(promise::fail);
|
||||||
return promise.future();
|
return promise.future();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,6 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化JDBC
|
* 初始化JDBC
|
||||||
* <br>Create date 2021/8/10 12:04
|
* <br>Create date 2021/8/10 12:04
|
||||||
@@ -46,9 +43,6 @@ public class JDBCPoolInit {
|
|||||||
if (StringUtils.isBlank(builder.dbConfig.getString("provider_class"))) {
|
if (StringUtils.isBlank(builder.dbConfig.getString("provider_class"))) {
|
||||||
builder.dbConfig.put("provider_class", providerClass);
|
builder.dbConfig.put("provider_class", providerClass);
|
||||||
}
|
}
|
||||||
if (StringUtils.isBlank(builder.dbConfig.getString("driverClassName"))) {
|
|
||||||
builder.dbConfig.put("driverClassName", this.type.getDriverClassName());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Builder builder() {
|
public static Builder builder() {
|
||||||
@@ -97,6 +91,8 @@ public class JDBCPoolInit {
|
|||||||
return CreateTable.createTable(pool, type);
|
return CreateTable.createTable(pool, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取连接池
|
* 获取连接池
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -8,38 +8,21 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
*/
|
*/
|
||||||
public enum JDBCType {
|
public enum JDBCType {
|
||||||
// 添加驱动类型字段
|
// 添加驱动类型字段
|
||||||
MySQL("com.mysql.cj.jdbc.Driver", "jdbc:mysql:"),
|
MySQL("jdbc:mysql:"),
|
||||||
H2DB("org.h2.Driver", "jdbc:h2:");
|
H2DB("jdbc:h2:"),
|
||||||
|
PostgreSQL("jdbc:postgresql:");
|
||||||
private final String driverClassName; // 驱动类名
|
|
||||||
private final String urlPrefix; // JDBC URL 前缀
|
private final String urlPrefix; // JDBC URL 前缀
|
||||||
|
|
||||||
// 构造函数
|
// 构造函数
|
||||||
JDBCType(String driverClassName, String urlPrefix) {
|
JDBCType(String urlPrefix) {
|
||||||
this.driverClassName = driverClassName;
|
|
||||||
this.urlPrefix = urlPrefix;
|
this.urlPrefix = urlPrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取驱动类名
|
|
||||||
public String getDriverClassName() {
|
|
||||||
return driverClassName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取 JDBC URL 前缀
|
// 获取 JDBC URL 前缀
|
||||||
public String getUrlPrefix() {
|
public String getUrlPrefix() {
|
||||||
return urlPrefix;
|
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 类型
|
// 根据 JDBC URL 获取 JDBC 类型
|
||||||
public static JDBCType getJDBCTypeByURL(String jdbcURL) {
|
public static JDBCType getJDBCTypeByURL(String jdbcURL) {
|
||||||
for (JDBCType jdbcType : values()) {
|
for (JDBCType jdbcType : values()) {
|
||||||
@@ -47,6 +30,6 @@ public enum JDBCType {
|
|||||||
return jdbcType;
|
return jdbcType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new RuntimeException("不支持的SQL驱动类型: " + jdbcURL);
|
throw new RuntimeException("不支持的SQL类型: " + jdbcURL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 响应实体 用于和前端交互
|
* 响应实体 用于和前端交互
|
||||||
@@ -31,12 +30,10 @@ public class JsonResult<T> implements Serializable {
|
|||||||
|
|
||||||
private int code = SUCCESS_CODE;//状态码
|
private int code = SUCCESS_CODE;//状态码
|
||||||
|
|
||||||
private String msg = SUCCESS_MESSAGE;//消息
|
private String msg = SUCCESS_MESSAGE; //消息
|
||||||
|
|
||||||
private boolean success = true; //是否成功
|
private boolean success = true; //是否成功
|
||||||
|
|
||||||
private int count;
|
|
||||||
|
|
||||||
private T data;
|
private T data;
|
||||||
|
|
||||||
private long timestamp = System.currentTimeMillis(); //时间戳
|
private long timestamp = System.currentTimeMillis(); //时间戳
|
||||||
@@ -55,20 +52,6 @@ public class JsonResult<T> implements Serializable {
|
|||||||
this.success = success;
|
this.success = success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonResult(int code, String msg, boolean success, T data, int count) {
|
|
||||||
this(code, msg, success, data);
|
|
||||||
this.count = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCount() {
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JsonResult<T> setCount(int count) {
|
|
||||||
this.count = count;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCode() {
|
public int getCode() {
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
@@ -137,24 +120,9 @@ public class JsonResult<T> implements Serializable {
|
|||||||
return new JsonResult<>(SUCCESS_CODE, msg, true, data);
|
return new JsonResult<>(SUCCESS_CODE, msg, true, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 响应成功消息和数据实体
|
|
||||||
public static <T> JsonResult<T> data(String msg, T data, int count) {
|
|
||||||
if (StringUtils.isEmpty(msg)) msg = SUCCESS_MESSAGE;
|
|
||||||
return new JsonResult<>(SUCCESS_CODE, msg, true, data, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 响应数据实体
|
// 响应数据实体
|
||||||
public static <T> JsonResult<T> data(T data) {
|
public static <T> JsonResult<T> data(T data) {
|
||||||
int count = 0;
|
return new JsonResult<>(SUCCESS_CODE, SUCCESS_MESSAGE, true, data);
|
||||||
if (data instanceof List<?>) {
|
|
||||||
count = ((List<?>) data).size();
|
|
||||||
}
|
|
||||||
return new JsonResult<>(SUCCESS_CODE, SUCCESS_MESSAGE, true, data, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 响应数据实体
|
|
||||||
public static <T> JsonResult<T> data(T data, int count) {
|
|
||||||
return new JsonResult<>(SUCCESS_CODE, SUCCESS_MESSAGE, true, data, count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 响应成功消息
|
// 响应成功消息
|
||||||
|
|||||||
@@ -87,7 +87,8 @@ public enum PanDomainTemplate {
|
|||||||
"https://cowtransfer.com/s/{shareKey}",
|
"https://cowtransfer.com/s/{shareKey}",
|
||||||
CowTool.class),
|
CowTool.class),
|
||||||
CT("城通网盘",
|
CT("城通网盘",
|
||||||
compile("https://(?:[a-zA-Z\\d-]+\\.)?(ctfile|545c|u062|ghpym|474b)\\.com/f(ile)?/(?<KEY>.+)"),
|
compile("https://(?:[a-zA-Z\\d-]+\\.)?(ctfile|545c|u062|ghpym|474b)\\.com/f(ile)?/" +
|
||||||
|
"(?<KEY>[0-9a-zA-Z_-]+)(\\?p=(?<PWD>\\w+))?"),
|
||||||
"https://474b.com/file/{shareKey}",
|
"https://474b.com/file/{shareKey}",
|
||||||
CtTool.class),
|
CtTool.class),
|
||||||
// https://xxx.118pan.com/bxxx
|
// https://xxx.118pan.com/bxxx
|
||||||
|
|||||||
@@ -183,9 +183,9 @@ public class LzTool extends PanBase {
|
|||||||
String jsText = getJsByPwd(pwd, html, "var urls =window.location.href");
|
String jsText = getJsByPwd(pwd, html, "var urls =window.location.href");
|
||||||
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText, "file");
|
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText, "file");
|
||||||
Map<String, Object> data = CastUtil.cast(scriptObjectMirror.get("data"));
|
Map<String, Object> data = CastUtil.cast(scriptObjectMirror.get("data"));
|
||||||
System.out.println(data);
|
|
||||||
MultiMap map = MultiMap.caseInsensitiveMultiMap();
|
MultiMap map = MultiMap.caseInsensitiveMultiMap();
|
||||||
data.forEach((k, v) -> map.set(k, v.toString()));
|
data.forEach((k, v) -> map.set(k, v.toString()));
|
||||||
|
log.debug("解析参数: {}", map);
|
||||||
MultiMap headers = getHeaders(sUrl);
|
MultiMap headers = getHeaders(sUrl);
|
||||||
|
|
||||||
String url = SHARE_URL_PREFIX + "/filemoreajax.php?file=" + data.get("fid");
|
String url = SHARE_URL_PREFIX + "/filemoreajax.php?file=" + data.get("fid");
|
||||||
@@ -223,7 +223,7 @@ public class LzTool extends PanBase {
|
|||||||
.setSize(sizeNum)
|
.setSize(sizeNum)
|
||||||
.setPanType(panType)
|
.setPanType(panType)
|
||||||
.setParserUrl(getDomainName() + "/d/" + panType + "/" + id);
|
.setParserUrl(getDomainName() + "/d/" + panType + "/" + id);
|
||||||
System.out.println(fileInfo);
|
log.debug("文件信息: {}", fileInfo);
|
||||||
list.add(fileInfo);
|
list.add(fileInfo);
|
||||||
});
|
});
|
||||||
promise.complete(list);
|
promise.complete(list);
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
<logger name="io.netty" level="warn"/>
|
<logger name="io.netty" level="warn"/>
|
||||||
<logger name="io.vertx" level="info"/>
|
<logger name="io.vertx" level="info"/>
|
||||||
<logger name="com.zaxxer.hikari" level="info"/>
|
<logger name="com.zaxxer.hikari" level="info"/>
|
||||||
|
<logger name="cn.qaiu" level="debug"/>
|
||||||
<root level="info">
|
<root level="info">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
<!-- <appender-ref ref="FILE"/>-->
|
<!-- <appender-ref ref="FILE"/>-->
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package cn.qaiu.lz;
|
|||||||
import cn.qaiu.WebClientVertxInit;
|
import cn.qaiu.WebClientVertxInit;
|
||||||
import cn.qaiu.db.pool.JDBCPoolInit;
|
import cn.qaiu.db.pool.JDBCPoolInit;
|
||||||
import cn.qaiu.lz.common.cache.CacheConfigLoader;
|
import cn.qaiu.lz.common.cache.CacheConfigLoader;
|
||||||
|
import cn.qaiu.lz.common.interceptorImpl.RateLimiter;
|
||||||
import cn.qaiu.vx.core.Deploy;
|
import cn.qaiu.vx.core.Deploy;
|
||||||
import cn.qaiu.vx.core.util.ConfigConstant;
|
import cn.qaiu.vx.core.util.ConfigConstant;
|
||||||
import cn.qaiu.vx.core.util.VertxHolder;
|
import cn.qaiu.vx.core.util.VertxHolder;
|
||||||
@@ -11,8 +12,9 @@ import io.vertx.core.json.JsonArray;
|
|||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
import io.vertx.core.json.jackson.DatabindCodec;
|
import io.vertx.core.json.jackson.DatabindCodec;
|
||||||
import io.vertx.core.shareddata.LocalMap;
|
import io.vertx.core.shareddata.LocalMap;
|
||||||
import org.slf4j.Logger;
|
import org.apache.commons.lang3.time.DateFormatUtils;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
import static cn.qaiu.vx.core.util.ConfigConstant.LOCAL;
|
import static cn.qaiu.vx.core.util.ConfigConstant.LOCAL;
|
||||||
|
|
||||||
@@ -25,8 +27,6 @@ import static cn.qaiu.vx.core.util.ConfigConstant.LOCAL;
|
|||||||
*/
|
*/
|
||||||
public class AppMain {
|
public class AppMain {
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(AppMain.class);
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
Deploy.instance().start(args, AppMain::exec);
|
Deploy.instance().start(args, AppMain::exec);
|
||||||
}
|
}
|
||||||
@@ -40,14 +40,22 @@ public class AppMain {
|
|||||||
private static void exec(JsonObject jsonObject) {
|
private static void exec(JsonObject jsonObject) {
|
||||||
WebClientVertxInit.init(VertxHolder.getVertxInstance());
|
WebClientVertxInit.init(VertxHolder.getVertxInstance());
|
||||||
DatabindCodec.mapper().registerModule(new JavaTimeModule());
|
DatabindCodec.mapper().registerModule(new JavaTimeModule());
|
||||||
|
// 限流
|
||||||
|
if (jsonObject.containsKey("rateLimit")) {
|
||||||
|
JsonObject rateLimit = jsonObject.getJsonObject("rateLimit");
|
||||||
|
RateLimiter.init(rateLimit);
|
||||||
|
}
|
||||||
// 数据库
|
// 数据库
|
||||||
if (jsonObject.getJsonObject(ConfigConstant.SERVER).getBoolean("enableDatabase")) {
|
if (jsonObject.getJsonObject(ConfigConstant.SERVER).getBoolean("enableDatabase")) {
|
||||||
JDBCPoolInit.builder().config(jsonObject.getJsonObject("dataSource"))
|
JDBCPoolInit.builder().config(jsonObject.getJsonObject("dataSource"))
|
||||||
.build()
|
.build()
|
||||||
.initPool().onSuccess(PreparedStatement -> {
|
.initPool().onSuccess(PreparedStatement -> {
|
||||||
LOGGER.info("数据库连接成功");
|
VertxHolder.getVertxInstance().setTimer(1000, id -> {
|
||||||
String addr = jsonObject.getJsonObject(ConfigConstant.SERVER).getString("domainName");
|
System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS"));
|
||||||
LOGGER.info("启动成功: \n本地服务地址: {}", addr);
|
System.out.println("数据库连接成功");
|
||||||
|
String addr = jsonObject.getJsonObject(ConfigConstant.SERVER).getString("domainName");
|
||||||
|
System.out.println("启动成功: \n本地服务地址: " + addr);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// 缓存
|
// 缓存
|
||||||
|
|||||||
@@ -2,12 +2,15 @@ package cn.qaiu.lz.common.interceptorImpl;
|
|||||||
|
|
||||||
import cn.qaiu.vx.core.annotaions.HandleSortFilter;
|
import cn.qaiu.vx.core.annotaions.HandleSortFilter;
|
||||||
import cn.qaiu.vx.core.interceptor.BeforeInterceptor;
|
import cn.qaiu.vx.core.interceptor.BeforeInterceptor;
|
||||||
|
import cn.qaiu.vx.core.util.ConfigConstant;
|
||||||
import cn.qaiu.vx.core.util.SharedDataUtil;
|
import cn.qaiu.vx.core.util.SharedDataUtil;
|
||||||
import io.vertx.core.json.JsonArray;
|
import io.vertx.core.json.JsonArray;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import static cn.qaiu.vx.core.util.ConfigConstant.IGNORES_REG;
|
import static cn.qaiu.vx.core.util.ConfigConstant.IGNORES_REG;
|
||||||
|
import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 前置拦截器实现
|
* 前置拦截器实现
|
||||||
@@ -20,8 +23,43 @@ public class DefaultInterceptor implements BeforeInterceptor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
// System.out.println("进入前置拦截器1->" + ctx.request().path());
|
// 读取配置 如果配置了限流 则进行限流
|
||||||
doNext(ctx);
|
if (!SharedDataUtil.getJsonConfig(ConfigConstant.GLOBAL_CONFIG).containsKey("rateLimit")) {
|
||||||
|
doNext(ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JsonObject rateLimit = SharedDataUtil.getJsonConfig(ConfigConstant.GLOBAL_CONFIG)
|
||||||
|
.getJsonObject("rateLimit");
|
||||||
|
// # 限流配置
|
||||||
|
//rateLimit:
|
||||||
|
// # 是否启用限流
|
||||||
|
// enable: true
|
||||||
|
// # 限流的请求数
|
||||||
|
// limit: 1000
|
||||||
|
// # 限流的时间窗口(单位秒)
|
||||||
|
// timeWindow: 60
|
||||||
|
if (rateLimit.getBoolean("enable")) {
|
||||||
|
// 获取当前请求的路径
|
||||||
|
String path = ctx.request().path();
|
||||||
|
// 正则匹配路径
|
||||||
|
if (ignores.stream().anyMatch(ignore -> path.matches(ignore.toString()))) {
|
||||||
|
// 如果匹配到忽略的路径,则不进行限流
|
||||||
|
doNext(ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RateLimiter.checkRateLimit(ctx.request())
|
||||||
|
.onSuccess(v -> {
|
||||||
|
// 继续执行下一个拦截器
|
||||||
|
doNext(ctx);
|
||||||
|
})
|
||||||
|
.onFailure(t -> {
|
||||||
|
// 限流失败,返回错误响应
|
||||||
|
log.warn("Rate limit exceeded for path: {}", path);
|
||||||
|
ctx.response().putHeader(CONTENT_TYPE, "text/html; charset=utf-8")
|
||||||
|
.setStatusCode(429)
|
||||||
|
.end(t.getMessage());
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package cn.qaiu.lz.common.interceptorImpl;
|
||||||
|
|
||||||
|
import io.vertx.core.Future;
|
||||||
|
import io.vertx.core.Promise;
|
||||||
|
import io.vertx.core.http.HttpServerRequest;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class RateLimiter {
|
||||||
|
|
||||||
|
private static final Map<String, RequestInfo> ipRequestMap = new ConcurrentHashMap<>();
|
||||||
|
private static int MAX_REQUESTS = 10; // 最大请求次数
|
||||||
|
private static long TIME_WINDOW = 60 * 1000; // 时间窗口(毫秒)
|
||||||
|
|
||||||
|
private static String PATH_REG; // 限流路径正则
|
||||||
|
|
||||||
|
public static void init(JsonObject rateLimitConfig) {
|
||||||
|
MAX_REQUESTS = rateLimitConfig.getInteger("limit", 10);
|
||||||
|
TIME_WINDOW = rateLimitConfig.getInteger("timeWindow", 60) * 1000L; // 转换为毫秒
|
||||||
|
PATH_REG = rateLimitConfig.getString("pathReg", "/.*");
|
||||||
|
log.info("RateLimiter initialized with max requests: {}, time window: {} ms, path regex: {}",
|
||||||
|
MAX_REQUESTS, TIME_WINDOW, PATH_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized public static Future<Void> checkRateLimit(HttpServerRequest request) {
|
||||||
|
Promise<Void> promise = Promise.promise();
|
||||||
|
if (!request.path().matches(PATH_REG)) {
|
||||||
|
// 如果请求路径不匹配正则,则不进行限流
|
||||||
|
promise.complete();
|
||||||
|
return promise.future();
|
||||||
|
}
|
||||||
|
|
||||||
|
String ip = request.remoteAddress().host();
|
||||||
|
|
||||||
|
ipRequestMap.compute(ip, (key, requestInfo) -> {
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
if (requestInfo == null || currentTime - requestInfo.timestamp > TIME_WINDOW) {
|
||||||
|
// 初始化或重置计数器
|
||||||
|
return new RequestInfo(1, currentTime);
|
||||||
|
} else {
|
||||||
|
// 增加计数器
|
||||||
|
requestInfo.count++;
|
||||||
|
return requestInfo;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
RequestInfo info = ipRequestMap.get(ip);
|
||||||
|
if (info.count > MAX_REQUESTS) {
|
||||||
|
// 超过限制
|
||||||
|
// 计算剩余时间
|
||||||
|
long remainingTime = TIME_WINDOW - (System.currentTimeMillis() - info.timestamp);
|
||||||
|
BigDecimal bigDecimal = BigDecimal.valueOf(remainingTime / 1000.0)
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
promise.fail("请求次数太多了,请" + bigDecimal + "秒后再试。");
|
||||||
|
} else {
|
||||||
|
// 未超过限制,继续处理
|
||||||
|
promise.complete();
|
||||||
|
}
|
||||||
|
return promise.future();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RequestInfo {
|
||||||
|
int count;
|
||||||
|
long timestamp;
|
||||||
|
|
||||||
|
RequestInfo(int count, long time) {
|
||||||
|
this.count = count;
|
||||||
|
this.timestamp = time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package cn.qaiu.lz.web.controller;
|
||||||
|
|
||||||
|
import cn.qaiu.lz.web.service.ShoutService;
|
||||||
|
import cn.qaiu.vx.core.annotaions.RouteHandler;
|
||||||
|
import cn.qaiu.vx.core.annotaions.RouteMapping;
|
||||||
|
import cn.qaiu.vx.core.enums.RouteMethod;
|
||||||
|
import cn.qaiu.vx.core.model.JsonResult;
|
||||||
|
import cn.qaiu.vx.core.util.AsyncServiceUtil;
|
||||||
|
import io.vertx.core.Future;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import io.vertx.ext.web.RoutingContext;
|
||||||
|
|
||||||
|
@RouteHandler("/v2/shout")
|
||||||
|
public class ShoutController {
|
||||||
|
|
||||||
|
private final ShoutService shoutService = AsyncServiceUtil.getAsyncServiceInstance(ShoutService.class);
|
||||||
|
|
||||||
|
@RouteMapping(value = "/submit", method = RouteMethod.POST)
|
||||||
|
public Future<JsonObject> submitMessage(RoutingContext ctx) {
|
||||||
|
String content = ctx.body().asJsonObject().getString("content");
|
||||||
|
if (content == null || content.trim().isEmpty()) {
|
||||||
|
return Future.failedFuture("内容不能为空");
|
||||||
|
}
|
||||||
|
return shoutService.submitMessage(content, ctx.request().remoteAddress().host()).compose(code ->
|
||||||
|
Future.succeededFuture(JsonResult.data(code).toJsonObject()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@RouteMapping(value = "/retrieve", method = RouteMethod.GET)
|
||||||
|
public Future<JsonObject> retrieveMessage(RoutingContext ctx) {
|
||||||
|
String code = ctx.request().getParam("code");
|
||||||
|
if (code == null || code.length() != 6) {
|
||||||
|
return Future.failedFuture("提取码必须为6位数字");
|
||||||
|
}
|
||||||
|
return shoutService.retrieveMessage(code);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package cn.qaiu.lz.web.model;
|
||||||
|
|
||||||
|
import cn.qaiu.db.ddl.Constraint;
|
||||||
|
import cn.qaiu.db.ddl.Length;
|
||||||
|
import cn.qaiu.db.ddl.Table;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 隔空喊话消息
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Table("t_messages")
|
||||||
|
public class ShoutMessage {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Constraint(autoIncrement= true, notNull = true)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Length(varcharSize = 16)
|
||||||
|
@Constraint(notNull = true, uniqueKey = "uk_code")
|
||||||
|
private String code; // 6位提取码
|
||||||
|
|
||||||
|
@Length(varcharSize = 4096)
|
||||||
|
private String content; // 消息内容
|
||||||
|
|
||||||
|
@Length(varcharSize = 32)
|
||||||
|
private String ip; // 发送者IP
|
||||||
|
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
private Date createTime = new Date(); // 创建时间
|
||||||
|
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
private Date expireTime; // 过期时间
|
||||||
|
|
||||||
|
private Boolean isUsed = false; // 是否已使用
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package cn.qaiu.lz.web.service;
|
||||||
|
|
||||||
|
import cn.qaiu.vx.core.base.BaseAsyncService;
|
||||||
|
import io.vertx.codegen.annotations.ProxyGen;
|
||||||
|
import io.vertx.core.Future;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
|
|
||||||
|
@ProxyGen
|
||||||
|
public interface ShoutService extends BaseAsyncService {
|
||||||
|
// 提交消息并返回提取码
|
||||||
|
Future<String> submitMessage(String content, String host);
|
||||||
|
|
||||||
|
// 通过提取码获取消息
|
||||||
|
Future<JsonObject> retrieveMessage(String code);
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package cn.qaiu.lz.web.service.impl;
|
||||||
|
|
||||||
|
import cn.qaiu.db.pool.JDBCPoolInit;
|
||||||
|
import cn.qaiu.lz.web.service.ShoutService;
|
||||||
|
import cn.qaiu.vx.core.annotaions.Service;
|
||||||
|
import cn.qaiu.vx.core.model.JsonResult;
|
||||||
|
import io.vertx.core.Future;
|
||||||
|
import io.vertx.core.Promise;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import io.vertx.jdbcclient.JDBCPool;
|
||||||
|
import io.vertx.sqlclient.Tuple;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@SuppressWarnings("SqlResolve") // 这里是为了避免检查SQL语句的警告
|
||||||
|
public class ShoutServiceImpl implements ShoutService {
|
||||||
|
private static final int CODE_LENGTH = 6;
|
||||||
|
private static final int EXPIRE_HOURS = 24;
|
||||||
|
private final JDBCPool jdbcPool = JDBCPoolInit.instance().getPool();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Future<String> submitMessage(String content, String host) {
|
||||||
|
Promise<String> promise = Promise.promise();
|
||||||
|
String code = generateRandomCode();
|
||||||
|
// 判断一下当前code是否存在消息
|
||||||
|
LocalDateTime expireTime = LocalDateTime.now().plusHours(EXPIRE_HOURS);
|
||||||
|
|
||||||
|
String sql = "INSERT INTO t_messages (code, content, expire_time, ip) VALUES (?, ?, ?, ?)";
|
||||||
|
|
||||||
|
jdbcPool.preparedQuery(sql)
|
||||||
|
.execute(Tuple.of(code, content,
|
||||||
|
java.sql.Timestamp.from(expireTime.atZone(ZoneId.systemDefault()).toInstant()),
|
||||||
|
host))
|
||||||
|
.onSuccess(res -> {
|
||||||
|
log.info("Message submitted with code: {}", code);
|
||||||
|
promise.complete(code);
|
||||||
|
})
|
||||||
|
.onFailure(err -> {
|
||||||
|
log.error("Failed to submit message", err);
|
||||||
|
promise.fail(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
return promise.future();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Future<JsonObject> retrieveMessage(String code) {
|
||||||
|
Promise<JsonObject> promise = Promise.promise();
|
||||||
|
|
||||||
|
String sql = "SELECT content FROM t_messages WHERE code = ? AND expire_time > NOW()";
|
||||||
|
|
||||||
|
jdbcPool.preparedQuery(sql)
|
||||||
|
.execute(Tuple.of(code))
|
||||||
|
.onSuccess(rows -> {
|
||||||
|
if (rows.size() > 0) {
|
||||||
|
String content = rows.iterator().next().getString("content");
|
||||||
|
// 标记为已使用
|
||||||
|
markAsUsed(code);
|
||||||
|
promise.complete(JsonResult.data(content).toJsonObject());
|
||||||
|
} else {
|
||||||
|
promise.fail("无效的提取码或消息已过期");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.onFailure(err -> {
|
||||||
|
log.error("Failed to retrieve message", err);
|
||||||
|
promise.fail(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
return promise.future();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void markAsUsed(String code) {
|
||||||
|
String sql = "UPDATE t_messages SET is_used = TRUE WHERE code = ?";
|
||||||
|
jdbcPool.preparedQuery(sql).execute(Tuple.of(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateRandomCode() {
|
||||||
|
Random random = new Random();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < CODE_LENGTH; i++) {
|
||||||
|
sb.append(random.nextInt(10));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,8 @@ server:
|
|||||||
# 使用数据库
|
# 使用数据库
|
||||||
enableDatabase: true
|
enableDatabase: true
|
||||||
# 服务域名或者IP 生成二维码链接时需要
|
# 服务域名或者IP 生成二维码链接时需要
|
||||||
domainName: http://127.0.0.1:6401
|
# domainName: http://127.0.0.1:6401
|
||||||
|
domainName: https://lz.qaiu.top
|
||||||
|
|
||||||
# 反向代理服务器配置路径(不用加后缀)
|
# 反向代理服务器配置路径(不用加后缀)
|
||||||
proxyConf: server-proxy
|
proxyConf: server-proxy
|
||||||
@@ -25,18 +26,29 @@ custom:
|
|||||||
routeTimeOut: 15000
|
routeTimeOut: 15000
|
||||||
# 拦截器匹配规则
|
# 拦截器匹配规则
|
||||||
ignoresReg:
|
ignoresReg:
|
||||||
- /v2/statisticsInfo
|
# - /v2/statisticsInfo
|
||||||
- .*/test.*$
|
- .*/test.*$
|
||||||
|
|
||||||
# 参数注入的实体类包路径匹配正则 (防止同名类引发歧义)
|
# 参数注入的实体类包路径匹配正则 (防止同名类引发歧义)
|
||||||
entityPackagesReg:
|
entityPackagesReg:
|
||||||
- ^cn\.qaiu\.lz\.web\.model\..*
|
- ^cn\.qaiu\.lz\.web\.model\..*
|
||||||
|
|
||||||
|
# 限流配置
|
||||||
|
rateLimit:
|
||||||
|
# 是否启用限流
|
||||||
|
enable: true
|
||||||
|
# 限流的请求数
|
||||||
|
limit: 5
|
||||||
|
# 限流的时间窗口(单位秒)
|
||||||
|
timeWindow: 10
|
||||||
|
# 路径匹配规则
|
||||||
|
pathReg: ^/v2/.*
|
||||||
|
|
||||||
|
|
||||||
# 数据源配置
|
# 数据源配置
|
||||||
dataSource:
|
dataSource:
|
||||||
#jdbcUrl: jdbc:mysql://127.0.0.1:3306/nfddata?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false
|
#jdbcUrl: jdbc:mysql://127.0.0.1:3306/nfddata?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false
|
||||||
jdbcUrl: jdbc:h2:file:./db/nfdData1;MODE=MySQL;DATABASE_TO_UPPER=FALSE
|
jdbcUrl: jdbc:h2:file:./db/nfdData;MODE=MySQL;DATABASE_TO_UPPER=FALSE
|
||||||
username: root
|
username: root
|
||||||
password: '123456'
|
password: '123456'
|
||||||
|
|
||||||
@@ -63,7 +75,8 @@ cache:
|
|||||||
mne: 30
|
mne: 30
|
||||||
mqq: 30
|
mqq: 30
|
||||||
mkg: 30
|
mkg: 30
|
||||||
p115: 5
|
p115: 30
|
||||||
|
ct: 30
|
||||||
|
|
||||||
# httpClient静态代理服务器配置(外网代理)
|
# httpClient静态代理服务器配置(外网代理)
|
||||||
proxy:
|
proxy:
|
||||||
|
|||||||
@@ -25,3 +25,4 @@ https://api.ilanzou.com/unproved/file/redirect?uuid=0&devType=6×tamp=453240
|
|||||||
https://www.ilanzou.com/s/zHkna1S
|
https://www.ilanzou.com/s/zHkna1S
|
||||||
|
|
||||||
### fileId: 145042258
|
### fileId: 145042258
|
||||||
|
https://api.ilanzou.com/unproved/recommend/list?devType=6&devModel=Chrome&uuid=AjiM-Wl782OuHyuvKiuaH&extra=2×tamp=311D0B438400DB5D98F1D2FF5A7A86F1&shareId=jQ9i3F0&type=0&offset=1&limit=60
|
||||||
|
|||||||
@@ -101,6 +101,128 @@ referer: https://www.vyuyun.com
|
|||||||
https://down2.bilnn.top/uploads/11283/306bdccd233ffd2c.jar?filename=C400003mAan70zUy5O+%282%29.m4a&mime=audio%2Fx-m4a&verify=1729911697-SLZtEHXB4TM*ze1j31WMyNA**p743DY*GN2sajUx5w*2mM**
|
https://down2.bilnn.top/uploads/11283/306bdccd233ffd2c.jar?filename=C400003mAan70zUy5O+%282%29.m4a&mime=audio%2Fx-m4a&verify=1729911697-SLZtEHXB4TM*ze1j31WMyNA**p743DY*GN2sajUx5w*2mM**
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
# @no-cookie-jar
|
||||||
|
# curl 'https://www.vyuyun.com/apiv1/share/getShareDownUrl/QPyZsb/gDZBTm?password=&downcode=Iv7YsjhM_6kzHijjtHyTLfPqlr6xwR5kqVNfMMAdWBEBcW1iNNIK-hDvrwLyzF4a'
|
||||||
|
# -H 'Accept: */*'
|
||||||
|
# -H 'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8'
|
||||||
|
# -H 'Cache-Control: no-cache'
|
||||||
|
# -H 'Connection: keep-alive'
|
||||||
|
# -H 'Cookie: Hm_lvt_6e5421de7bb814e1dfc49bbc577c04d3=1734489414,1736133991,1736139184; HMACCOUNT=7C4EDB1414D4E56F; ginmin-session=MTczNjEzOTY5OHxEWDhFQVFMX2dBQUJFQUVRQUFBRV80QUFBQT09fE1kmd-TQNIU-AcLRbEhAMzpcoaTIqnDkU_z1Z2kW64A; Hm_lpvt_6e5421de7bb814e1dfc49bbc577c04d3=1736139719; __gads=ID=710230eb796d6baf:T=1736139187:RT=1736139729:S=ALNI_MauDIW3Tl0IYOZILi-6C0qMU328RA; __gpi=UID=00000fa7e525a50e:T=1736139187:RT=1736139729:S=ALNI_MYOvo89qg4zJq0s35CanMI3lx-zLw; __eoi=ID=df2245386092f112:T=1736139187:RT=1736139729:S=AA-AfjbzvOhiQPaERKQKlmEEC7Ds'
|
||||||
|
# -H 'DNT: 1'
|
||||||
|
# -H 'Pragma: no-cache'
|
||||||
|
# -H 'Referer: https://www.vyuyun.com/s/QPyZsb/file?password='
|
||||||
|
# -H 'Sec-Fetch-Dest: empty'
|
||||||
|
# -H 'Sec-Fetch-Mode: cors'
|
||||||
|
# -H 'Sec-Fetch-Site: same-origin'
|
||||||
|
# -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
|
||||||
|
# -H 'sec-ch-ua: "Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"'
|
||||||
|
# -H 'sec-ch-ua-mobile: ?0'
|
||||||
|
# -H 'sec-ch-ua-platform: "Windows"'
|
||||||
|
# -H 'token;'
|
||||||
|
GET https://www.vyuyun.com/apiv1/share/getShareDownUrl/QPyZsb/gDZBTm?password=&downcode=Iv7YsjhM_6kzHijjtHyTLfPqlr6xwR5kqVNfMMAdWBEBcW1iNNIK-hDvrwLyzF4a
|
||||||
|
Accept: */*
|
||||||
|
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
|
||||||
|
Cache-Control: no-cache
|
||||||
|
Connection: keep-alive
|
||||||
|
Cookie: Hm_lvt_6e5421de7bb814e1dfc49bbc577c04d3=1734489414,1736133991,1736139184; HMACCOUNT=7C4EDB1414D4E56F; ginmin-session=MTczNjEzOTY5OHxEWDhFQVFMX2dBQUJFQUVRQUFBRV80QUFBQT09fE1kmd-TQNIU-AcLRbEhAMzpcoaTIqnDkU_z1Z2kW64A; Hm_lpvt_6e5421de7bb814e1dfc49bbc577c04d3=1736139719; __gads=ID=710230eb796d6baf:T=1736139187:RT=1736139729:S=ALNI_MauDIW3Tl0IYOZILi-6C0qMU328RA; __gpi=UID=00000fa7e525a50e:T=1736139187:RT=1736139729:S=ALNI_MYOvo89qg4zJq0s35CanMI3lx-zLw; __eoi=ID=df2245386092f112:T=1736139187:RT=1736139729:S=AA-AfjbzvOhiQPaERKQKlmEEC7Ds
|
||||||
|
DNT: 1
|
||||||
|
Pragma: no-cache
|
||||||
|
Referer: https://www.vyuyun.com/s/QPyZsb/file?password=
|
||||||
|
Sec-Fetch-Dest: empty
|
||||||
|
Sec-Fetch-Mode: cors
|
||||||
|
Sec-Fetch-Site: same-origin
|
||||||
|
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
|
||||||
|
sec-ch-ua: "Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"
|
||||||
|
sec-ch-ua-mobile: ?0
|
||||||
|
sec-ch-ua-platform: "Windows"
|
||||||
|
token:
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
# curl 'https://www.vyuyun.com/apiv1/share/file/QPyZsb?password='
|
||||||
|
# -H 'Accept: application/json, text/plain, */*'
|
||||||
|
# -H 'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8'
|
||||||
|
# -H 'Cache-Control: no-cache'
|
||||||
|
# -H 'Connection: keep-alive'
|
||||||
|
# -H 'Cookie: Hm_lvt_6e5421de7bb814e1dfc49bbc577c04d3=1734489414,1736133991; HMACCOUNT=845216228CFDAEF3; ginmin-session=MTczNjEzNzIwNXxEWDhFQVFMX2dBQUJFQUVRQUFBaV80QUFBUVp6ZEhKcGJtY01CUUFEWVdsa0JuTjBjbWx1Wnd3SEFBVXhNVGt3T0E9PXygMqAo7e0FsZpAm5tggrVEAmipmptNAe4RF-StdbItOA==; __gads=ID=02846a0224427b16:T=1729911643:RT=1736137206:S=ALNI_MYN-82qd45RW0rYq1JewWVxCmoZAQ; __gpi=UID=00000f553e085dd5:T=1729911643:RT=1736137206:S=ALNI_Mb2dIMzZrO14lDlqCBOShH29OEfng; __eoi=ID=3e810b8ce65b0a46:T=1729911643:RT=1736137206:S=AA-AfjbN5kpzrPK6QBBlTEmMlxXx; Hm_lpvt_6e5421de7bb814e1dfc49bbc577c04d3=1736137222'
|
||||||
|
# -H 'DNT: 1'
|
||||||
|
# -H 'Pragma: no-cache'
|
||||||
|
# -H 'Referer: https://www.vyuyun.com/s/QPyZsb/file?password='
|
||||||
|
# -H 'Sec-Fetch-Dest: empty'
|
||||||
|
# -H 'Sec-Fetch-Mode: cors'
|
||||||
|
# -H 'Sec-Fetch-Site: same-origin'
|
||||||
|
# -H 'Token;'
|
||||||
|
# -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
|
||||||
|
# -H 'X-Requested-With: XMLHttpRequest'
|
||||||
|
# -H 'sec-ch-ua: "Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"'
|
||||||
|
# -H 'sec-ch-ua-mobile: ?0'
|
||||||
|
# -H 'sec-ch-ua-platform: "Windows"'
|
||||||
|
GET https://www.vyuyun.com/apiv1/share/file/QPyZsb?password=
|
||||||
|
Accept: application/json, text/plain, */*
|
||||||
|
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
|
||||||
|
Cache-Control: no-cache
|
||||||
|
Connection: keep-alive
|
||||||
|
Cookie: Hm_lvt_6e5421de7bb814e1dfc49bbc577c04d3=1734489414,1736133991; HMACCOUNT=845216228CFDAEF3; ginmin-session=MTczNjEzNzIwNXxEWDhFQVFMX2dBQUJFQUVRQUFBaV80QUFBUVp6ZEhKcGJtY01CUUFEWVdsa0JuTjBjbWx1Wnd3SEFBVXhNVGt3T0E9PXygMqAo7e0FsZpAm5tggrVEAmipmptNAe4RF-StdbItOA==; __gads=ID=02846a0224427b16:T=1729911643:RT=1736137206:S=ALNI_MYN-82qd45RW0rYq1JewWVxCmoZAQ; __gpi=UID=00000f553e085dd5:T=1729911643:RT=1736137206:S=ALNI_Mb2dIMzZrO14lDlqCBOShH29OEfng; __eoi=ID=3e810b8ce65b0a46:T=1729911643:RT=1736137206:S=AA-AfjbN5kpzrPK6QBBlTEmMlxXx; Hm_lpvt_6e5421de7bb814e1dfc49bbc577c04d3=1736137222
|
||||||
|
DNT: 1
|
||||||
|
Pragma: no-cache
|
||||||
|
Referer: https://www.vyuyun.com/s/QPyZsb/file?password=
|
||||||
|
Sec-Fetch-Dest: empty
|
||||||
|
Sec-Fetch-Mode: cors
|
||||||
|
Sec-Fetch-Site: same-origin
|
||||||
|
Token:
|
||||||
|
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
|
||||||
|
X-Requested-With: XMLHttpRequest
|
||||||
|
sec-ch-ua: "Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"
|
||||||
|
sec-ch-ua-mobile: ?0
|
||||||
|
sec-ch-ua-platform: "Windows"
|
||||||
|
|
||||||
|
###
|
||||||
|
# curl 'https://www.vyuyun.com/apiv1/share/getShareDownUrl/QPyZsb/gDZBTm?password=&downcode=Iv7YsjhM_6kzHijjtHyTLT2CySejYHyXEtW_2oI9kqCnevPaRjMpzFDaq4dT4z3R'
|
||||||
|
# -H 'Accept: */*'
|
||||||
|
# -H 'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6'
|
||||||
|
# -H 'Cache-Control: no-cache'
|
||||||
|
# -H 'Connection: keep-alive'
|
||||||
|
# -H 'Cookie: noticeId=1; Hm_lvt_6e5421de7bb814e1dfc49bbc577c04d3=1736134006; HMACCOUNT=DD7A065B1B5C7BCF; ginmin-session=MTczNjEzNDExNXxEWDhFQVFMX2dBQUJFQUVRQUFELUFRal9nQUFEQm5OMGNtbHVad3dIQUFWMGIydGxiZ1p6ZEhKcGJtY01fNjhBXzZ4b1pVOVNMWGRwVVRWemVrTlFhRGxzTjNCRlNHOW5jMWRLU2pKVFluUlZOVWR2UlhkWGNEbElUMEZNYlV0RVMwRkJTeloxVlhaS1UycE5aMXBrTW1jMWJYVlRPVjlOWkVVMWNHMU1iMkZMTW1sR1NHcFhRbWhPWjAxb05FWmpWV2swVWpOU01GZE9aRk5UZUd0WVJFSmphMWw0WVZKVkxYRlhSalZ5UlhSSmRYaG9jbVJuTWpkbmRFWlBWRlpDV0ZkWGMzWjJaVFZtUjFwSWMwRnBlbXhhUVROVFowaEtZakJqTlc4cUJuTjBjbWx1Wnd3SUFBWnZjR1Z1YVdRR2MzUnlhVzVuREFJQUFBWnpkSEpwYm1jTUNnQUlZV1J0YVc1ZmFYTUdjM1J5YVc1bkRBTUFBVEE9fMMethsDCW-b_YQHRj_0KHUVB1AcmohDXI4L4en8_8Nd; Hm_lpvt_6e5421de7bb814e1dfc49bbc577c04d3=1736138831'
|
||||||
|
# -H 'DNT: 1'
|
||||||
|
# -H 'Pragma: no-cache'
|
||||||
|
# -H 'Referer: https://www.vyuyun.com/s/QPyZsb/file?password='
|
||||||
|
# -H 'Sec-Fetch-Dest: empty'
|
||||||
|
# -H 'Sec-Fetch-Mode: cors'
|
||||||
|
# -H 'Sec-Fetch-Site: same-origin'
|
||||||
|
# -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0'
|
||||||
|
# -H 'sec-ch-ua: "Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"'
|
||||||
|
# -H 'sec-ch-ua-mobile: ?0'
|
||||||
|
# -H 'sec-ch-ua-platform: "Windows"'
|
||||||
|
# -H 'token: heOR-wiQ5szCPh9l7pEHogsWJJ2SbtU5GoEwWp9HOALmKDKAAK6uUvJSjMgZd2g5muS9_MdE5pmLoaK2iFHjWBhNgMh4FcUi4R3R0WNdSSxkXDBckYxaRU-qWF5rEtIuxhrdg27gtFOTVBXWWsvve5fGZHsAizlZA3SgHJb0c5o*'
|
||||||
|
GET https://www.vyuyun.com/apiv1/share/getShareDownUrl/QPyZsb/gDZBTm?password=&downcode=Iv7YsjhM_6kzHijjtHyTLT2CySejYHyXEtW_2oI9kqCnevPaRjMpzFDaq4dT4z3R
|
||||||
|
Accept: */*
|
||||||
|
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
|
||||||
|
Cache-Control: no-cache
|
||||||
|
Connection: keep-alive
|
||||||
|
Cookie: noticeId=1; Hm_lvt_6e5421de7bb814e1dfc49bbc577c04d3=1736134006; HMACCOUNT=DD7A065B1B5C7BCF; ginmin-session=MTczNjEzNDExNXxEWDhFQVFMX2dBQUJFQUVRQUFELUFRal9nQUFEQm5OMGNtbHVad3dIQUFWMGIydGxiZ1p6ZEhKcGJtY01fNjhBXzZ4b1pVOVNMWGRwVVRWemVrTlFhRGxzTjNCRlNHOW5jMWRLU2pKVFluUlZOVWR2UlhkWGNEbElUMEZNYlV0RVMwRkJTeloxVlhaS1UycE5aMXBrTW1jMWJYVlRPVjlOWkVVMWNHMU1iMkZMTW1sR1NHcFhRbWhPWjAxb05FWmpWV2swVWpOU01GZE9aRk5UZUd0WVJFSmphMWw0WVZKVkxYRlhSalZ5UlhSSmRYaG9jbVJuTWpkbmRFWlBWRlpDV0ZkWGMzWjJaVFZtUjFwSWMwRnBlbXhhUVROVFowaEtZakJqTlc4cUJuTjBjbWx1Wnd3SUFBWnZjR1Z1YVdRR2MzUnlhVzVuREFJQUFBWnpkSEpwYm1jTUNnQUlZV1J0YVc1ZmFYTUdjM1J5YVc1bkRBTUFBVEE9fMMethsDCW-b_YQHRj_0KHUVB1AcmohDXI4L4en8_8Nd; Hm_lpvt_6e5421de7bb814e1dfc49bbc577c04d3=1736138831
|
||||||
|
DNT: 1
|
||||||
|
Pragma: no-cache
|
||||||
|
Referer: https://www.vyuyun.com/s/QPyZsb/file?password=
|
||||||
|
Sec-Fetch-Dest: empty
|
||||||
|
Sec-Fetch-Mode: cors
|
||||||
|
Sec-Fetch-Site: same-origin
|
||||||
|
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0
|
||||||
|
sec-ch-ua: "Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"
|
||||||
|
sec-ch-ua-mobile: ?0
|
||||||
|
sec-ch-ua-platform: "Windows"
|
||||||
|
token: heOR-wiQ5szCPh9l7pEHogsWJJ2SbtU5GoEwWp9HOALmKDKAAK6uUvJSjMgZd2g5muS9_MdE5pmLoaK2iFHjWBhNgMh4FcUi4R3R0WNdSSxkXDBckYxaRU-qWF5rEtIuxhrdg27gtFOTVBXWWsvve5fGZHsAizlZA3SgHJb0c5o*
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 118网盘 https://qaiu.118pan.com/b1228264
|
### 118网盘 https://qaiu.118pan.com/b1228264
|
||||||
#密码:qaiu
|
#密码:qaiu
|
||||||
https://qaiu.118pan.com/b1228264
|
https://qaiu.118pan.com/b1228264
|
||||||
|
|||||||
18
web-service/src/main/resources/http-tools/test2.http
Normal file
18
web-service/src/main/resources/http-tools/test2.http
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
###
|
||||||
|
POST http://127.0.0.1:6400/v2/shout/submit
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"content": "CREATE UNIQUE INDEX `idx_uk_code` ON `t_messages` (`code`);"
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
GET http://127.0.0.1:6400/v2/shout/retrieve?code=878696
|
||||||
|
|
||||||
|
###
|
||||||
|
响应:
|
||||||
|
{
|
||||||
|
"data": "这是一条秘密消息",
|
||||||
|
"code": 200,
|
||||||
|
"msg": "success"
|
||||||
|
}
|
||||||
@@ -55,6 +55,7 @@
|
|||||||
<logger name="io.netty" level="warn"/>
|
<logger name="io.netty" level="warn"/>
|
||||||
<logger name="io.vertx" level="info"/>
|
<logger name="io.vertx" level="info"/>
|
||||||
<logger name="com.zaxxer.hikari" level="info"/>
|
<logger name="com.zaxxer.hikari" level="info"/>
|
||||||
|
<logger name="cn.qaiu" level="debug"/>
|
||||||
<root level="info">
|
<root level="info">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
<!-- <appender-ref ref="FILE"/>-->
|
<!-- <appender-ref ref="FILE"/>-->
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package cn.qaiu.db.ddl;
|
||||||
|
|
||||||
|
import cn.qaiu.db.pool.JDBCType;
|
||||||
|
import io.vertx.sqlclient.templates.annotations.Column;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class CreateTableTest {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static class TestModel2 {
|
||||||
|
@Column(name = "id")
|
||||||
|
@Constraint(autoIncrement = true)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "name")
|
||||||
|
@Constraint(notNull = true, uniqueKey = "ne_unique")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Column(name = "age")
|
||||||
|
private Integer age;
|
||||||
|
|
||||||
|
@Column(name = "email")
|
||||||
|
@Constraint(notNull = true, uniqueKey = "ne_unique")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@Column(name = "created_at")
|
||||||
|
private java.util.Date createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCreateTableSQL() {
|
||||||
|
// 测试
|
||||||
|
String sql = String.join("\n", CreateTable.getCreateTableSQL(TestModel2.class, JDBCType.H2DB));
|
||||||
|
System.out.println(sql);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void getCreateTableSQL2() {
|
||||||
|
// 测试
|
||||||
|
String sql = String.join("\n", CreateTable.getCreateTableSQL(TestModel2.class, JDBCType.MySQL));
|
||||||
|
System.out.println(sql);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void getCreateTableSQL3() {
|
||||||
|
// 测试
|
||||||
|
String sql = String.join("\n", CreateTable.getCreateTableSQL(TestModel2.class, JDBCType.PostgreSQL));
|
||||||
|
System.out.println(sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user