mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2025-12-15 11:53:02 +00:00
first commit ZZZzzzzzz
This commit is contained in:
36
.gitignore
vendored
Normal file
36
.gitignore
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
# IntelliJ IDEA #
|
||||
.idea/
|
||||
/.idea/
|
||||
*/.idea/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
# Eclipse Project files
|
||||
.classpath
|
||||
.project
|
||||
/.settings/
|
||||
.settings/
|
||||
|
||||
# Java class files
|
||||
*.class
|
||||
|
||||
# Generated files
|
||||
*/bin/
|
||||
*/gen/
|
||||
*/out/
|
||||
|
||||
### user ###
|
||||
target/
|
||||
/target/
|
||||
/src/logs/
|
||||
*.zip
|
||||
sdkTest.log
|
||||
|
||||
|
||||
#some local files
|
||||
*/.DS_Store
|
||||
.DS_Store
|
||||
gradlew
|
||||
gradlew.bat
|
||||
unused.txt
|
||||
5
bin/run.bat
Normal file
5
bin/run.bat
Normal file
@@ -0,0 +1,5 @@
|
||||
@echo off && @chcp 65001 > nul
|
||||
pushd %~dp0
|
||||
set LIB_DIR=%~dp0
|
||||
for /f "delims=X" %%i in ('dir /b %LIB_DIR%\web-*.jar') do set LAUNCH_JAR=%LIB_DIR%\%%i
|
||||
"%JAVA_HOME%\bin\java.exe" -Xmx512M -Dfile.encoding=utf8 -jar %LAUNCH_JAR% %*
|
||||
5
bin/run.sh
Normal file
5
bin/run.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
# set -x
|
||||
LAUNCH_JAR="web-*.jar"
|
||||
nohup java -Xmx512M -jar "$LAUNCH_JAR" "$@" >startup.log 2>&1 &
|
||||
tail -f startup.log
|
||||
9
core/README.md
Normal file
9
core/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
TODO
|
||||
|
||||
- Interceptor重构 -> (0%)
|
||||
- 可配置的反向代理服务器 -> (70%)
|
||||
- SQL-gen/ORM/JSON-Model -> (1%)
|
||||
- 注解式APO -> (0%)
|
||||
- 注解式eventbus,sockjs-bridge -> (10%)
|
||||
- Code-gen TemplateEngine -> (1%)
|
||||
- HTML TemplateEngine -> (0%)
|
||||
127
core/pom.xml
Normal file
127
core/pom.xml
Normal file
@@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>lz-cow-api</artifactId>
|
||||
<groupId>cn.qaiu</groupId>
|
||||
<version>0.0.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<version>1.0.8</version>
|
||||
<artifactId>core</artifactId>
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<vertx.version>4.1.3</vertx.version>
|
||||
<org.reflections.version>0.9.12</org.reflections.version>
|
||||
<lombok.version>1.18.12</lombok.version>
|
||||
<slf4j.version>2.0.5</slf4j.version>
|
||||
<commons-lang3.version>3.8.1</commons-lang3.version>
|
||||
<jackson.version>2.11.3</jackson.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-dependencies</artifactId>
|
||||
<version>${vertx.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<!--logback日志实现-->
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.4.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-codegen</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-config</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-config-yaml</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-service-proxy</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-jdbc-client</artifactId>
|
||||
</dependency>
|
||||
<!-- SQL模板 -->
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-sql-client-templates</artifactId>
|
||||
</dependency>
|
||||
<!-- jwt鉴权 -->
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-auth-jwt</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-web-proxy</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-stomp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.reflections</groupId>
|
||||
<artifactId>reflections</artifactId>
|
||||
<version>${org.reflections.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons-lang3.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
<version>1.9.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
159
core/src/main/java/cn/com/yhinfo/core/Deploy.java
Normal file
159
core/src/main/java/cn/com/yhinfo/core/Deploy.java
Normal file
@@ -0,0 +1,159 @@
|
||||
package cn.com.yhinfo.core;
|
||||
|
||||
import cn.com.yhinfo.core.util.ConfigUtil;
|
||||
import cn.com.yhinfo.core.util.VertxHolder;
|
||||
import cn.com.yhinfo.core.verticle.ReverseProxyVerticle;
|
||||
import cn.com.yhinfo.core.verticle.ServiceVerticle;
|
||||
import cn.com.yhinfo.core.verticle.RouterVerticle;
|
||||
import io.vertx.core.*;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.core.shareddata.LocalMap;
|
||||
import io.vertx.core.shareddata.SharedData;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* vertx启动类 需要在主启动类完成回调
|
||||
* <br>Create date 2021-05-07 10:26:54
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public final class Deploy {
|
||||
|
||||
private static final Deploy INSTANCE = new Deploy();
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Deploy.class);
|
||||
private static final long startTime = System.currentTimeMillis();
|
||||
|
||||
private final Vertx tempVertx = Vertx.vertx();
|
||||
StringBuilder path = new StringBuilder("app");
|
||||
|
||||
private JsonObject customConfig;
|
||||
private Handler<JsonObject> handle;
|
||||
|
||||
public static Deploy instance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public void start(String[] args, Handler<JsonObject> handle) {
|
||||
this.handle = handle;
|
||||
if (args.length > 0) {
|
||||
// 启动参数dev或者prod
|
||||
path.append("-").append(args[0]);
|
||||
}
|
||||
|
||||
// 读取yml配置
|
||||
ConfigUtil.readYamlConfig(path.toString(), tempVertx)
|
||||
.onSuccess(this::readConf)
|
||||
.onFailure(Throwable::printStackTrace);
|
||||
}
|
||||
|
||||
private void readConf(JsonObject conf) {
|
||||
outLogo(conf);
|
||||
String activeMode = conf.getString("active");
|
||||
if ("dev".equals(activeMode)) {
|
||||
LOGGER.info("---------------> development environment <--------------\n");
|
||||
System.setProperty("vertxweb.environment","dev");
|
||||
} else {
|
||||
LOGGER.info("---------------> Production environment <--------------\n");
|
||||
}
|
||||
ConfigUtil.readYamlConfig(path + "-" + activeMode, tempVertx).onSuccess(this::deployVerticle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印logo
|
||||
*/
|
||||
private void outLogo(JsonObject conf) {
|
||||
Date date = new Date();
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
int year = calendar.get(Calendar.YEAR);
|
||||
String logoTemplete = "\nWeb Server powered by: \n" +
|
||||
" ____ ____ _ _ _ \n" +
|
||||
"|_^^_| |_^^_| / |_ | | | | \n" +
|
||||
" \\ \\ / /.---. _ .--.`| |-' _ __ | |__| |_ \n" +
|
||||
" \\ \\ / // /__\\\\[ `/'`\\]| | [ \\ [ ]|____ _| \n" +
|
||||
" \\ V / | \\__., | | | |, _ > ' < _| |_ \n" +
|
||||
" \\_/ '.__.'[___] \\__/(_)[__]`\\_] |_____| \n" +
|
||||
" Version: %s; Framework version: %s; %s©%d.\n\n";
|
||||
|
||||
System.out.printf(logoTemplete,
|
||||
conf.getString("version_app"),
|
||||
conf.getString("version_vertx"),
|
||||
conf.getString("copyright"),
|
||||
year
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 部署Verticle
|
||||
*
|
||||
* @param globalConfig 配置
|
||||
*/
|
||||
private void deployVerticle(JsonObject globalConfig) {
|
||||
tempVertx.close();
|
||||
LOGGER.info("配置读取成功");
|
||||
customConfig = globalConfig.getJsonObject("custom");
|
||||
|
||||
VertxOptions vertxOptions = new VertxOptions(globalConfig.getJsonObject("vertx"));
|
||||
Vertx vertx = Vertx.vertx(vertxOptions);
|
||||
VertxHolder.init(vertx);
|
||||
//配置保存在共享数据中
|
||||
SharedData sharedData = vertx.sharedData();
|
||||
LocalMap<String, Object> localMap = sharedData.getLocalMap("local");
|
||||
localMap.put("globalConfig", globalConfig);
|
||||
localMap.put("customConfig", customConfig);
|
||||
localMap.put("server", globalConfig.getJsonObject("server"));
|
||||
handle.handle(globalConfig);
|
||||
|
||||
Future<String> future1 = vertx.deployVerticle(RouterVerticle.class, getWorkDeploymentOptions("Router"));
|
||||
Future<String> future2 = vertx.deployVerticle(ServiceVerticle.class, getWorkDeploymentOptions("Service"));
|
||||
Future<String> future3 = vertx.deployVerticle(ReverseProxyVerticle.class, getWorkDeploymentOptions("proxy"));
|
||||
|
||||
CompositeFuture.all(future1, future2, future3)
|
||||
.onSuccess(this::deployWorkVerticalSuccess)
|
||||
.onFailure(this::deployVerticalFailed);
|
||||
}
|
||||
|
||||
/**
|
||||
* 部署失败
|
||||
*
|
||||
* @param throwable Exception信息
|
||||
*/
|
||||
private void deployVerticalFailed(Throwable throwable) {
|
||||
LOGGER.error(throwable.getClass().getName() + ": " + throwable.getMessage());
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动时间信息
|
||||
*
|
||||
* @param compositeFuture future wraps a list
|
||||
*/
|
||||
private void deployWorkVerticalSuccess(CompositeFuture compositeFuture) {
|
||||
double t1 = ((double) (System.currentTimeMillis() - startTime)) / 1000;
|
||||
double t2 = ((double) System.currentTimeMillis() - ManagementFactory.getRuntimeMXBean().getStartTime()) / 1000;
|
||||
LOGGER.info("web服务启动成功 -> 用时: {}s, jvm启动用时: {}s", t1, t2);
|
||||
}
|
||||
|
||||
/**
|
||||
* deploy Verticle Options
|
||||
*
|
||||
* @param name the worker pool name
|
||||
* @return Deployment Options
|
||||
*/
|
||||
private DeploymentOptions getWorkDeploymentOptions(String name) {
|
||||
return getWorkDeploymentOptions(name, customConfig.getInteger("asyncServiceInstances"));
|
||||
}
|
||||
|
||||
private DeploymentOptions getWorkDeploymentOptions(String name, int ins) {
|
||||
return new DeploymentOptions()
|
||||
.setWorkerPoolName(name)
|
||||
.setWorker(true)
|
||||
.setInstances(ins);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package cn.com.yhinfo.core.annotaions;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 日期参数格式化注解
|
||||
* <br>Create date 2021-05-06 09:20:37
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
@Target(ElementType.PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DateFormat {
|
||||
String value() default "yyyy-MM-dd HH:mm:ss";
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package cn.com.yhinfo.core.annotaions;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Web Router API类 标识注解
|
||||
* <br>Create date 2021-04-30 09:22:18
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
@Documented
|
||||
@Inherited
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface RouteHandler {
|
||||
|
||||
String value() default "";
|
||||
|
||||
boolean isOpen() default false;
|
||||
|
||||
/**
|
||||
* 注册顺序,数字越大越先注册
|
||||
*/
|
||||
int order() default 0;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package cn.com.yhinfo.core.annotaions;
|
||||
|
||||
import cn.com.yhinfo.core.enums.MIMEType;
|
||||
import cn.com.yhinfo.core.enums.RouteMethod;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Router API Method 标识注解
|
||||
* <br>Create date 2021-05-06 09:20:37
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RouteMapping {
|
||||
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* 使用http method
|
||||
*/
|
||||
RouteMethod method() default RouteMethod.GET;
|
||||
|
||||
/**
|
||||
* 接口description
|
||||
*/
|
||||
String description() default "";
|
||||
|
||||
/**
|
||||
* 注册顺序,数字越大越先注册
|
||||
*/
|
||||
int order() default 0;
|
||||
|
||||
/**
|
||||
* 响应类型
|
||||
*/
|
||||
MIMEType responseMimeType() default MIMEType.APPLICATION_JSON;
|
||||
|
||||
/**
|
||||
* 请求类型
|
||||
*/
|
||||
MIMEType requestMIMEType() default MIMEType.ALL;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package cn.com.yhinfo.core.annotaions;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 服务实现层注解(XXServiceImpl)
|
||||
* <br>Create date 2021/8/25 15:57
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Service {
|
||||
String name() default "";
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package cn.com.yhinfo.core.annotaions;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* WebSocket api 注解类
|
||||
* <br>Create date 2021/8/25 15:57
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
@Documented
|
||||
@Inherited
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface SockRouteMapper {
|
||||
String value() default "";
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package cn.com.yhinfo.core.base;
|
||||
|
||||
import cn.com.yhinfo.core.util.CastUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 反射获取父接口类名辅助类, 异步服务需要实现此接口
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public interface BaseAsyncService {
|
||||
|
||||
/**
|
||||
* 获取异步服务接口地址
|
||||
* @see BaseAsyncService#getAsyncInterfaceClass
|
||||
* @return 服务接口类名
|
||||
* @throws ClassNotFoundException 接口不存在
|
||||
*/
|
||||
default String getAddress() throws ClassNotFoundException {
|
||||
return getAsyncInterfaceClass().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取异步服务接口地址
|
||||
* @return 服务接口类对象
|
||||
* @throws ClassNotFoundException 接口不存在
|
||||
*/
|
||||
default Class<Object> getAsyncInterfaceClass() throws ClassNotFoundException {
|
||||
// 获取实现接口 作为地址注册到EventBus
|
||||
Class<Object> clazz = CastUtil.cast(Arrays.stream(this.getClass().getInterfaces()).filter(
|
||||
clz-> Arrays.asList(clz.getInterfaces()).contains(BaseAsyncService.class)
|
||||
).findFirst().orElse(null));
|
||||
if (clazz == null) {
|
||||
throw new ClassNotFoundException("No interface found: \""+this.getClass().getName()+"\" need to implement interface");
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
}
|
||||
34
core/src/main/java/cn/com/yhinfo/core/base/BaseHttpApi.java
Normal file
34
core/src/main/java/cn/com/yhinfo/core/base/BaseHttpApi.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package cn.com.yhinfo.core.base;
|
||||
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
|
||||
import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE;
|
||||
|
||||
/**
|
||||
* 统一响应处理
|
||||
* <br>Create date 2021-05-06 09:20:37
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public interface BaseHttpApi {
|
||||
|
||||
default void fireJsonResponse(RoutingContext ctx, JsonObject jsonResult) {
|
||||
ctx.response().putHeader(CONTENT_TYPE, "application/json; charset=utf-8")
|
||||
.setStatusCode(200)
|
||||
.end(jsonResult.encode());
|
||||
}
|
||||
|
||||
default <T> void fireJsonResponse(RoutingContext ctx, T jsonResult) {
|
||||
JsonObject jsonObject = JsonObject.mapFrom(jsonResult);
|
||||
fireJsonResponse(ctx, jsonObject);
|
||||
}
|
||||
|
||||
default void fireTextResponse(RoutingContext ctx, String text) {
|
||||
ctx.response().putHeader("content-type", "text/html; charset=utf-8").end(text);
|
||||
}
|
||||
|
||||
default void sendError(int statusCode, RoutingContext ctx) {
|
||||
ctx.response().setStatusCode(statusCode).end();
|
||||
}
|
||||
}
|
||||
39
core/src/main/java/cn/com/yhinfo/core/enums/MIMEType.java
Normal file
39
core/src/main/java/cn/com/yhinfo/core/enums/MIMEType.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package cn.com.yhinfo.core.enums;
|
||||
|
||||
/**
|
||||
* MIMEType: request or response head
|
||||
* <br>Create date 2021/8/30 4:35
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public enum MIMEType {
|
||||
|
||||
NULL(""),
|
||||
ALL("*/*"),
|
||||
TEXT_HTML("text/html"),
|
||||
APPLICATION_POSTSCRIPT("application/postscript"),
|
||||
TEXT_PLAIN("text/plain"),
|
||||
APPLICATION_X_WWW_FORM_URLENCODED("application/x-www-form-urlencoded"),
|
||||
APPLICATION_OCTET_STREAM("application/octet-stream"),
|
||||
MULTIPART_FORM_DATA("multipart/form-data"),
|
||||
APPLICATION_X_JAVA_AGENT("application/x-java-agent"),
|
||||
MESSAGE_HTTP("message/http"),
|
||||
TEXT_CSS("text/css"),
|
||||
TEXT_XML("text/xml"),
|
||||
TEXT("text/*"),
|
||||
APPLICATION_RDF_XML("application/rdf+xml"),
|
||||
APPLICATION_XHTML_XML("application/xhtml+xml"),
|
||||
APPLICATION_XML("application/xml"),
|
||||
APPLICATION_JSON("application/json");
|
||||
|
||||
public String getValue() {
|
||||
return type;
|
||||
}
|
||||
|
||||
private final String type;
|
||||
|
||||
MIMEType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
}
|
||||
11
core/src/main/java/cn/com/yhinfo/core/enums/RouteMethod.java
Normal file
11
core/src/main/java/cn/com/yhinfo/core/enums/RouteMethod.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package cn.com.yhinfo.core.enums;
|
||||
|
||||
/**
|
||||
* Router API 请求处理方式枚举
|
||||
* <br>Create date 2021-04-30 09:22:18
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public enum RouteMethod {
|
||||
OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT, PATCH, ROUTE
|
||||
}
|
||||
@@ -0,0 +1,383 @@
|
||||
package cn.com.yhinfo.core.handlerfactory;
|
||||
|
||||
import cn.com.yhinfo.core.annotaions.DateFormat;
|
||||
import cn.com.yhinfo.core.annotaions.RouteHandler;
|
||||
import cn.com.yhinfo.core.annotaions.RouteMapping;
|
||||
import cn.com.yhinfo.core.annotaions.SockRouteMapper;
|
||||
import cn.com.yhinfo.core.base.BaseHttpApi;
|
||||
import cn.com.yhinfo.core.enums.MIMEType;
|
||||
import cn.com.yhinfo.core.model.JsonResult;
|
||||
import cn.com.yhinfo.core.util.*;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.core.MultiMap;
|
||||
import io.vertx.core.http.HttpMethod;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.Route;
|
||||
import io.vertx.ext.web.Router;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
import io.vertx.ext.web.handler.BodyHandler;
|
||||
import io.vertx.ext.web.handler.CorsHandler;
|
||||
import io.vertx.ext.web.handler.sockjs.SockJSHandler;
|
||||
import io.vertx.ext.web.handler.sockjs.SockJSHandlerOptions;
|
||||
import javassist.CtClass;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.reflections.Reflections;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static io.vertx.core.http.HttpHeaders.*;
|
||||
|
||||
/**
|
||||
* 路由映射, 参数绑定
|
||||
* <br>Create date 2021-05-07 10:26:54
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public class RouterHandlerFactory implements BaseHttpApi {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RouterHandlerFactory.class);
|
||||
|
||||
private static final Set<HttpMethod> httpMethods = new HashSet<HttpMethod>() {{
|
||||
add(HttpMethod.GET);
|
||||
add(HttpMethod.POST);
|
||||
add(HttpMethod.OPTIONS);
|
||||
add(HttpMethod.PUT);
|
||||
add(HttpMethod.DELETE);
|
||||
add(HttpMethod.HEAD);
|
||||
}};
|
||||
// 需要扫描注册的Router路径
|
||||
private static volatile Reflections reflections;
|
||||
|
||||
private final String gatewayPrefix;
|
||||
|
||||
public RouterHandlerFactory(String routerScanAddress, String gatewayPrefix) {
|
||||
Objects.requireNonNull(routerScanAddress, "The router package address scan is empty.");
|
||||
Objects.requireNonNull(gatewayPrefix, "The gateway prefix is empty.");
|
||||
reflections = ReflectionUtil.getReflections(routerScanAddress);
|
||||
this.gatewayPrefix = gatewayPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始扫描并注册handler
|
||||
*/
|
||||
public Router createRouter() {
|
||||
Router router = Router.router(VertxHolder.getVertxInstance());
|
||||
router.route().handler(ctx -> {
|
||||
LOGGER.debug("The HTTP service request address information ===>path:{}, uri:{}, method:{}",
|
||||
ctx.request().path(), ctx.request().absoluteURI(), ctx.request().method());
|
||||
ctx.response().headers().add(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
|
||||
ctx.response().headers().add(ACCESS_CONTROL_ALLOW_METHODS, "POST, GET, OPTIONS, PUT, DELETE, HEAD");
|
||||
ctx.response().headers().add(ACCESS_CONTROL_ALLOW_HEADERS, "X-PINGOTHER, Origin,Content-Type, Accept, X-Requested-With, Dev, Authorization, Version, Token");
|
||||
ctx.response().headers().add(ACCESS_CONTROL_MAX_AGE, "1728000");
|
||||
ctx.next();
|
||||
});
|
||||
// 添加跨域的方法
|
||||
router.route().handler(CorsHandler.create("*").allowCredentials(true).allowedMethods(httpMethods));
|
||||
|
||||
// 配置文件上传路径
|
||||
router.route().handler(BodyHandler.create().setUploadsDirectory("uploads"));
|
||||
|
||||
|
||||
try {
|
||||
Set<Class<?>> handlers = reflections.getTypesAnnotatedWith(RouteHandler.class);
|
||||
Comparator<Class<?>> comparator = (c1, c2) -> {
|
||||
RouteHandler routeHandler1 = c1.getAnnotation(RouteHandler.class);
|
||||
RouteHandler routeHandler2 = c2.getAnnotation(RouteHandler.class);
|
||||
return Integer.compare(routeHandler2.order(), routeHandler1.order());
|
||||
};
|
||||
// 获取处理器类列表
|
||||
List<Class<?>> sortedHandlers = handlers.stream().sorted(comparator).collect(Collectors.toList());
|
||||
for (Class<?> handler : sortedHandlers) {
|
||||
try {
|
||||
// 注册请求处理方法
|
||||
registerNewHandler(router, handler);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Error register {}, Error details:", handler, e.getCause());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Manually Register Handler Fail, Error details:" + e.getMessage());
|
||||
}
|
||||
// 错误请求处理
|
||||
router.errorHandler(405, ctx -> fireJsonResponse(ctx, JsonResult
|
||||
.error("Method Not Allowed", 405)));
|
||||
router.errorHandler(404, ctx -> ctx.response().setStatusCode(404).setChunked(true)
|
||||
.end("Internal server error: 404 not found"));
|
||||
return router;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册handler
|
||||
*/
|
||||
private void registerNewHandler(Router router, Class<?> handler) throws Throwable {
|
||||
String root = getRootPath(handler);
|
||||
Object instance = ReflectionUtil.newWithNoParam(handler);
|
||||
Method[] methods = handler.getMethods();
|
||||
// 注册处理方法排序
|
||||
Comparator<Method> comparator = (m1, m2) -> {
|
||||
RouteMapping mapping1 = m1.getAnnotation(RouteMapping.class);
|
||||
RouteMapping mapping2 = m2.getAnnotation(RouteMapping.class);
|
||||
return Integer.compare(mapping2.order(), mapping1.order());
|
||||
};
|
||||
List<Method> methodList = Stream.of(methods).filter(
|
||||
method -> method.isAnnotationPresent(RouteMapping.class)
|
||||
).sorted(comparator).collect(Collectors.toList());
|
||||
|
||||
methodList.addAll(Stream.of(methods).filter(
|
||||
method -> method.isAnnotationPresent(SockRouteMapper.class)
|
||||
).toList());
|
||||
|
||||
// 拦截器
|
||||
Handler<RoutingContext> interceptor = getInterceptor();
|
||||
// 依次注册处理方法
|
||||
for (Method method : methodList) {
|
||||
if (method.isAnnotationPresent(RouteMapping.class)) {
|
||||
// 普通路由
|
||||
RouteMapping mapping = method.getAnnotation(RouteMapping.class);
|
||||
HttpMethod routeMethod = HttpMethod.valueOf(mapping.method().name());
|
||||
String routeUrl = getRouteUrl(method.getName(), mapping.value());
|
||||
String url = root.concat(routeUrl);
|
||||
// 匹配方法
|
||||
Route route = router.route(routeMethod, url);
|
||||
String mineType = mapping.requestMIMEType().getValue();
|
||||
LOGGER.info("route -> {}:{} -> {}", routeMethod.name(), url, mineType);
|
||||
if (StringUtils.isNotEmpty(mineType)) {
|
||||
route.consumes(mineType);
|
||||
}
|
||||
|
||||
// 先执行拦截方法, 再进入业务请求
|
||||
route.handler(interceptor);
|
||||
route.handler(ctx -> handlerMethod(instance, method, ctx)).failureHandler(ctx -> {
|
||||
if (ctx.response().ended()) return;
|
||||
ctx.failure().printStackTrace();
|
||||
fireJsonResponse(ctx, JsonResult.error(ctx.failure().getMessage(), 500));
|
||||
});
|
||||
} else if (method.isAnnotationPresent(SockRouteMapper.class)) {
|
||||
// websocket 基于sockJs
|
||||
SockRouteMapper mapping = method.getAnnotation(SockRouteMapper.class);
|
||||
String routeUrl = getRouteUrl(method.getName(), mapping.value());
|
||||
String url = root.concat(routeUrl);
|
||||
LOGGER.info("Register New Websocket Handler -> {}", url);
|
||||
SockJSHandlerOptions options = new SockJSHandlerOptions()
|
||||
.setHeartbeatInterval(2000)
|
||||
.setRegisterWriteHandler(true);
|
||||
|
||||
SockJSHandler sockJSHandler = SockJSHandler.create(VertxHolder.getVertxInstance(), options);
|
||||
Router route = sockJSHandler.socketHandler(sock -> {
|
||||
try {
|
||||
ReflectionUtil.invokeWithArguments(method, instance, sock);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
router.mountSubRouter(url, route);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取并处理路由URL分隔符
|
||||
*
|
||||
* @param methodName 路由method
|
||||
* @return String
|
||||
*/
|
||||
private String getRouteUrl(String methodName, String mapperValue) {
|
||||
String routeUrl;
|
||||
if (mapperValue.startsWith("/:") || "/".equals(mapperValue)) {
|
||||
routeUrl = (methodName + mapperValue);
|
||||
} else if (mapperValue.startsWith("/")) {
|
||||
routeUrl = mapperValue.substring(1);
|
||||
} else {
|
||||
routeUrl = mapperValue;
|
||||
}
|
||||
return routeUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置拦截
|
||||
*
|
||||
* @return Handler
|
||||
* @throws Throwable Throwable
|
||||
*/
|
||||
private Handler<RoutingContext> getInterceptor() throws Throwable {
|
||||
// 配置拦截
|
||||
Class<?> interceptorClass = Class.forName(SharedDataUtil.getValueForCustomConfig("interceptorClassPath"));
|
||||
Object handleInstance = ReflectionUtil.newWithNoParam(interceptorClass);
|
||||
Method doHandle = interceptorClass.getMethod("doHandle");
|
||||
// 反射调用
|
||||
return CastUtil.cast(ReflectionUtil.invoke(doHandle, handleInstance));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求根路径
|
||||
*
|
||||
* @param handler handler
|
||||
* @return 根路径
|
||||
*/
|
||||
private String getRootPath(Class<?> handler) {
|
||||
// 处理请求路径前缀和后缀
|
||||
String root = gatewayPrefix;
|
||||
if (!root.startsWith("/")) {
|
||||
root = "/" + root;
|
||||
}
|
||||
if (!root.endsWith("/")) {
|
||||
root = root + "/";
|
||||
}
|
||||
// 子路径
|
||||
if (handler.isAnnotationPresent(RouteHandler.class)) {
|
||||
RouteHandler routeHandler = handler.getAnnotation(RouteHandler.class);
|
||||
String value = routeHandler.value();
|
||||
root += ("/".equals(value) ? "" : value);
|
||||
}
|
||||
if (!root.endsWith("/")) {
|
||||
root = root + "/";
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理请求-参数绑定
|
||||
*
|
||||
* @param instance 类实例
|
||||
* @param method 处理方法
|
||||
* @param ctx 路由上下文
|
||||
*/
|
||||
private void handlerMethod(Object instance, Method method, RoutingContext ctx) {
|
||||
// 方法参数名列表
|
||||
Map<String, Pair<Annotation[], CtClass>> methodParameters = ReflectionUtil.getMethodParameter(method);
|
||||
Map<String, Pair<Annotation[], CtClass>> methodParametersTemp = new LinkedHashMap<>(methodParameters);
|
||||
Map<String, String> pathParamValues = ctx.pathParams();
|
||||
|
||||
// 参数名-参数值
|
||||
Map<String, Object> parameterValueList = new LinkedHashMap<>();
|
||||
methodParameters.forEach((k, v) -> parameterValueList.put(k, null));
|
||||
|
||||
//绑定rest路径变量
|
||||
if (!pathParamValues.isEmpty()) {
|
||||
methodParameters.forEach((k, v) -> {
|
||||
if (pathParamValues.containsKey(k)) {
|
||||
methodParametersTemp.remove(k);
|
||||
if (ReflectionUtil.isBasicType(v.getRight())) {
|
||||
String fmt = getFmt(v.getLeft(), v.getRight());
|
||||
parameterValueList.put(k, ReflectionUtil.conversion(v.getRight(), pathParamValues.get(k), fmt));
|
||||
} else if (ReflectionUtil.isBasicTypeArray(v.getRight())) {
|
||||
parameterValueList.put(k, ReflectionUtil.conversionArray(v.getRight(), pathParamValues.get(k)));
|
||||
} else {
|
||||
throw new RuntimeException("参数绑定异常: 类型不匹配");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final MultiMap queryParams = ctx.queryParams();
|
||||
if ("POST".equals(ctx.request().method().name())) {
|
||||
queryParams.addAll(ctx.request().params());
|
||||
}
|
||||
|
||||
JsonArray entityPackagesReg = SharedDataUtil.getJsonArrayForCustomConfig("entityPackagesReg");
|
||||
// 绑定get或post请求头的请求参数
|
||||
methodParametersTemp.forEach((k, v) -> {
|
||||
if (ReflectionUtil.isBasicType(v.getRight())) {
|
||||
String fmt = getFmt(v.getLeft(), v.getRight());
|
||||
String value = queryParams.get(k);
|
||||
parameterValueList.put(k, ReflectionUtil.conversion(v.getRight(), value, fmt));
|
||||
} else if ("io.vertx.ext.web.RoutingContext".equals(v.getRight().getName())) {
|
||||
parameterValueList.put(k, ctx);
|
||||
} else if ("io.vertx.core.http.HttpServerRequest".equals(v.getRight().getName())) {
|
||||
parameterValueList.put(k, ctx.request());
|
||||
} else if ("io.vertx.core.http.HttpServerResponse".equals(v.getRight().getName())) {
|
||||
parameterValueList.put(k, ctx.response());
|
||||
} else if (CommonUtil.matchRegList(entityPackagesReg.getList(), v.getRight().getName())) {
|
||||
// 绑定实体类
|
||||
try {
|
||||
Class<?> aClass = Class.forName(v.getRight().getName());
|
||||
Object entity = ParamUtil.multiMapToEntity(queryParams, aClass);
|
||||
parameterValueList.put(k, entity);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
// 解析body-json参数
|
||||
if ("application/json".equals(ctx.parsedHeaders().contentType().value()) && ctx.getBodyAsJson() != null) {
|
||||
JsonObject body = ctx.getBodyAsJson();
|
||||
if (body != null) {
|
||||
methodParametersTemp.forEach((k, v) -> {
|
||||
// 只解析已配置包名前缀的实体类
|
||||
if (CommonUtil.matchRegList(entityPackagesReg.getList(), v.getRight().getName())) {
|
||||
try {
|
||||
Class<?> aClass = Class.forName(v.getRight().getName());
|
||||
JsonObject data = CommonUtil.getSubJsonForEntity(body, aClass);
|
||||
if (!data.isEmpty()) {
|
||||
Object entity = data.mapTo(aClass);
|
||||
parameterValueList.put(k, entity);
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// 调用handle 获取响应对象
|
||||
Object[] parameterValueArray = parameterValueList.values().toArray(new Object[0]);
|
||||
try {
|
||||
// 反射调用
|
||||
Object data = ReflectionUtil.invokeWithArguments(method, instance, parameterValueArray);
|
||||
if (data != null) {
|
||||
if (data instanceof JsonResult) {
|
||||
fireJsonResponse(ctx, data);
|
||||
} else if (data instanceof Future) { // 处理异步响应
|
||||
((Future<?>) data).onSuccess(res -> {
|
||||
if (res instanceof JsonObject) {
|
||||
fireJsonResponse(ctx, res);
|
||||
} else {
|
||||
fireJsonResponse(ctx, JsonResult.data(res));
|
||||
}
|
||||
}).onFailure(e -> fireJsonResponse(ctx, JsonResult.error(e.getMessage())));
|
||||
} else {
|
||||
ctx.response().headers().set(CONTENT_TYPE, MIMEType.TEXT_HTML.getValue());
|
||||
ctx.end(data.toString());
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
String err = e.getMessage();
|
||||
if (e.getCause() != null) {
|
||||
if (e.getCause() instanceof InvocationTargetException) {
|
||||
err = ((InvocationTargetException)e.getCause()).getTargetException().getMessage();
|
||||
} else {
|
||||
err = e.getCause().getMessage();
|
||||
}
|
||||
}
|
||||
fireJsonResponse(ctx, JsonResult.error(err));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取DateFormat注解值
|
||||
*/
|
||||
private String getFmt(Annotation[] parameterAnnotations, CtClass v) {
|
||||
String fmt = "";
|
||||
if ("java.util.Date".equals(v.getName())) {
|
||||
for (Annotation annotation : parameterAnnotations) {
|
||||
if (annotation instanceof DateFormat) {
|
||||
fmt = ((DateFormat) annotation).value();
|
||||
}
|
||||
}
|
||||
}
|
||||
return fmt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package cn.com.yhinfo.core.interceptor;
|
||||
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
|
||||
/**
|
||||
* 拦截器接口
|
||||
* <br>Create date 2021-05-06 09:20:37
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public interface Interceptor {
|
||||
|
||||
default Handler<RoutingContext> doHandle() {
|
||||
return this::handle;
|
||||
}
|
||||
|
||||
void handle(RoutingContext context);
|
||||
}
|
||||
160
core/src/main/java/cn/com/yhinfo/core/model/JsonResult.java
Normal file
160
core/src/main/java/cn/com/yhinfo/core/model/JsonResult.java
Normal file
@@ -0,0 +1,160 @@
|
||||
package cn.com.yhinfo.core.model;
|
||||
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 响应实体 用于和前端交互
|
||||
* <br>Create date 2021-05-06 09:20:37
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public class JsonResult<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final int SUCCESS_CODE = 200;
|
||||
|
||||
private static final int FAIL_CODE = 500;
|
||||
|
||||
private static final String SUCCESS_MESSAGE = "success";
|
||||
|
||||
private static final String FAIL_MESSAGE = "failed";
|
||||
|
||||
private int code = SUCCESS_CODE;//状态码
|
||||
|
||||
private String msg = SUCCESS_MESSAGE;//消息
|
||||
|
||||
private boolean success = true; //是否成功
|
||||
|
||||
private int count;
|
||||
|
||||
private T data;
|
||||
|
||||
private long timestamp = System.currentTimeMillis(); //时间戳
|
||||
|
||||
public JsonResult() {
|
||||
}
|
||||
|
||||
public JsonResult(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public JsonResult(int code, String msg, boolean success, T data) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
this.data = data;
|
||||
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() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public JsonResult<T> setCode(int code) {
|
||||
this.code = code;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public JsonResult<T> setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
return this;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public boolean getSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public JsonResult<T> setData(T data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
public JsonResult<T> setSuccess(boolean success) {
|
||||
this.success = success;
|
||||
return this;
|
||||
}
|
||||
|
||||
public JsonResult<T> setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
return this;
|
||||
}
|
||||
|
||||
// 响应失败消息
|
||||
public static <T> JsonResult<T> error() {
|
||||
return new JsonResult<>(FAIL_CODE, FAIL_MESSAGE, false, null);
|
||||
}
|
||||
|
||||
// 响应失败消息
|
||||
public static <T> JsonResult<T> error(String msg) {
|
||||
if (StringUtils.isEmpty(msg)) msg = FAIL_MESSAGE;
|
||||
return new JsonResult<>(FAIL_CODE, msg, false, null);
|
||||
}
|
||||
|
||||
// 响应失败消息和状态码
|
||||
public static <T> JsonResult<T> error(String msg, int code) {
|
||||
if (StringUtils.isEmpty(msg)) msg = FAIL_MESSAGE;
|
||||
return new JsonResult<>(code, msg, false, null);
|
||||
}
|
||||
|
||||
// 响应成功消息和数据实体
|
||||
public static <T> JsonResult<T> data(String msg, T data) {
|
||||
if (StringUtils.isEmpty(msg)) msg = SUCCESS_MESSAGE;
|
||||
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) {
|
||||
return new JsonResult<>(SUCCESS_CODE, SUCCESS_MESSAGE, true, data, 0);
|
||||
}
|
||||
|
||||
// 响应数据实体
|
||||
public static <T> JsonResult<T> data(T data, int count) {
|
||||
return new JsonResult<>(SUCCESS_CODE, SUCCESS_MESSAGE, true, data, count);
|
||||
}
|
||||
|
||||
// 响应成功消息
|
||||
public static <T> JsonResult<T> success(String msg) {
|
||||
if (StringUtils.isEmpty(msg)) msg = SUCCESS_MESSAGE;
|
||||
return new JsonResult<>(SUCCESS_CODE, msg, true, null);
|
||||
}
|
||||
|
||||
// 响应成功消息
|
||||
public static <T> JsonResult<T> success() {
|
||||
return new JsonResult<>(SUCCESS_CODE, SUCCESS_MESSAGE, true, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package cn.com.yhinfo.core.util;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.serviceproxy.ServiceProxyBuilder;
|
||||
|
||||
/**
|
||||
* @author Xu Haidong
|
||||
* @date 2018/8/15
|
||||
*/
|
||||
public final class AsyncServiceUtil {
|
||||
|
||||
public static <T> T getAsyncServiceInstance(Class<T> asClazz, Vertx vertx) {
|
||||
String address = asClazz.getName();
|
||||
return new ServiceProxyBuilder(vertx).setAddress(address).build(asClazz);
|
||||
}
|
||||
|
||||
public static <T> T getAsyncServiceInstance(Class<T> asClazz) {
|
||||
return getAsyncServiceInstance(asClazz, VertxHolder.getVertxInstance());
|
||||
}
|
||||
}
|
||||
18
core/src/main/java/cn/com/yhinfo/core/util/CastUtil.java
Normal file
18
core/src/main/java/cn/com/yhinfo/core/util/CastUtil.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package cn.com.yhinfo.core.util;
|
||||
|
||||
/**
|
||||
* 转换为任意类型 旨在消除泛型转换时的异常
|
||||
*/
|
||||
public interface CastUtil {
|
||||
|
||||
/**
|
||||
* 泛型转换
|
||||
* @param object 要转换的object
|
||||
* @param <T> T
|
||||
* @return T
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T> T cast(Object object) {
|
||||
return (T) object;
|
||||
}
|
||||
}
|
||||
129
core/src/main/java/cn/com/yhinfo/core/util/CommonUtil.java
Normal file
129
core/src/main/java/cn/com/yhinfo/core/util/CommonUtil.java
Normal file
@@ -0,0 +1,129 @@
|
||||
package cn.com.yhinfo.core.util;
|
||||
|
||||
import io.vertx.core.buffer.Buffer;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import org.apache.commons.beanutils.ConvertUtils;
|
||||
import org.apache.commons.beanutils.Converter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* CommonUtil
|
||||
* <br>Create date 2021/5/8 14:52
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public class CommonUtil {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CommonUtil.class);
|
||||
|
||||
/**
|
||||
* 匹配正则list
|
||||
*
|
||||
* @param regList 正则list
|
||||
* @param destStr 要匹配的目标字符
|
||||
* @return 匹配成功返回true 否则返回false
|
||||
*/
|
||||
public static boolean matchRegList(List<?> regList, String destStr) {
|
||||
// 判断是否忽略
|
||||
for (Object ignores : regList) {
|
||||
if (destStr.matches(ignores.toString())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 测试本机端口是否被使用
|
||||
*
|
||||
* @param port port
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isPortUsing(int port) {
|
||||
//如果该端口还在使用则返回true,否则返回false,127.0.0.1代表本机
|
||||
return isPortUsing("127.0.0.1", port);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试主机Host的port端口是否被使用
|
||||
*
|
||||
* @param host host
|
||||
* @param port port
|
||||
* @throws UnknownHostException
|
||||
*/
|
||||
public static boolean isPortUsing(String host, int port) {
|
||||
boolean flag = false;
|
||||
InetAddress Address;
|
||||
try {
|
||||
Address = InetAddress.getByName(host);
|
||||
} catch (UnknownHostException e) {
|
||||
return false;
|
||||
}
|
||||
try(Socket ignored = new Socket(Address, port)) {
|
||||
//建立一个Socket连接
|
||||
flag = true;
|
||||
} catch (IOException ignoredException) {}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体类匹配的json字段组成的json
|
||||
*
|
||||
* @param jsonObject 要解析的json
|
||||
* @param clazz 对应的实体类
|
||||
* @return 子json
|
||||
*/
|
||||
public static JsonObject getSubJsonForEntity(JsonObject jsonObject, Class<?> clazz) {
|
||||
JsonObject data = new JsonObject();
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
if (jsonObject.containsKey(field.getName())) {
|
||||
data.put(field.getName(), jsonObject.getValue(field.getName()));
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册枚举转换器
|
||||
*
|
||||
* @param enums 枚举类
|
||||
*/
|
||||
@SafeVarargs
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public static void enumConvert(Class<? extends Enum>... enums) {
|
||||
for (Class<? extends Enum> anEnum : enums) {
|
||||
ConvertUtils.register(new Converter() {
|
||||
public Object convert(Class type, Object value) {
|
||||
return Enum.valueOf(anEnum, (String) value);
|
||||
}
|
||||
}, anEnum);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理其他配置
|
||||
*
|
||||
* @param configName configName
|
||||
*/
|
||||
public static void initConfig(String configName, Class<?> tClass) {
|
||||
URL resource = tClass.getResource("/conf/" + configName);
|
||||
if (resource == null) throw new RuntimeException("路径不存在");
|
||||
Buffer buffer = VertxHolder.getVertxInstance().fileSystem().readFileBlocking(resource.getPath());
|
||||
JsonObject entries = new JsonObject(buffer);
|
||||
Map<String, Object> map = entries.getMap();
|
||||
LocalConstant.put(configName, map);
|
||||
LOGGER.info("读取配置{}成功", configName);
|
||||
}
|
||||
}
|
||||
60
core/src/main/java/cn/com/yhinfo/core/util/ConfigUtil.java
Normal file
60
core/src/main/java/cn/com/yhinfo/core/util/ConfigUtil.java
Normal file
@@ -0,0 +1,60 @@
|
||||
package cn.com.yhinfo.core.util;
|
||||
|
||||
import io.vertx.config.ConfigRetriever;
|
||||
import io.vertx.config.ConfigRetrieverOptions;
|
||||
import io.vertx.config.ConfigStoreOptions;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
|
||||
/**
|
||||
* 异步读取配置工具类
|
||||
* <br>Create date 2021/9/2 1:23
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public class ConfigUtil {
|
||||
|
||||
/**
|
||||
* 异步读取配置文件
|
||||
*
|
||||
* @param format 配置文件格式
|
||||
* @param path 路径
|
||||
* @param vertx vertx
|
||||
* @return JsonObject的Future
|
||||
*/
|
||||
public static Future<JsonObject> readConfig(String format, String path, Vertx vertx) {
|
||||
// 读取yml配置
|
||||
ConfigStoreOptions store = new ConfigStoreOptions()
|
||||
.setType("file")
|
||||
.setFormat(format)
|
||||
.setConfig(new JsonObject().put("path", path));
|
||||
|
||||
ConfigRetriever retriever = ConfigRetriever
|
||||
.create(vertx, new ConfigRetrieverOptions().addStore(store));
|
||||
|
||||
return retriever.getConfig();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 异步读取Yaml配置文件
|
||||
*
|
||||
* @param path 路径
|
||||
* @param vertx vertx
|
||||
* @return JsonObject的Future
|
||||
*/
|
||||
synchronized public static Future<JsonObject> readYamlConfig(String path, Vertx vertx) {
|
||||
return readConfig("yaml", path+".yml", vertx);
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步读取Yaml配置文件
|
||||
*
|
||||
* @param path 路径
|
||||
* @return JsonObject的Future
|
||||
*/
|
||||
synchronized public static Future<JsonObject> readYamlConfig(String path) {
|
||||
return readConfig("yaml", path+".yml", VertxHolder.getVertxInstance());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package cn.com.yhinfo.core.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* vertx 上下文外的本地容器 为不在vertx线程的方法传递数据
|
||||
* <br>Create date 2021-05-07 10:26:54
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public class LocalConstant {
|
||||
private static final Map<String, Object> LOCAL_CONST = new HashMap<>();
|
||||
|
||||
public static Map<String, Object> put(String k, Object v) {
|
||||
if (LOCAL_CONST.containsKey(k)) return LOCAL_CONST;
|
||||
LOCAL_CONST.put(k, v);
|
||||
return LOCAL_CONST;
|
||||
}
|
||||
|
||||
public static Object get(String k) {
|
||||
return LOCAL_CONST.get(k);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getWithCast(String k) {
|
||||
return (T) LOCAL_CONST.get(k);
|
||||
}
|
||||
|
||||
public static boolean containsKey(String k) {
|
||||
return LOCAL_CONST.containsKey(k);
|
||||
}
|
||||
|
||||
public static Map<?, ?> getMap(String k) {
|
||||
return (Map<?, ?>) LOCAL_CONST.get(k);
|
||||
}
|
||||
|
||||
public static String getString(String k) {
|
||||
return LOCAL_CONST.get(k).toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
45
core/src/main/java/cn/com/yhinfo/core/util/ParamUtil.java
Normal file
45
core/src/main/java/cn/com/yhinfo/core/util/ParamUtil.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package cn.com.yhinfo.core.util;
|
||||
|
||||
import io.vertx.core.MultiMap;
|
||||
import org.apache.commons.beanutils.BeanUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 参数 工具类
|
||||
* <br>Create date 2021-04-30 09:22:18
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public final class ParamUtil {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ParamUtil.class);
|
||||
|
||||
public static Map<String, String> multiMapToMap(MultiMap multiMap) {
|
||||
if (multiMap == null) return null;
|
||||
Map<String, String> map = new HashMap<>();
|
||||
for (Map.Entry<String, String> entry : multiMap.entries()) {
|
||||
map.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <T> T multiMapToEntity(MultiMap multiMap,Class<T> tClass) throws NoSuchMethodException {
|
||||
Map<String,String> map = multiMapToMap(multiMap);
|
||||
T obj = null;
|
||||
try {
|
||||
obj = tClass.getDeclaredConstructor().newInstance();
|
||||
BeanUtils.populate(obj,map);
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("实例化异常");
|
||||
} catch (InvocationTargetException e2) {
|
||||
e2.printStackTrace();
|
||||
LOGGER.error("map2bean转换异常");
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
270
core/src/main/java/cn/com/yhinfo/core/util/ReflectionUtil.java
Normal file
270
core/src/main/java/cn/com/yhinfo/core/util/ReflectionUtil.java
Normal file
@@ -0,0 +1,270 @@
|
||||
package cn.com.yhinfo.core.util;
|
||||
|
||||
import javassist.*;
|
||||
import javassist.bytecode.AccessFlag;
|
||||
import javassist.bytecode.CodeAttribute;
|
||||
import javassist.bytecode.LocalVariableAttribute;
|
||||
import javassist.bytecode.MethodInfo;
|
||||
import org.apache.commons.beanutils.ConversionException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.reflections.Reflections;
|
||||
import org.reflections.scanners.*;
|
||||
import org.reflections.util.ClasspathHelper;
|
||||
import org.reflections.util.ConfigurationBuilder;
|
||||
import org.reflections.util.FilterBuilder;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.text.ParseException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 基于org.reflection和javassist的反射工具包
|
||||
* 通过包扫描实现路由地址的注解映射
|
||||
* <br>Create date 2021-05-07 10:26:54
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public final class ReflectionUtil {
|
||||
|
||||
/**
|
||||
* 获取反射器
|
||||
*
|
||||
* @param packageAddress Package address String
|
||||
* @return Reflections object
|
||||
*/
|
||||
public static Reflections getReflections(String packageAddress) {
|
||||
List<String> packageAddressList;
|
||||
if (packageAddress.contains(",")) {
|
||||
packageAddressList = Arrays.asList(packageAddress.split(","));
|
||||
} else if (packageAddress.contains(";")) {
|
||||
packageAddressList = Arrays.asList(packageAddress.split(";"));
|
||||
} else {
|
||||
packageAddressList = Collections.singletonList(packageAddress);
|
||||
}
|
||||
return getReflections(packageAddressList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取反射器
|
||||
*
|
||||
* @param packageAddresses Package address List
|
||||
* @return Reflections object
|
||||
*/
|
||||
public static Reflections getReflections(List<String> packageAddresses) {
|
||||
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
|
||||
FilterBuilder filterBuilder = new FilterBuilder();
|
||||
packageAddresses.forEach(str -> {
|
||||
Collection<URL> urls = ClasspathHelper.forPackage(str.trim());
|
||||
configurationBuilder.addUrls(urls);
|
||||
filterBuilder.includePackage(str.trim());
|
||||
});
|
||||
|
||||
// 采坑记录 2021-05-08
|
||||
// 发现注解api层 没有继承父类时 这里反射一直有问题(Scanner SubTypesScanner was not configured)
|
||||
// 因此这里需要手动配置各种Scanner扫描器 -- https://blog.csdn.net/qq_29499107/article/details/106889781
|
||||
configurationBuilder.setScanners(
|
||||
new SubTypesScanner(false), //允许getAllTypes获取所有Object的子类, 不设置为false则 getAllTypes 会报错.默认为true.
|
||||
new MethodParameterNamesScanner(), //设置方法参数名称 扫描器,否则调用getConstructorParamNames 会报错
|
||||
new MethodAnnotationsScanner(), //设置方法注解 扫描器, 否则getConstructorsAnnotatedWith,getMethodsAnnotatedWith 会报错
|
||||
new MemberUsageScanner(), //设置 member 扫描器,否则 getMethodUsage 会报错, 不推荐使用,有可能会报错 Caused by: java.lang.ClassCastException: javassist.bytecode.InterfaceMethodrefInfo cannot be cast to javassist.bytecode.MethodrefInfo
|
||||
new TypeAnnotationsScanner() //设置类注解 扫描器 ,否则 getTypesAnnotatedWith 会报错
|
||||
);
|
||||
|
||||
configurationBuilder.filterInputsBy(filterBuilder);
|
||||
return new Reflections(configurationBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定类指定方法的参数名和类型列表(忽略重载方法)
|
||||
*
|
||||
* @param method 方法名(不考虑重载)
|
||||
* @return 参数名类型map
|
||||
* @apiNote ..
|
||||
*/
|
||||
public static Map<String, Pair<Annotation[], CtClass>> getMethodParameter(Method method) {
|
||||
Map<String, Pair<Annotation[], CtClass>> paramMap = new LinkedHashMap<>();
|
||||
try {
|
||||
ClassPool pool = ClassPool.getDefault();
|
||||
CtClass ctClass = pool.get(method.getDeclaringClass().getName());
|
||||
CtMethod cm = ctClass.getDeclaredMethod(method.getName());
|
||||
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
|
||||
MethodInfo methodInfo = cm.getMethodInfo();
|
||||
CtClass[] parameterTypes = cm.getParameterTypes();
|
||||
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
|
||||
LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
|
||||
|
||||
boolean flag = true;
|
||||
boolean flag2 = cm.getModifiers() - 1 != AccessFlag.STATIC;
|
||||
for (int j = 0, k = 0; j < parameterTypes.length + k; j++) {
|
||||
// 注意这里 只能从tableLength处获取 目前还没发现问题
|
||||
String name = attr.variableName(j);
|
||||
if (!"this".equals(name) && flag && flag2) {
|
||||
k++;
|
||||
continue;
|
||||
}
|
||||
flag = false;
|
||||
paramMap.put(attr.variableName(j + (flag2 ? 1 : 0)), Pair.of(parameterAnnotations[j - k], parameterTypes[j - k]));
|
||||
}
|
||||
} catch (NotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return paramMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型转换: 字符串转对应类型
|
||||
*
|
||||
* @param ctClass 目标类: javassist的ctClass类对象
|
||||
* @param value 字符串值
|
||||
* @param fmt 日期格式(如果value是日期的话这个字段将有用,否则置为null或空字符串)
|
||||
* @return 基本类型或目标对象
|
||||
*/
|
||||
public static Object conversion(CtClass ctClass, String value, String fmt) {
|
||||
if (StringUtils.isEmpty(value)) {
|
||||
return null;
|
||||
}
|
||||
if (StringUtils.isEmpty(fmt)) {
|
||||
fmt = "yyyy-MM-dd";
|
||||
}
|
||||
String name = ctClass.getName();
|
||||
if (ctClass.isArray()) {
|
||||
name = ctClass.getName().substring(0, ctClass.getName().length() - 2);
|
||||
}
|
||||
switch (name) {
|
||||
case "java.lang.Boolean":
|
||||
case "boolean":
|
||||
return Boolean.valueOf(value);
|
||||
case "java.lang.Character":
|
||||
case "char":
|
||||
return value.charAt(0);
|
||||
case "java.lang.Byte":
|
||||
case "byte":
|
||||
return Byte.valueOf(value);
|
||||
case "java.lang.Short":
|
||||
case "short":
|
||||
return Short.valueOf(value);
|
||||
case "java.lang.Integer":
|
||||
case "int":
|
||||
return Integer.valueOf(value);
|
||||
case "java.lang.Long":
|
||||
case "long":
|
||||
return Long.valueOf(value);
|
||||
case "java.lang.Float":
|
||||
case "float":
|
||||
return Float.valueOf(value);
|
||||
case "java.lang.Double":
|
||||
case "double":
|
||||
return Double.valueOf(value);
|
||||
case "java.lang.String":
|
||||
return value;
|
||||
case "java.util.Date":
|
||||
try {
|
||||
return DateUtils.parseDate(value, fmt);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
throw new ConversionException("无法将格式化日期");
|
||||
}
|
||||
default:
|
||||
throw new ConversionException("无法将String类型" + value + "转为[" + name + "]");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数组类型的转换
|
||||
*
|
||||
* @param ctClass 目标类: javassist的ctClass类对象
|
||||
* @param value 字符串表示的数组(逗号分隔符)
|
||||
* @return Array
|
||||
*/
|
||||
public static Object conversionArray(CtClass ctClass, String value) {
|
||||
if (!isBasicTypeArray(ctClass)) throw new ConversionException("无法解析数组");
|
||||
String[] strArr = value.split(",");
|
||||
List<Object> obj = new ArrayList<>();
|
||||
Arrays.stream(strArr).forEach(v -> obj.add(conversion(ctClass, v, null)));
|
||||
|
||||
try {
|
||||
// 暂时这么处理
|
||||
String name = "[" + ((CtPrimitiveType) ctClass.getComponentType()).getDescriptor();
|
||||
Class<?> cls = Class.forName(name).getComponentType();
|
||||
Object arr = Array.newInstance(cls, obj.size());//初始化对应类型的数组
|
||||
|
||||
for (int i = 0; i < obj.size(); i++) {
|
||||
Array.set(arr, i, obj.get(i));
|
||||
}
|
||||
return arr;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是基本类型 8种原始类型和包装类以及String类型 返回true
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static boolean isBasicType(CtClass ctClass) {
|
||||
if (ctClass.isPrimitive() || "java.util.Date".equals(ctClass.getName())) {
|
||||
return true;
|
||||
}
|
||||
return ctClass.getName().matches("^java\\.lang\\.((Boolean)|(Character)|(Byte)|(Short)|(Integer)|(Long)|(Float)|(Double)|(String))$");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是基本类型数组 8种原始数组类型和String数组 返回true
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static boolean isBasicTypeArray(CtClass ctClass) {
|
||||
if (!ctClass.isArray()) {
|
||||
return false;
|
||||
} else return (ctClass.getName().matches("^(boolen|char|byte|short|int|long|float|double|String)\\[]$"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 反射通过无参构造创建对象
|
||||
*
|
||||
* @param handler 类对象
|
||||
* @return 目标对象
|
||||
* @throws NoSuchMethodException NoSuchMethodException
|
||||
* @throws InvocationTargetException InvocationTargetException
|
||||
* @throws InstantiationException InstantiationException
|
||||
* @throws IllegalAccessException IllegalAccessException
|
||||
*/
|
||||
public static <T> T newWithNoParam(Class<T> handler) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
|
||||
return handler.getConstructor().newInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 反射调用有参方法
|
||||
*
|
||||
* @param method 方法类对象
|
||||
* @param instance 方法所在的对象实例
|
||||
* @param arguments 方法参数
|
||||
* @return 方法返回值
|
||||
* @throws Throwable Throwable
|
||||
*/
|
||||
public static Object invokeWithArguments(Method method, Object instance, Object... arguments) throws Throwable {
|
||||
return MethodHandles.lookup().unreflect(method).bindTo(instance).invokeWithArguments(arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* 反射调用无参方法
|
||||
*
|
||||
* @param method 方法类对象
|
||||
* @param instance 方法所在的对象实例
|
||||
* @return 方法返回值
|
||||
* @throws Throwable Throwable
|
||||
*/
|
||||
public static Object invoke(Method method, Object instance) throws Throwable {
|
||||
return MethodHandles.lookup().unreflect(method).bindTo(instance).invoke();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package cn.com.yhinfo.core.util;
|
||||
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.core.shareddata.LocalMap;
|
||||
import io.vertx.core.shareddata.SharedData;
|
||||
|
||||
/**
|
||||
* vertx 共享数据
|
||||
* <br>Create date 2021-05-07 10:26:54
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public class SharedDataUtil {
|
||||
|
||||
private static final SharedData sharedData = VertxHolder.getVertxInstance().sharedData();
|
||||
|
||||
public static SharedData shareData() {
|
||||
return sharedData;
|
||||
}
|
||||
|
||||
public static LocalMap<String, Object> getLocalMap(String key) {
|
||||
return shareData().getLocalMap(key);
|
||||
}
|
||||
|
||||
public static <T> LocalMap<String, T> getLocalMapWithCast(String key) {
|
||||
return sharedData.getLocalMap(key);
|
||||
}
|
||||
|
||||
public static JsonObject getJsonConfig(String key) {
|
||||
LocalMap<String, Object> localMap = getLocalMap("local");
|
||||
return (JsonObject) localMap.get(key);
|
||||
}
|
||||
|
||||
public static JsonObject getJsonObjectForCustomConfig(String key) {
|
||||
return getJsonConfig("customConfig").getJsonObject(key);
|
||||
}
|
||||
|
||||
public static String getJsonStringForCustomConfig(String key) {
|
||||
return getJsonConfig("customConfig").getString(key);
|
||||
}
|
||||
|
||||
public static JsonArray getJsonArrayForCustomConfig(String key) {
|
||||
return getJsonConfig("customConfig").getJsonArray(key);
|
||||
}
|
||||
|
||||
public static <T> T getValueForCustomConfig(String key) {
|
||||
return CastUtil.cast(getJsonConfig("customConfig").getValue(key));
|
||||
}
|
||||
|
||||
public static JsonObject getJsonObjectForServerConfig(String key) {
|
||||
return getJsonConfig("server").getJsonObject(key);
|
||||
}
|
||||
|
||||
public static JsonArray getJsonArrayForServerConfig(String key) {
|
||||
return getJsonConfig("server").getJsonArray(key);
|
||||
}
|
||||
|
||||
public static String getJsonStringForServerConfig(String key) {
|
||||
return getJsonConfig("server").getString(key);
|
||||
}
|
||||
|
||||
public static <T> T getValueForServerConfig(String key) {
|
||||
return CastUtil.cast(getJsonConfig("server").getValue(key));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
package cn.com.yhinfo.core.util;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
|
||||
/**
|
||||
* Twitter_Snowflake<br>
|
||||
* SnowFlake的结构如下(每部分用-分开):<br>
|
||||
* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br>
|
||||
* 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0<br>
|
||||
* 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截)
|
||||
* 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br>
|
||||
* 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId<br>
|
||||
* 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号<br>
|
||||
* 加起来刚好64位,为一个Long型。<br>
|
||||
* SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。
|
||||
*
|
||||
* <br>Create date 2021-04-30 09:22:18
|
||||
*
|
||||
* @author Twitter, <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public class SnowflakeIdWorker {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SnowflakeIdWorker.class);
|
||||
|
||||
// ==============================Fields===========================================
|
||||
|
||||
/**
|
||||
* 机器id所占的位数
|
||||
*/
|
||||
private final long workerIdBits = 5L;
|
||||
|
||||
/**
|
||||
* 数据标识id所占的位数
|
||||
*/
|
||||
private final long datacenterIdBits = 5L;
|
||||
|
||||
/**
|
||||
* 工作机器ID(0~31)
|
||||
*/
|
||||
private final long workerId;
|
||||
|
||||
/**
|
||||
* 数据中心ID(0~31)
|
||||
*/
|
||||
private final long datacenterId;
|
||||
|
||||
/**
|
||||
* 毫秒内序列(0~4095)
|
||||
*/
|
||||
private long sequence = 0L;
|
||||
|
||||
/**
|
||||
* 上次生成ID的时间截
|
||||
*/
|
||||
private long lastTimestamp = -1L;
|
||||
|
||||
//==============================Constructors=====================================
|
||||
public SnowflakeIdWorker() {
|
||||
this.datacenterId = getDatacenterId();
|
||||
this.workerId = getMaxWorkerId(datacenterId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param workerId 工作ID (0~31)
|
||||
* @param datacenterId 数据中心ID (0~31)
|
||||
*/
|
||||
public SnowflakeIdWorker(long workerId, long datacenterId) {
|
||||
// 支持的最大机器id,结果是31 (这个移位算法可以很快地计算出几位二进制数所能表示的最大十进制数)
|
||||
|
||||
long maxWorkerId = ~(-1L << workerIdBits);
|
||||
if (workerId > maxWorkerId || workerId < 0) {
|
||||
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
|
||||
}
|
||||
long maxDatacenterId = ~(-1L << datacenterIdBits);
|
||||
if (datacenterId > maxDatacenterId || datacenterId < 0) {
|
||||
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
|
||||
}
|
||||
this.workerId = workerId;
|
||||
this.datacenterId = datacenterId;
|
||||
}
|
||||
|
||||
// ==============================Methods==========================================
|
||||
|
||||
/**
|
||||
* 获得下一个ID (该方法是线程安全的)
|
||||
*
|
||||
* @return SnowflakeId
|
||||
*/
|
||||
public synchronized long nextId() {
|
||||
long timestamp = timeGen();
|
||||
|
||||
//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
|
||||
if (timestamp < lastTimestamp) {
|
||||
throw new RuntimeException(
|
||||
String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
|
||||
}
|
||||
|
||||
//如果是同一时间生成的,则进行毫秒内序列
|
||||
|
||||
//序列在id中占的位数
|
||||
long sequenceBits = 12L;
|
||||
if (lastTimestamp == timestamp) {
|
||||
//生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095)
|
||||
long sequenceMask = ~(-1L << sequenceBits);
|
||||
sequence = (sequence + 1) & sequenceMask;
|
||||
//毫秒内序列溢出
|
||||
if (sequence == 0) {
|
||||
//阻塞到下一个毫秒,获得新的时间戳
|
||||
timestamp = tilNextMillis(lastTimestamp);
|
||||
}
|
||||
}
|
||||
//时间戳改变,毫秒内序列重置
|
||||
else {
|
||||
sequence = 0L;
|
||||
}
|
||||
|
||||
//上次生成ID的时间截
|
||||
lastTimestamp = timestamp;
|
||||
|
||||
//移位并通过或运算拼到一起组成64位的ID
|
||||
//机器ID向左移12位
|
||||
//数据标识id向左移17位(12+5)
|
||||
long datacenterIdShift = sequenceBits + workerIdBits;
|
||||
|
||||
//时间截向左移22位(5+5+12)
|
||||
long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
|
||||
|
||||
//开始时间截 (2021-01-01)
|
||||
long twepoch = 1609459200000L;
|
||||
return ((timestamp - twepoch) << timestampLeftShift) //
|
||||
| (datacenterId << datacenterIdShift) //
|
||||
| (workerId << sequenceBits) //
|
||||
| sequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* 阻塞到下一个毫秒,直到获得新的时间戳
|
||||
*
|
||||
* @param lastTimestamp 上次生成ID的时间截
|
||||
* @return 当前时间戳
|
||||
*/
|
||||
protected long tilNextMillis(long lastTimestamp) {
|
||||
long timestamp = timeGen();
|
||||
while (timestamp <= lastTimestamp) {
|
||||
timestamp = timeGen();
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回以毫秒为单位的当前时间
|
||||
*
|
||||
* @return 当前时间(毫秒)
|
||||
*/
|
||||
protected long timeGen() {
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 获取 maxWorkerId
|
||||
* </p>
|
||||
*/
|
||||
protected static long getMaxWorkerId(long datacenterId) {
|
||||
StringBuilder mpid = new StringBuilder();
|
||||
mpid.append(datacenterId);
|
||||
String name = ManagementFactory.getRuntimeMXBean().getName();
|
||||
if (StringUtils.isNotEmpty(name)) {
|
||||
//GET jvmPid
|
||||
mpid.append(name.split("@")[0]);
|
||||
}
|
||||
//MAC + PID 的 hashcode 获取16个低位
|
||||
return (mpid.toString().hashCode() & 0xffff) % ((long) 31 + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 数据标识id部分
|
||||
* </p>
|
||||
*/
|
||||
protected static long getDatacenterId() {
|
||||
long id = 0L;
|
||||
try {
|
||||
InetAddress ip = InetAddress.getLocalHost();
|
||||
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
|
||||
if (network == null) {
|
||||
id = 1L;
|
||||
} else {
|
||||
byte[] mac = network.getHardwareAddress();
|
||||
if (null != mac) {
|
||||
id = ((0x000000FF & (long) mac[mac.length - 1]) | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
|
||||
id = id % ((long) 31 + 1);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn(" getDatacenterId: " + e.getMessage());
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
private static final SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker();
|
||||
private static volatile SnowflakeIdWorker snowflakeIdWorkerCluster = null;
|
||||
|
||||
|
||||
synchronized public static SnowflakeIdWorker idWorker() {
|
||||
return snowflakeIdWorker;
|
||||
}
|
||||
|
||||
synchronized public static SnowflakeIdWorker idWorkerCluster(long workerId, long datacenterId) {
|
||||
if (snowflakeIdWorkerCluster == null) {
|
||||
snowflakeIdWorkerCluster = new SnowflakeIdWorker(workerId, datacenterId);
|
||||
}
|
||||
return snowflakeIdWorkerCluster;
|
||||
}
|
||||
//==============================Test=============================================
|
||||
|
||||
/**
|
||||
* 测试
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
final SnowflakeIdWorker snowflakeIdWorkerCluster = idWorkerCluster(0, 1);
|
||||
final SnowflakeIdWorker idWorker = idWorker();
|
||||
for (int i = 0; i < 100; i++) {
|
||||
long id = idWorker.nextId();
|
||||
System.out.println(Long.toBinaryString(id));
|
||||
System.out.println(id);
|
||||
System.out.println("------------");
|
||||
id = snowflakeIdWorkerCluster.nextId();
|
||||
System.out.println(Long.toBinaryString(id));
|
||||
System.out.println(id);
|
||||
System.out.println("------------\n");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
110
core/src/main/java/cn/com/yhinfo/core/util/StringCase.java
Normal file
110
core/src/main/java/cn/com/yhinfo/core/util/StringCase.java
Normal file
@@ -0,0 +1,110 @@
|
||||
package cn.com.yhinfo.core.util;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
* 驼峰式下划线命名的字符串相互转换
|
||||
*
|
||||
* <br>Create date 2021/6/2 0:41
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public class StringCase {
|
||||
|
||||
/**
|
||||
* 将驼峰式命名的字符串转换为下划线方式。如果转换前的驼峰式命名的字符串为空,则返回空字符串。<br>
|
||||
* 例如:
|
||||
*
|
||||
* <pre>
|
||||
* HelloWorld=》hello_world
|
||||
* Hello_World=》hello_world
|
||||
* HelloWorld_test=》hello_world_test
|
||||
* </pre>
|
||||
*
|
||||
* @param str 转换前的驼峰式命名的字符串,也可以为下划线形式
|
||||
* @return 转换后下划线方式命名的字符串
|
||||
*/
|
||||
public static String toUnderlineCase(String str) {
|
||||
if (StringUtils.isEmpty(str)) return str;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String s : StringUtils.splitByCharacterTypeCamelCase(str)) {
|
||||
if (!s.startsWith("_")) {
|
||||
sb.append(s.toLowerCase()).append("_");
|
||||
} else {
|
||||
sb.append(s);
|
||||
}
|
||||
}
|
||||
return sb.substring(0, sb.length() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str 转换前的驼峰式命名的字符串,也可以为下划线形式
|
||||
* @return 转换后下划线方式命名的字符串(大写)
|
||||
*/
|
||||
public static String toUnderlineUpperCase(String str) {
|
||||
return toUnderlineCase(str).toUpperCase();
|
||||
}
|
||||
|
||||
public static String toCamelCase(String str, boolean isBigCamel) {
|
||||
if (StringUtils.isEmpty(str)) {
|
||||
return str;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String[] split = StringUtils.split(str, '_');
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
String s = split[i];
|
||||
char[] chars = s.toCharArray();
|
||||
if ((i == 0 && isBigCamel) || (i > 0 && chars[0] >= 'a')) {
|
||||
chars[0] -= ('a' - 'A');
|
||||
}
|
||||
sb.append(new String(chars));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将下划线方式命名的字符串转换为大驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。<br>
|
||||
* 例如:hello_world=》HelloWorld
|
||||
*
|
||||
* @param str 转换前的下划线大写方式命名的字符串
|
||||
* @return 转换后的驼峰式命名的字符串
|
||||
*/
|
||||
public static String toBigCamelCase(String str) {
|
||||
return toCamelCase(str, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将下划线方式命名的字符串转换为小驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。<br>
|
||||
* 例如:hello_world=》helloWorld
|
||||
*
|
||||
* @param str 转换前的下划线大写方式命名的字符串
|
||||
* @return 转换后的驼峰式命名的字符串
|
||||
*/
|
||||
public static String toLittleCamelCase(String str) {
|
||||
return toCamelCase(str, false);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 下划线->驼峰
|
||||
System.out.println(toLittleCamelCase("my_name_qaiu"));
|
||||
System.out.println(toLittleCamelCase(null));
|
||||
System.out.println(toLittleCamelCase(" "));
|
||||
System.out.println(toLittleCamelCase(""));
|
||||
// 大驼峰
|
||||
System.out.println(toBigCamelCase("my_name_qaiu"));
|
||||
System.out.println(toLittleCamelCase("____my_name_qaiu"));
|
||||
|
||||
// 驼峰 ->下划线
|
||||
System.out.println(toUnderlineCase("MyNameQaiu"));
|
||||
System.out.println(toUnderlineCase(null));
|
||||
System.out.println(toUnderlineCase(" "));
|
||||
System.out.println(toUnderlineCase(""));
|
||||
System.out.println(toUnderlineCase("__my_nameQaiu___"));
|
||||
// 大写下划线
|
||||
System.out.println(toUnderlineUpperCase("MyNameQaiu"));
|
||||
System.out.println(toUnderlineUpperCase("__my_nameQaiu___"));
|
||||
}
|
||||
|
||||
}
|
||||
26
core/src/main/java/cn/com/yhinfo/core/util/VertxHolder.java
Normal file
26
core/src/main/java/cn/com/yhinfo/core/util/VertxHolder.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package cn.com.yhinfo.core.util;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 保存vertx实例
|
||||
* <br>Create date 2021-04-30 09:22:18
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public final class VertxHolder {
|
||||
|
||||
private static volatile Vertx singletonVertx;
|
||||
|
||||
public static synchronized void init(Vertx vertx) {
|
||||
Objects.requireNonNull(vertx, "未初始化Vertx");
|
||||
singletonVertx = vertx;
|
||||
}
|
||||
|
||||
public static Vertx getVertxInstance() {
|
||||
Objects.requireNonNull(singletonVertx, "未初始化Vertx");
|
||||
return singletonVertx;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
package cn.com.yhinfo.core.verticle;
|
||||
|
||||
import cn.com.yhinfo.core.util.CastUtil;
|
||||
import cn.com.yhinfo.core.util.ConfigUtil;
|
||||
import cn.com.yhinfo.core.util.SharedDataUtil;
|
||||
import cn.com.yhinfo.core.util.VertxHolder;
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.http.HttpClient;
|
||||
import io.vertx.core.http.HttpServer;
|
||||
import io.vertx.core.http.WebSocket;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.Router;
|
||||
import io.vertx.ext.web.handler.StaticHandler;
|
||||
import io.vertx.ext.web.handler.sockjs.SockJSHandler;
|
||||
import io.vertx.ext.web.handler.sockjs.SockJSHandlerOptions;
|
||||
import io.vertx.ext.web.proxy.handler.ProxyHandler;
|
||||
import io.vertx.httpproxy.HttpProxy;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>反向代理服务</p>
|
||||
* <p>可以根据配置文件自动生成代理服务</p>
|
||||
* <p>可以配置多个服务, 配置文件见示例</p>
|
||||
* <br>Create date 2021/9/2 0:41
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public class ReverseProxyVerticle extends AbstractVerticle {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ReverseProxyVerticle.class);
|
||||
|
||||
private static final String PATH_PROXY_CONFIG = SharedDataUtil.getJsonConfig("globalConfig").getString("proxyConf");
|
||||
private static final Future<JsonObject> CONFIG = ConfigUtil.readYamlConfig(PATH_PROXY_CONFIG);
|
||||
private static final String DEFAULT_PATH_404 = "webroot/err/404.html";
|
||||
|
||||
private static String serverName = "Vert.x-proxy-server"; //Server name in Http response header
|
||||
|
||||
|
||||
@Override
|
||||
public void start(Promise<Void> startPromise) throws Exception {
|
||||
CONFIG.onSuccess(this::handleProxyConfList);
|
||||
startPromise.complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取主配置文件
|
||||
*
|
||||
* @param config proxy config
|
||||
*/
|
||||
private void handleProxyConfList(JsonObject config) {
|
||||
serverName = config.getString("server-name");
|
||||
JsonArray proxyConfList = config.getJsonArray("proxy");
|
||||
|
||||
proxyConfList.forEach(proxyConf -> {
|
||||
if (proxyConf instanceof JsonObject) {
|
||||
handleProxyConf((JsonObject) proxyConf);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理单个反向代理配置
|
||||
*
|
||||
* @param proxyConf 代理配置
|
||||
*/
|
||||
private void handleProxyConf(JsonObject proxyConf) {
|
||||
// 404 path
|
||||
if (proxyConf.containsKey("404")) {
|
||||
System.getProperty("user.dir");
|
||||
String path = proxyConf.getString("404");
|
||||
if (StringUtils.isEmpty(path)) {
|
||||
proxyConf.put("404", DEFAULT_PATH_404);
|
||||
} else {
|
||||
if (!path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
}
|
||||
if (!new File(System.getProperty("user.dir") + path).exists()) {
|
||||
proxyConf.put("404", DEFAULT_PATH_404);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
proxyConf.put("404", DEFAULT_PATH_404);
|
||||
}
|
||||
|
||||
final HttpClient httpClient = VertxHolder.getVertxInstance().createHttpClient();
|
||||
Router proxyRouter = Router.router(vertx);
|
||||
|
||||
// Add Server name header
|
||||
proxyRouter.route().handler(ctx -> {
|
||||
ctx.response().putHeader("Server", serverName);
|
||||
ctx.next();
|
||||
});
|
||||
|
||||
// http api proxy
|
||||
if (proxyConf.containsKey("location")) {
|
||||
handleLocation(proxyConf.getJsonArray("location"), httpClient, proxyRouter);
|
||||
}
|
||||
|
||||
// static server
|
||||
if (proxyConf.containsKey("static")) {
|
||||
handleStatic(proxyConf.getJsonObject("static"), proxyRouter);
|
||||
}
|
||||
|
||||
// static server
|
||||
if (proxyConf.containsKey("sock")) {
|
||||
handleSock(proxyConf.getJsonArray("sock"), httpClient, proxyRouter);
|
||||
}
|
||||
|
||||
// Send 404 page
|
||||
proxyRouter.errorHandler(404, ctx -> {
|
||||
ctx.response().sendFile(proxyConf.getString("404"));
|
||||
});
|
||||
|
||||
HttpServer server = vertx.createHttpServer();
|
||||
server.requestHandler(proxyRouter);
|
||||
|
||||
Integer port = proxyConf.getInteger("listen");
|
||||
LOGGER.info("proxy server start on {} port", port);
|
||||
server.listen(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理静态资源配置
|
||||
*
|
||||
* @param staticConf 静态资源配置
|
||||
* @param proxyRouter 代理路由
|
||||
*/
|
||||
private void handleStatic(JsonObject staticConf, Router proxyRouter) {
|
||||
String path = staticConf.getString("path");
|
||||
proxyRouter.route(path + "*").handler(ctx -> {
|
||||
if (staticConf.containsKey("add-headers")) {
|
||||
Map<String, String> headers = CastUtil.cast(staticConf.getJsonObject("add-headers").getMap());
|
||||
headers.forEach(ctx.response()::putHeader);
|
||||
}
|
||||
ctx.next();
|
||||
});
|
||||
|
||||
final StaticHandler staticHandler = StaticHandler.create();
|
||||
if (staticConf.containsKey("root")) {
|
||||
staticHandler.setWebRoot(staticConf.getString("root"));
|
||||
}
|
||||
if (staticConf.containsKey("directory-listing")) {
|
||||
staticHandler.setDirectoryListing(staticConf.getBoolean("directory-listing"));
|
||||
} else if (staticConf.containsKey("index")) {
|
||||
staticHandler.setIndexPage(staticConf.getString("index"));
|
||||
}
|
||||
proxyRouter.route(path + "*").handler(staticHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理Location配置 代理请求Location(和nginx类似?)
|
||||
*
|
||||
* @param locationsConf location配置
|
||||
* @param httpClient 客户端
|
||||
* @param proxyRouter 代理路由
|
||||
*/
|
||||
private void handleLocation(JsonArray locationsConf, HttpClient httpClient, Router proxyRouter) {
|
||||
|
||||
locationsConf.stream().map(e -> (JsonObject) e).forEach(location -> {
|
||||
// 代理规则
|
||||
String origin = location.getString("origin");
|
||||
String path = location.getString("path");
|
||||
try {
|
||||
URL url = new URL("https://" + origin);
|
||||
String host = url.getHost();
|
||||
int port = url.getPort();
|
||||
if (port == -1) {
|
||||
port = 80;
|
||||
}
|
||||
String originPath = url.getPath();
|
||||
LOGGER.debug("Conf(path, originPath, host, port) ----> {},{},{},{}", path, originPath, host, port);
|
||||
|
||||
// 注意这里不能origin多个代理地址, 一个实例只能代理一个origin
|
||||
final HttpProxy httpProxy = HttpProxy.reverseProxy(httpClient);
|
||||
httpProxy.origin(port, host);
|
||||
if (StringUtils.isEmpty(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 代理目标路径为空 就像nginx一样路径穿透 (相对路径)
|
||||
if (StringUtils.isEmpty(originPath) || path.equals(originPath)) {
|
||||
proxyRouter.route(path + "*").handler(ProxyHandler.create(httpProxy));
|
||||
} else {
|
||||
proxyRouter.route(originPath + "*").handler(ProxyHandler.create(httpProxy));
|
||||
proxyRouter.route(path + "*").handler(ctx -> {
|
||||
String realPath = ctx.request().path();
|
||||
if (realPath.startsWith(path)) {
|
||||
// vertx web proxy暂不支持rewrite, 所以这里进行手动替换, 请求地址中的请求path前缀替换为originPath
|
||||
String rePath = realPath.replaceAll("^" + path, originPath);
|
||||
ctx.reroute(rePath);
|
||||
} else {
|
||||
ctx.next();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理websocket
|
||||
*
|
||||
* @param confList sock配置
|
||||
* @param httpClient 客户端
|
||||
* @param proxyRouter 代理路由
|
||||
*/
|
||||
private void handleSock(JsonArray confList, HttpClient httpClient, Router proxyRouter) {
|
||||
// 代理规则
|
||||
confList.stream().map(e -> (JsonObject) e).forEach(conf -> {
|
||||
|
||||
String origin = conf.getString("origin");
|
||||
String path = conf.getString("path");
|
||||
LOGGER.info("websocket proxy: {}, {}",origin,path);
|
||||
|
||||
SockJSHandlerOptions options = new SockJSHandlerOptions()
|
||||
.setHeartbeatInterval(2000)
|
||||
.setRegisterWriteHandler(true);
|
||||
|
||||
SockJSHandler sockJSHandler = SockJSHandler.create(VertxHolder.getVertxInstance(), options);
|
||||
if (!path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
}
|
||||
|
||||
|
||||
Router route = sockJSHandler.socketHandler(sock -> {
|
||||
sock.handler(buffer -> {
|
||||
Future<WebSocket> webSocketFuture = httpClient.webSocket(8086,"127.0.0.1",sock.uri());
|
||||
webSocketFuture.onSuccess(s -> {
|
||||
System.out.println(buffer.toString());
|
||||
s.write(buffer).onSuccess(v -> {
|
||||
s.handler(w->{
|
||||
System.out.println("--------"+w.toString());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
sock.endHandler(v -> {
|
||||
|
||||
});
|
||||
sock.closeHandler(v -> {
|
||||
|
||||
});
|
||||
});
|
||||
proxyRouter.mountSubRouter("/real/serverApi/test", route);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package cn.com.yhinfo.core.verticle;
|
||||
|
||||
import cn.com.yhinfo.core.handlerfactory.RouterHandlerFactory;
|
||||
import cn.com.yhinfo.core.util.CommonUtil;
|
||||
import cn.com.yhinfo.core.util.SharedDataUtil;
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.http.HttpServer;
|
||||
import io.vertx.core.http.HttpServerOptions;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.stomp.StompServer;
|
||||
import io.vertx.ext.stomp.StompServerHandler;
|
||||
import io.vertx.ext.stomp.StompServerOptions;
|
||||
import io.vertx.ext.web.Router;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Http服务 注册路由
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public class RouterVerticle extends AbstractVerticle {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RouterVerticle.class);
|
||||
|
||||
private static final int port = SharedDataUtil.getValueForServerConfig("port");
|
||||
private static final Router router = new RouterHandlerFactory(
|
||||
SharedDataUtil.getJsonStringForCustomConfig("routerLocations"),
|
||||
SharedDataUtil.getJsonStringForServerConfig("contextPath")).createRouter();
|
||||
|
||||
private static final JsonObject globalConfig = SharedDataUtil.getJsonConfig("globalConfig");
|
||||
|
||||
private HttpServer server;
|
||||
|
||||
static {
|
||||
LOGGER.info("To start listening to port {} ......", port);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Promise<Void> startPromise) {
|
||||
// 端口是否占用
|
||||
if (CommonUtil.isPortUsing(port)) {
|
||||
throw new RuntimeException("Start fail: the '" + port + "' port is already in use...");
|
||||
}
|
||||
HttpServerOptions options;
|
||||
if (globalConfig.containsKey("http") && globalConfig.getValue("http") != null) {
|
||||
options = new HttpServerOptions(globalConfig.getJsonObject("http"));
|
||||
} else {
|
||||
options = new HttpServerOptions();
|
||||
}
|
||||
options.setPort(port);
|
||||
server = vertx.createHttpServer(options);
|
||||
|
||||
server.requestHandler(router).webSocketHandler(s->{}).listen()
|
||||
.onSuccess(s -> startPromise.complete())
|
||||
.onFailure(e -> startPromise.fail(e.getCause()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(Promise<Void> stopPromise) {
|
||||
if (server == null) {
|
||||
stopPromise.complete();
|
||||
return;
|
||||
}
|
||||
server.close(result -> {
|
||||
if (result.failed()) {
|
||||
stopPromise.fail(result.cause());
|
||||
} else {
|
||||
stopPromise.complete();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package cn.com.yhinfo.core.verticle;
|
||||
|
||||
import cn.com.yhinfo.core.annotaions.Service;
|
||||
import cn.com.yhinfo.core.base.BaseAsyncService;
|
||||
import cn.com.yhinfo.core.util.ReflectionUtil;
|
||||
import cn.com.yhinfo.core.util.SharedDataUtil;
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.serviceproxy.ServiceBinder;
|
||||
import org.reflections.Reflections;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 服务注册到EventBus
|
||||
* <br>Create date 2021-05-07 10:26:54
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public class ServiceVerticle extends AbstractVerticle {
|
||||
|
||||
Logger LOGGER = LoggerFactory.getLogger(ServiceVerticle.class);
|
||||
private static final AtomicInteger ID = new AtomicInteger(1);
|
||||
private static final Set<Class<?>> handlers;
|
||||
|
||||
static {
|
||||
String handlerLocations = SharedDataUtil.getJsonStringForCustomConfig("handlerLocations");
|
||||
Reflections reflections = ReflectionUtil.getReflections(handlerLocations);
|
||||
handlers = reflections.getTypesAnnotatedWith(Service.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Promise<Void> startPromise) {
|
||||
ServiceBinder binder = new ServiceBinder(vertx);
|
||||
if (null != handlers && handlers.size() > 0) {
|
||||
handlers.forEach(asyncService -> {
|
||||
try {
|
||||
BaseAsyncService asInstance = (BaseAsyncService) ReflectionUtil.newWithNoParam(asyncService);
|
||||
binder.setAddress(asInstance.getAddress()).register(asInstance.getAsyncInterfaceClass(), asInstance);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error(e.getMessage());
|
||||
}
|
||||
});
|
||||
LOGGER.info("registered async services -> id: {}", ID.getAndIncrement());
|
||||
}
|
||||
startPromise.complete();
|
||||
}
|
||||
}
|
||||
59
core/src/main/resources/logback.xml
Normal file
59
core/src/main/resources/logback.xml
Normal file
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<!-- 日志自定义颜色 -->
|
||||
<!-- https://logback.qos.ch/manual/layouts.html#coloring -->
|
||||
|
||||
<!--日志文件主目录:这里${user.home}为当前服务器用户主目录-->
|
||||
<property name="LOG_HOME" value="logs"/>
|
||||
<!--日志文件名称:这里spring.application.name表示工程名称-->
|
||||
|
||||
<property name="LOGBACK_DEFAULT" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/>
|
||||
<property name="CUSTOMER_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %magenta([%t]) %highlight(%-5p) %yellow(${PID:-}) %cyan(%-40.40logger{39}) : %green(%m%n)"/>
|
||||
<property name="CUSTOMER_PATTERN2" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) -> %magenta([%15.15thread]) %cyan(%-40.40logger{39}) : %msg%n"/>
|
||||
|
||||
<!--配置日志文件(File)-->
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!--设置策略-->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!--日志文件路径:这里%d{yyyyMMdd}表示按天分类日志-->
|
||||
<FileNamePattern>${LOG_HOME}/%d{yyyyMMdd}/run.log</FileNamePattern>
|
||||
<!--日志保留天数-->
|
||||
<MaxHistory>15</MaxHistory>
|
||||
</rollingPolicy>
|
||||
<!--设置格式-->
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
|
||||
<!-- 或者使用默认配置 -->
|
||||
<!--<pattern>${FILE_LOG_PATTERN}</pattern>-->
|
||||
<charset>utf8</charset>
|
||||
</encoder>
|
||||
<!--日志文件最大的大小-->
|
||||
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
|
||||
<MaxFileSize>100MB</MaxFileSize>
|
||||
</triggeringPolicy>
|
||||
</appender>
|
||||
|
||||
<!-- 将文件输出设置成异步输出 -->
|
||||
<appender name="ASYNC-FILE" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
|
||||
<queueSize>256</queueSize>
|
||||
<!-- 添加附加的appender,最多只能添加一个 -->
|
||||
<appender-ref ref="FILE"/>
|
||||
</appender>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
|
||||
<pattern>${CUSTOMER_PATTERN2}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<logger name="io.netty" level="warn"/>
|
||||
<logger name="io.vertx" level="info"/>
|
||||
<root level="debug">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
</configuration>
|
||||
0
logs/20230420/run.log
Normal file
0
logs/20230420/run.log
Normal file
120
pom.xml
Normal file
120
pom.xml
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>cn.qaiu</groupId>
|
||||
<artifactId>lz-cow-api</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>0.0.1</version>
|
||||
|
||||
<modules>
|
||||
<module>core</module>
|
||||
<module>web</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<vertx.version>4.1.3</vertx.version>
|
||||
<packageDirectory>${project.basedir}/web/target/package</packageDirectory>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.6.2</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- 跳过测试类-->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
<configuration>
|
||||
<skipTests>true</skipTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-static-web</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${project.basedir}/webroot</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<outputDirectory>${packageDirectory}/webroot</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-bin</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${project.basedir}/bin</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<outputDirectory>${packageDirectory}</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-db</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${project.basedir}/db</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<outputDirectory>${packageDirectory}/db</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<!--<skip>true</skip>-->
|
||||
<!--<failOnError>false</failOnError>-->
|
||||
<!--当配置true时,只清理filesets里的文件,构建目录中得文件不被清理.默认是flase.-->
|
||||
<excludeDefaultDirectories>false</excludeDefaultDirectories>
|
||||
<filesets>
|
||||
<fileset>
|
||||
<!--要清理的目录位置-->
|
||||
<directory>${project.basedir}/logs</directory>
|
||||
<!--是否跟随符号链接 (symbolic links)-->
|
||||
<followSymlinks>false</followSymlinks>
|
||||
</fileset>
|
||||
</filesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
</project>
|
||||
13
web/assembly.xml
Normal file
13
web/assembly.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<assembly>
|
||||
<id>bin</id>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
<fileSets>
|
||||
<!-- 从目标目录拷贝文件去压缩 -->
|
||||
<fileSet>
|
||||
<directory>target/package/</directory>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
0
web/logs/20230420/run.log
Normal file
0
web/logs/20230420/run.log
Normal file
198
web/pom.xml
Normal file
198
web/pom.xml
Normal file
@@ -0,0 +1,198 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>lz-cow-api</artifactId>
|
||||
<groupId>cn.qaiu</groupId>
|
||||
<version>0.0.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<version>0.0.1</version>
|
||||
<artifactId>web</artifactId>
|
||||
|
||||
<properties>
|
||||
<packageDirectory>${project.basedir}/target/package</packageDirectory>
|
||||
<java.version>17</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<slf4j.version>2.0.5</slf4j.version>
|
||||
<vertx-jooq.version>6.1.0</vertx-jooq.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.qaiu</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>1.0.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.26</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!--logback日志实现-->
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.4.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<directory>${project.basedir}/target/</directory>
|
||||
<outputDirectory>${project.build.directory}/classes</outputDirectory>
|
||||
<finalName>${project.artifactId}-${project.version}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
<!-- 代码生成器 -->
|
||||
<annotationProcessors>
|
||||
<annotationProcessor>lombok.launch.AnnotationProcessorHider$AnnotationProcessor</annotationProcessor>
|
||||
<annotationProcessor>io.vertx.codegen.CodeGenProcessor</annotationProcessor>
|
||||
</annotationProcessors>
|
||||
<generatedSourcesDirectory>
|
||||
${project.basedir}/src/main/generated
|
||||
</generatedSourcesDirectory>
|
||||
<compilerArgs>
|
||||
<arg>-AoutputDirectory=${project.basedir}/src/main -Xlint:unchecked</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!--打包jar-->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<configuration>
|
||||
<!--不打包资源文件-->
|
||||
<excludes>
|
||||
<exclude>*.**</exclude>
|
||||
<exclude>*/*.xml</exclude>
|
||||
<exclude>conf/**</exclude>
|
||||
</excludes>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addClasspath>true</addClasspath>
|
||||
<!--MANIFEST.MF 中 Class-Path 加入前缀-->
|
||||
<classpathPrefix>lib/</classpathPrefix>
|
||||
<!--jar包不包含唯一版本标识-->
|
||||
<useUniqueVersions>false</useUniqueVersions>
|
||||
<!--指定入口类-->
|
||||
<mainClass>cn.com.yhinfo.real.AppMain</mainClass>
|
||||
</manifest>
|
||||
<manifestEntries>
|
||||
<!--MANIFEST.MF 中 Class-Path 加入资源文件目录-->
|
||||
<Class-Path>./resources/</Class-Path>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
<outputDirectory>${packageDirectory}</outputDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!--拷贝依赖 copy-dependencies-->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.1.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-dependencies</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<!--打包时排除的依赖作用域-->
|
||||
<excludeScope>test</excludeScope>
|
||||
<excludeScope>provided</excludeScope>
|
||||
<outputDirectory>
|
||||
${packageDirectory}/lib/
|
||||
</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!--拷贝资源文件 copy-resources-->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-resources</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<outputDirectory>${packageDirectory}/resources</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<!--<skip>true</skip>-->
|
||||
<!--<failOnError>false</failOnError>-->
|
||||
<!--当配置true时,只清理filesets里的文件,构建目录中得文件不被清理.默认是flase.-->
|
||||
<excludeDefaultDirectories>false</excludeDefaultDirectories>
|
||||
<filesets>
|
||||
<fileset>
|
||||
<!--要清理的目录位置-->
|
||||
<directory>${basedir}/src/main/generated</directory>
|
||||
<!--是否跟随符号链接 (symbolic links)-->
|
||||
<followSymlinks>false</followSymlinks>
|
||||
</fileset>
|
||||
</filesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- 自定义打zip包 -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>assembly.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.com.yhinfo.real.common.model;
|
||||
|
||||
/**
|
||||
* Mapper for {@link MyData}.
|
||||
* NOTE: This class has been automatically generated from the {@link MyData} original class using Vert.x codegen.
|
||||
*/
|
||||
@io.vertx.codegen.annotations.VertxGen
|
||||
public interface MyDataParametersMapper extends io.vertx.sqlclient.templates.TupleMapper<MyData> {
|
||||
|
||||
MyDataParametersMapper INSTANCE = new MyDataParametersMapper() {};
|
||||
|
||||
default io.vertx.sqlclient.Tuple map(java.util.function.Function<Integer, String> mapping, int size, MyData params) {
|
||||
java.util.Map<String, Object> args = map(params);
|
||||
Object[] array = new Object[size];
|
||||
for (int i = 0;i < array.length;i++) {
|
||||
String column = mapping.apply(i);
|
||||
array[i] = args.get(column);
|
||||
}
|
||||
return io.vertx.sqlclient.Tuple.wrap(array);
|
||||
}
|
||||
|
||||
default java.util.Map<String, Object> map(MyData obj) {
|
||||
java.util.Map<String, Object> params = new java.util.HashMap<>();
|
||||
params.put("id", obj.getId());
|
||||
params.put("max_size", obj.getMaxSize());
|
||||
return params;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.com.yhinfo.real.common.model;
|
||||
|
||||
/**
|
||||
* Mapper for {@link MyData}.
|
||||
* NOTE: This class has been automatically generated from the {@link MyData} original class using Vert.x codegen.
|
||||
*/
|
||||
@io.vertx.codegen.annotations.VertxGen
|
||||
public interface MyDataRowMapper extends io.vertx.sqlclient.templates.RowMapper<MyData> {
|
||||
|
||||
@io.vertx.codegen.annotations.GenIgnore
|
||||
MyDataRowMapper INSTANCE = new MyDataRowMapper() { };
|
||||
|
||||
@io.vertx.codegen.annotations.GenIgnore
|
||||
java.util.stream.Collector<io.vertx.sqlclient.Row, ?, java.util.List<MyData>> COLLECTOR = java.util.stream.Collectors.mapping(INSTANCE::map, java.util.stream.Collectors.toList());
|
||||
|
||||
@io.vertx.codegen.annotations.GenIgnore
|
||||
default MyData map(io.vertx.sqlclient.Row row) {
|
||||
MyData obj = new MyData();
|
||||
Object val;
|
||||
int idx;
|
||||
if ((idx = row.getColumnIndex("id")) != -1 && (val = row.getString(idx)) != null) {
|
||||
obj.setId((java.lang.String)val);
|
||||
}
|
||||
if ((idx = row.getColumnIndex("max_size")) != -1 && (val = row.getString(idx)) != null) {
|
||||
obj.setMaxSize((java.lang.String)val);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package cn.com.yhinfo.real.common.model;
|
||||
|
||||
/**
|
||||
* Mapper for {@link UserInfo}.
|
||||
* NOTE: This class has been automatically generated from the {@link UserInfo} original class using Vert.x codegen.
|
||||
*/
|
||||
@io.vertx.codegen.annotations.VertxGen
|
||||
public interface UserInfoParametersMapper extends io.vertx.sqlclient.templates.TupleMapper<UserInfo> {
|
||||
|
||||
UserInfoParametersMapper INSTANCE = new UserInfoParametersMapper() {};
|
||||
|
||||
default io.vertx.sqlclient.Tuple map(java.util.function.Function<Integer, String> mapping, int size, UserInfo params) {
|
||||
java.util.Map<String, Object> args = map(params);
|
||||
Object[] array = new Object[size];
|
||||
for (int i = 0;i < array.length;i++) {
|
||||
String column = mapping.apply(i);
|
||||
array[i] = args.get(column);
|
||||
}
|
||||
return io.vertx.sqlclient.Tuple.wrap(array);
|
||||
}
|
||||
|
||||
default java.util.Map<String, Object> map(UserInfo obj) {
|
||||
java.util.Map<String, Object> params = new java.util.HashMap<>();
|
||||
params.put("permission", obj.getPermission());
|
||||
params.put("pwd_crc32", obj.getPwdCrc32());
|
||||
params.put("username", obj.getUsername());
|
||||
params.put("uuid", obj.getUuid());
|
||||
return params;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package cn.com.yhinfo.real.common.model;
|
||||
|
||||
/**
|
||||
* Mapper for {@link UserInfo}.
|
||||
* NOTE: This class has been automatically generated from the {@link UserInfo} original class using Vert.x codegen.
|
||||
*/
|
||||
@io.vertx.codegen.annotations.VertxGen
|
||||
public interface UserInfoRowMapper extends io.vertx.sqlclient.templates.RowMapper<UserInfo> {
|
||||
|
||||
@io.vertx.codegen.annotations.GenIgnore
|
||||
UserInfoRowMapper INSTANCE = new UserInfoRowMapper() { };
|
||||
|
||||
@io.vertx.codegen.annotations.GenIgnore
|
||||
java.util.stream.Collector<io.vertx.sqlclient.Row, ?, java.util.List<UserInfo>> COLLECTOR = java.util.stream.Collectors.mapping(INSTANCE::map, java.util.stream.Collectors.toList());
|
||||
|
||||
@io.vertx.codegen.annotations.GenIgnore
|
||||
default UserInfo map(io.vertx.sqlclient.Row row) {
|
||||
UserInfo obj = new UserInfo();
|
||||
Object val;
|
||||
int idx;
|
||||
if ((idx = row.getColumnIndex("permission")) != -1 && (val = row.getString(idx)) != null) {
|
||||
obj.setPermission((java.lang.String)val);
|
||||
}
|
||||
if ((idx = row.getColumnIndex("pwd_crc32")) != -1 && (val = row.getString(idx)) != null) {
|
||||
obj.setPwdCrc32((java.lang.String)val);
|
||||
}
|
||||
if ((idx = row.getColumnIndex("username")) != -1 && (val = row.getString(idx)) != null) {
|
||||
obj.setUsername((java.lang.String)val);
|
||||
}
|
||||
if ((idx = row.getColumnIndex("uuid")) != -1 && (val = row.getString(idx)) != null) {
|
||||
obj.setUuid((java.lang.String)val);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2014 Red Hat, Inc.
|
||||
*
|
||||
* Red Hat licenses this file to you under the Apache License, version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package cn.com.yhinfo.real.web.service;
|
||||
|
||||
import io.vertx.core.eventbus.DeliveryOptions;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.function.Function;
|
||||
import io.vertx.serviceproxy.ServiceException;
|
||||
import io.vertx.serviceproxy.ServiceExceptionMessageCodec;
|
||||
import io.vertx.serviceproxy.ProxyUtils;
|
||||
|
||||
import cn.com.yhinfo.real.common.model.UserInfo;
|
||||
import cn.com.yhinfo.core.base.BaseAsyncService;
|
||||
import io.vertx.core.Future;
|
||||
/*
|
||||
Generated Proxy code - DO NOT EDIT
|
||||
@author Roger the Robot
|
||||
*/
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class DbServiceVertxEBProxy implements DbService {
|
||||
private Vertx _vertx;
|
||||
private String _address;
|
||||
private DeliveryOptions _options;
|
||||
private boolean closed;
|
||||
|
||||
public DbServiceVertxEBProxy(Vertx vertx, String address) {
|
||||
this(vertx, address, null);
|
||||
}
|
||||
|
||||
public DbServiceVertxEBProxy(Vertx vertx, String address, DeliveryOptions options) {
|
||||
this._vertx = vertx;
|
||||
this._address = address;
|
||||
this._options = options;
|
||||
try {
|
||||
this._vertx.eventBus().registerDefaultCodec(ServiceException.class, new ServiceExceptionMessageCodec());
|
||||
} catch (IllegalStateException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<JsonObject> sayOk(String data){
|
||||
if (closed) return io.vertx.core.Future.failedFuture("Proxy is closed");
|
||||
JsonObject _json = new JsonObject();
|
||||
_json.put("data", data);
|
||||
|
||||
DeliveryOptions _deliveryOptions = (_options != null) ? new DeliveryOptions(_options) : new DeliveryOptions();
|
||||
_deliveryOptions.addHeader("action", "sayOk");
|
||||
return _vertx.eventBus().<JsonObject>request(_address, _json, _deliveryOptions).map(msg -> {
|
||||
return msg.body();
|
||||
});
|
||||
}
|
||||
@Override
|
||||
public Future<JsonObject> sayOk2(String data, UserInfo holder){
|
||||
if (closed) return io.vertx.core.Future.failedFuture("Proxy is closed");
|
||||
JsonObject _json = new JsonObject();
|
||||
_json.put("data", data);
|
||||
_json.put("holder", holder != null ? holder.toJson() : null);
|
||||
|
||||
DeliveryOptions _deliveryOptions = (_options != null) ? new DeliveryOptions(_options) : new DeliveryOptions();
|
||||
_deliveryOptions.addHeader("action", "sayOk2");
|
||||
return _vertx.eventBus().<JsonObject>request(_address, _json, _deliveryOptions).map(msg -> {
|
||||
return msg.body();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2014 Red Hat, Inc.
|
||||
*
|
||||
* Red Hat licenses this file to you under the Apache License, version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package cn.com.yhinfo.real.web.service;
|
||||
|
||||
import cn.com.yhinfo.real.web.service.DbService;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.core.AsyncResult;
|
||||
import io.vertx.core.eventbus.EventBus;
|
||||
import io.vertx.core.eventbus.Message;
|
||||
import io.vertx.core.eventbus.MessageConsumer;
|
||||
import io.vertx.core.eventbus.DeliveryOptions;
|
||||
import io.vertx.core.eventbus.ReplyException;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import java.util.Collection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import io.vertx.serviceproxy.ProxyHandler;
|
||||
import io.vertx.serviceproxy.ServiceException;
|
||||
import io.vertx.serviceproxy.ServiceExceptionMessageCodec;
|
||||
import io.vertx.serviceproxy.HelperUtils;
|
||||
import io.vertx.serviceproxy.ServiceBinder;
|
||||
|
||||
import cn.com.yhinfo.real.common.model.UserInfo;
|
||||
import cn.com.yhinfo.core.base.BaseAsyncService;
|
||||
import io.vertx.core.Future;
|
||||
/*
|
||||
Generated Proxy code - DO NOT EDIT
|
||||
@author Roger the Robot
|
||||
*/
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class DbServiceVertxProxyHandler extends ProxyHandler {
|
||||
|
||||
public static final long DEFAULT_CONNECTION_TIMEOUT = 5 * 60; // 5 minutes
|
||||
private final Vertx vertx;
|
||||
private final DbService service;
|
||||
private final long timerID;
|
||||
private long lastAccessed;
|
||||
private final long timeoutSeconds;
|
||||
private final boolean includeDebugInfo;
|
||||
|
||||
public DbServiceVertxProxyHandler(Vertx vertx, DbService service){
|
||||
this(vertx, service, DEFAULT_CONNECTION_TIMEOUT);
|
||||
}
|
||||
|
||||
public DbServiceVertxProxyHandler(Vertx vertx, DbService service, long timeoutInSecond){
|
||||
this(vertx, service, true, timeoutInSecond);
|
||||
}
|
||||
|
||||
public DbServiceVertxProxyHandler(Vertx vertx, DbService service, boolean topLevel, long timeoutInSecond){
|
||||
this(vertx, service, true, timeoutInSecond, false);
|
||||
}
|
||||
|
||||
public DbServiceVertxProxyHandler(Vertx vertx, DbService service, boolean topLevel, long timeoutSeconds, boolean includeDebugInfo) {
|
||||
this.vertx = vertx;
|
||||
this.service = service;
|
||||
this.includeDebugInfo = includeDebugInfo;
|
||||
this.timeoutSeconds = timeoutSeconds;
|
||||
try {
|
||||
this.vertx.eventBus().registerDefaultCodec(ServiceException.class,
|
||||
new ServiceExceptionMessageCodec());
|
||||
} catch (IllegalStateException ex) {}
|
||||
if (timeoutSeconds != -1 && !topLevel) {
|
||||
long period = timeoutSeconds * 1000 / 2;
|
||||
if (period > 10000) {
|
||||
period = 10000;
|
||||
}
|
||||
this.timerID = vertx.setPeriodic(period, this::checkTimedOut);
|
||||
} else {
|
||||
this.timerID = -1;
|
||||
}
|
||||
accessed();
|
||||
}
|
||||
|
||||
|
||||
private void checkTimedOut(long id) {
|
||||
long now = System.nanoTime();
|
||||
if (now - lastAccessed > timeoutSeconds * 1000000000) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (timerID != -1) {
|
||||
vertx.cancelTimer(timerID);
|
||||
}
|
||||
super.close();
|
||||
}
|
||||
|
||||
private void accessed() {
|
||||
this.lastAccessed = System.nanoTime();
|
||||
}
|
||||
|
||||
public void handle(Message<JsonObject> msg) {
|
||||
try{
|
||||
JsonObject json = msg.body();
|
||||
String action = msg.headers().get("action");
|
||||
if (action == null) throw new IllegalStateException("action not specified");
|
||||
accessed();
|
||||
switch (action) {
|
||||
case "sayOk": {
|
||||
service.sayOk((java.lang.String)json.getValue("data")).onComplete(HelperUtils.createHandler(msg, includeDebugInfo));
|
||||
break;
|
||||
}
|
||||
case "sayOk2": {
|
||||
service.sayOk2((java.lang.String)json.getValue("data"),
|
||||
json.getJsonObject("holder") != null ? new cn.com.yhinfo.real.common.model.UserInfo((JsonObject)json.getJsonObject("holder")) : null).onComplete(HelperUtils.createHandler(msg, includeDebugInfo));
|
||||
break;
|
||||
}
|
||||
default: throw new IllegalStateException("Invalid action: " + action);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
if (includeDebugInfo) msg.reply(new ServiceException(500, t.getMessage(), HelperUtils.generateDebugInfo(t)));
|
||||
else msg.reply(new ServiceException(500, t.getMessage()));
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2014 Red Hat, Inc.
|
||||
*
|
||||
* Red Hat licenses this file to you under the Apache License, version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package cn.com.yhinfo.real.web.service;
|
||||
|
||||
import io.vertx.core.eventbus.DeliveryOptions;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.function.Function;
|
||||
import io.vertx.serviceproxy.ServiceException;
|
||||
import io.vertx.serviceproxy.ServiceExceptionMessageCodec;
|
||||
import io.vertx.serviceproxy.ProxyUtils;
|
||||
|
||||
import cn.com.yhinfo.core.base.BaseAsyncService;
|
||||
import cn.com.yhinfo.real.web.model.RealUser;
|
||||
import io.vertx.core.Future;
|
||||
/*
|
||||
Generated Proxy code - DO NOT EDIT
|
||||
@author Roger the Robot
|
||||
*/
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class UserServiceVertxEBProxy implements UserService {
|
||||
private Vertx _vertx;
|
||||
private String _address;
|
||||
private DeliveryOptions _options;
|
||||
private boolean closed;
|
||||
|
||||
public UserServiceVertxEBProxy(Vertx vertx, String address) {
|
||||
this(vertx, address, null);
|
||||
}
|
||||
|
||||
public UserServiceVertxEBProxy(Vertx vertx, String address, DeliveryOptions options) {
|
||||
this._vertx = vertx;
|
||||
this._address = address;
|
||||
this._options = options;
|
||||
try {
|
||||
this._vertx.eventBus().registerDefaultCodec(ServiceException.class, new ServiceExceptionMessageCodec());
|
||||
} catch (IllegalStateException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<String> login(RealUser user){
|
||||
if (closed) return io.vertx.core.Future.failedFuture("Proxy is closed");
|
||||
JsonObject _json = new JsonObject();
|
||||
_json.put("user", user != null ? user.toJson() : null);
|
||||
|
||||
DeliveryOptions _deliveryOptions = (_options != null) ? new DeliveryOptions(_options) : new DeliveryOptions();
|
||||
_deliveryOptions.addHeader("action", "login");
|
||||
return _vertx.eventBus().<String>request(_address, _json, _deliveryOptions).map(msg -> {
|
||||
return msg.body();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2014 Red Hat, Inc.
|
||||
*
|
||||
* Red Hat licenses this file to you under the Apache License, version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package cn.com.yhinfo.real.web.service;
|
||||
|
||||
import cn.com.yhinfo.real.web.service.UserService;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.core.AsyncResult;
|
||||
import io.vertx.core.eventbus.EventBus;
|
||||
import io.vertx.core.eventbus.Message;
|
||||
import io.vertx.core.eventbus.MessageConsumer;
|
||||
import io.vertx.core.eventbus.DeliveryOptions;
|
||||
import io.vertx.core.eventbus.ReplyException;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import java.util.Collection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import io.vertx.serviceproxy.ProxyHandler;
|
||||
import io.vertx.serviceproxy.ServiceException;
|
||||
import io.vertx.serviceproxy.ServiceExceptionMessageCodec;
|
||||
import io.vertx.serviceproxy.HelperUtils;
|
||||
import io.vertx.serviceproxy.ServiceBinder;
|
||||
|
||||
import cn.com.yhinfo.core.base.BaseAsyncService;
|
||||
import cn.com.yhinfo.real.web.model.RealUser;
|
||||
import io.vertx.core.Future;
|
||||
/*
|
||||
Generated Proxy code - DO NOT EDIT
|
||||
@author Roger the Robot
|
||||
*/
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class UserServiceVertxProxyHandler extends ProxyHandler {
|
||||
|
||||
public static final long DEFAULT_CONNECTION_TIMEOUT = 5 * 60; // 5 minutes
|
||||
private final Vertx vertx;
|
||||
private final UserService service;
|
||||
private final long timerID;
|
||||
private long lastAccessed;
|
||||
private final long timeoutSeconds;
|
||||
private final boolean includeDebugInfo;
|
||||
|
||||
public UserServiceVertxProxyHandler(Vertx vertx, UserService service){
|
||||
this(vertx, service, DEFAULT_CONNECTION_TIMEOUT);
|
||||
}
|
||||
|
||||
public UserServiceVertxProxyHandler(Vertx vertx, UserService service, long timeoutInSecond){
|
||||
this(vertx, service, true, timeoutInSecond);
|
||||
}
|
||||
|
||||
public UserServiceVertxProxyHandler(Vertx vertx, UserService service, boolean topLevel, long timeoutInSecond){
|
||||
this(vertx, service, true, timeoutInSecond, false);
|
||||
}
|
||||
|
||||
public UserServiceVertxProxyHandler(Vertx vertx, UserService service, boolean topLevel, long timeoutSeconds, boolean includeDebugInfo) {
|
||||
this.vertx = vertx;
|
||||
this.service = service;
|
||||
this.includeDebugInfo = includeDebugInfo;
|
||||
this.timeoutSeconds = timeoutSeconds;
|
||||
try {
|
||||
this.vertx.eventBus().registerDefaultCodec(ServiceException.class,
|
||||
new ServiceExceptionMessageCodec());
|
||||
} catch (IllegalStateException ex) {}
|
||||
if (timeoutSeconds != -1 && !topLevel) {
|
||||
long period = timeoutSeconds * 1000 / 2;
|
||||
if (period > 10000) {
|
||||
period = 10000;
|
||||
}
|
||||
this.timerID = vertx.setPeriodic(period, this::checkTimedOut);
|
||||
} else {
|
||||
this.timerID = -1;
|
||||
}
|
||||
accessed();
|
||||
}
|
||||
|
||||
|
||||
private void checkTimedOut(long id) {
|
||||
long now = System.nanoTime();
|
||||
if (now - lastAccessed > timeoutSeconds * 1000000000) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (timerID != -1) {
|
||||
vertx.cancelTimer(timerID);
|
||||
}
|
||||
super.close();
|
||||
}
|
||||
|
||||
private void accessed() {
|
||||
this.lastAccessed = System.nanoTime();
|
||||
}
|
||||
|
||||
public void handle(Message<JsonObject> msg) {
|
||||
try{
|
||||
JsonObject json = msg.body();
|
||||
String action = msg.headers().get("action");
|
||||
if (action == null) throw new IllegalStateException("action not specified");
|
||||
accessed();
|
||||
switch (action) {
|
||||
case "login": {
|
||||
service.login(json.getJsonObject("user") != null ? new cn.com.yhinfo.real.web.model.RealUser((JsonObject)json.getJsonObject("user")) : null).onComplete(HelperUtils.createHandler(msg, includeDebugInfo));
|
||||
break;
|
||||
}
|
||||
default: throw new IllegalStateException("Invalid action: " + action);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
if (includeDebugInfo) msg.reply(new ServiceException(500, t.getMessage(), HelperUtils.generateDebugInfo(t)));
|
||||
else msg.reply(new ServiceException(500, t.getMessage()));
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
}
|
||||
29
web/src/main/java/cn/com/yhinfo/real/AppMain.java
Normal file
29
web/src/main/java/cn/com/yhinfo/real/AppMain.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package cn.com.yhinfo.real;
|
||||
|
||||
import cn.com.yhinfo.core.Deploy;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
|
||||
|
||||
/**
|
||||
* 程序入口
|
||||
* <br>Create date 2021-05-08 13:00:01
|
||||
*
|
||||
* @author qiu
|
||||
*/
|
||||
public class AppMain {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 注册枚举类型转换器
|
||||
Deploy.instance().start(args, AppMain::exec);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param jsonObject 配置
|
||||
*/
|
||||
private static void exec(JsonObject jsonObject) {
|
||||
//
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
22
web/src/main/java/cn/com/yhinfo/real/common/ToJson.java
Normal file
22
web/src/main/java/cn/com/yhinfo/real/common/ToJson.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package cn.com.yhinfo.real.common;
|
||||
|
||||
import io.vertx.core.json.JsonObject;
|
||||
|
||||
/**
|
||||
* sinoreal2-web <br>
|
||||
* 实现此接口 POJO转JSON对象
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
* <br>Create date 2021/8/27 11:40
|
||||
*/
|
||||
public interface ToJson {
|
||||
|
||||
/**
|
||||
* POJO转JSON对象
|
||||
*
|
||||
* @return Json Object
|
||||
*/
|
||||
default JsonObject toJson() {
|
||||
return JsonObject.mapFrom(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package cn.com.yhinfo.real.common.interceptorImpl;
|
||||
|
||||
import cn.com.yhinfo.core.base.BaseHttpApi;
|
||||
import cn.com.yhinfo.core.interceptor.Interceptor;
|
||||
import cn.com.yhinfo.core.model.JsonResult;
|
||||
import cn.com.yhinfo.core.util.CommonUtil;
|
||||
import cn.com.yhinfo.core.util.SharedDataUtil;
|
||||
import cn.com.yhinfo.core.util.VertxHolder;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.core.shareddata.LocalMap;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import lombok.val;
|
||||
|
||||
/**
|
||||
* 默认拦截器实现
|
||||
* 校验用户是否合法 <br>
|
||||
* TODO 暂时只做简单实现
|
||||
*/
|
||||
@Slf4j
|
||||
public class DefaultInterceptor implements Interceptor, BaseHttpApi {
|
||||
|
||||
private final JsonArray ignores = SharedDataUtil.getJsonArrayForCustomConfig("ignoresReg");
|
||||
|
||||
@Override
|
||||
public void handle(RoutingContext ctx) {
|
||||
|
||||
// 判断是否忽略
|
||||
if (CommonUtil.matchRegList(ignores.getList(), ctx.request().path())) {
|
||||
ctx.next();
|
||||
return;
|
||||
}
|
||||
// 执行拦截
|
||||
val token = ctx.request().getHeader("token");
|
||||
|
||||
|
||||
LocalMap<String, String> tokenMap = SharedDataUtil.getLocalMapWithCast("token");
|
||||
if (token != null && tokenMap != null && tokenMap.containsKey(token)) {
|
||||
VertxHolder.getVertxInstance().getOrCreateContext().put("username", tokenMap.get(token));
|
||||
ctx.next();
|
||||
} else {
|
||||
fireJsonResponse(ctx, JsonResult.error("没有权限", 401));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package cn.com.yhinfo.real.common.model;
|
||||
|
||||
import io.vertx.codegen.annotations.DataObject;
|
||||
import io.vertx.codegen.format.SnakeCase;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.sqlclient.templates.annotations.ParametersMapped;
|
||||
import io.vertx.sqlclient.templates.annotations.RowMapped;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
* <br>Create date 2021/7/22 3:34
|
||||
*/
|
||||
@DataObject
|
||||
@RowMapped(formatter = SnakeCase.class)
|
||||
@ParametersMapped(formatter = SnakeCase.class)
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class MyData implements Serializable {
|
||||
public static final long serialVersionUID = 1L;
|
||||
|
||||
private String id;
|
||||
|
||||
private String maxSize;
|
||||
|
||||
|
||||
public MyData(JsonObject jsonObject) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package cn.com.yhinfo.real.common.model;
|
||||
|
||||
import cn.com.yhinfo.real.common.ToJson;
|
||||
import io.vertx.codegen.annotations.DataObject;
|
||||
import io.vertx.codegen.format.SnakeCase;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.sqlclient.templates.annotations.ParametersMapped;
|
||||
import io.vertx.sqlclient.templates.annotations.RowMapped;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* sinoreal2-web
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
* <br>Create date 2021/8/10 11:10
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@DataObject
|
||||
@RowMapped(formatter = SnakeCase.class)
|
||||
@ParametersMapped(formatter = SnakeCase.class)
|
||||
public class UserInfo implements ToJson {
|
||||
|
||||
private String username;
|
||||
|
||||
private String permission;
|
||||
|
||||
private String pwdCrc32;
|
||||
|
||||
private String uuid;
|
||||
|
||||
public UserInfo(JsonObject jsonObject) {
|
||||
this.username = jsonObject.getString("username");
|
||||
this.permission = jsonObject.getString("permission");
|
||||
this.pwdCrc32 = jsonObject.getString("pwdCrc32");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package cn.com.yhinfo.real.common.util;
|
||||
|
||||
public class ArrayUtil {
|
||||
|
||||
public static int[] parseIntArray(String[] arr) {
|
||||
int[] ints = new int[arr.length];
|
||||
for (int i = 0; i < ints.length; i++) {
|
||||
ints[i] = Integer.parseInt(arr[i]);
|
||||
}
|
||||
return ints;
|
||||
}
|
||||
|
||||
public static float[] parseFloatArray(String[] arr) {
|
||||
float[] ints = new float[arr.length];
|
||||
for (int i = 0; i < ints.length; i++) {
|
||||
ints[i] = Float.parseFloat(arr[i]);
|
||||
}
|
||||
return ints;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package cn.com.yhinfo.real.common.util;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 获取连接
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public enum ConnectUtil {
|
||||
|
||||
// 实现枚举单例
|
||||
INSTANCE;
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConnectUtil.class);
|
||||
|
||||
|
||||
}
|
||||
10
web/src/main/java/cn/com/yhinfo/real/package-info.java
Normal file
10
web/src/main/java/cn/com/yhinfo/real/package-info.java
Normal file
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* sinoreal2-web
|
||||
* <br>Create date 2021/7/8 13:29
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
@ModuleGen(name = "proxy", groupPackage = "cn.com.yhinfo.real", useFutures = true)
|
||||
package cn.com.yhinfo.real;
|
||||
|
||||
import io.vertx.codegen.annotations.ModuleGen;
|
||||
76
web/src/main/java/cn/com/yhinfo/real/web/http/ServerApi.java
Normal file
76
web/src/main/java/cn/com/yhinfo/real/web/http/ServerApi.java
Normal file
@@ -0,0 +1,76 @@
|
||||
package cn.com.yhinfo.real.web.http;
|
||||
|
||||
import cn.com.yhinfo.core.annotaions.RouteHandler;
|
||||
import cn.com.yhinfo.core.annotaions.RouteMapping;
|
||||
import cn.com.yhinfo.core.annotaions.SockRouteMapper;
|
||||
import cn.com.yhinfo.core.enums.RouteMethod;
|
||||
import cn.com.yhinfo.core.model.JsonResult;
|
||||
import cn.com.yhinfo.core.util.AsyncServiceUtil;
|
||||
import cn.com.yhinfo.core.util.SnowflakeIdWorker;
|
||||
import cn.com.yhinfo.core.util.VertxHolder;
|
||||
import cn.com.yhinfo.real.web.model.RealUser;
|
||||
import cn.com.yhinfo.real.web.service.UserService;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.ext.web.handler.sockjs.SockJSSocket;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 连接服务API
|
||||
* <br>Create date 2021/4/28 9:15
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
@Slf4j
|
||||
@RouteHandler("serverApi")
|
||||
public class ServerApi {
|
||||
|
||||
private final UserService userService = AsyncServiceUtil.getAsyncServiceInstance(UserService.class);
|
||||
|
||||
@RouteMapping(value = "/login", method = RouteMethod.POST)
|
||||
public Future<String> login(RealUser user) {
|
||||
log.info("<------- login: {}", user.getUsername());
|
||||
return userService.login(user);
|
||||
}
|
||||
|
||||
long sid = 0;
|
||||
|
||||
@SockRouteMapper(value = "/test")
|
||||
public void test02(SockJSSocket sock) {
|
||||
String s = sock.writeHandlerID();
|
||||
System.out.println("客户端连接 --> " + s);
|
||||
sock.handler(sock::write);
|
||||
sock.endHandler(v -> System.out.println("客户端断开"));
|
||||
String id = sock.writeHandlerID();
|
||||
System.out.println("客户端连接 --> " + id);
|
||||
// sock.handler(sock::write);
|
||||
sock.handler(buffer -> {
|
||||
sock.write("服务端开始处理------->");
|
||||
final String msg = buffer.toString();
|
||||
if ("1".equals(msg)) {
|
||||
sid = VertxHolder.getVertxInstance().setPeriodic(1000, v ->
|
||||
sock.write(v + "-->" + SnowflakeIdWorker.idWorker().nextId()));
|
||||
} else {
|
||||
if (sid != 0) {
|
||||
if (VertxHolder.getVertxInstance().cancelTimer(sid)) {
|
||||
sock.write(sid + " -----> 定时推送取消");
|
||||
}
|
||||
} else {
|
||||
|
||||
sock.write(msg + "----- ok");
|
||||
}
|
||||
}
|
||||
});
|
||||
sock.endHandler(v -> {
|
||||
System.out.println("客户端断开");
|
||||
if (VertxHolder.getVertxInstance().cancelTimer(sid)) {
|
||||
sock.write(sid + " -----> 定时推送取消");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@RouteMapping(value = "/test2", method = RouteMethod.GET)
|
||||
public JsonResult<String> test01() {
|
||||
return JsonResult.data("ok");
|
||||
}
|
||||
|
||||
}
|
||||
22
web/src/main/java/cn/com/yhinfo/real/web/model/RealUser.java
Normal file
22
web/src/main/java/cn/com/yhinfo/real/web/model/RealUser.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package cn.com.yhinfo.real.web.model;
|
||||
|
||||
import cn.com.yhinfo.real.common.ToJson;
|
||||
import io.vertx.codegen.annotations.DataObject;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@DataObject
|
||||
public class RealUser implements ToJson {
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
public RealUser(JsonObject json) {
|
||||
this.username = json.getString("username");
|
||||
this.password = json.getString("password");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package cn.com.yhinfo.real.web.service;
|
||||
|
||||
import cn.com.yhinfo.core.base.BaseAsyncService;
|
||||
import cn.com.yhinfo.real.common.model.UserInfo;
|
||||
import io.vertx.codegen.annotations.ProxyGen;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
|
||||
/**
|
||||
* sinoreal2-web
|
||||
* <br>Create date 2021/7/12 17:16
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
@ProxyGen
|
||||
public interface DbService extends BaseAsyncService {
|
||||
Future<JsonObject> sayOk(String data);
|
||||
Future<JsonObject> sayOk2(String data, UserInfo holder);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package cn.com.yhinfo.real.web.service;
|
||||
|
||||
import cn.com.yhinfo.core.util.CastUtil;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
/**
|
||||
* JDK代理类工厂
|
||||
*/
|
||||
public class JdkProxyFactory {
|
||||
public static <T> T getProxy(T target) {
|
||||
return CastUtil.cast(Proxy.newProxyInstance(
|
||||
target.getClass().getClassLoader(),
|
||||
target.getClass().getInterfaces(),
|
||||
new ServiceJdkProxy<>(target))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.com.yhinfo.real.web.service;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* sinoreal2-web
|
||||
* <br>Create date 2021/8/25 14:28
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
@Slf4j
|
||||
public class ServiceJdkProxy<T> implements InvocationHandler {
|
||||
|
||||
private final T target;
|
||||
|
||||
public ServiceJdkProxy(T target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
|
||||
return method.invoke(target, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package cn.com.yhinfo.real.web.service;
|
||||
|
||||
import cn.com.yhinfo.core.base.BaseAsyncService;
|
||||
import cn.com.yhinfo.real.web.model.RealUser;
|
||||
import io.vertx.codegen.annotations.ProxyGen;
|
||||
import io.vertx.core.Future;
|
||||
|
||||
/**
|
||||
* sinoreal2-web
|
||||
* <br>Create date 2021/8/27 14:06
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
@ProxyGen
|
||||
public interface UserService extends BaseAsyncService {
|
||||
Future<String> login(RealUser user);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package cn.com.yhinfo.real.web.service.impl;
|
||||
|
||||
import cn.com.yhinfo.core.annotaions.Service;
|
||||
import cn.com.yhinfo.core.model.JsonResult;
|
||||
import cn.com.yhinfo.real.common.model.UserInfo;
|
||||
import cn.com.yhinfo.real.web.service.DbService;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* sinoreal2-web
|
||||
* <br>Create date 2021/7/12 17:26
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DbServiceImpl implements DbService {
|
||||
@Override
|
||||
public Future<JsonObject> sayOk(String data) {
|
||||
log.info("say ok1 -> wait...");
|
||||
try {
|
||||
Thread.sleep(4000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Future.succeededFuture(JsonObject.mapFrom(JsonResult.data("Hi: " + data)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<JsonObject> sayOk2(String data, UserInfo holder) {
|
||||
// val context = VertxHolder.getVertxInstance().getOrCreateContext();
|
||||
// log.info("say ok2 -> " + context.get("username"));
|
||||
// log.info("--> {}", holder.toString());
|
||||
return Future.succeededFuture(JsonObject.mapFrom(JsonResult.data("Hi: " + data)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.com.yhinfo.real.web.service.impl;
|
||||
|
||||
import cn.com.yhinfo.core.annotaions.Service;
|
||||
import cn.com.yhinfo.real.web.model.RealUser;
|
||||
import cn.com.yhinfo.real.web.service.UserService;
|
||||
import io.vertx.core.Future;
|
||||
|
||||
/**
|
||||
* sinoreal2-web
|
||||
* <br>Create date 2021/8/27 14:09
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
@Service
|
||||
public class UserServiceImpl implements UserService {
|
||||
|
||||
@Override
|
||||
public Future<String> login(RealUser user) {
|
||||
|
||||
return Future.succeededFuture("111");
|
||||
}
|
||||
}
|
||||
163
web/src/main/resources/1.http
Normal file
163
web/src/main/resources/1.http
Normal file
@@ -0,0 +1,163 @@
|
||||
|
||||
###
|
||||
POST http://127.0.0.1:8088/real/serverApi/login
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
username=sa&password=sinoreal
|
||||
|
||||
###
|
||||
POST http://47.114.185.111:8088/real/serverApi/login
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
username=sa&password=sinoreal
|
||||
|
||||
###
|
||||
|
||||
GET http://127.0.0.1:8088/real/basePointApi/getTables
|
||||
token: cab5bcd2fc250f27c3984205fbffc46e
|
||||
Content-Type: application/json
|
||||
|
||||
###
|
||||
|
||||
GET http://127.0.0.1:8088/real/basePointApi/getTags?tablemask=JTdevice
|
||||
token: 7670b1a3da5e22ffc42a1e738ea4f0f6
|
||||
|
||||
###
|
||||
GET http://127.0.0.1:8088/real/basePointApi/getSnapshotDataByTag/adasd?aaa=3
|
||||
token: 7670b1a3da5e22ffc42a1e738ea4f0f6
|
||||
|
||||
###
|
||||
|
||||
POST http://127.0.0.1:8088/real/serverApi/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"username": "sa",
|
||||
"password": "sinoreal"
|
||||
}
|
||||
|
||||
###
|
||||
|
||||
POST http://127.0.0.1:8088/real/basePointApi/updateTag
|
||||
token: cab5bcd2fc250f27c3984205fbffc46e
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"userints": [123223,35356],
|
||||
"id": 123,
|
||||
"equation": "asd",
|
||||
"trigger": "RTDB_EVENT_TRIGGER",
|
||||
"shutdown": true
|
||||
}
|
||||
|
||||
|
||||
|
||||
###
|
||||
|
||||
GET http://127.0.0.1:8088/real/basePointApi/getTagById/753
|
||||
token: eb7d391ad89d4bb4a81897af8829f0e8
|
||||
|
||||
###
|
||||
|
||||
GET http://127.0.0.1:8088/real/basePointApi/aaaa
|
||||
token: cab5bcd2fc250f27c3984205fbffc46e
|
||||
|
||||
###
|
||||
|
||||
GET http://127.0.0.1:8088/real/serverApi/test
|
||||
|
||||
###
|
||||
|
||||
POST http://127.0.0.1:8088/real/serverApi/addUser
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
token: 2b4769b63c90adb6490cfe6e449da90b
|
||||
|
||||
username=sa1&password=sinoreal&permission=3
|
||||
|
||||
|
||||
###
|
||||
POST http://127.0.0.1:8088/real/serverApi/removeUser
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
token: 2b4769b63c90adb6490cfe6e449da90b
|
||||
|
||||
username=sa1
|
||||
|
||||
|
||||
###
|
||||
|
||||
POST http://127.0.0.1:8088/real/serverApi/updatePassword
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
token: 33c21f7cf053b90a713f1f9e124d0335
|
||||
|
||||
oldPassword=sinoreal1&newPassword=sinoreal
|
||||
|
||||
|
||||
###
|
||||
|
||||
POST http://127.0.0.1:8088/real/serverApi/changePriv
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
token: 2b4769b63c90adb6490cfe6e449da90b
|
||||
|
||||
username=sa1&permission=3
|
||||
|
||||
|
||||
###
|
||||
POST http://127.0.0.1:8088/real/serverApi/addAuthorization
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
token: 2b4769b63c90adb6490cfe6e449da90b
|
||||
|
||||
addr=192.168.1.56&mask=255.255.255.255&permission=3&description=测试信任666111
|
||||
|
||||
|
||||
###
|
||||
POST http://127.0.0.1:8088/real/serverApi/removeAuthorization
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
token: 2b4769b63c90adb6490cfe6e449da90b
|
||||
|
||||
addr=192.168.1.56&mask=255.255.255.255
|
||||
|
||||
|
||||
###
|
||||
POST http://127.0.0.1:8088/real/historyApi/getHistory
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
token: 2b4769b63c90adb6490cfe6e449da90b
|
||||
|
||||
startDate=2021-05-17 11:03&endDate=2021-05-17 11:04&interval=3
|
||||
|
||||
###
|
||||
POST http://127.0.0.1:8088/real/historyApi/getHistory
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
token: 2b4769b63c90adb6490cfe6e449da90b
|
||||
|
||||
startDate=2021-05-17 11:03
|
||||
|
||||
###
|
||||
GET http://127.0.0.1:8088/real/dict/getDictByName?name=dict2
|
||||
token: 7670b1a3da5e22ffc42a1e738ea4f0f6
|
||||
|
||||
###
|
||||
tagmask=*&desc=*&_PointType=Every&_ValueTypeString=*&_TimeAccuracy=-1&_SearchCondition=SEARCH_NULL&SearchMaskValue=*&source=*&instrument=*&
|
||||
|
||||
###
|
||||
http://127.0.0.1:8088/real/basePointApi/getTags?tablemask=demo02&tagmask=*&desc=*&_PointType=Every&_ValueTypeString=*&_TimeAccuracy=-1&_SearchCondition=SEARCH_NULL&SearchMaskValue=*&source=*&instrument=*&pageNumber=1&pageSize=10
|
||||
token: eb7d391ad89d4bb4a81897af8829f0e8
|
||||
|
||||
###
|
||||
http://127.0.0.1:8088/real/serverApi/getFile?path=D:
|
||||
token: 7670b1a3da5e22ffc42a1e738ea4f0f6
|
||||
|
||||
###
|
||||
#http://127.0.0.1:8088/real/serverApi/hello1/:msg
|
||||
http://127.0.0.1:8088/real/serverApi/hello1/ok1
|
||||
token: a3cada4c97be40d3bc35cfe6ec1288ab
|
||||
|
||||
###
|
||||
http://127.0.0.1:8088/real/serverApi/hello2/ok2
|
||||
token: a3cada4c97be40d3bc35cfe6ec1288ab
|
||||
|
||||
|
||||
|
||||
|
||||
###
|
||||
http://127.0.0.1:8085/real/basePointApi/getTags?tablemask=demo02&tagmask=*&desc=*&unit=*&pointType=Every&valueTypeString=*&timeAccuracy=-1&searchCondition=SEARCH_NULL&SearchMaskValue=*&source=*&instrument=*&pageNumber=1&pageSize=10&accurateSearch=
|
||||
token: c423c04a55964571bd34aaa1683229e8
|
||||
47
web/src/main/resources/2.http
Normal file
47
web/src/main/resources/2.http
Normal file
@@ -0,0 +1,47 @@
|
||||
###
|
||||
http://127.0.0.1:8088/real/test
|
||||
|
||||
###
|
||||
POST http://127.0.0.1:8088/real/serverApi/login
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
username=sa&password=sinoreal
|
||||
###
|
||||
POST http://47.114.185.111:8070/real/serverApi/login
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
username=sa&password=sinoreal
|
||||
|
||||
###
|
||||
http://127.0.0.1:8088/real/serverApi/hello2/ok2
|
||||
token: 11f1a7ad9dd907bf1fa6a9e79277d053
|
||||
|
||||
|
||||
|
||||
###
|
||||
http://127.0.0.1:8088/real/test2
|
||||
|
||||
|
||||
###
|
||||
POST http://127.0.0.1:8088/real/serverApi/getConnections
|
||||
token: 370ba165d3164049b7704e8b3d595930
|
||||
|
||||
###
|
||||
POST http://127.0.0.1:8085/real/serverApi/getConnectionInfo
|
||||
token: 21f99c6080074ae79cda2e988ab2bdb8
|
||||
|
||||
###
|
||||
http://127.0.0.1:7070/demo/foo
|
||||
|
||||
###
|
||||
http://127.0.0.1:8085/api/foo
|
||||
|
||||
|
||||
###
|
||||
http://127.0.0.1:8085/real/serverApi/thread-test
|
||||
token: c1b89b3193bd4498be77b6e782e0df38
|
||||
|
||||
|
||||
###
|
||||
http://127.0.0.1:8085/
|
||||
Accept: application/json
|
||||
33
web/src/main/resources/app-dev.yml
Normal file
33
web/src/main/resources/app-dev.yml
Normal file
@@ -0,0 +1,33 @@
|
||||
# 服务配置
|
||||
server:
|
||||
port: 6400
|
||||
contextPath: /api
|
||||
enableStaticHtmlService: false
|
||||
staticResourcePath: webroot/
|
||||
# 反向代理服务器配置路径(不用加后缀)
|
||||
proxyConf: server-proxy
|
||||
|
||||
vertx:
|
||||
eventLoopPoolSize: 8
|
||||
workerPoolSize: 20
|
||||
custom:
|
||||
asyncServiceInstances: 8
|
||||
routerLocations: cn.com.yhinfo.real.web.http
|
||||
interceptorClassPath: cn.com.yhinfo.real.common.interceptorImpl.DefaultInterceptor
|
||||
handlerLocations: cn.com.yhinfo.real.web.service
|
||||
ignoresReg:
|
||||
- .*/login$
|
||||
- .*/test.*$
|
||||
entityPackagesReg:
|
||||
- ^cn\.com\.yhinfo\.real\.web\.model\..*
|
||||
- ^sinereal\.core\..*
|
||||
otherConfig:
|
||||
- dictionaries.json
|
||||
errorPage404: /index.html
|
||||
indexPage: /test2
|
||||
sharedLogin: true
|
||||
lzConfig:
|
||||
config: '111'
|
||||
|
||||
cowConfig:
|
||||
config: '111'
|
||||
7
web/src/main/resources/app.yml
Normal file
7
web/src/main/resources/app.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
# 要激活的配置: dev--连接本地数据库; prod连接线上数据库
|
||||
active: dev
|
||||
# 框架版本号 和主版本号
|
||||
version_vertx: 4.1.3
|
||||
version_app: 0.0.1
|
||||
# 公司名称 -> LOGO版权文字
|
||||
copyright: QAIU
|
||||
3
web/src/main/resources/conf/dictionaries.json
Normal file
3
web/src/main/resources/conf/dictionaries.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
||||
3
web/src/main/resources/curl/curl.sh
Normal file
3
web/src/main/resources/curl/curl.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
curl -F "file=@C:\Users\qaiu\Desktop\real\sinoreal2-web\web\src\main\resources\logback.xml" -i -XPOST 127.0.0.1:8088/demo/basePointApi/importTags
|
||||
|
||||
curl -F "file=@C:\Users\qaiu\Desktop\3.csv" -i -XPOST 127.0.0.1:8088/demo/basePointApi/importTags
|
||||
30
web/src/main/resources/server-proxy.yml
Normal file
30
web/src/main/resources/server-proxy.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
# 反向代理
|
||||
server-name: Vert.x-proxy-server(v4.1.2)
|
||||
|
||||
proxy:
|
||||
- listen: 8085
|
||||
# 404的路径
|
||||
404: webroot/real-html/index.html
|
||||
static:
|
||||
path: /
|
||||
# add-headers:
|
||||
# x-token: ABC
|
||||
root: webroot/real-html/
|
||||
index: realIndex
|
||||
location:
|
||||
- path: /real/
|
||||
origin: 127.0.0.1:8088
|
||||
- path: /api/
|
||||
origin: 127.0.0.1:7070/demo/
|
||||
|
||||
- listen: 8086
|
||||
static:
|
||||
path: /t2/
|
||||
root: webroot/test/
|
||||
index: sockTest.html
|
||||
# location:
|
||||
# - path: /real/
|
||||
# origin: 127.0.0.1:8088
|
||||
# sock:
|
||||
# - path: /real/
|
||||
# origin: 127.0.0.1:8088
|
||||
42
web/src/test/java/cn/com/yhinfo/test/StompTest.java
Normal file
42
web/src/test/java/cn/com/yhinfo/test/StompTest.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package cn.com.yhinfo.test;
|
||||
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.http.HttpServer;
|
||||
import io.vertx.core.http.HttpServerOptions;
|
||||
import io.vertx.ext.stomp.StompServer;
|
||||
import io.vertx.ext.stomp.StompServerHandler;
|
||||
import io.vertx.ext.stomp.StompServerOptions;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* sinoreal2-web
|
||||
* <p>create 2021/9/18 12:10</p>
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
public class StompTest {
|
||||
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
Vertx vertx = Vertx.vertx();
|
||||
|
||||
StompServer stompServer = StompServer.create(vertx, new StompServerOptions()
|
||||
.setPort(-1) // 禁用 tcp 端口,这一项是可选的
|
||||
.setWebsocketBridge(true) // 开启 websocket 支持
|
||||
.setWebsocketPath("/stomp")) // 配置 websocket 路径,默认是 /stomp
|
||||
.handler(StompServerHandler.create(vertx));
|
||||
Future<HttpServer> http = vertx.createHttpServer(
|
||||
new HttpServerOptions().setWebSocketSubProtocols(Arrays.asList("v10.stomp", "v11.stomp"))
|
||||
)
|
||||
.webSocketHandler(stompServer.webSocketHandler())
|
||||
.listen(8080);
|
||||
http.onSuccess(res->{
|
||||
System.out.println("okk");
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
223
web/src/test/java/cn/com/yhinfo/test/Test01.java
Normal file
223
web/src/test/java/cn/com/yhinfo/test/Test01.java
Normal file
@@ -0,0 +1,223 @@
|
||||
package cn.com.yhinfo.test;
|
||||
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.beanutils.BeanUtils;
|
||||
import org.apache.commons.beanutils.ConvertUtils;
|
||||
import org.apache.commons.beanutils.Converter;
|
||||
import org.apache.commons.lang3.time.DateFormatUtils;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <br>Create date 2021/4/29 15:27
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
@Slf4j
|
||||
public class Test01 {
|
||||
|
||||
public static class A {
|
||||
String name;
|
||||
String num;
|
||||
String num2;
|
||||
String num3;
|
||||
|
||||
Integer num5;
|
||||
|
||||
public Integer getNum5() {
|
||||
return num5;
|
||||
}
|
||||
|
||||
public void setNum5(Integer num5) {
|
||||
this.num5 = num5;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getNum() {
|
||||
return num;
|
||||
}
|
||||
|
||||
public void setNum(String num) {
|
||||
this.num = num;
|
||||
}
|
||||
|
||||
public String getNum2() {
|
||||
return num2;
|
||||
}
|
||||
|
||||
public void setNum2(String num2) {
|
||||
this.num2 = num2;
|
||||
}
|
||||
|
||||
public String getNum3() {
|
||||
return num3;
|
||||
}
|
||||
|
||||
public void setNum3(String num3) {
|
||||
this.num3 = num3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class B0 {
|
||||
int num;
|
||||
|
||||
public int getNum() {
|
||||
return num;
|
||||
}
|
||||
|
||||
public void setNum(int num) {
|
||||
this.num = num;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class B extends B0 {
|
||||
String name;
|
||||
|
||||
boolean flag;
|
||||
int num4;
|
||||
Date date;
|
||||
String dateStr;
|
||||
|
||||
Integer num5;
|
||||
|
||||
public Boolean getFlag() {
|
||||
return flag;
|
||||
}
|
||||
|
||||
public void setFlag(Boolean flag) {
|
||||
this.flag = flag;
|
||||
}
|
||||
|
||||
public Integer getNum5() {
|
||||
return num5;
|
||||
}
|
||||
|
||||
public void setNum5(Integer num5) {
|
||||
this.num5 = num5;
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(Date date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public String getDateStr() {
|
||||
return dateStr;
|
||||
}
|
||||
|
||||
public void setDateStr(String dateStr) {
|
||||
this.dateStr = dateStr;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getNum4() {
|
||||
return num4;
|
||||
}
|
||||
|
||||
public void setNum4(int num4) {
|
||||
this.num4 = num4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "B{" +
|
||||
"num=" + num +
|
||||
", name='" + name + '\'' +
|
||||
", flag=" + flag +
|
||||
", num4=" + num4 +
|
||||
", date=" + date +
|
||||
", dateStr='" + dateStr + '\'' +
|
||||
", num5=" + num5 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static <T> T getParamsToBean(RoutingContext ctx, Class<T> tClass) {
|
||||
// ObjectUtils.identityToString()
|
||||
return null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test01() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
|
||||
|
||||
A a = new A();
|
||||
a.setName("asd");
|
||||
a.setNum("123");
|
||||
a.setNum2("123");
|
||||
a.setNum3("123");
|
||||
a.setNum5(9999);
|
||||
B b = new B();
|
||||
BeanUtils.copyProperties(b, a);
|
||||
System.out.println(b);
|
||||
a.setNum5(233);
|
||||
System.out.println(b);
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("name", "小米");
|
||||
map.put("flag", "1");
|
||||
map.put("num", "553454344");
|
||||
map.put("num2", "123");
|
||||
map.put("num4", "q");
|
||||
map.put("dateStr", new Date());
|
||||
map.put("date", "2021-01-01");
|
||||
B b1 = new B();
|
||||
|
||||
ConvertUtils.register(
|
||||
new Converter() {
|
||||
@Override
|
||||
public <T> T convert(Class<T> clazz, Object value) {
|
||||
//字符串转换为日期
|
||||
try {
|
||||
return (T) DateUtils.parseDate(value.toString(), "yyyy-MM-dd");
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, Date.class);
|
||||
|
||||
|
||||
ConvertUtils.register(
|
||||
new Converter() {
|
||||
@Override
|
||||
public <T> T convert(Class<T> clazz, Object value) {
|
||||
//日期->字符串
|
||||
try {
|
||||
return (T) DateFormatUtils.format((Date) value, "yyyy-MM-dd");
|
||||
} catch (Exception e) {
|
||||
return (T) value;
|
||||
}
|
||||
}
|
||||
}, String.class);
|
||||
|
||||
BeanUtils.populate(b1, map);
|
||||
log.info("---------> {}", b1);
|
||||
}
|
||||
|
||||
}
|
||||
85
web/src/test/java/cn/com/yhinfo/test/Test02.java
Normal file
85
web/src/test/java/cn/com/yhinfo/test/Test02.java
Normal file
@@ -0,0 +1,85 @@
|
||||
package cn.com.yhinfo.test;
|
||||
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtMethod;
|
||||
import javassist.NotFoundException;
|
||||
import javassist.bytecode.CodeAttribute;
|
||||
import javassist.bytecode.ExceptionsAttribute;
|
||||
import javassist.bytecode.LocalVariableAttribute;
|
||||
import javassist.bytecode.MethodInfo;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Test02 {
|
||||
|
||||
|
||||
public String[] getParameterName(Class<?> className, String method) {
|
||||
String[] paramNames = null;
|
||||
try {
|
||||
ClassPool pool = ClassPool.getDefault();
|
||||
CtClass ctClass = pool.get(className.getName());
|
||||
CtMethod cm = ctClass.getDeclaredMethod(method);
|
||||
MethodInfo methodInfo = cm.getMethodInfo();
|
||||
CtClass[] parameterTypes = cm.getParameterTypes();
|
||||
|
||||
for (CtClass parameterType : parameterTypes) {
|
||||
System.out.println(parameterType.getDeclaringClass());
|
||||
System.out.println(parameterType.getName() + "----" + parameterType.getSimpleName());
|
||||
}
|
||||
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
|
||||
LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute
|
||||
.getAttribute(LocalVariableAttribute.tag);
|
||||
paramNames = new String[cm.getParameterTypes().length];
|
||||
CtClass[] exceptionTypes = cm.getExceptionTypes();
|
||||
ExceptionsAttribute exceptionsAttribute = methodInfo.getExceptionsAttribute();
|
||||
|
||||
for (int j = 0; j < paramNames.length; j++) {
|
||||
String s = attr.variableName(attr.tableLength() - paramNames.length + j);
|
||||
paramNames[j] = s;
|
||||
}
|
||||
|
||||
} catch (NotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return paramNames;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test01() throws NoSuchMethodException {
|
||||
|
||||
//
|
||||
// Method[] methods = RealUser.class.getMethods();
|
||||
// for (Method m : methods) {
|
||||
// if (m.getName().equals("setUsername2")) {
|
||||
// Class<?>[] parameterTypes = m.getParameterTypes();
|
||||
// for (Class<?> type : parameterTypes) {
|
||||
// System.out.println(type + "--"+type.getName());
|
||||
// System.out.println(type.isPrimitive());
|
||||
// System.out.println("------------");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
System.out.println(("java.lang.Double".matches("^java\\.lang\\.((Integer)|(Double))$")));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test3() {
|
||||
Map map = new LinkedHashMap();
|
||||
map.put("1", "1");
|
||||
map.put("2", "11");
|
||||
map.put("3", "111");
|
||||
|
||||
System.out.println(map);
|
||||
map.put("1", "12");
|
||||
System.out.println(map);
|
||||
|
||||
}
|
||||
}
|
||||
161
web/src/test/java/cn/com/yhinfo/test/TestOS.java
Normal file
161
web/src/test/java/cn/com/yhinfo/test/TestOS.java
Normal file
@@ -0,0 +1,161 @@
|
||||
package cn.com.yhinfo.test;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
public class TestOS {
|
||||
//通过截取cmd流方式得到计算机的配置信息(不好)
|
||||
public static List<String> getIpAddress() {
|
||||
Process p = null;
|
||||
List<String> address = new ArrayList<String>();
|
||||
try {
|
||||
p = new ProcessBuilder("ipconfig", "/all").start();
|
||||
} catch (Exception e) {
|
||||
return address;
|
||||
}
|
||||
StringBuffer sb = new StringBuffer();
|
||||
//读取进程输出值
|
||||
InputStream inputStream = p.getInputStream();
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
|
||||
String s = "";
|
||||
try {
|
||||
while ((s = br.readLine()) != null) {
|
||||
sb.append(s + "\n");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
System.out.println(sb);
|
||||
return address;
|
||||
}
|
||||
|
||||
public static void getIpconfig() {
|
||||
Map<String, String> map = System.getenv();
|
||||
System.out.println(map.get("USERNAME"));//获取username
|
||||
System.out.println(map.get("COMPUTERNAME"));//获取计算机名
|
||||
System.out.println(map.get("USERDOMAIN"));//获取计算机域名
|
||||
}
|
||||
|
||||
//得到计算机的ip地址和mac地址
|
||||
public static void getConfig() {
|
||||
try {
|
||||
InetAddress address = InetAddress.getLocalHost();
|
||||
NetworkInterface ni = NetworkInterface.getByInetAddress(address);
|
||||
//ni.getInetAddresses().nextElement().getAddress();
|
||||
byte[] mac = ni.getHardwareAddress();
|
||||
String sIP = address.getHostAddress();
|
||||
String sMAC = "";
|
||||
Formatter formatter = new Formatter();
|
||||
for (int i = 0; i < mac.length; i++) {
|
||||
sMAC = formatter.format(Locale.getDefault(), "%02X%s", mac[i],
|
||||
(i < mac.length - 1) ?
|
||||
"-" : "").toString();
|
||||
}
|
||||
System.out.println("IP:" + sIP);
|
||||
System.out.println("MAC:" + sMAC);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
//得到计算机的ip,名称,操作系统名称,操作系统版本号
|
||||
public static void Config() {
|
||||
try {
|
||||
InetAddress addr = InetAddress.getLocalHost();
|
||||
String ip = addr.getHostAddress().toString(); //获取本机ip
|
||||
String hostName = addr.getHostName().toString(); //获取本机计算机名称
|
||||
System.out.println("本机IP:" + ip + "\n本机名称:" + hostName);
|
||||
Properties props = System.getProperties();
|
||||
System.out.println("操作系统的名称:" + props.getProperty("os.name"));
|
||||
System.out.println("操作系统的版本号:" + props.getProperty("os.version"));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
//其他的一些东西,会实用到的时候的
|
||||
public static void all() {
|
||||
Properties props = System.getProperties();
|
||||
System.out.println("Java的执行环境版本号:" + props.getProperty("java.version"));
|
||||
System.out.println("Java的执行环境供应商:" + props.getProperty("java.vendor"));
|
||||
System.out.println("Java供应商的URL:" + props.getProperty("java.vendor.url"));
|
||||
System.out.println("Java的安装路径:" + props.getProperty("java.home"));
|
||||
System.out.println("Java的虚拟机规范版本号:" + props.getProperty("java.vm.specification.version"));
|
||||
System.out.println("Java的虚拟机规范供应商:" + props.getProperty("java.vm.specification.vendor"));
|
||||
System.out.println("Java的虚拟机规范名称:" + props.getProperty("java.vm.specification.name"));
|
||||
System.out.println("Java的虚拟机实现版本号:" + props.getProperty("java.vm.version"));
|
||||
System.out.println("Java的虚拟机实现供应商:" + props.getProperty("java.vm.vendor"));
|
||||
System.out.println("Java的虚拟机实现名称:" + props.getProperty("java.vm.name"));
|
||||
System.out.println("Java执行时环境规范版本号:" + props.getProperty("java.specification.version"));
|
||||
System.out.println("Java执行时环境规范供应商:" + props.getProperty("java.specification.vender"));
|
||||
System.out.println("Java执行时环境规范名称:" + props.getProperty("java.specification.name"));
|
||||
System.out.println("Java的类格式版本号号:" + props.getProperty("java.class.version"));
|
||||
System.out.println("Java的类路径:" + props.getProperty("java.class.path"));
|
||||
System.out.println("载入库时搜索的路径列表:" + props.getProperty("java.library.path"));
|
||||
System.out.println("默认的暂时文件路径:" + props.getProperty("java.io.tmpdir"));
|
||||
System.out.println("一个或多个扩展文件夹的路径:" + props.getProperty("java.ext.dirs"));
|
||||
System.out.println("操作系统的名称:" + props.getProperty("os.name"));
|
||||
System.out.println("操作系统的构架:" + props.getProperty("os.arch"));
|
||||
System.out.println("操作系统的版本号:" + props.getProperty("os.version"));
|
||||
System.out.println("文件分隔符:" + props.getProperty("file.separator"));
|
||||
//在 unix 系统中是"/"
|
||||
System.out.println("路径分隔符:" + props.getProperty("path.separator"));
|
||||
//在 unix 系统中是":"
|
||||
System.out.println("行分隔符:" + props.getProperty("line.separator"));
|
||||
//在 unix 系统中是"/n"
|
||||
System.out.println("用户的账户名称:" + props.getProperty("user.name"));
|
||||
System.out.println("用户的主文件夹:" + props.getProperty("user.home"));
|
||||
System.out.println("用户的当前工作文件夹:" + props.getProperty("user.dir"));
|
||||
}
|
||||
|
||||
|
||||
public void showURL() throws IOException {
|
||||
|
||||
// 第一种:获取类加载的根路径 D:\git\daotie\daotie\target\classes
|
||||
File f = new File(this.getClass().getResource("/").getPath());
|
||||
System.out.println(f);
|
||||
|
||||
// 获取当前类的所在工程路径; 如果不加“/” 获取当前类的加载目录 D:\git\daotie\daotie\target\classes\my
|
||||
File f2 = new File(this.getClass().getResource("").getPath());
|
||||
System.out.println(f2);
|
||||
|
||||
// 第二种:获取项目路径 D:\git\daotie\daotie
|
||||
File directory = new File("");// 参数为空
|
||||
String courseFile = directory.getCanonicalPath();
|
||||
System.out.println(courseFile);
|
||||
|
||||
|
||||
// 第三种: file:/D:/git/daotie/daotie/target/classes/
|
||||
URL xmlpath = this.getClass().getClassLoader().getResource("");
|
||||
System.out.println(xmlpath);
|
||||
|
||||
|
||||
// 第四种: D:\git\daotie\daotie
|
||||
System.out.println(System.getProperty("user.dir"));
|
||||
/*
|
||||
* 结果: C:\Documents and Settings\Administrator\workspace\projectName
|
||||
* 获取当前工程路径
|
||||
*/
|
||||
|
||||
// 第五种: 获取所有的类路径 包括jar包的路径
|
||||
System.out.println(System.getProperty("java.class.path"));
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
// getConfig();
|
||||
// Config();
|
||||
// all();
|
||||
// new TestOS().showURL();
|
||||
System.out.println(File.separator);
|
||||
}
|
||||
}
|
||||
169
web/src/test/java/cn/com/yhinfo/test/WebProxyExamples.java
Normal file
169
web/src/test/java/cn/com/yhinfo/test/WebProxyExamples.java
Normal file
@@ -0,0 +1,169 @@
|
||||
package cn.com.yhinfo.test;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.http.HttpClient;
|
||||
import io.vertx.core.http.HttpMethod;
|
||||
import io.vertx.core.http.HttpServer;
|
||||
import io.vertx.ext.web.Router;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
import io.vertx.ext.web.handler.StaticHandler;
|
||||
import io.vertx.ext.web.proxy.handler.ProxyHandler;
|
||||
import io.vertx.httpproxy.HttpProxy;
|
||||
import io.vertx.httpproxy.ProxyRequest;
|
||||
import io.vertx.httpproxy.ProxyResponse;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:emad.albloushi@gmail.com">Emad Alblueshi</a>
|
||||
*/
|
||||
|
||||
public class WebProxyExamples {
|
||||
|
||||
public void origin() {
|
||||
HttpServer backendServer = vertx.createHttpServer();
|
||||
|
||||
Router backendRouter = Router.router(vertx);
|
||||
backendRouter.route().handler(ctx -> {
|
||||
System.out.println(ctx.request().path());
|
||||
ctx.next();
|
||||
});
|
||||
|
||||
backendRouter.route(HttpMethod.GET, "/demo/foo").handler(rc -> rc.response()
|
||||
.putHeader("content-type", "text/html")
|
||||
.end("<html><body><h1>I'm the target resource111!</h1></body></html>"));
|
||||
backendRouter.route(HttpMethod.GET, "/demo/a")
|
||||
.handler(rc -> rc.response().putHeader("content-type", "text/html").end("AAA"));
|
||||
backendRouter.route(HttpMethod.GET, "/demo/b")
|
||||
.handler(rc -> rc.response().putHeader("content-type", "text/html").end("BBB"));
|
||||
|
||||
backendServer.requestHandler(backendRouter).listen(7070);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
/a -> 7070/foo/a
|
||||
/aaa/b -> '7070/foo/' -> 7070/foo/b
|
||||
/aaa/b -> /foo/b -> 7070/foo/b
|
||||
|
||||
/aaa/b -> '7070/foo' -> 7070/foob
|
||||
/aaa/a -> '7070/' -> 7070/aaa/a
|
||||
/aaa/a -> '7070/aaa/' -> 7070/aaa/a
|
||||
|
||||
|
||||
*/
|
||||
|
||||
public Vertx vertx = Vertx.vertx();
|
||||
public HttpClient proxyClient = vertx.createHttpClient();
|
||||
// 创建 http代理处理器
|
||||
HttpProxy httpProxy = HttpProxy.reverseProxy(proxyClient);
|
||||
// 代理处理器绑定到路由
|
||||
Router proxyRouter = Router.router(vertx);
|
||||
|
||||
public void route() {
|
||||
httpProxy.origin(7070, "localhost");
|
||||
|
||||
proxyRouter.route("/demo/*").handler(ProxyHandler.create(httpProxy));
|
||||
proxyRouter.route("/api/*").handler(ctx -> ctx.reroute(ctx.request().path().replaceAll("^/api/", "/demo/")));
|
||||
|
||||
// Router r1 = Router.router(vertx);
|
||||
// r1.route().handler(ctx -> {
|
||||
// int statusCode = ctx.response().getStatusCode();
|
||||
// if (statusCode == 404) {
|
||||
// ctx.response().write("subRouter ---------------> 404");
|
||||
// ctx.end();
|
||||
// }
|
||||
// });
|
||||
|
||||
proxyRouter.route("/*").handler(StaticHandler.create("webroot/test"));
|
||||
|
||||
proxyRouter.errorHandler(404, this::handle404);
|
||||
|
||||
// proxyRouter.route("/api/*").handler(ctx -> ctx.end("123123"));
|
||||
// 路由绑定到代理服务器
|
||||
HttpServer proxyServer = vertx.createHttpServer();
|
||||
proxyServer.requestHandler(proxyRouter);
|
||||
proxyServer.listen(1080);
|
||||
}
|
||||
|
||||
private void handle404(RoutingContext routingContext) {
|
||||
routingContext.end(routingContext.request().path() + "-------> 404");
|
||||
}
|
||||
|
||||
public void routeShort(Vertx vertx, Router proxyRouter) {
|
||||
HttpClient proxyClient = vertx.createHttpClient();
|
||||
|
||||
HttpProxy httpProxy = HttpProxy.reverseProxy(proxyClient);
|
||||
|
||||
proxyRouter
|
||||
.route(HttpMethod.GET, "/*")
|
||||
.handler(ProxyHandler.create(httpProxy, 7070, "localhost"));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void lowLevel() {
|
||||
HttpServer proxyServer = vertx.createHttpServer();
|
||||
proxyServer.requestHandler(outboundRequest -> {
|
||||
ProxyRequest proxyRequest = ProxyRequest.reverseProxy(outboundRequest);
|
||||
|
||||
proxyClient.request(proxyRequest.getMethod(), 443, "qaiu.top", proxyRequest.getURI())
|
||||
.compose(proxyRequest::send)
|
||||
// Send the proxy response
|
||||
.onSuccess(ProxyResponse::send)
|
||||
.onFailure(err -> {
|
||||
// Release the request
|
||||
proxyRequest.release();
|
||||
|
||||
// Send error
|
||||
outboundRequest.response().setStatusCode(500)
|
||||
.send();
|
||||
});
|
||||
}).listen(8181);
|
||||
}
|
||||
|
||||
|
||||
public void multi(Vertx vertx, Router proxyRouter) {
|
||||
HttpClient proxyClient = vertx.createHttpClient();
|
||||
|
||||
HttpProxy httpProxy1 = HttpProxy.reverseProxy(proxyClient);
|
||||
httpProxy1.origin(7070, "localhost");
|
||||
|
||||
HttpProxy httpProxy2 = HttpProxy.reverseProxy(proxyClient);
|
||||
httpProxy2.origin(6060, "localhost");
|
||||
|
||||
proxyRouter
|
||||
.route(HttpMethod.GET, "/foo").handler(ProxyHandler.create(httpProxy1));
|
||||
|
||||
proxyRouter
|
||||
.route(HttpMethod.GET, "/bar").handler(ProxyHandler.create(httpProxy2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1() throws IOException, URISyntaxException {
|
||||
// URL url = new URL("www.runoob.com/html/html-tutorial.html");
|
||||
URI uri = new URI("http://www.runoob.com");
|
||||
|
||||
System.out.println(StringUtils.isEmpty(uri.getPath()));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
final WebProxyExamples examples = new WebProxyExamples();
|
||||
examples.vertx.executeBlocking(rs -> {
|
||||
rs.complete();
|
||||
examples.origin();
|
||||
});
|
||||
examples.vertx.executeBlocking(rs -> {
|
||||
rs.complete();
|
||||
examples.route();
|
||||
});
|
||||
System.out.println("ok");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
15
webroot/err/404.html
Normal file
15
webroot/err/404.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>404 not fount</title>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width: 100%;text-align: center">
|
||||
<h1>
|
||||
server error - 404 not fount
|
||||
</h1>
|
||||
<p> -- vert.x反向代理服务器(version 4.1.2)</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
52
webroot/test/sockTest.html
Normal file
52
webroot/test/sockTest.html
Normal file
@@ -0,0 +1,52 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ZH-cn">
|
||||
<script src="sockjs-min.js"></script>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>测试021</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<label>
|
||||
<input id="input0"/>
|
||||
<input type="button" value="发送" onclick="send()">
|
||||
</label>
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
|
||||
var sock = new SockJS('http://127.0.0.1:8086/real/serverApi/test');
|
||||
|
||||
// 测试websocket直接http反向代理
|
||||
// var sock = new SockJS('http://'+location.host+'/real/serverApi/test'); // 这会导致sockjs降级处理 (使用普通post轮询 模拟websocket)
|
||||
|
||||
|
||||
sock.onopen = function () {
|
||||
console.log('open');
|
||||
};
|
||||
|
||||
function send() {
|
||||
|
||||
var v = document.getElementById("input0");
|
||||
console.log('client:', v.value)
|
||||
sock.send(v.value)
|
||||
}
|
||||
|
||||
sock.onmessage = function (e) {
|
||||
console.log('message', e.data);
|
||||
};
|
||||
|
||||
sock.onevent = function (event, message) {
|
||||
console.log('event: %o, message:%o', event, message);
|
||||
return true; // 为了标记消息已被处理了
|
||||
};
|
||||
|
||||
sock.onunhandled = function (json) {
|
||||
console.log('this message has no address:', json);
|
||||
};
|
||||
|
||||
sock.onclose = function () {
|
||||
console.log('close');
|
||||
};
|
||||
</script>
|
||||
</html>
|
||||
27
webroot/test/sockjs-min.js
vendored
Normal file
27
webroot/test/sockjs-min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
15
webroot/test2/index.html
Normal file
15
webroot/test2/index.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>TEST2</title>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width: 100%;text-align: center">
|
||||
<h1>
|
||||
OOOOOOOOOOOOOOOOOK
|
||||
</h1>
|
||||
<p><i> ---来自宇宙无敌的vert.x反向代理服务器(version 4.1.2)</i></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user