Compare commits

...
Author SHA1 Message Date
aoshiguchen 40a3624910 更新README.MD 2023-03-12 22:51:35 +08:00
aoshiguchen 9ebe6b1fcd client端启动参数优化. 2023-03-12 22:06:46 +08:00
aoshiguchen 21ee60de10 client端solon化改造 2023-03-12 20:32:32 +08:00
aoshiguchen 534dd4ed9c 升级lombok版本 2023-03-12 19:23:17 +08:00
aoshiguchen 6d3b0db745 去除冗余代码,全局访问日志处理优化 2023-03-12 17:47:44 +08:00
傲世孤尘 e1abbea5d9 !7 换了几个较小的包。缩了下 server 大小
Merge pull request !7 from 西东/feature/1.6.5-solon
2023-03-12 09:16:29 +00:00
noear a7bd61945d 换了几个较小的包。缩了下 server 大小 2023-03-12 16:58:08 +08:00
aoshiguchen c8ceb9c8ca .. 2023-03-12 15:48:17 +08:00
aoshiguchen 402baf2201 调整pom 2023-03-12 14:31:30 +08:00
aoshiguchen 28aa1337b4 服务端代码优化 2023-03-12 14:20:02 +08:00
aoshiguchen 21920ea7fe orika插件优化。 2023-03-12 14:14:45 +08:00
aoshiguchen fcae667457 orika插件优化 2023-03-12 14:10:23 +08:00
aoshiguchen afaef4d1b2 服务端全局访问日志调整。 2023-03-12 13:53:29 +08:00
aoshiguchen a6b651065f 服务端全局访问日志调整 2023-03-12 13:10:38 +08:00
aoshiguchen 56b216406e 服务端去除neutrino-core依赖 2023-03-12 02:01:09 +08:00
aoshiguchen 3e1bbfbd02 job相关功能封装为solon插件 2023-03-12 01:15:09 +08:00
aoshiguchen 251073b26d job相关功能封装为solon插件. 2023-03-12 01:14:50 +08:00
aoshiguchen 8d6a2860d9 job相关功能封装为solon插件 2023-03-12 01:12:48 +08:00
aoshiguchen b0c3c311af 服务端去除JdbcTemplate相关代码 2023-03-11 23:54:51 +08:00
aoshiguchen 64785bb87d 服务端db初始化改为使用ActiveRecord 2023-03-11 23:51:24 +08:00
aoshiguchen 4d0738b391 服务端rest接口调整,去掉无用的mapper.xml 2023-03-11 23:14:33 +08:00
aoshiguchen 6823ac07c4 为了支持数据初始化逻辑,将JdbcTemplate代码迁移至server端。mybatis、hutool-db不方便直接sql操作 2023-03-11 18:22:07 +08:00
aoshiguchen 28625f193c 分页接口改造 2023-03-11 17:13:58 +08:00
aoshiguchen 0fcc4c96ac .. 2023-03-10 15:53:35 +08:00
aoshiguchen 3b0403052b db相关调整 2023-03-10 15:48:42 +08:00
aoshiguchen bdf9b6dc5e job功能调通 2023-03-10 13:49:46 +08:00
aoshiguchen a8654d0a35 解决全局异常拦截不到的问题. 2023-03-10 13:01:37 +08:00
aoshiguchen 310d87e851 代理服务端solon化改造,rest接口、静态资源服务调通。 2023-03-10 10:06:43 +08:00
aoshiguchen 5269fb9149 代理服务端solon化改造,rest接口、静态资源服务调通 2023-03-09 23:37:20 +08:00
aoshiguchen e940edeee9 代理服务端solon化改造 2023-03-09 22:04:44 +08:00
aoshiguchen c3f7bb571f Environment初始化逻辑调整,针对5级配置优化 2023-03-06 18:52:40 +08:00
aoshiguchen db41228ce8 完善NvMaps工具类、测试代码. 2023-03-06 17:46:30 +08:00
aoshiguchen 294e5efdae 完善NvMaps工具类、测试代码 2023-03-06 17:45:48 +08:00
aoshiguchen 4efd86751a Kv工具类调整. 2023-03-05 13:19:32 +08:00
aoshiguchen c1583de157 Kv工具类名更新为Cfg 2023-03-05 13:07:26 +08:00
aoshiguchen c35a05ac08 Kv工具alias机制调整. 2023-03-05 13:02:33 +08:00
aoshiguchen 33299e3b2e Kv工具alias机制调整。明确key与alias的相关性、相反性. 2023-03-04 00:30:32 +08:00
aoshiguchen 2c9793858b Kv工具alias机制调整。明确key与alias的相关性、相反性 2023-03-04 00:27:21 +08:00
aoshiguchen a16e93ec09 kv工具新增别名支持 2023-03-02 14:07:08 +08:00
aoshiguchen a0634f15ac Kv工具类取值优化 2023-03-02 11:44:39 +08:00
aoshiguchen a4173984e5 Kv工具类取值优化 2023-03-01 18:37:14 +08:00
aoshiguchen a9f04eb785 增加Kv工具类及测试代码 2023-03-01 18:14:56 +08:00
aoshiguchen 251b4c660a Preload处理调整 2023-03-01 15:50:42 +08:00
aoshiguchen 790ded499c AsgcCompiler使用方式优化 2023-03-01 12:05:14 +08:00
aoshiguchen b8d957fccb Jar in Jar处理逻辑优化 2023-03-01 11:52:04 +08:00
aoshiguchen 24d20d954c 解决数据清理job失效的问题 2023-02-27 18:17:07 +08:00
aoshiguchen da26b631a6 增加2.x规划 2023-02-27 17:49:26 +08:00
傲世孤尘 307fd4327f !4 修复 You need to specify Statement.RETURN_GENERATED_KEYS to Statement.executeUpdate(), Statement.executeLargeUpdate() or Connection.prepareStatement(). 问题
Merge pull request !4 from tan90/feature/1.6.5
2023-02-26 07:56:27 +00:00
陈浩杰 ae8d90a29a fix: Generated keys not requested. bug 2023-02-26 15:51:11 +08:00
傲世孤尘 eb2e5204be !3 完善MD,添加代理示意图
Merge pull request !3 from tan90/feature/1.6.5
2023-02-25 15:50:38 +00:00
陈浩杰 2e301dc897 完善MD,添加代理示意图 2023-02-25 23:47:13 +08:00
zCans 0856ff823c 更新样式 2023-02-25 20:54:11 +08:00
zCans 58819bb5b9 Merge remote-tracking branch 'origin/feature/1.6.5' into feature/1.6.5 2023-02-25 20:49:10 +08:00
zCans 01efd2267a 左侧导航栏菜单折叠,logo切换 2023-02-25 20:49:04 +08:00
aoshiguchen 4d58244007 更新jar in jar测试代码 2023-02-25 20:30:55 +08:00
aoshiguchen 6abaa5cb5e 使用登记去掉logo列. 2023-02-24 21:08:14 +08:00
aoshiguchen e5534fe4a3 使用登记去掉logo列 2023-02-24 21:06:53 +08:00
傲世孤尘 d56d195e99 !2 使用者登记
Merge pull request !2 from jiang_wenJ/feature/1.6.5
2023-02-24 13:01:16 +00:00
jiang_wenJ ca0b85e8f1 update 使用登记.MD.
Signed-off-by: jiang_wenJ <[email protected]>
2023-02-24 12:58:56 +00:00
aoshiguchen 2158909259 增加使用登记.MD 2023-02-24 16:30:18 +08:00
aoshiguchen f9b0d65ab4 增加使用登记.MD 2023-02-24 16:29:28 +08:00
aoshiguchen 0d4bc5284f 解决动态生成类依赖jar in jar编译报找不到类的问题. 2023-02-24 00:18:40 +08:00
231 changed files with 7213 additions and 4435 deletions
+2
View File
@@ -49,3 +49,5 @@ hs_err_pid*
**/*.log
**/gifs/
**/deploy/
**/app-**.yml
+116 -16
View File
@@ -7,7 +7,9 @@
</p>
# 1、简介
中微子代理(neutrino-proxy)是一个基于netty的、开源的java内网穿透项目。遵循MIT许可,因此您可以对它进行复制、修改、传播并用于任何个人或商业行为。
- 中微子代理(neutrino-proxy)是一个基于netty的、开源的java内网穿透项目。
- 技术栈:Solon、MybatisPlus
- 遵循MIT许可,因此您可以对它进行复制、修改、传播并用于任何个人或商业行为。
# 2、名称由来
中微子,是轻子的一种,是组成自然界的最基本的粒子之一。它十分微小、不带电,可自由穿过地球,以接近光速运动,与其他物质的相互作用十分微弱,号称宇宙间的“隐身人”。
@@ -25,7 +27,6 @@
# 4、项目结构
- neutrino-proxy
- neutrino-core 与代理无关的基础封装
- neutrino-proxy-core 与代理相关的公共常量、编解码器
- neutrino-proxy-client 代理客户端项目
- neutrino-proxy-server 代理服务端项目
@@ -63,14 +64,16 @@ proxy:
# 证书存放路径,若不想打进jar包,可不带classpath:前缀
jks-path: classpath:/test.jks
data:
# 数据库配置(不用动,项目自动会自动初始化
sqlite:
# 数据库配置(支持mysql
type: sqlite
url: jdbc:sqlite:data.db
driver-class: org.sqlite.JDBC
username:
password:
```
## 5.3、启动服务端
> fun.asgc.neutrino.proxy.server.ProxyServer
> java -jar neutrino-proxy-server.jar
## 5.4、修改客户端配置
```yml
@@ -98,16 +101,28 @@ proxy:
server-port: 9000
# 是否启用ssl,启用则必须配置ssl相关参数
ssl-enable: false
# 获取license提示间隔(秒)
obtain-license-interval: 5
```
## 5.5、代理示意图
![代理流程](assets/neutrino-proxy-process.jpg)
## 5.6、启动客户端
### 5.6.1、启动参数直接指定配置
> java -jar neutrino-proxy-client.jar serverIp=localhost serverPort=9000 licenseKey=b0a907332b474b25897c4dcb31fc7eb6
### 5.6.2、启动参数指定外部配置文件
> java -jar neutrino-proxy-client.jar config=app.properties
配置文件格式如下:
```
neutrino.proxy.client.server-ip=localhost
neutrino.proxy.client.server-port=9002
neutrino.proxy.client.ssl-enable=true
neutrino.proxy.client.key-store-password=123456
neutrino.proxy.client.jks-path=classpath:/test.jks
neutrino.proxy.client.license-key=b0a907332b474b25897c4dcb31fc7eb6
```
## 5.5、启动客户端
> fun.asgc.neutrino.proxy.client.ProxyClient
默认情况下,客户端会加载当前目录下的.neutrino-proxy.license里的license,可通过命令行参数指定,如:java -jar neutrino-proxy-client.jar license=xxx
若启动参数未指定license,且是首次启动(当前目录下未缓存license),则需要根据命令行提示输入正确的license, 输入完成后完成连接,可在服务端管理页面控制端口转发,参见[2、运行示例](#2)
## 5.6、Docker快速启动
## 5.7、Docker快速启动
```shell script
# 一键部署前端和后端,客户端按上方部署即可
docker run -it -p 9000-9200:9000-9200/tcp -p 8888:8888 -d --name neutrino registry.cn-hangzhou.aliyuncs.com/asgc/aoshiguchen-docker-images:1.64
@@ -133,7 +148,92 @@ proxy:
- 微信: yuyunshize
- Gitee: https://gitee.com/asgc/neutrino-proxy
# 10、特别鸣
* [JetBrains](https://www.jetbrains.com?from=RedisFront)
# ❤️ 感
* [Solon](https://gitee.com/noear/solon?from=NeutrinoProxy)
* [Hutool](https://hutool.cn?from=NeutrinoProxy)
* [JetBrains](https://www.jetbrains.com?from=NeutrinoProxy)
![JenBrains logo](assets/jetbrains.svg)
![JenBrains logo](assets/jetbrains.svg)
# 📚 Dromara 成员项目
<p align="center">
<a href="https://gitee.com/dromara/TLog" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/tlog2.png" alt="一个轻量级的分布式日志标记追踪神器,10分钟即可接入,自动对日志打标签完成微服务的链路追踪" width="15%">
</a>
<a href="https://gitee.com/dromara/liteFlow" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/liteflow.png" alt="轻量,快速,稳定,可编排的组件式流程引擎" width="15%">
</a>
<a href="https://hutool.cn/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/hutool.jpg" alt="小而全的Java工具类库,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。" width="15%">
</a>
<a href="https://sa-token.dev33.cn/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/sa-token.png" alt="一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!" width="15%">
</a>
<a href="https://gitee.com/dromara/hmily" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/hmily.png" alt="高性能一站式分布式事务解决方案。" width="15%">
</a>
<a href="https://gitee.com/dromara/Raincat" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/raincat.png" alt="强一致性分布式事务解决方案。" width="15%">
</a>
</p>
<p align="center">
<a href="https://gitee.com/dromara/myth" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/myth.png" alt="可靠消息分布式事务解决方案。" width="15%">
</a>
<a href="https://cubic.jiagoujishu.com/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/cubic.png" alt="一站式问题定位平台,以agent的方式无侵入接入应用,完整集成arthas功能模块,致力于应用级监控,帮助开发人员快速定位问题" width="15%">
</a>
<a href="https://maxkey.top/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/maxkey.png" alt="业界领先的身份管理和认证产品" width="15%">
</a>
<a href="http://forest.dtflyx.com/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/forest-logo.png" alt="Forest能够帮助您使用更简单的方式编写Java的HTTP客户端" width="15%">
</a>
<a href="https://jpom.io/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/jpom.png" alt="一款简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件" width="15%">
</a>
<a href="https://su.usthe.com/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/sureness.png" alt="面向 REST API 的高性能认证鉴权框架" width="15%">
</a>
</p>
<p align="center">
<a href="https://easy-es.cn/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/easy-es2.png" alt="傻瓜级ElasticSearch搜索引擎ORM框架" width="15%">
</a>
<a href="https://gitee.com/dromara/northstar" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/northstar_logo.png" alt="Northstar盈富量化交易平台" width="15%">
</a>
<a href="https://hertzbeat.com/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/hertzbeat_brand.jpg" alt="易用友好的云监控系统" width="15%">
</a>
<a href="https://plugins.sheng90.wang/fast-request/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/fast-request.gif" alt="Idea 版 Postman,为简化调试API而生" width="15%">
</a>
<a href="https://www.jeesuite.com/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/mendmix.png" alt="开源分布式云原生架构一站式解决方案" width="15%">
</a>
<a href="https://gitee.com/dromara/koalas-rpc" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/koalas-rpc2.png" alt="企业生产级百亿日PV高可用可拓展的RPC框架。" width="15%">
</a>
</p>
<p align="center">
<a href="https://async.sizegang.cn/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/gobrs-async.png" alt="配置极简功能强大的异步任务动态编排框架" width="15%">
</a>
<a href="https://dynamictp.cn/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/dynamic-tp.png" alt="基于配置中心的轻量级动态可监控线程池" width="15%">
</a>
<a href="https://www.x-easypdf.cn" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/x-easypdf.png" alt="一个用搭积木的方式构建pdf的框架(基于pdfbox" width="15%">
</a>
<a href="http://dromara.gitee.io/image-combiner" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/image-combiner.png" alt="一个专门用于图片合成的工具,没有很复杂的功能,简单实用,却不失强大" width="15%">
</a>
<a href="https://www.herodotus.cn/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/dante-cloud2.png" alt="Dante-Cloud 是一款企业级微服务架构和服务能力开发平台。" width="15%">
</a>
<a href="https://dromara.org/zh/projects/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/dromara.png" alt="让每一位开源爱好者,体会到开源的快乐。" width="15%">
</a>
</p>
+39
View File
@@ -0,0 +1,39 @@
<?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>
<parent>
<groupId>org.noear</groupId>
<artifactId>solon-parent</artifactId>
<version>2.2.2</version>
</parent>
<groupId>fun.asgc</groupId>
<artifactId>job-solon-plugin</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--quartz-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.1</version>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>5.8.15</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,34 @@
package fun.asgc.solon.extend.job;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
*
* @author: aoshiguchen
* @date: 2022/9/4
*/
public class CustomThreadFactory implements ThreadFactory {
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
public CustomThreadFactory(String prefix) {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = prefix + "-thread-";
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
if (t.isDaemon()) {
t.setDaemon(false);
}
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
}
@@ -0,0 +1,17 @@
package fun.asgc.solon.extend.job;
/**
*
* @author: aoshiguchen
* @date: 2022/9/4
*/
public interface IJobCallback {
/**
* 执行日志
* @param jobInfo
* @param param
* @param throwable
*/
void executeLog(JobInfo jobInfo, String param, Throwable throwable);
}
@@ -0,0 +1,34 @@
package fun.asgc.solon.extend.job;
/**
*
* @author: aoshiguchen
* @date: 2022/9/4
*/
public interface IJobExecutor {
/**
* 初始化
* @throws JobException
*/
void init() throws Exception;
/**
* 新增job
* @param jobInfo
*/
void add(JobInfo jobInfo);
/**
* 删除job
* @param jobName
*/
void remove(String jobName);
/**
* 触发
* @param jobName
* @param param
*/
void trigger(String jobName, String param);
}
@@ -0,0 +1,16 @@
package fun.asgc.solon.extend.job;
/**
* @author: aoshiguchen
* @date: 2022/9/4
*/
public interface IJobHandler {
/**
* job执行
* @param param
* @throws Exception
*/
void execute(String param) throws Exception;
}
@@ -0,0 +1,17 @@
package fun.asgc.solon.extend.job;
import java.util.List;
/**
*
* @author: aoshiguchen
* @date: 2022/9/4
*/
public interface IJobSource {
/**
* 获取所有job列表
* @return
*/
List<JobInfo> sourceList();
}
@@ -0,0 +1,26 @@
package fun.asgc.solon.extend.job;
import fun.asgc.solon.extend.job.impl.JobExecutor;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.Solon;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
*
* @author: aoshiguchen
* @date: 2022/9/4
*/
@Slf4j
public class JobBean implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
JobExecutor jobExecutor = Solon.context().getBean(JobExecutor.class);
if (null != jobExecutor) {
jobExecutor.execute(jobExecutionContext);
}
}
}
@@ -0,0 +1,23 @@
package fun.asgc.solon.extend.job;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Map;
/**
*
* @author: aoshiguchen
* @date: 2022/9/4
*/
@Accessors(chain = true)
@Data
public class JobInfo {
private String id;
private String name;
private String desc;
private String cron;
private String param;
private boolean enable;
private Map<String, Object> extension;
}
@@ -0,0 +1,45 @@
package fun.asgc.solon.extend.job;
import fun.asgc.solon.extend.job.annotation.EnableJob;
import fun.asgc.solon.extend.job.impl.DefaultJobCallback;
import fun.asgc.solon.extend.job.impl.DefaultJobSource;
import fun.asgc.solon.extend.job.impl.JobExecutor;
import org.noear.solon.Solon;
import org.noear.solon.core.AopContext;
import org.noear.solon.core.Plugin;
import org.noear.solon.core.event.AppLoadEndEvent;
/**
* @author: aoshiguchen
* @date: 2023/3/11
*/
public class XPluginImp implements Plugin {
@Override
public void start(AopContext context) throws Throwable {
EnableJob enableJob = Solon.app().source().getAnnotation(EnableJob.class);
if (null == enableJob || !enableJob.value()) {
return;
}
//应用加载完后,再启动任务
Solon.app().onEvent(AppLoadEndEvent.class, e -> {
IJobSource jobSource = context.getBean(IJobSource.class);
IJobCallback jobCallback = context.getBean(IJobCallback.class);
if (null == jobSource) {
jobSource = new DefaultJobSource();
}
if (null == jobCallback) {
jobCallback = new DefaultJobCallback();
}
JobExecutor jobExecutor = new JobExecutor();
jobExecutor.setJobSource(jobSource);
jobExecutor.setJobCallback(jobCallback);
jobExecutor.start();
context.wrapAndPut(JobExecutor.class, jobExecutor);
});
}
}
@@ -0,0 +1,16 @@
package fun.asgc.solon.extend.job.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author: aoshiguchen
* @date: 2023/3/12
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableJob {
boolean value() default true;
}
@@ -0,0 +1,20 @@
package fun.asgc.solon.extend.job.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @author: aoshiguchen
* @date: 2022/9/4
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface JobHandler {
String name();
String desc() default "";
String cron();
String param() default "";
}
@@ -0,0 +1,23 @@
package fun.asgc.solon.extend.job.impl;
import fun.asgc.solon.extend.job.IJobCallback;
import fun.asgc.solon.extend.job.JobInfo;
import lombok.extern.slf4j.Slf4j;
/**
* @author: aoshiguchen
* @date: 2023/3/12
*/
@Slf4j
public class DefaultJobCallback implements IJobCallback {
@Override
public void executeLog(JobInfo jobInfo, String param, Throwable throwable) {
if (null == throwable) {
log.debug("[Solon Plugin Job] Job执行 id:{} name:{} desc:{} param:{}", jobInfo.getId(), jobInfo.getName(), jobInfo.getDesc(), param);
} else {
log.error("[Solon Plugin Job] Job执行 id:{} name:{} desc:{} param:{}", jobInfo.getId(), jobInfo.getName(), jobInfo.getDesc(), param, throwable);
}
}
}
@@ -0,0 +1,44 @@
package fun.asgc.solon.extend.job.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import fun.asgc.solon.extend.job.IJobHandler;
import fun.asgc.solon.extend.job.IJobSource;
import fun.asgc.solon.extend.job.annotation.JobHandler;
import fun.asgc.solon.extend.job.JobInfo;
import org.noear.solon.Solon;
import java.util.List;
/**
*
* @author: aoshiguchen
* @date: 2022/9/4
*/
public class DefaultJobSource implements IJobSource {
@Override
public List<JobInfo> sourceList() {
List<IJobHandler> jobHandlerList = Solon.context().getBeansOfType(IJobHandler.class);
if (CollectionUtil.isEmpty(jobHandlerList)) {
return CollectionUtil.newArrayList();
}
List<JobInfo> jobInfoList = CollectionUtil.newArrayList();
for (IJobHandler jobHandler : jobHandlerList) {
JobHandler handler = jobHandler.getClass().getAnnotation(JobHandler.class);
if (null == handler || StrUtil.isEmpty(handler.name()) || StrUtil.isEmpty(handler.cron())) {
continue;
}
jobInfoList.add(new JobInfo()
.setId(handler.name())
.setName(handler.name())
.setDesc(handler.desc())
.setCron(handler.cron())
.setParam(handler.param())
.setEnable(true)
);
}
return jobInfoList;
}
}
@@ -0,0 +1,175 @@
package fun.asgc.solon.extend.job.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import fun.asgc.solon.extend.job.*;
import fun.asgc.solon.extend.job.annotation.JobHandler;
import org.noear.solon.Solon;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Job执行器
* @author: aoshiguchen
* @date: 2022/9/4
*/
public class JobExecutor implements IJobExecutor {
private IJobSource jobSource;
private ThreadPoolExecutor threadPoolExecutor;
private Map<String, JobInfo> jobInfoMap = new ConcurrentHashMap<>();
private SchedulerFactory schedulerFactory;
private Scheduler scheduler;
private Map<String, IJobHandler> jobHandlerMap = new ConcurrentHashMap<>();
private Set<String> runJobSet = CollectionUtil.newHashSet();
private IJobCallback jobCallback;
private Map<String, TriggerKey> triggerKeyMap = new ConcurrentHashMap<>();
public void start() {
if (null == threadPoolExecutor) {
threadPoolExecutor = new ThreadPoolExecutor(5, 20, 10L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(), new CustomThreadFactory("SolonJob"));
}
List<IJobHandler> jobHandlerList = Solon.context().getBeansOfType(IJobHandler.class);
if (!CollectionUtil.isEmpty(jobHandlerList)) {
for (IJobHandler item : jobHandlerList) {
JobHandler jobHandler = item.getClass().getAnnotation(JobHandler.class);
if (null == jobHandler) {
continue;
}
jobHandlerMap.put(jobHandler.name(), item);
}
}
try {
this.schedulerFactory = new StdSchedulerFactory();
this.scheduler = schedulerFactory.getScheduler();
this.init();
} catch (Exception e){
throw new RuntimeException("job初始化异常");
}
}
public void setJobSource(IJobSource jobSource) {
this.jobSource = jobSource;
}
public void setThreadPoolExecutor(ThreadPoolExecutor threadPoolExecutor) {
this.threadPoolExecutor = threadPoolExecutor;
}
public void setJobCallback(IJobCallback jobCallback) {
this.jobCallback = jobCallback;
}
@Override
public void init() throws Exception {
List<JobInfo> jobInfoList = jobSource.sourceList();
if (CollectionUtil.isEmpty(jobInfoList)) {
return;
}
for (JobInfo jobInfo : jobInfoList) {
add(jobInfo);
}
}
@Override
public void add(JobInfo jobInfo) {
if (null == jobInfo || StrUtil.isEmpty(jobInfo.getId()) || StrUtil.isEmpty(jobInfo.getName()) ||
StrUtil.isEmpty(jobInfo.getCron())) {
return;
}
synchronized (jobInfo.getId()) {
runJobSet.add(jobInfo.getName());
jobInfoMap.put(jobInfo.getId(), jobInfo);
TriggerKey triggerKey = TriggerKey.triggerKey(jobInfo.getId());
triggerKeyMap.put(jobInfo.getId(), triggerKey);
JobKey jobKey = new JobKey(jobInfo.getName());
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobInfo.getCron()).withMisfireHandlingInstructionDoNothing();
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
JobDetail jobDetail = JobBuilder.newJob(JobBean.class).withIdentity(jobKey).build();
try {
if (jobInfo.isEnable()) {
scheduler.scheduleJob(jobDetail, cronTrigger);
scheduler.start();
}
} catch (Exception e) {
throw new RuntimeException(String.format("新增job[name=%s]异常", jobInfo.getName()));
}
}
}
@Override
public void remove(String jobId) {
JobInfo jobInfo = jobInfoMap.get(jobId);
if (null == jobInfo) {
return;
}
synchronized (jobId) {
runJobSet.remove(jobInfo.getName());
unscheduleJob(jobId);
}
}
@Override
public void trigger(String jobId, String param) {
doExecute(jobId, param);
}
public void execute(JobExecutionContext context) throws JobExecutionException {
if (null == context || null == context.getTrigger()) {
return;
}
String jobId = context.getTrigger().getKey().getName();
JobInfo jobInfo = jobInfoMap.get(jobId);
if (null == jobInfo) {
unscheduleJob(jobId);
return;
}
doExecute(jobId, jobInfo.getParam());
}
private void unscheduleJob(String jobId) {
TriggerKey triggerKey = triggerKeyMap.get(jobId);
if (null != triggerKey) {
try {
scheduler.unscheduleJob(triggerKey);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void doExecute(String jobId, String param) {
JobInfo jobInfo = jobInfoMap.get(jobId);
if (null == jobInfo) {
return;
}
IJobHandler jobHandler =jobHandlerMap.get(jobInfo.getName());
if (null == jobHandler) {
return;
}
threadPoolExecutor.submit(() -> {
try {
jobHandler.execute(param);
if (null != jobCallback) {
jobCallback.executeLog(jobInfo, param, null);
}
} catch (Throwable e) {
jobCallback.executeLog(jobInfo, param, e);
}
});
}
}
@@ -0,0 +1 @@
package fun.asgc.solon.extend.job;
@@ -0,0 +1,2 @@
solon.plugin=fun.asgc.solon.extend.job.XPluginImp
solon.plugin.priority=2
+30
View File
@@ -0,0 +1,30 @@
<?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>
<parent>
<groupId>org.noear</groupId>
<artifactId>solon-parent</artifactId>
<version>2.2.2</version>
</parent>
<groupId>fun.asgc</groupId>
<artifactId>orika-solon-plugin</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon</artifactId>
</dependency>
<!--orika-->
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.5.4</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,33 @@
package fun.asgc.solon.extend.orika;
import ma.glasnost.orika.CustomConverter;
import ma.glasnost.orika.Mapper;
import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.ClassMapBuilder;
import org.noear.solon.core.AopContext;
import org.noear.solon.core.Plugin;
/**
* @author: aoshiguchen
* @date: 2023/3/11
*/
public class XPluginImp implements Plugin {
@Override
public void start(AopContext context) throws Throwable {
DefaultMapperFactory factory = new DefaultMapperFactory.Builder().build();
context.subBeansOfType(CustomConverter.class, bean -> {
factory.getConverterFactory().registerConverter(bean);
});
context.subBeansOfType(Mapper.class, bean -> {
factory.registerMapper(bean);
});
context.subBeansOfType(ClassMapBuilder.class, bean -> {
factory.registerClassMap((ClassMapBuilder<? extends Object, ? extends Object>) bean);
});
context.wrapAndPut(MapperFactory.class, factory);
context.wrapAndPut(MapperFacade.class, factory.getMapperFacade());
}
}
@@ -0,0 +1 @@
package fun.asgc.solon.extend.orika;
@@ -0,0 +1,2 @@
solon.plugin=fun.asgc.solon.extend.orika.XPluginImp
solon.plugin.priority=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

+2 -5
View File
@@ -26,21 +26,18 @@
<artifactId>snakeyaml</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.24</version>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.7.2</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -36,4 +36,5 @@ import java.lang.annotation.*;
@NonIntercept
public @interface NeutrinoApplication {
String[] scanBasePackages() default {};
String environmentVariableKey() default "";
}
@@ -22,6 +22,7 @@
package fun.asgc.neutrino.core.aop.compiler;
import com.google.common.collect.Lists;
import fun.asgc.neutrino.core.aop.compiler.internal.SpringBootJarClassLoader;
import fun.asgc.neutrino.core.base.GlobalConfig;
import fun.asgc.neutrino.core.util.CollectionUtil;
import fun.asgc.neutrino.core.util.FileUtil;
@@ -54,6 +55,7 @@ public class AsgcCompiler {
private boolean isSaveClassFile;
private String generatorCodeSavePath;
private DynamicClassLoader dynamicClassLoader;
private SpringBootJarClassLoader springBootJarClassLoader;
private final List<Diagnostic<? extends JavaFileObject>> errors = new ArrayList<Diagnostic<? extends JavaFileObject>>();
private final List<Diagnostic<? extends JavaFileObject>> warnings = new ArrayList<Diagnostic<? extends JavaFileObject>>();
@@ -73,11 +75,22 @@ public class AsgcCompiler {
if (null == javaCompiler) {
throw new RuntimeException("Can not load JavaCompiler from javax.tools.ToolProvider#getSystemJavaCompiler(),\n please confirm the application running in JDK not JRE.");
}
this.springBootJarClassLoader = new SpringBootJarClassLoader(classLoader);
// if (SystemUtil.isStartupFromJar() && GlobalConfig.isIsUseSpringBootJar()) {
// try {
// log.debug("使用LaunchedURLClassLoader jar路径:{}", SystemUtil.getCurrentJarFilePath());
// parent = new SpringBootJarClassLoader(classLoader);
// log.debug("使用LaunchedURLClassLoader instance:{}", parent);
// } catch (Exception e) {
// // ignore
// log.error("使用LaunchedURLClassLoader异常", e);
// }
// }
this.collector = new DiagnosticCollector<>();
this.standardJavaFileManager = javaCompiler.getStandardFileManager(collector, null, null);
this.isSaveClassFile = false;
this.generatorCodeSavePath = GlobalConfig.getGeneratorCodeSavePath();
this.dynamicClassLoader = new DynamicClassLoader(classLoader, this);
this.dynamicClassLoader = new DynamicClassLoader(springBootJarClassLoader, this);
addOption("-Xlint:unchecked");
addOption("-implicit:class");
@@ -169,19 +182,33 @@ public class AsgcCompiler {
compilationUnits.add(javaFileObject);
}
public void addDependSpringBootJar(String path) {
try {
this.springBootJarClassLoader.addJar(path);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 编译代码
* @param pkg 包名
* @param className 类名
* @param sourceCode 源代码
*/
public Class<?> compile(String pkg, String className, String sourceCode) throws ClassNotFoundException {
public Class<?> compile(String className, String sourceCode) throws ClassNotFoundException {
log.info("options:" + getOptions());
int index = className.lastIndexOf(".");
String pkg = "";
String simpleClassName = className;
if (index >= 0) {
pkg = className.substring(0, index);
simpleClassName = className.substring(index + 1);
}
JavaFileManager javaFileManager = new DynamicJavaFileManager(standardJavaFileManager, dynamicClassLoader);
Iterable<? extends JavaFileObject> compilationUnits = Lists.newArrayList(new StringSource(className, sourceCode));
if (GlobalConfig.isSaveGeneratorCode()) {
javaFileManager = standardJavaFileManager;
File file = FileUtil.save(GlobalConfig.getGeneratorCodeSavePath() + pkg.replaceAll("\\.", "/"), className + ".java", sourceCode);
File file = FileUtil.save(GlobalConfig.getGeneratorCodeSavePath() + pkg.replaceAll("\\.", "/"), simpleClassName + ".java", sourceCode);
compilationUnits = standardJavaFileManager.getJavaFileObjects(file);
addClasspath(GlobalConfig.getGeneratorCodeSavePath());
}
@@ -208,7 +235,7 @@ public class AsgcCompiler {
}
}
return dynamicClassLoader.findClass(pkg + "." + className);
return dynamicClassLoader.findClass(className);
}
/**
@@ -1,103 +0,0 @@
package fun.asgc.neutrino.core.aop.compiler.internal;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* A class path index file that provides ordering information for JARs.
*
* @author Madhura Bhave
* @author Phillip Webb
*/
final class ClassPathIndexFile {
private final File root;
private final List<String> lines;
private ClassPathIndexFile(File root, List<String> lines) {
this.root = root;
this.lines = lines.stream().map(this::extractName).collect(Collectors.toList());
}
private String extractName(String line) {
if (line.startsWith("- \"") && line.endsWith("\"")) {
return line.substring(3, line.length() - 1);
}
throw new IllegalStateException("Malformed classpath index line [" + line + "]");
}
int size() {
return this.lines.size();
}
boolean containsEntry(String name) {
if (name == null || name.isEmpty()) {
return false;
}
return this.lines.contains(name);
}
List<URL> getUrls() {
return this.lines.stream().map(this::asUrl).collect(Collectors.toList());
}
private URL asUrl(String line) {
try {
return new File(this.root, line).toURI().toURL();
}
catch (MalformedURLException ex) {
throw new IllegalStateException(ex);
}
}
static ClassPathIndexFile loadIfPossible(URL root, String location) throws IOException {
return loadIfPossible(asFile(root), location);
}
private static ClassPathIndexFile loadIfPossible(File root, String location) throws IOException {
return loadIfPossible(root, new File(root, location));
}
private static ClassPathIndexFile loadIfPossible(File root, File indexFile) throws IOException {
if (indexFile.exists() && indexFile.isFile()) {
try (InputStream inputStream = new FileInputStream(indexFile)) {
return new ClassPathIndexFile(root, loadLines(inputStream));
}
}
return null;
}
private static List<String> loadLines(InputStream inputStream) throws IOException {
List<String> lines = new ArrayList<>();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
String line = reader.readLine();
while (line != null) {
if (!line.trim().isEmpty()) {
lines.add(line);
}
line = reader.readLine();
}
return Collections.unmodifiableList(lines);
}
private static File asFile(URL url) {
if (!"file".equals(url.getProtocol())) {
throw new IllegalArgumentException("URL does not reference a file");
}
try {
return new File(url.toURI());
}
catch (URISyntaxException ex) {
return new File(url.getPath());
}
}
}
@@ -1,199 +0,0 @@
package fun.asgc.neutrino.core.aop.compiler.internal;
import fun.asgc.neutrino.core.aop.compiler.internal.archive.Archive;
import fun.asgc.neutrino.core.aop.compiler.internal.archive.ExplodedArchive;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
/**
* Base class for executable archive {@link Launcher}s.
*
* @author Phillip Webb
* @author Andy Wilkinson
* @author Madhura Bhave
* @author Scott Frederick
* @since 1.0.0
*/
public abstract class ExecutableArchiveLauncher extends Launcher {
private static final String START_CLASS_ATTRIBUTE = "Start-Class";
protected static final String BOOT_CLASSPATH_INDEX_ATTRIBUTE = "Spring-Boot-Classpath-Index";
protected static final String DEFAULT_CLASSPATH_INDEX_FILE_NAME = "classpath.idx";
private Archive archive;
private ClassPathIndexFile classPathIndex;
public ExecutableArchiveLauncher() {
try {
this.archive = createArchive();
this.classPathIndex = getClassPathIndex(this.archive);
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
protected ExecutableArchiveLauncher(Archive archive) {
try {
this.archive = archive;
this.classPathIndex = getClassPathIndex(this.archive);
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
protected ClassPathIndexFile getClassPathIndex(Archive archive) throws IOException {
// Only needed for exploded archives, regular ones already have a defined order
if (archive instanceof ExplodedArchive) {
String location = getClassPathIndexFileLocation(archive);
return ClassPathIndexFile.loadIfPossible(archive.getUrl(), location);
}
return null;
}
private String getClassPathIndexFileLocation(Archive archive) throws IOException {
Manifest manifest = archive.getManifest();
Attributes attributes = (manifest != null) ? manifest.getMainAttributes() : null;
String location = (attributes != null) ? attributes.getValue(BOOT_CLASSPATH_INDEX_ATTRIBUTE) : null;
return (location != null) ? location : getArchiveEntryPathPrefix() + DEFAULT_CLASSPATH_INDEX_FILE_NAME;
}
@Override
protected String getMainClass() throws Exception {
Manifest manifest = this.archive.getManifest();
String mainClass = null;
if (manifest != null) {
mainClass = manifest.getMainAttributes().getValue(START_CLASS_ATTRIBUTE);
}
if (mainClass == null) {
throw new IllegalStateException("No 'Start-Class' manifest entry specified in " + this);
}
return mainClass;
}
@Override
protected ClassLoader createClassLoader(Iterator<Archive> archives) throws Exception {
List<URL> urls = new ArrayList<>(guessClassPathSize());
while (archives.hasNext()) {
urls.add(archives.next().getUrl());
}
if (this.classPathIndex != null) {
urls.addAll(this.classPathIndex.getUrls());
}
return createClassLoader(urls.toArray(new URL[0]));
}
private int guessClassPathSize() {
if (this.classPathIndex != null) {
return this.classPathIndex.size() + 10;
}
return 50;
}
@Override
protected Iterator<Archive> getClassPathArchivesIterator() throws Exception {
Archive.EntryFilter searchFilter = this::isSearchCandidate;
Iterator<Archive> archives = this.archive.getNestedArchives(searchFilter,
(entry) -> isNestedArchive(entry) && !isEntryIndexed(entry));
if (isPostProcessingClassPathArchives()) {
archives = applyClassPathArchivePostProcessing(archives);
}
return archives;
}
private boolean isEntryIndexed(Archive.Entry entry) {
if (this.classPathIndex != null) {
return this.classPathIndex.containsEntry(entry.getName());
}
return false;
}
private Iterator<Archive> applyClassPathArchivePostProcessing(Iterator<Archive> archives) throws Exception {
List<Archive> list = new ArrayList<>();
while (archives.hasNext()) {
list.add(archives.next());
}
postProcessClassPathArchives(list);
return list.iterator();
}
/**
* Determine if the specified entry is a candidate for further searching.
* @param entry the entry to check
* @return {@code true} if the entry is a candidate for further searching
* @since 2.3.0
*/
protected boolean isSearchCandidate(Archive.Entry entry) {
if (getArchiveEntryPathPrefix() == null) {
return true;
}
return entry.getName().startsWith(getArchiveEntryPathPrefix());
}
/**
* Determine if the specified entry is a nested item that should be added to the
* classpath.
* @param entry the entry to check
* @return {@code true} if the entry is a nested item (jar or directory)
*/
protected abstract boolean isNestedArchive(Archive.Entry entry);
/**
* Return if post-processing needs to be applied to the archives. For back
* compatibility this method returns {@code true}, but subclasses that don't override
* {@link #postProcessClassPathArchives(List)} should provide an implementation that
* returns {@code false}.
* @return if the {@link #postProcessClassPathArchives(List)} method is implemented
* @since 2.3.0
*/
protected boolean isPostProcessingClassPathArchives() {
return true;
}
/**
* Called to post-process archive entries before they are used. Implementations can
* add and remove entries.
* @param archives the archives
* @throws Exception if the post-processing fails
* @see #isPostProcessingClassPathArchives()
*/
protected void postProcessClassPathArchives(List<Archive> archives) throws Exception {
}
/**
* Return the path prefix for entries in the archive.
* @return the path prefix
*/
protected String getArchiveEntryPathPrefix() {
return null;
}
@Override
protected boolean isExploded() {
return this.archive.isExploded();
}
@Override
protected final Archive getArchive() {
return this.archive;
}
protected void setArchive(Archive archive) {
this.archive = archive;
}
protected void setClassPathIndex(ClassPathIndexFile classPathIndex) {
this.classPathIndex = classPathIndex;
}
}
@@ -1,88 +0,0 @@
package fun.asgc.neutrino.core.aop.compiler.internal;
import fun.asgc.neutrino.core.aop.compiler.internal.archive.Archive;
import fun.asgc.neutrino.core.aop.compiler.internal.archive.ExplodedArchive;
import fun.asgc.neutrino.core.aop.compiler.internal.archive.JarFileArchive;
import java.io.File;
/**
* {@link Launcher} for JAR based archives. This launcher assumes that dependency jars are
* included inside a {@code /BOOT-INF/lib} directory and that application classes are
* included inside a {@code /BOOT-INF/classes} directory.
*
* @author Phillip Webb
* @author Andy Wilkinson
* @author Madhura Bhave
* @author Scott Frederick
* @since 1.0.0
*/
public class JarLauncher extends ExecutableArchiveLauncher {
private String path;
static final Archive.EntryFilter NESTED_ARCHIVE_ENTRY_FILTER = (entry) -> {
if (entry.isDirectory()) {
return entry.getName().equals("BOOT-INF/classes/");
}
return entry.getName().startsWith("BOOT-INF/lib/");
};
public JarLauncher(String path) {
this.path = path;
try {
this.setArchive(createArchive(this.path));
this.setClassPathIndex(getClassPathIndex(this.getArchive()));
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
public JarLauncher(ClassLoader classLoader, String path) {
this.path = path;
try {
this.setArchive(createArchive(this.path));
this.setClassPathIndex(getClassPathIndex(this.getArchive()));
this.setClassLoader(classLoader);
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
public ClassLoader createClassLoader() throws Exception {
return createClassLoader(getClassPathArchivesIterator());
}
protected final Archive createArchive(String path) throws Exception {
if (path == null) {
throw new IllegalStateException("Unable to determine code source archive");
}
File root = new File(path);
if (!root.exists()) {
throw new IllegalStateException("Unable to determine code source archive from " + root);
}
return (root.isDirectory() ? new ExplodedArchive(root) : new JarFileArchive(root));
}
protected JarLauncher(Archive archive) {
super(archive);
}
@Override
protected boolean isPostProcessingClassPathArchives() {
return false;
}
@Override
protected boolean isNestedArchive(Archive.Entry entry) {
return NESTED_ARCHIVE_ENTRY_FILTER.matches(entry);
}
@Override
protected String getArchiveEntryPathPrefix() {
return "BOOT-INF/";
}
}
@@ -1,354 +0,0 @@
package fun.asgc.neutrino.core.aop.compiler.internal;
import fun.asgc.neutrino.core.aop.compiler.internal.archive.Archive;
import fun.asgc.neutrino.core.aop.compiler.internal.jar.Handler;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.function.Supplier;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
/**
* {@link ClassLoader} used by the {@link Launcher}.
*
* @author Phillip Webb
* @author Dave Syer
* @author Andy Wilkinson
* @since 1.0.0
*/
public class LaunchedURLClassLoader extends URLClassLoader {
private static final int BUFFER_SIZE = 4096;
static {
ClassLoader.registerAsParallelCapable();
}
private final boolean exploded;
private final Archive rootArchive;
private final Object packageLock = new Object();
private volatile DefinePackageCallType definePackageCallType;
/**
* Create a new {@link LaunchedURLClassLoader} instance.
* @param urls the URLs from which to load classes and resources
* @param parent the parent class loader for delegation
*/
public LaunchedURLClassLoader(URL[] urls, ClassLoader parent) {
this(false, urls, parent);
}
/**
* Create a new {@link LaunchedURLClassLoader} instance.
* @param exploded if the underlying archive is exploded
* @param urls the URLs from which to load classes and resources
* @param parent the parent class loader for delegation
*/
public LaunchedURLClassLoader(boolean exploded, URL[] urls, ClassLoader parent) {
this(exploded, null, urls, parent);
}
/**
* Create a new {@link LaunchedURLClassLoader} instance.
* @param exploded if the underlying archive is exploded
* @param rootArchive the root archive or {@code null}
* @param urls the URLs from which to load classes and resources
* @param parent the parent class loader for delegation
* @since 2.3.1
*/
public LaunchedURLClassLoader(boolean exploded, Archive rootArchive, URL[] urls, ClassLoader parent) {
super(urls, parent);
this.exploded = exploded;
this.rootArchive = rootArchive;
}
@Override
public URL findResource(String name) {
if (this.exploded) {
return super.findResource(name);
}
Handler.setUseFastConnectionExceptions(true);
try {
return super.findResource(name);
}
finally {
Handler.setUseFastConnectionExceptions(false);
}
}
@Override
public Enumeration<URL> findResources(String name) throws IOException {
if (this.exploded) {
return super.findResources(name);
}
Handler.setUseFastConnectionExceptions(true);
try {
return new UseFastConnectionExceptionsEnumeration(super.findResources(name));
}
finally {
Handler.setUseFastConnectionExceptions(false);
}
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (name.startsWith("org.springframework.boot.loader.jarmode.")) {
try {
Class<?> result = loadClassInLaunchedClassLoader(name);
if (resolve) {
resolveClass(result);
}
return result;
}
catch (ClassNotFoundException ex) {
}
}
if (this.exploded) {
return super.loadClass(name, resolve);
}
Handler.setUseFastConnectionExceptions(true);
try {
try {
definePackageIfNecessary(name);
}
catch (IllegalArgumentException ex) {
// Tolerate race condition due to being parallel capable
// if (getDefinedPackage(name) == null) {
// // This should never happen as the IllegalArgumentException indicates
// // that the package has already been defined and, therefore,
// // getDefinedPackage(name) should not return null.
// throw new AssertionError("Package " + name + " has already been defined but it could not be found");
// }
}
return super.loadClass(name, resolve);
}
finally {
Handler.setUseFastConnectionExceptions(false);
}
}
public void addURL(URL url) {
addURL(url);
}
private Class<?> loadClassInLaunchedClassLoader(String name) throws ClassNotFoundException {
String internalName = name.replace('.', '/') + ".class";
InputStream inputStream = getParent().getResourceAsStream(internalName);
if (inputStream == null) {
throw new ClassNotFoundException(name);
}
try {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
inputStream.close();
byte[] bytes = outputStream.toByteArray();
Class<?> definedClass = defineClass(name, bytes, 0, bytes.length);
definePackageIfNecessary(name);
return definedClass;
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new ClassNotFoundException("Cannot load resource for class [" + name + "]", ex);
}
}
/**
* Define a package before a {@code findClass} call is made. This is necessary to
* ensure that the appropriate manifest for nested JARs is associated with the
* package.
* @param className the class name being found
*/
private void definePackageIfNecessary(String className) {
int lastDot = className.lastIndexOf('.');
if (lastDot >= 0) {
String packageName = className.substring(0, lastDot);
// if (getDefinedPackage(packageName) == null) {
try {
definePackage(className, packageName);
}
catch (IllegalArgumentException ex) {
// Tolerate race condition due to being parallel capable
// if (getDefinedPackage(packageName) == null) {
// // This should never happen as the IllegalArgumentException
// // indicates that the package has already been defined and,
// // therefore, getDefinedPackage(name) should not have returned
// // null.
// throw new AssertionError(
// "Package " + packageName + " has already been defined but it could not be found");
// }
}
// }
}
}
private void definePackage(String className, String packageName) {
String packageEntryName = packageName.replace('.', '/') + "/";
String classEntryName = className.replace('.', '/') + ".class";
for (URL url : getURLs()) {
try {
URLConnection connection = url.openConnection();
if (connection instanceof JarURLConnection) {
JarFile jarFile = ((JarURLConnection)connection).getJarFile();
if (jarFile.getEntry(classEntryName) != null && jarFile.getEntry(packageEntryName) != null
&& jarFile.getManifest() != null) {
definePackage(packageName, jarFile.getManifest(), url);
return;
}
}
}
catch (IOException ex) {
// Ignore
}
}
}
@Override
protected Package definePackage(String name, Manifest man, URL url) throws IllegalArgumentException {
if (!this.exploded) {
return super.definePackage(name, man, url);
}
synchronized (this.packageLock) {
return doDefinePackage(DefinePackageCallType.MANIFEST, () -> super.definePackage(name, man, url));
}
}
@Override
protected Package definePackage(String name, String specTitle, String specVersion, String specVendor,
String implTitle, String implVersion, String implVendor, URL sealBase) throws IllegalArgumentException {
if (!this.exploded) {
return super.definePackage(name, specTitle, specVersion, specVendor, implTitle, implVersion, implVendor,
sealBase);
}
synchronized (this.packageLock) {
if (this.definePackageCallType == null) {
// We're not part of a call chain which means that the URLClassLoader
// is trying to define a package for our exploded JAR. We use the
// manifest version to ensure package attributes are set
Manifest manifest = getManifest(this.rootArchive);
if (manifest != null) {
return definePackage(name, manifest, sealBase);
}
}
return doDefinePackage(DefinePackageCallType.ATTRIBUTES, () -> super.definePackage(name, specTitle,
specVersion, specVendor, implTitle, implVersion, implVendor, sealBase));
}
}
private Manifest getManifest(Archive archive) {
try {
return (archive != null) ? archive.getManifest() : null;
}
catch (IOException ex) {
return null;
}
}
private <T> T doDefinePackage(DefinePackageCallType type, Supplier<T> call) {
DefinePackageCallType existingType = this.definePackageCallType;
try {
this.definePackageCallType = type;
return call.get();
}
finally {
this.definePackageCallType = existingType;
}
}
/**
* Clear URL caches.
*/
public void clearCache() {
if (this.exploded) {
return;
}
for (URL url : getURLs()) {
try {
URLConnection connection = url.openConnection();
if (connection instanceof JarURLConnection) {
clearCache(connection);
}
}
catch (IOException ex) {
// Ignore
}
}
}
private void clearCache(URLConnection connection) throws IOException {
Object jarFile = ((JarURLConnection) connection).getJarFile();
if (jarFile instanceof fun.asgc.neutrino.core.aop.compiler.internal.jar.JarFile) {
((fun.asgc.neutrino.core.aop.compiler.internal.jar.JarFile) jarFile).clearCache();
}
}
private static class UseFastConnectionExceptionsEnumeration implements Enumeration<URL> {
private final Enumeration<URL> delegate;
UseFastConnectionExceptionsEnumeration(Enumeration<URL> delegate) {
this.delegate = delegate;
}
@Override
public boolean hasMoreElements() {
Handler.setUseFastConnectionExceptions(true);
try {
return this.delegate.hasMoreElements();
}
finally {
Handler.setUseFastConnectionExceptions(false);
}
}
@Override
public URL nextElement() {
Handler.setUseFastConnectionExceptions(true);
try {
return this.delegate.nextElement();
}
finally {
Handler.setUseFastConnectionExceptions(false);
}
}
}
/**
* The different types of call made to define a package. We track these for exploded
* jars so that we can detect packages that should have manifest attributes applied.
*/
private enum DefinePackageCallType {
/**
* A define package call from a resource that has a manifest.
*/
MANIFEST,
/**
* A define package call with a direct set of attributes.
*/
ATTRIBUTES
}
}
@@ -1,109 +0,0 @@
package fun.asgc.neutrino.core.aop.compiler.internal;
import fun.asgc.neutrino.core.aop.compiler.internal.archive.Archive;
import fun.asgc.neutrino.core.aop.compiler.internal.archive.ExplodedArchive;
import fun.asgc.neutrino.core.aop.compiler.internal.archive.JarFileArchive;
import java.io.File;
import java.net.URI;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Base class for launchers that can start an application with a fully configured
* classpath backed by one or more {@link Archive}s.
*
* @author Phillip Webb
* @author Dave Syer
* @since 1.0.0
*/
public abstract class Launcher {
private ClassLoader classLoader;
/**
* Create a classloader for the specified archives.
* @param archives the archives
* @return the classloader
* @throws Exception if the classloader cannot be created
* @since 2.3.0
*/
protected ClassLoader createClassLoader(Iterator<Archive> archives) throws Exception {
List<URL> urls = new ArrayList<>(50);
while (archives.hasNext()) {
urls.add(archives.next().getUrl());
}
return createClassLoader(urls.toArray(new URL[0]));
}
/**
* Create a classloader for the specified URLs.
* @param urls the URLs
* @return the classloader
* @throws Exception if the classloader cannot be created
*/
protected ClassLoader createClassLoader(URL[] urls) throws Exception {
return new LaunchedURLClassLoader(isExploded(),
getArchive(),
urls,
(null == classLoader) ? getClass().getClassLoader() : classLoader);
}
/**
* Returns the main class that should be launched.
* @return the name of the main class
* @throws Exception if the main class cannot be obtained
*/
protected abstract String getMainClass() throws Exception;
/**
* Returns the archives that will be used to construct the class path.
* @return the class path archives
* @throws Exception if the class path archives cannot be obtained
* @since 2.3.0
*/
protected abstract Iterator<Archive> getClassPathArchivesIterator() throws Exception;
protected final Archive createArchive() throws Exception {
ProtectionDomain protectionDomain = getClass().getProtectionDomain();
CodeSource codeSource = protectionDomain.getCodeSource();
URI location = (codeSource != null) ? codeSource.getLocation().toURI() : null;
String path = (location != null) ? location.getSchemeSpecificPart() : null;
if (path == null) {
throw new IllegalStateException("Unable to determine code source archive");
}
File root = new File(path);
if (!root.exists()) {
throw new IllegalStateException("Unable to determine code source archive from " + root);
}
return (root.isDirectory() ? new ExplodedArchive(root) : new JarFileArchive(root));
}
/**
* Returns if the launcher is running in an exploded mode. If this method returns
* {@code true} then only regular JARs are supported and the additional URL and
* ClassLoader support infrastructure can be optimized.
* @return if the jar is exploded.
* @since 2.3.0
*/
protected boolean isExploded() {
return false;
}
/**
* Return the root archive.
* @return the root archive
* @since 2.3.1
*/
protected Archive getArchive() {
return null;
}
public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
}
@@ -0,0 +1,109 @@
package fun.asgc.neutrino.core.aop.compiler.internal;
import fun.asgc.neutrino.core.aop.compiler.internal.archive.Archive;
import fun.asgc.neutrino.core.aop.compiler.internal.archive.JarFileArchive;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* {@link ClassLoader} used by the {@link Launcher}.
*
* @author Phillip Webb
* @author Dave Syer
* @author Andy Wilkinson
* @since 1.0.0
*/
public class SpringBootJarClassLoader extends URLClassLoader {
protected static final String BOOT_CLASSPATH_INDEX_ATTRIBUTE = "Spring-Boot-Classpath-Index";
protected static final String DEFAULT_CLASSPATH_INDEX_FILE_NAME = "classpath.idx";
static {
ClassLoader.registerAsParallelCapable();
}
/**
* Create a new {@link SpringBootJarClassLoader} instance.
* @param parent the parent class loader for delegation
*/
public SpringBootJarClassLoader(ClassLoader parent) {
super(new URL[0], parent);
}
/**
* Create a new {@link SpringBootJarClassLoader} instance.
*/
public SpringBootJarClassLoader() {
super(new URL[0], ClassLoader.getSystemClassLoader());
}
public void addJar(String path) throws Exception {
Archive archive = createArchive(path);
Iterator<Archive> archives = getClassPathArchivesIterator(archive);
List<URL> urls = new ArrayList<>(50);
while (archives.hasNext()) {
urls.add(archives.next().getUrl());
}
urls.forEach(url -> addURL(url));
}
private Archive createArchive(String path) throws Exception {
if (path == null) {
throw new IllegalStateException("Unable to determine code source archive");
}
File root = new File(path);
if (!root.exists()) {
throw new IllegalStateException("Unable to determine code source archive from " + root);
}
return new JarFileArchive(root);
}
protected Iterator<Archive> getClassPathArchivesIterator(Archive archive) throws Exception {
Archive.EntryFilter searchFilter = this::isSearchCandidate;
Iterator<Archive> archives = archive.getNestedArchives(searchFilter,
(entry) -> isNestedArchive(entry));
archives = applyClassPathArchivePostProcessing(archives);
return archives;
}
private Iterator<Archive> applyClassPathArchivePostProcessing(Iterator<Archive> archives) throws Exception {
List<Archive> list = new ArrayList<>();
while (archives.hasNext()) {
list.add(archives.next());
}
return list.iterator();
}
static final Archive.EntryFilter NESTED_ARCHIVE_ENTRY_FILTER = (entry) -> {
if (entry.isDirectory()) {
return entry.getName().equals("BOOT-INF/classes/");
}
return entry.getName().startsWith("BOOT-INF/lib/");
};
protected boolean isNestedArchive(Archive.Entry entry) {
return NESTED_ARCHIVE_ENTRY_FILTER.matches(entry);
}
/**
* Determine if the specified entry is a candidate for further searching.
* @param entry the entry to check
* @return {@code true} if the entry is a candidate for further searching
* @since 2.3.0
*/
protected boolean isSearchCandidate(Archive.Entry entry) {
if (getArchiveEntryPathPrefix() == null) {
return true;
}
return entry.getName().startsWith(getArchiveEntryPathPrefix());
}
protected String getArchiveEntryPathPrefix() {
return "BOOT-INF/";
}
}
@@ -23,21 +23,25 @@ public final class SpringBootJarParser {
*/
public static InputStream getInputStream(URI uri) {
try {
if (uri.getScheme().equals("jar")) {
URL url = uri.toURL();
String path = url.getPath();
int index = path.indexOf("!");
if (index >= 0) {
path = path.substring(0, index);
return uri.toURL().openStream();
} catch (Exception e) {
try {
if (uri.getScheme().equals("jar")) {
URL url = uri.toURL();
String path = url.getPath();
int index = path.indexOf("!");
if (index >= 0) {
path = path.substring(0, index);
}
if (path.startsWith("file:")) {
path = path.substring(5);
}
JarFile jarFile = new JarFile(new File(path));
return JarURLConnection.get(url, jarFile).getInputStream();
}
if (path.startsWith("file:")) {
path = path.substring(5);
}
JarFile jarFile = new JarFile(new File(path));
return JarURLConnection.get(url, jarFile).getInputStream();
} catch (Exception e1) {
// ignore
}
} catch (Exception e1) {
// ignore
}
return null;
}
@@ -1,216 +0,0 @@
package fun.asgc.neutrino.core.aop.compiler.internal;
import java.util.HashSet;
import java.util.Locale;
import java.util.Properties;
import java.util.Set;
/**
* Helper class for resolving placeholders in texts. Usually applied to file paths.
* <p>
* A text may contain {@code $ ...} placeholders, to be resolved as system properties:
* e.g. {@code $ user.dir}. Default values can be supplied using the ":" separator between
* key and value.
* <p>
* Adapted from Spring.
*
* @author Juergen Hoeller
* @author Rob Harrop
* @author Dave Syer
* @since 1.0.0
* @see System#getProperty(String)
*/
public abstract class SystemPropertyUtils {
/**
* Prefix for system property placeholders: "${".
*/
public static final String PLACEHOLDER_PREFIX = "${";
/**
* Suffix for system property placeholders: "}".
*/
public static final String PLACEHOLDER_SUFFIX = "}";
/**
* Value separator for system property placeholders: ":".
*/
public static final String VALUE_SEPARATOR = ":";
private static final String SIMPLE_PREFIX = PLACEHOLDER_PREFIX.substring(1);
/**
* Resolve ${...} placeholders in the given text, replacing them with corresponding
* system property values.
* @param text the String to resolve
* @return the resolved String
* @throws IllegalArgumentException if there is an unresolvable placeholder
* @see #PLACEHOLDER_PREFIX
* @see #PLACEHOLDER_SUFFIX
*/
public static String resolvePlaceholders(String text) {
if (text == null) {
return text;
}
return parseStringValue(null, text, text, new HashSet<>());
}
/**
* Resolve ${...} placeholders in the given text, replacing them with corresponding
* system property values.
* @param properties a properties instance to use in addition to System
* @param text the String to resolve
* @return the resolved String
* @throws IllegalArgumentException if there is an unresolvable placeholder
* @see #PLACEHOLDER_PREFIX
* @see #PLACEHOLDER_SUFFIX
*/
public static String resolvePlaceholders(Properties properties, String text) {
if (text == null) {
return text;
}
return parseStringValue(properties, text, text, new HashSet<>());
}
private static String parseStringValue(Properties properties, String value, String current,
Set<String> visitedPlaceholders) {
StringBuilder buf = new StringBuilder(current);
int startIndex = current.indexOf(PLACEHOLDER_PREFIX);
while (startIndex != -1) {
int endIndex = findPlaceholderEndIndex(buf, startIndex);
if (endIndex != -1) {
String placeholder = buf.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
String originalPlaceholder = placeholder;
if (!visitedPlaceholders.add(originalPlaceholder)) {
throw new IllegalArgumentException(
"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
}
// Recursive invocation, parsing placeholders contained in the
// placeholder
// key.
placeholder = parseStringValue(properties, value, placeholder, visitedPlaceholders);
// Now obtain the value for the fully resolved key...
String propVal = resolvePlaceholder(properties, value, placeholder);
if (propVal == null) {
int separatorIndex = placeholder.indexOf(VALUE_SEPARATOR);
if (separatorIndex != -1) {
String actualPlaceholder = placeholder.substring(0, separatorIndex);
String defaultValue = placeholder.substring(separatorIndex + VALUE_SEPARATOR.length());
propVal = resolvePlaceholder(properties, value, actualPlaceholder);
if (propVal == null) {
propVal = defaultValue;
}
}
}
if (propVal != null) {
// Recursive invocation, parsing placeholders contained in the
// previously resolved placeholder value.
propVal = parseStringValue(properties, value, propVal, visitedPlaceholders);
buf.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), propVal);
startIndex = buf.indexOf(PLACEHOLDER_PREFIX, startIndex + propVal.length());
}
else {
// Proceed with unprocessed value.
startIndex = buf.indexOf(PLACEHOLDER_PREFIX, endIndex + PLACEHOLDER_SUFFIX.length());
}
visitedPlaceholders.remove(originalPlaceholder);
}
else {
startIndex = -1;
}
}
return buf.toString();
}
private static String resolvePlaceholder(Properties properties, String text, String placeholderName) {
String propVal = getProperty(placeholderName, null, text);
if (propVal != null) {
return propVal;
}
return (properties != null) ? properties.getProperty(placeholderName) : null;
}
public static String getProperty(String key) {
return getProperty(key, null, "");
}
public static String getProperty(String key, String defaultValue) {
return getProperty(key, defaultValue, "");
}
/**
* Search the System properties and environment variables for a value with the
* provided key. Environment variables in {@code UPPER_CASE} style are allowed where
* System properties would normally be {@code lower.case}.
* @param key the key to resolve
* @param defaultValue the default value
* @param text optional extra context for an error message if the key resolution fails
* (e.g. if System properties are not accessible)
* @return a static property value or null of not found
*/
public static String getProperty(String key, String defaultValue, String text) {
try {
String propVal = System.getProperty(key);
if (propVal == null) {
// Fall back to searching the system environment.
propVal = System.getenv(key);
}
if (propVal == null) {
// Try with underscores.
String name = key.replace('.', '_');
propVal = System.getenv(name);
}
if (propVal == null) {
// Try uppercase with underscores as well.
String name = key.toUpperCase(Locale.ENGLISH).replace('.', '_');
propVal = System.getenv(name);
}
if (propVal != null) {
return propVal;
}
}
catch (Throwable ex) {
System.err.println("Could not resolve key '" + key + "' in '" + text
+ "' as system property or in environment: " + ex);
}
return defaultValue;
}
private static int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
int index = startIndex + PLACEHOLDER_PREFIX.length();
int withinNestedPlaceholder = 0;
while (index < buf.length()) {
if (substringMatch(buf, index, PLACEHOLDER_SUFFIX)) {
if (withinNestedPlaceholder > 0) {
withinNestedPlaceholder--;
index = index + PLACEHOLDER_SUFFIX.length();
}
else {
return index;
}
}
else if (substringMatch(buf, index, SIMPLE_PREFIX)) {
withinNestedPlaceholder++;
index = index + SIMPLE_PREFIX.length();
}
else {
index++;
}
}
return -1;
}
private static boolean substringMatch(CharSequence str, int index, CharSequence substring) {
for (int j = 0; j < substring.length(); j++) {
int i = index + j;
if (i >= str.length() || str.charAt(i) != substring.charAt(j)) {
return false;
}
}
return true;
}
}
@@ -1,7 +1,5 @@
package fun.asgc.neutrino.core.aop.compiler.internal.archive;
import fun.asgc.neutrino.core.aop.compiler.internal.Launcher;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
@@ -85,7 +85,7 @@ public class AsgcProxyFactory implements ProxyFactory {
if (GlobalConfig.isPrintGeneratorCode()) {
log.debug("类:{} 的代理类源码:\n{}", targetType.getName(), sourceCode);
}
Class<P> retClass = (Class<P>)compiler.compile(proxyClass.getPkg(), proxyClass.getName(), proxyClass.getSourceCode());
Class<P> retClass = (Class<P>)compiler.compile(proxyClass.getClassName(), proxyClass.getSourceCode());
P obj = retClass.newInstance();
return obj;
}
@@ -21,6 +21,7 @@
*/
package fun.asgc.neutrino.core.aop.proxy;
import fun.asgc.neutrino.core.util.StringUtil;
import lombok.Data;
import java.util.Map;
@@ -65,4 +66,11 @@ public class ProxyClass {
public ProxyClass() {
}
public String getClassName() {
if (StringUtil.isEmpty(pkg)) {
return name;
}
return String.format("%s.%s", pkg, name);
}
}
@@ -44,6 +44,10 @@ public class GlobalConfig {
* 当程序是以jar方式运行时,强制保存生成的代码
*/
private static volatile boolean isSaveGeneratorCode = false;
/**
* 是否使用SpringBoot方式的jar
*/
private static volatile boolean isUseSpringBootJar = true;
/**
* 自动生成代码保存路径
*/
@@ -88,4 +92,12 @@ public class GlobalConfig {
public static String getMapperXmlFileBasePath() {
return mapperXmlFileBasePath;
}
public static boolean isIsPrintGeneratorCode() {
return isPrintGeneratorCode;
}
public static boolean isIsUseSpringBootJar() {
return isUseSpringBootJar;
}
}
@@ -0,0 +1,557 @@
package fun.asgc.neutrino.core.base;
import fun.asgc.neutrino.core.util.TypeUtil;
import java.io.Serializable;
import java.util.*;
/**
* 用于统一参数配置 <br/>
* <p>
* 1、有序性(适用于方法参数)<br/>
* 2、key为String类型时,忽略大小写、忽略分隔符(_、-),兼容启动命令传参 + 配置文件传参 <br/>
* 3、父级委托机制:如果存在父级,且当前实例查不到,则委托父级查找。(适用于配置优先级:启动参数 > 配置文件 > 默认值) <br/>
* </p>
*
* 使用说明:<br/>
* 1、take开头的方法,适用于配置层。利用parent委托机制,做优先级。 如5级配置:默认值 -> 内部配置文件 -> 环境变量 -> 外部配置文件 -> 启动参数 <br/>
* 2、inx开头的方法,适用于不关心参数名称,根据下标取值。如普通方法参数、sql顺序参数(非具名参数) <br/>
* 3、get方法取值,没有委托机制,适用于sql具名参数、bean方法具名参数 <br/>
* 4、setAlias用于为一个key设置别名,用于解决应用层简化配置,避免冗长的配置名。<br/>
* @author: aoshiguchen
* @date: 2023/3/1
*/
public class NvMap<K,V> implements Map<K,V> , Serializable, Cloneable {
private HashMap<K,K> aliasMap;
private LinkedHashMap<K, V> _m;
private HashMap<K, K> _k;
private Locale locale;
private String SEPARATOR = "_|-";
private NvMap<K,V> parent;
private NvMap() {
this(null, 16, null);
}
private NvMap(NvMap<K,V> parent) {
this(parent, 16, null);
}
public static <K,V> NvMap<K,V> of() {
return new NvMap<>();
}
public static <K,V> NvMap<K,V> of(NvMap<K,V> parent) {
NvMap<K,V> nvMap = new NvMap(parent);
nvMap.aliasMap.putAll(parent.aliasMap);
return nvMap;
}
public NvMap<K,V> set(K k, V v) {
if (this.aliasMap.containsKey(convertKey(k))) {
this.put(this.aliasMap.get(convertKey(k)), v);
} else {
this.put(k, v);
}
return this;
}
public NvMap<K,V> set(K k, K alias, V v) {
this.set(k, v);
this.setAlias(k, alias);
return this;
}
public NvMap<K,V> setAlias(K k, K alias) {
this.aliasMap.put(convertKey(alias), convertKey(k));
return this;
}
public NvMap(NvMap<K,V> parent, int initialCapacity, Locale locale) {
this.parent = parent;
this._m = new LinkedHashMap<K, V>(initialCapacity) {
@Override
public boolean containsKey(Object key) {
return NvMap.this.containsKey(key);
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
boolean doRemove = NvMap.this.removeEldestEntry(eldest);
if (doRemove) {
_k.remove(convertKey(eldest.getKey()));
}
return doRemove;
}
};
this._k = new HashMap<>(initialCapacity);
this.aliasMap = new HashMap<>(initialCapacity);
this.locale = (locale != null ? locale : Locale.getDefault());
}
@Override
public int size() {
return this._m.size();
}
public int stackSize() {
return this._m.size() + (null == parent ? 0 : parent.stackSize());
}
@Override
public boolean isEmpty() {
return this._m.isEmpty();
}
public boolean isStackEmpty() {
boolean res = this._m.isEmpty();
if (res && null != parent) {
res = parent.isStackEmpty();
}
return res;
}
@Override
public boolean containsKey(Object key) {
return this._k.containsKey(convertKey(key));
}
public boolean stackContainsKey(K k) {
return this.containsKey(k) || (null != parent && parent.containsKey(k));
}
@Override
public boolean containsValue(Object value) {
return this._m.containsValue(value);
}
public boolean stackContainsValue(Object value) {
return this.containsValue(value) || (null != parent && parent.containsValue(value));
}
public V stackGet(K k) {
V res = get(k);
if (null == res && null != parent) {
res = parent.stackGet(k);
}
return res;
}
public V stackGetOrDefault(K k, V defaultValue) {
V res = this.stackGet(k);
if (null == res) {
res = defaultValue;
}
return res;
}
@Override
public V put(K key, V value) {
K k = key;
if (null != k && k instanceof String) {
k = (K) convertKey((String) key);
}
K oldKey = this._k.put(k, key);
if (null != oldKey && !oldKey.equals(key)) {
this._m.remove(oldKey);
}
return this._m.put(key, value);
}
@Override
public V remove(Object key) {
K k1 = null;
try {
k1 = (K) key;
} catch (Exception e) {
return null;
}
K k2 = null;
if (k1 instanceof String) {
k1 = (K) convertKey((String) k1);
k2 = this._k.remove(k1);
} else {
k2 = this._k.remove(k1);
}
if (null != k2) {
return this._m.remove(k2);
}
return null;
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
if (m.isEmpty()) {
return;
}
m.forEach(this::put);
}
@Override
public void clear() {
this._k.clear();
this._m.clear();
}
@Override
public Set<K> keySet() {
return this._m.keySet();
}
@Override
public Collection<V> values() {
return this._m.values();
}
@Override
public Set<Entry<K, V>> entrySet() {
return this._m.entrySet();
}
public Locale getLocale() {
return this.locale;
}
protected String convertKey(String key) {
return key.toLowerCase(getLocale()).replaceAll(SEPARATOR, "");
}
protected K convertKey(Object k) {
K res = null;
try {
res = (K) convertKey((String) k);
} catch (Exception e) {
res = (K)k;
}
return res;
}
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return false;
}
@Override
protected NvMap<K,V> clone() {
NvMap<K,V> res = new NvMap<>();
if (null != parent) {
res.parent = parent.clone();
}
res._m = (LinkedHashMap<K, V>) _m.clone();
res._k = (HashMap<K, K>) _k.clone();
res.aliasMap = (HashMap<K, K>) aliasMap.clone();
res.locale = locale;
return res;
}
// ====== 为了方便取值操作,get方法保持Map接口原有语义,不支持栈式取值 =======
@Override
public V get(Object key) {
V res = null;
if (this.aliasMap.containsKey(convertKey(key))) {
Object aliasKey = this.aliasMap.get(convertKey(key));
res = this._m.get(this._k.get(convertKey(aliasKey)));
}
if (null == res) {
res = this._m.get(this._k.get(convertKey(key)));
}
return res;
}
public V get(Object key, V defaultValue) {
V res = get(key);
if (null == res) {
res = defaultValue;
}
return res;
}
public String getStr(K k) {
return TypeUtil.conversion(get(k), String.class);
}
public String getStr(K k, String defaultValue) {
return TypeUtil.conversion(get(k, (V)defaultValue), String.class);
}
public Byte getByte(K k) {
return TypeUtil.conversion(get(k), Byte.class);
}
public Byte getByte(K k, Byte defaultValue) {
return TypeUtil.conversion(get(k, (V)defaultValue), Byte.class);
}
public Character getChar(K k) {
return TypeUtil.conversion(get(k), Character.class);
}
public Character getChar(K k, Character defaultValue) {
return TypeUtil.conversion(get(k, (V)defaultValue), Character.class);
}
public Boolean getBool(K k) {
return TypeUtil.conversion(get(k), Boolean.class);
}
public Boolean getBool(K k, Boolean defaultValue) {
return TypeUtil.conversion(get(k, (V)defaultValue), Boolean.class);
}
public Short getShort(K k) {
return TypeUtil.conversion(get(k), Short.class);
}
public Short getShort(K k, Short defaultValue) {
return TypeUtil.conversion(get(k, (V)defaultValue), Short.class);
}
public Integer getInt(K k) {
return TypeUtil.conversion(get(k), Integer.class);
}
public Integer getInt(K k, Integer defaultValue) {
return TypeUtil.conversion(get(k, (V)defaultValue), Integer.class);
}
public Long getLong(K k) {
return TypeUtil.conversion(get(k), Long.class);
}
public Long getLong(K k, Long defaultValue) {
return TypeUtil.conversion(get(k, (V)defaultValue), Long.class);
}
public Float getFloat(K k) {
return TypeUtil.conversion(get(k), Float.class);
}
public Float getFloat(K k, Float defaultValue) {
return TypeUtil.conversion(get(k, (V)defaultValue), Float.class);
}
public Double getDouble(K k) {
return TypeUtil.conversion(get(k), Double.class);
}
public Double getDouble(K k, Double defaultValue) {
return TypeUtil.conversion(get(k, (V)defaultValue), Double.class);
}
public Date getDate(K k) {
return TypeUtil.conversion(get(k), Date.class);
}
public Date getDate(K k, Date defaultValue) {
return TypeUtil.conversion(get(k, (V)defaultValue), Date.class);
}
public K getAlias(K k) {
return this.aliasMap.get(convertKey(k));
}
public K stackGetAlias(K k) {
K res = getAlias(k);
if (null == res && null != parent) {
res = parent.stackGetAlias(k);
}
return res;
}
// ====== 为了方便取值操作,take开头的方法,全部基于栈式取值 =======
public V take(K k) {
V res = null;
K aliasK = this.getAlias(k);
if (null != aliasK) {
res = stackGet(aliasK);
}
if (null == res) {
res = stackGet(k);
}
return res;
}
public V take(K k, V defaultValue) {
V res = take(k);
if (null == res ) {
res = defaultValue;
}
return res;
}
public String takeStr(K k) {
return TypeUtil.conversion(take(k), String.class);
}
public String takeStr(K k, String defaultValue) {
return TypeUtil.conversion(take(k, (V)defaultValue), String.class);
}
public Byte takeByte(K k) {
return TypeUtil.conversion(take(k), Byte.class);
}
public Byte takeByte(K k, Byte defaultValue) {
return TypeUtil.conversion(take(k, (V)defaultValue), Byte.class);
}
public Character takeChar(K k) {
return TypeUtil.conversion(take(k), Character.class);
}
public Character takeChar(K k, Character defaultValue) {
return TypeUtil.conversion(take(k, (V)defaultValue), Character.class);
}
public Boolean takeBool(K k) {
return TypeUtil.conversion(take(k), Boolean.class);
}
public Boolean takeBool(K k, Boolean defaultValue) {
return TypeUtil.conversion(take(k, (V)defaultValue), Boolean.class);
}
public Short takeShort(K k) {
return TypeUtil.conversion(take(k), Short.class);
}
public Short takeShort(K k, Short defaultValue) {
return TypeUtil.conversion(take(k, (V)defaultValue), Short.class);
}
public Integer takeInt(K k) {
return TypeUtil.conversion(take(k), Integer.class);
}
public Integer takeInt(K k, Integer defaultValue) {
return TypeUtil.conversion(take(k, (V)defaultValue), Integer.class);
}
public Long takeLong(K k) {
return TypeUtil.conversion(take(k), Long.class);
}
public Long takeLong(K k, Long defaultValue) {
return TypeUtil.conversion(take(k, (V)defaultValue), Long.class);
}
public Float takeFloat(K k) {
return TypeUtil.conversion(take(k), Float.class);
}
public Float takeFloat(K k, Float defaultValue) {
return TypeUtil.conversion(take(k, (V)defaultValue), Float.class);
}
public Double takeDouble(K k) {
return TypeUtil.conversion(take(k), Double.class);
}
public Double takeDouble(K k, Double defaultValue) {
return TypeUtil.conversion(take(k, (V)defaultValue), Double.class);
}
public Date takeDate(K k) {
return TypeUtil.conversion(take(k), Date.class);
}
public Date takeDate(K k, Date defaultValue) {
return TypeUtil.conversion(take(k, (V)defaultValue), Date.class);
}
// ====== 为了方便取值操作,idx开头的方法,全部基于下标取值 =======
public V idx(int i) {
if (i >= 0 && i < this.size()) {
return (V)this._m.values().toArray(new Object[]{})[i];
}
return null;
}
public V idx(int i, V defaultValue) {
V res = idx(i);
if (null == res) {
res = defaultValue;
}
return defaultValue;
}
public String idxStr(int i) {
return TypeUtil.conversion(idx(i), String.class);
}
public String idxStr(int i, String defaultValue) {
return TypeUtil.conversion(idx(i, (V)defaultValue), String.class);
}
public Byte idxByte(int i) {
return TypeUtil.conversion(idx(i), Byte.class);
}
public Byte idxByte(int i, Byte defaultValue) {
return TypeUtil.conversion(idx(i, (V)defaultValue), Byte.class);
}
public Character idxChar(int i) {
return TypeUtil.conversion(idx(i), Character.class);
}
public Character idxChar(int i, Character defaultValue) {
return TypeUtil.conversion(idx(i, (V)defaultValue), Character.class);
}
public Boolean idxBool(int i) {
return TypeUtil.conversion(idx(i), Boolean.class);
}
public Boolean idxBool(int i, Boolean defaultValue) {
return TypeUtil.conversion(idx(i, (V)defaultValue), Boolean.class);
}
public Short idxShort(int i) {
return TypeUtil.conversion(idx(i), Short.class);
}
public Short idxShort(int i, Short defaultValue) {
return TypeUtil.conversion(idx(i, (V)defaultValue), Short.class);
}
public Integer idxInt(int i) {
return TypeUtil.conversion(idx(i), Integer.class);
}
public Integer idxInt(int i, Integer defaultValue) {
return TypeUtil.conversion(idx(i, (V)defaultValue), Integer.class);
}
public Long idxLong(int i) {
return TypeUtil.conversion(idx(i), Long.class);
}
public Long idxLong(int i, Long defaultValue) {
return TypeUtil.conversion(idx(i, (V)defaultValue), Long.class);
}
public Float idxFloat(int i) {
return TypeUtil.conversion(idx(i), Float.class);
}
public Float idxFloat(int i, Float defaultValue) {
return TypeUtil.conversion(idx(i, (V)defaultValue), Float.class);
}
public Double idxDouble(int i) {
return TypeUtil.conversion(idx(i), Double.class);
}
public Double idxDouble(int i, Double defaultValue) {
return TypeUtil.conversion(idx(i, (V)defaultValue), Double.class);
}
public Date idxDate(int i) {
return TypeUtil.conversion(idx(i), Date.class);
}
public Date idxDate(int i, Date defaultValue) {
return TypeUtil.conversion(idx(i, (V)defaultValue), Date.class);
}
}
@@ -0,0 +1,205 @@
package fun.asgc.neutrino.core.base;
import com.alibaba.fastjson.JSONObject;
import fun.asgc.neutrino.core.constant.FileTypeEnum;
import fun.asgc.neutrino.core.constant.MetaDataConstant;
import fun.asgc.neutrino.core.util.*;
import org.yaml.snakeyaml.Yaml;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* 配置管理器
*
* <p>
* 支持以下五级配置:
* 1、别名、默认值
* 2、内部配置文件
* 3、环境变量
* 4、外部配置文件
* 5、启动参数
* </p>
*
* <p>
* 支持以下3种配置文件格式:
* 1、yml
* 2、properties
* 3、json
* </p>
*
* <p>
* 支持指定以下配置:
* 1、内部配置文件路径、格式 (可根据文件后缀自动识别格式)
* 2、环境变量前缀 (若指定了前缀,则只加载包含该前缀的环境变量)
* 3、外部配置文件路径、格式(可根据文件后缀自动识别格式)
* 4、启动参数前缀(若指定了前缀,则只加载包含该前缀的启动参数)
* </p>
* @author: aoshiguchen
* @date: 2023/3/5
*/
public final class NvMaps {
private NvMap nvMap;
private NvMaps() {
this.nvMap = NvMap.of();
}
public static NvMaps of() {
return new NvMaps();
}
public NvMaps stageDone() {
this.nvMap = NvMap.of(this.nvMap);
return this;
}
public NvMap getNvMap() {
return this.nvMap;
}
public NvMaps setKv(Object k, Object v) {
this.nvMap.set(k, v);
return this;
}
public NvMaps setKv(Object k, Object alias, Object v) {
this.nvMap.set(k, alias, v);
return this;
}
public NvMaps setAlias(Object k, Object alias) {
this.nvMap.setAlias(k, alias);
return this;
}
public NvMaps loadFile(String path) throws IOException {
if (StringUtil.isEmpty(path)) {
return this;
}
String suffix = FileUtil.getFileSuffix(path);
if (StringUtil.isEmpty(suffix)) {
return this;
}
suffix = suffix.toLowerCase();
if (FileTypeEnum.YML.getSuffixSet().contains(suffix)) {
return loadFile(FileTypeEnum.YML, path);
} else if (FileTypeEnum.PROPERTIES.getSuffixSet().contains(suffix)) {
return loadFile(FileTypeEnum.PROPERTIES, path);
} else if (FileTypeEnum.JSON.getSuffixSet().contains(suffix)) {
return loadFile(FileTypeEnum.JSON, path);
}
return this;
}
public NvMaps loadYmlFile(String path) throws IOException {
return loadFile(FileTypeEnum.YML, path);
}
public NvMaps loadPropertiesFile(String path) throws IOException {
return loadFile(FileTypeEnum.PROPERTIES, path);
}
public NvMaps loadJsonFile(String path) throws IOException {
return loadFile(FileTypeEnum.JSON, path);
}
public NvMaps loadFile(FileTypeEnum fileType, String path) throws IOException {
try (InputStream in = FileUtil.getInputStream(path)){
return loadFile(fileType, in);
}
}
public NvMaps loadFile(FileTypeEnum fileType, InputStream in) throws IOException {
if (null == fileType || null == in) {
return this;
}
if (fileType == FileTypeEnum.YML) {
Map<String, Object> map = new Yaml().load(in);
load(map);
} else if (fileType == FileTypeEnum.PROPERTIES) {
Properties properties = new Properties();
properties.load(in);
load(properties);
} else if (fileType == FileTypeEnum.JSON) {
String content = FileUtil.readContentAsString(in);
JSONObject jsonObject = JSONObject.parseObject(content);
load(jsonObject);
}
return null;
}
public NvMaps load(Properties properties) {
if (null == properties) {
return this;
}
for (String k : properties.stringPropertyNames()) {
this.setKv(k, properties.getProperty(k));
}
return this;
}
public NvMaps load(Map<String, Object> config) {
if (CollectionUtil.isEmpty(config)) {
return this;
}
for (String key : config.keySet()) {
Object value = config.get(key);
if (null != value && Map.class.isAssignableFrom(value.getClass())) {
load(key, (Map)config.get(key));
} else {
this.setKv(key, value);
}
}
return this;
}
private void load(String prefix, Map<Object, Object> config) {
for (Object key : config.keySet()) {
String k = TypeUtil.conversion(key, String.class);
if (null == k) {
continue;
}
Object value = config.get(key);
if (null != value && Map.class.isAssignableFrom(value.getClass())) {
load(prefix.concat("." + k), (Map)config.get(key));
} else {
this.setKv(prefix.concat("." + k), value);
}
}
}
public NvMaps loadEnvironmentVariable(String envKey) {
String env = System.getenv(MetaDataConstant.ENVIRONMENT_VARIABLE_KEY);
if (StringUtil.isEmpty(env)) {
return this;
}
String[] tmp = env.split(File.pathSeparator);
if (ArrayUtil.isEmpty(tmp) || tmp.length < 2) {
return this;
}
load(kvListToMap(tmp));
return this;
}
public NvMaps loadMainArgs(String[] mainArgs) {
load(kvListToMap(mainArgs));
return this;
}
private Map<String, Object> kvListToMap(String[] args) {
Map<String, Object> map = new HashMap<>();
if (ArrayUtil.isEmpty(args)) {
return map;
}
for (String kv : args) {
if (!StringUtil.isEmpty(kv)) {
int index = kv.indexOf("=");
if (index > 0 && index < kv.length() - 1) {
String key = kv.substring(0, index);
String val = kv.substring(index + 1);
map.put(key, val);
}
}
}
return map;
}
}
@@ -0,0 +1,33 @@
package fun.asgc.neutrino.core.constant;
import com.google.common.collect.Sets;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author: aoshiguchen
* @date: 2023/3/6
*/
@AllArgsConstructor
@Getter
public enum FileTypeEnum {
YML(1, "yml", Sets.newHashSet(".yml", ".yaml")),
PROPERTIES(2, "properties", Sets.newHashSet(".properties")),
JSON(3, "json", Sets.newHashSet(".json")),
;
private Integer type;
private String desc;
private Set<String> suffixSet;
private static final Map<Integer, FileTypeEnum> typeMap = Stream.of(FileTypeEnum.values()).collect(Collectors.toMap(FileTypeEnum::getType, Function.identity()));
public static FileTypeEnum ofType(Integer type) {
return typeMap.get(type);
}
}
@@ -84,4 +84,41 @@ public interface MetaDataConstant {
* app生命周期主题
*/
String TOPIC_APP_LIFE_CYCLE = "TP_APP_LIFE_CYCLE";
/**
* 环境变量key
*/
String ENVIRONMENT_VARIABLE_KEY = "NEUTRINO_PROXY";
interface Config {
String NEUTRINO_APPLICATION_NAME = "neutrino.application.name";
String NEUTRINO_HTTP_ENABLE = "neutrino.http.enable";
String NEUTRINO_HTTP_PORT = "neutrino.http.port";
String NEUTRINO_HTTP_CONTEXT_PATH = "neutrino.http.context-path";
String NEUTRINO_HTTP_MAX_CONTENT_LENGTH_DESC = "neutrino.http.max-content-length-desc";
String NEUTRINO_HTTP_STATIC_RESOURCE_LOCATIONS = "neutrino.http.static-resource.locations";
String NEUTRINO_PROXY_PROTOCOL_MAX_FRAME_LENGTH = "neutrino.proxy.protocol.max-frame-length";
String NEUTRINO_PROXY_PROTOCOL_LENGTH_FIELD_OFFSET = "neutrino.proxy.protocol.length-field-offset";
String NEUTRINO_PROXY_PROTOCOL_LENGTH_FIELD_LENGTH = "neutrino.proxy.protocol.length-field-length";
String NEUTRINO_PROXY_PROTOCOL_INITIAL_BYTES_TO_STRIP = "neutrino.proxy.protocol.initial-bytes-to-strip";
String NEUTRINO_PROXY_PROTOCOL_LENGTH_ADJUSTMENT = "neutrino.proxy.protocol.length-adjustment";
String NEUTRINO_PROXY_PROTOCOL_READ_IDLE_TIME = "neutrino.proxy.protocol.read-idle-time";
String NEUTRINO_PROXY_PROTOCOL_WRITE_IDLE_TIME = "neutrino.proxy.protocol.write-idle-time";
String NEUTRINO_PROXY_PROTOCOL_ALL_IDLE_TIME_SECONDS = "neutrino.proxy.protocol.all-idle-time-seconds";
String NEUTRINO_PROXY_SERVER_PORT = "neutrino.proxy.server.port";
String NEUTRINO_PROXY_SERVER_SSL_PORT = "neutrino.proxy.server.ssl-port";
String NEUTRINO_PROXY_SERVER_KEY_STORE_PASSWORD = "neutrino.proxy.server.key-store-password";
String NEUTRINO_PROXY_SERVER_KEY_MANAGER_PASSWORD = "neutrino.proxy.server.key-manager-password";
String NEUTRINO_PROXY_SERVER_JKS_PATH = "neutrino.proxy.server.jks-path";
String NEUTRINO_PROXY_CLIENT_KEY_STORE_PASSWORD = "neutrino.proxy.client.key-store-password";
String NEUTRINO_PROXY_CLIENT_JKS_PATH = "neutrino.proxy.client.jks-path";
String NEUTRINO_PROXY_CLIENT_SERVER_IP = "neutrino.proxy.client.server-ip";
String NEUTRINO_PROXY_CLIENT_SERVER_PORT = "neutrino.proxy.client.server-port";
String NEUTRINO_PROXY_CLIENT_SSL_ENABLE = "neutrino.proxy.client.ssl-enable";
String NEUTRINO_PROXY_CLIENT_OBTAIN_LICENSE_INTERVAL = "neutrino.proxy.client.obtain-license-interval";
String NEUTRINO_DATA_DB_TYPE = "neutrino.data.db.type";
String NEUTRINO_DATA_DB_URL = "neutrino.data.db.url";
String NEUTRINO_DATA_DB_DRIVER_CLASS = "neutrino.data.db.driver-class";
String NEUTRINO_DATA_DB_USERNAME = "neutrino.data.db.username";
String NEUTRINO_DATA_DB_PASSWORD = "neutrino.data.db.password";
}
}
@@ -125,8 +125,7 @@ public class ApplicationContext implements LifeCycle {
continue;
}
Optional<Method> methodOptional = methodSet.stream().filter(m -> m.getName().equals(name) && Modifier.isStatic(m.getModifiers())
&& (m.getParameterCount() == 0 ||
(m.getParameterCount() == 1 && m.getParameters()[0].getType().isArray() && String.class.isAssignableFrom(m.getParameters()[0].getType().getComponentType()))))
&& (m.getParameterCount() == 0 || m.getParameterCount() == 1))
.findFirst();
if (!methodOptional.isPresent()) {
continue;
@@ -136,8 +135,16 @@ public class ApplicationContext implements LifeCycle {
log.debug("PreLoad execute {}#{}", c.getName(), method.getName());
if (method.getParameterCount() == 0) {
method.invoke(o);
} else if (method.getParameterCount() == 1){
if (String[].class.isAssignableFrom(method.getParameters()[0].getType())) {
method.invoke(o, new Object[]{this.environment.getMainArgs()});
} else if (Environment.class.isAssignableFrom(method.getParameters()[0].getType())){
method.invoke(o, this.environment);
} else {
log.error("PreLoad execute failed. init method args nonsupport");
}
} else {
method.invoke(o, new Object[]{this.environment.getMainArgs()});
log.error("PreLoad execute failed. init method args nonsupport");
}
}
}
@@ -22,7 +22,10 @@
package fun.asgc.neutrino.core.context;
import fun.asgc.neutrino.core.base.NvMap;
import fun.asgc.neutrino.core.base.NvMaps;
import fun.asgc.neutrino.core.base.event.SimpleApplicationEventManager;
import fun.asgc.neutrino.core.constant.MetaDataConstant;
import fun.asgc.neutrino.core.util.ArrayUtil;
import fun.asgc.neutrino.core.util.LockUtil;
import fun.asgc.neutrino.core.util.StringUtil;
@@ -34,6 +37,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static fun.asgc.neutrino.core.constant.MetaDataConstant.Config.*;
/**
*
* @author: aoshiguchen
@@ -74,11 +79,92 @@ public class Environment {
* 默认的应用事件管理器
*/
private SimpleApplicationEventManager defaultApplicationEventManager;
/**
* 全局配置
*/
private NvMap nvMap;
public NvMap getNvMap() {
return nvMap;
}
public void loadNvMap(String envKey) throws Exception {
// 创建NvMaps实例
NvMaps nvMaps = NvMaps.of();
// 阶段1:设置内部默认值、别名
nvMaps.setAlias(NEUTRINO_APPLICATION_NAME, "app.name");
nvMaps.setKv(NEUTRINO_APPLICATION_NAME, "neutrino-app");
nvMaps.setAlias(NEUTRINO_HTTP_ENABLE, "http.enable");
nvMaps.setKv(NEUTRINO_HTTP_ENABLE, true);
nvMaps.setAlias(NEUTRINO_HTTP_PORT, "http.port");
nvMaps.setKv(NEUTRINO_HTTP_PORT, 8080);
nvMaps.setAlias(NEUTRINO_HTTP_CONTEXT_PATH, "http.context-path");
nvMaps.setKv(NEUTRINO_HTTP_CONTEXT_PATH, "/");
nvMaps.setAlias(NEUTRINO_HTTP_MAX_CONTENT_LENGTH_DESC, "http.max-content-length-desc");
nvMaps.setKv(NEUTRINO_HTTP_MAX_CONTENT_LENGTH_DESC, "/");
nvMaps.setAlias(NEUTRINO_HTTP_STATIC_RESOURCE_LOCATIONS, "http.static-resource");
nvMaps.setAlias(NEUTRINO_PROXY_PROTOCOL_MAX_FRAME_LENGTH, "protocol.max-frame-length");
nvMaps.setAlias(NEUTRINO_PROXY_PROTOCOL_LENGTH_FIELD_OFFSET, "protocol.length-field-offset");
nvMaps.setAlias(NEUTRINO_PROXY_PROTOCOL_LENGTH_FIELD_LENGTH, "protocol.length-field-length");
nvMaps.setAlias(NEUTRINO_PROXY_PROTOCOL_INITIAL_BYTES_TO_STRIP, "protocol.initial-bytes-to-strip");
nvMaps.setAlias(NEUTRINO_PROXY_PROTOCOL_LENGTH_ADJUSTMENT, "protocol.length-adjustment");
nvMaps.setAlias(NEUTRINO_PROXY_PROTOCOL_READ_IDLE_TIME, "protocol.read-idle-time");
nvMaps.setAlias(NEUTRINO_PROXY_PROTOCOL_WRITE_IDLE_TIME, "protocol.write-idle-time");
nvMaps.setAlias(NEUTRINO_PROXY_PROTOCOL_ALL_IDLE_TIME_SECONDS, "protocol.all-idle-time-seconds");
nvMaps.setAlias(NEUTRINO_PROXY_SERVER_PORT, "proxy.port");
nvMaps.setAlias(NEUTRINO_PROXY_SERVER_SSL_PORT, "proxy.ssl-port");
nvMaps.setAlias(NEUTRINO_PROXY_SERVER_KEY_STORE_PASSWORD, "proxy.key-store-password");
nvMaps.setAlias(NEUTRINO_PROXY_SERVER_KEY_MANAGER_PASSWORD, "proxy.key-manager-password");
nvMaps.setAlias(NEUTRINO_PROXY_SERVER_JKS_PATH, "proxy.jks-path");
nvMaps.setAlias(NEUTRINO_PROXY_CLIENT_KEY_STORE_PASSWORD, "proxy.key-store-password");
nvMaps.setAlias(NEUTRINO_PROXY_CLIENT_JKS_PATH, "proxy.jks-path");
nvMaps.setAlias(NEUTRINO_PROXY_CLIENT_SERVER_IP, "proxy.server-ip");
nvMaps.setAlias(NEUTRINO_PROXY_CLIENT_SERVER_PORT, "proxy.server-port");
nvMaps.setAlias(NEUTRINO_PROXY_CLIENT_SSL_ENABLE, "proxy.ssl-enable");
nvMaps.setAlias(NEUTRINO_PROXY_CLIENT_OBTAIN_LICENSE_INTERVAL, "proxy.obtain-license-interval");
nvMaps.setAlias(NEUTRINO_DATA_DB_TYPE, "db.type");
nvMaps.setAlias(NEUTRINO_DATA_DB_URL, "db.url");
nvMaps.setAlias(NEUTRINO_DATA_DB_DRIVER_CLASS, "db.driver-class");
nvMaps.setAlias(NEUTRINO_DATA_DB_USERNAME, "db.username");
nvMaps.setAlias(NEUTRINO_DATA_DB_PASSWORD, "db.password");
nvMaps.stageDone();
// 阶段2:内部配置文件
nvMaps.loadFile(MetaDataConstant.CLASSPATH_RESOURCE_IDENTIFIER.concat("/application.yml"));
nvMaps.stageDone();
// 阶段3:环境变量
if (!StringUtil.isEmpty(envKey)) {
nvMaps.loadEnvironmentVariable(envKey);
nvMaps.stageDone();
}
// 结算4:外部配置文件
nvMaps.loadFile("./.application.properties");
nvMaps.stageDone();
// 阶段5:启动参数
nvMaps.loadMainArgs(this.mainArgs);
nvMaps.stageDone();
// 获取NvMap实例
this.nvMap = nvMaps.getNvMap();
}
/**
* 参数map
*/
@Deprecated
private Map<String, String> mainArgsMap = null;
@Deprecated
private Map<String, String> getMainArgsMap() {
return LockUtil.doubleCheckProcessForNoException(
() -> null == mainArgsMap,
@@ -103,10 +189,12 @@ public class Environment {
);
}
@Deprecated
private String getMainArgs(String key) {
return getMainArgsMap().get(key);
}
@Deprecated
public Integer getMainArgsForInteger(String key, Integer defaultValue) {
String val = getMainArgs(key);
Integer res = null;
@@ -120,6 +208,7 @@ public class Environment {
return (null != res) ? res : defaultValue;
}
@Deprecated
public Boolean getMainArgsForBoolean(String key, Boolean defaultValue) {
String val = getMainArgs(key);
Boolean res = null;
@@ -133,11 +222,13 @@ public class Environment {
return (null != res) ? res : defaultValue;
}
@Deprecated
public String getMainArgsForString(String key, String defaultValue) {
String res = getMainArgs(key);
return !StringUtil.isEmpty(res) ? res : defaultValue;
}
@Deprecated
public String getMainArgsForString(String key) {
return getMainArgsForString(key, null);
}
@@ -118,7 +118,13 @@ public class NeutrinoLauncher {
// 加载应用配置
environment.setConfig(ConfigUtil.getYmlConfig(ApplicationConfig.class));
log.info("load ApplicationConfig finished.");
try {
environment.loadNvMap(neutrinoApplication.environmentVariableKey());
log.info("load ApplicationConfig finished.");
} catch (Exception e) {
log.error("load ApplicationConfig err.", e);
}
}
/**
@@ -26,11 +26,12 @@ import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.annotation.Param;
import fun.asgc.neutrino.core.aop.Invocation;
import fun.asgc.neutrino.core.aop.interceptor.Interceptor;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageInfo;
import fun.asgc.neutrino.core.db.template.JdbcTemplate;
import fun.asgc.neutrino.core.util.*;
import java.lang.reflect.Parameter;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -65,14 +66,14 @@ public class SqlMapperInterceptor implements Interceptor {
res = jdbcTemplate.queryForListByMap(resultComponentType, sql, (Map)params);
}
} else {
if (Page.class.isAssignableFrom(inv.getTargetMethod().getParameters()[0].getType())) {
if (PageInfo.class.isAssignableFrom(inv.getTargetMethod().getParameters()[0].getType())) {
// 分页查询 TODO 此处暂时临时处理,假设后面的参数是一个DO对象
Page page = (Page) inv.getArgs()[0];
int offset = (page.getCurrentPage() - 1) * page.getPageSize();
PageInfo pageInfo = (PageInfo) inv.getArgs()[0];
int offset = (pageInfo.getCurrent() - 1) * pageInfo.getSize();
long total = jdbcTemplate.queryForLongByModel(String.format("select count(1) from (%s) T", sql), inv.getArgs()[1]);
List resultList = jdbcTemplate.queryForListByModel(resultComponentType, String.format("%s limit %s,%s", sql, offset, page.getPageSize()), inv.getArgs()[1]);
page.setTotal(total);
page.setRecords(resultList);
List resultList = jdbcTemplate.queryForListByModel(resultComponentType, String.format("%s limit %s,%s", sql, offset, pageInfo.getSize()), inv.getArgs()[1]);
pageInfo.setTotal(total);
pageInfo.setRecords(resultList);
} else {
Object params = getParams(inv);
if (null == params || params.getClass().isArray()) {
@@ -86,7 +87,8 @@ public class SqlMapperInterceptor implements Interceptor {
int argsCount = ArrayUtil.isEmpty(inv.getArgs()) ? 0 : inv.getArgs().length;
if (argsCount == 1 && inv.getArgs()[0] instanceof Map) {
res = jdbcTemplate.updateByMap(sql, (Map)inv.getArgs()[0]);
} else if (argsCount == 1 && !TypeUtil.isNormalBasicType(inv.getArgs()[0].getClass())) {
// 临时解决只有一个参数,且参数类型不是实体类型时,参数未起作用的情况
} else if (argsCount == 1 && !TypeUtil.isNormalBasicType(inv.getArgs()[0].getClass()) && !(inv.getArgs()[0] instanceof Date)) {
res = jdbcTemplate.updateByModel(sql, inv.getArgs()[0]);
} else {
Object params = getParams(inv);
@@ -0,0 +1,123 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.db.page;
import lombok.Data;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
/**
*
* @author: aoshiguchen
* @date: 2022/8/6
*/
@Data
public class PageInfo<T> implements Serializable {
private static final long serialVersionUID = 8545996863226528797L;
private List<T> records;
private Long total;
private Integer size;
private Integer current;
public PageInfo() {
this.records = Collections.emptyList();
this.total = 0L;
this.size = 10;
this.current = 1;
}
public PageInfo(Integer current, Integer size) {
this(current, size, 0L);
}
public PageInfo(Integer current, Integer size, Long total) {
this.records = Collections.emptyList();
this.total = 0L;
this.size = 10;
this.current = 1;
if ((long)current > 1L) {
this.current = current;
}
this.size = size;
this.total = total;
}
public Long getPages() {
if ((long)this.getSize() == 0L) {
return 0L;
} else {
Long pages = this.getTotal() / (long)this.getSize();
if (this.getTotal() % (long)this.getSize() != 0L) {
pages = pages + 1L;
}
return pages;
}
}
public Long getTotal() {
return this.total;
}
public Integer getSize() {
return this.size;
}
public boolean hasPrevious() {
return (long)this.current > 1L;
}
public boolean hasNext() {
return (long)this.current < this.getPages();
}
public List<T> getRecords() {
return this.records;
}
public PageInfo<T> setRecords(List<T> records) {
this.records = records;
return this;
}
public PageInfo<T> setTotal(Long total) {
this.total = total;
return this;
}
public PageInfo<T> setSize(Integer size) {
this.size = size;
return this;
}
public Integer getCurrent() {
return this.current;
}
public PageInfo<T> setCurrent(Integer current) {
this.current = current;
return this;
}
}
@@ -21,34 +21,23 @@
*/
package fun.asgc.neutrino.core.db.page;
import lombok.Data;
import java.io.Serializable;
/**
*
* @author: aoshiguchen
* @date: 2022/8/6
*/
public class PageQuery {
@Data
public class PageQuery implements Serializable {
/**
* 当前页
*/
private int currentPage = 1;
private int current = 1;
/**
* 分页大小
*/
private int pageSize = 10;
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
private int size = 10;
}
@@ -1,16 +1,16 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* <p>
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* <p>
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* <p>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -27,6 +27,7 @@ import lombok.extern.slf4j.Slf4j;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
/**
*
@@ -36,59 +37,59 @@ import java.sql.SQLException;
@Slf4j
public abstract class PreparedStatementJdbcCallback<T> implements JdbcCallback<T> {
@Override
public T execute() throws SQLException {
PreparedStatement pstm = null;
Object[] params = this.getParams();
Connection conn = getConnection();
@Override
public T execute() throws SQLException {
PreparedStatement pstm = null;
Object[] params = this.getParams();
Connection conn = getConnection();
T res = null;
T res = null;
log.debug("sql:" + this.getSql());
StringBuffer sb = new StringBuffer();
if (ArrayUtil.notEmpty(params)) {
for(Object o : params){
sb.append(o).append(",");
}
log.debug("sql:" + this.getSql());
StringBuffer sb = new StringBuffer();
if (ArrayUtil.notEmpty(params)) {
for (Object o : params) {
sb.append(o).append(",");
}
if(sb.length() > 0 && sb.charAt(sb.length() - 1) == ','){
sb.deleteCharAt(sb.length() - 1);
}
}
log.debug("params:" + sb.toString());
pstm = conn.prepareStatement(this.getSql());
if (ArrayUtil.notEmpty(params)) {
for(int i = 0;i < params.length;i++){
pstm.setObject(i + 1, params[i]);
}
}
res = this.execute(pstm);
if (sb.length() > 0 && sb.charAt(sb.length() - 1) == ',') {
sb.deleteCharAt(sb.length() - 1);
}
}
log.debug("params:" + sb.toString());
pstm = conn.prepareStatement(this.getSql(), Statement.RETURN_GENERATED_KEYS);
if (ArrayUtil.notEmpty(params)) {
for (int i = 0; i < params.length; i++) {
pstm.setObject(i + 1, params[i]);
}
}
res = this.execute(pstm);
return res;
}
return res;
}
/**
* 获取参数
* @return
*/
abstract Object[] getParams();
/**
* 获取参数
* @return
*/
abstract Object[] getParams();
/**
* 获取sql语句
* @return
*/
abstract String getSql();
/**
* 获取sql语句
* @return
*/
abstract String getSql();
/**
* 执行
* @param ps
* @return
*/
abstract T execute(PreparedStatement ps) throws SQLException;
/**
* 执行
* @param ps
* @return
*/
abstract T execute(PreparedStatement ps) throws SQLException;
/**
* 获取数据库连接
* @return
*/
abstract Connection getConnection();
/**
* 获取数据库连接
* @return
*/
abstract Connection getConnection();
}
@@ -28,10 +28,6 @@ import org.apache.commons.io.FileDeleteStrategy;
import org.apache.commons.lang3.StringUtils;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
@@ -90,6 +86,20 @@ public class FileUtil {
}
}
/**
* 读取文件内容
* @param in
* @return
* @throws IOException
*/
public static String readContentAsString(InputStream in) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(in))){
return br.lines().collect(Collectors.joining("\n"));
} catch (Exception e) {
return null;
}
}
/**
* 读取文件内容
* @param path
@@ -220,4 +230,15 @@ public class FileUtil {
}
}
}
public static String getFileSuffix(String path) {
if (StringUtils.isBlank(path)) {
return "";
}
int index = path.lastIndexOf(".");
if (index >= 0) {
return path.substring(index);
}
return "";
}
}
@@ -23,6 +23,7 @@
package fun.asgc.neutrino.core.util;
import fun.asgc.neutrino.core.base.CodeBlock;
import lombok.extern.slf4j.Slf4j;
import java.util.Objects;
@@ -31,6 +32,7 @@ import java.util.Objects;
* @author: aoshiguchen
* @date: 2022/6/16
*/
@Slf4j
public class SystemUtil {
public static void addShutdownHook(Runnable runnable) {
@@ -98,14 +100,17 @@ public class SystemUtil {
if (!isStartupFromJar()) {
return null;
}
String url = SystemUtil.class.getResource("").getPath();
if (url.startsWith("file:")) {
url = url.substring(5);
String path = SystemUtil.class.getResource("").getPath();
String res = path;
if (res.startsWith("file:")) {
res = res.substring(5);
}
if (url.contains("!")) {
url = url.substring(0, url.indexOf("!"));
int index = res.indexOf("!");
if (index >= 0) {
res = res.substring(0, index);
}
return url;
log.debug("getCurrentJarFilePath path:{} index:{} url:{}", path, index, res);
return res;
}
public static boolean isWindows() {
@@ -23,7 +23,6 @@ package fun.asgc.neutrino.core.web.interceptor;
import fun.asgc.neutrino.core.web.context.HttpRequestWrapper;
import fun.asgc.neutrino.core.web.context.HttpResponseWrapper;
import io.netty.channel.ChannelHandlerContext;
/**
* 异常处理
@@ -21,7 +21,6 @@
*/
package fun.asgc.neutrino.core.aop.compiler;
import fun.asgc.neutrino.core.aop.compiler.internal.JarLauncher;
import fun.asgc.neutrino.core.util.ReflectUtil;
import org.junit.Test;
@@ -45,7 +44,7 @@ public class AsgcCompilerTest {
"\t\tSystem.out.println(\"hello\");\n" +
"\t}\n" +
"}\n";
Class clazz = compiler.compile("a.b","Hello", code);
Class clazz = compiler.compile("a.b.Hello", code);
Method method = ReflectUtil.getMethods(clazz).stream().filter(m -> m.getName().equals("hello")).findFirst().get();
Object instance = clazz.newInstance();
method.invoke(instance);
@@ -61,7 +60,7 @@ public class AsgcCompilerTest {
"\t\tSystem.out.println(\"熊猫正在吃\" + food);\n" +
"\t}\n" +
"}\n";
Class clazz = compiler.compile("a.b","Panda", code);
Class clazz = compiler.compile("a.b.Panda", code);
Method method = ReflectUtil.getMethods(clazz).stream().filter(m -> m.getName().equals("eat")).findFirst().get();
Object instance = clazz.newInstance();
method.invoke(instance, "竹子");
@@ -78,7 +77,7 @@ public class AsgcCompilerTest {
"\t\tSystem.out.println(\"收音机播放\");\n" +
"\t}\n" +
"}\n";
Class clazz = compiler.compile("a.b","RadioPlayer", code);
Class clazz = compiler.compile("a.b.RadioPlayer", code);
Method method = ReflectUtil.getMethods(clazz).stream().filter(m -> m.getName().equals("play")).findFirst().get();
Object instance = clazz.newInstance();
method.invoke(instance);
@@ -100,7 +99,7 @@ public class AsgcCompilerTest {
"\t}\n" +
"}\n";
// GlobalConfig.setIsSaveGeneratorCode(true);
Class clazz = compiler.compile("a.b","RadioPlayer", code);
Class clazz = compiler.compile("a.b.RadioPlayer", code);
Method method = ReflectUtil.getMethods(clazz).stream().filter(m -> m.getName().equals("play")).findFirst().get();
Object instance = clazz.newInstance();
method.invoke(instance);
@@ -122,8 +121,8 @@ public class AsgcCompilerTest {
*/
@Test
public void compileAndLoadClass5() throws Exception {
JarLauncher jarLauncher = new JarLauncher("/Users/yangwen/my/tmp/java/asgc-package-lab2.jar");
AsgcCompiler compiler = new AsgcCompiler(jarLauncher.createClassLoader());
AsgcCompiler compiler = new AsgcCompiler();
compiler.addDependSpringBootJar(AsgcCompilerTest.class.getResource("/asgc-package-lab2.jar").getPath());
String code = "package a.b;\n" +
"import fun.asgc.lab.pkg.lab2.Console;\n" +
"import fun.asgc.lab.pkg.lab1.Dog;\n" +
@@ -139,7 +138,7 @@ public class AsgcCompilerTest {
"\t}\n" +
"}\n";
System.out.println(code);
Class clazz = compiler.compile("a.b","Test", code);
Class clazz = compiler.compile("a.b.Test", code);
Method executeMethod = ReflectUtil.getMethods(clazz).stream().filter(m -> m.getName().equals("execute")).findFirst().get();
Method echoMethod = Stream.of(clazz.getDeclaredMethods()).filter(m -> m.getName().equals("echo")).findFirst().get();
Method dogEatMethod = Stream.of(clazz.getDeclaredMethods()).filter(m -> m.getName().equals("dogEat")).findFirst().get();
@@ -160,7 +159,7 @@ public class AsgcCompilerTest {
"}\n";
AsgcCompiler compiler = new AsgcCompiler();
try {
Class clazz = compiler.compile( "fun.asgc.test","Calc", code);
Class clazz = compiler.compile( "fun.asgc.test.Calc", code);
Method method = ReflectUtil.getMethods(clazz).stream().filter(m -> m.getName().equals("invoke")).findFirst().get();
return method.invoke(null);
} catch (ClassNotFoundException|IllegalAccessException|InvocationTargetException e) {
@@ -0,0 +1,85 @@
package fun.asgc.neutrino.core.base;
import org.junit.Assert;
import org.junit.Test;
/**
* @author: aoshiguchen
* @date: 2023/3/1
*/
public class NvMapTest {
@Test
public void test1() {
Object key1 = new Object();
NvMap nvMap0 = NvMap.of()
.setAlias("app.server.http.http-port", "aaa")
;
NvMap nvMap1 = NvMap.of(nvMap0)
.set("app.server.http.http-port", 8080)
.set("app.server.http.jks_Path", "/123/456")
.set("app.server.websocket.port", "ws-port", 8888) // 设值的同时设置别名
.set(key1, 1)
.setAlias("app.server.http.http-port", "http-port")
;
NvMap nvMap2 = NvMap.of(nvMap1)
.set("app.server.http.httpPort", 8081)
.set("app.server.http.context-path", "/")
;
NvMap nvMap3 = NvMap.of(nvMap2)
.setAlias("app.server.http.http-port", "port")
.setAlias("http-port", "p");
Assert.assertTrue(!nvMap1.isEmpty());
Assert.assertTrue(nvMap1.size() == 4);
Assert.assertTrue(nvMap1.stackSize() == 4);
Assert.assertTrue(nvMap1.get("app.server.http.http-port").equals(8080));
Assert.assertTrue(nvMap1.get("app.server.http.httpPort").equals(8080));
Assert.assertTrue(nvMap1.idx(0).equals(8080));
Assert.assertTrue(nvMap1.get("app.server.http.jks_Path").equals("/123/456"));
Assert.assertTrue(nvMap1.get("app.server.http.jksPath").equals("/123/456"));
Assert.assertTrue(nvMap1.idx(1).equals("/123/456"));
Assert.assertTrue(nvMap1.containsKey("app.server.http.http-port"));
Assert.assertTrue(nvMap1.containsKey(key1));
Assert.assertFalse(nvMap1.containsKey(new Object()));
Assert.assertTrue(!nvMap2.isEmpty());
Assert.assertTrue(nvMap2.size() == 2);
Assert.assertTrue(nvMap2.stackSize() == 6);
Assert.assertTrue(nvMap2.get("app.server.http.http-port").equals(8081));
Assert.assertTrue(nvMap2.get("app.server.http.httpPort").equals(8081));
Assert.assertTrue(nvMap2.get("app.server.http.jks-path") == null);
Assert.assertTrue(nvMap2.get("app.server.http.jksPath") == null);
Assert.assertTrue(nvMap2.get("app.server.http.context-path").equals("/"));
Assert.assertTrue(nvMap2.stackGet("app.server.http.jks-path").equals("/123/456"));
Assert.assertTrue(nvMap2.stackGet("app.server.http.jksPath").equals("/123/456"));
Assert.assertTrue(nvMap2.stackGet("app.server.http.context-path").equals("/"));
Assert.assertTrue(nvMap3.isEmpty());
Assert.assertTrue(!nvMap3.isStackEmpty());
Assert.assertTrue(nvMap3.size() == 0);
Assert.assertTrue(nvMap3.stackSize() == 6);
Assert.assertTrue(nvMap3.get("app.server.http.jks-path") == null);
Assert.assertTrue(nvMap3.get("app.server.http.jksPath") == null);
Assert.assertTrue(nvMap3.get("app.server.http.context-path") == null);
Assert.assertTrue(nvMap3.stackGet("app.server.http.jks-path").equals("/123/456"));
Assert.assertTrue(nvMap3.stackGet("app.server.http.jksPath").equals("/123/456"));
Assert.assertTrue(nvMap3.stackGet("app.server.http.context-path").equals("/"));
Assert.assertTrue(nvMap3.stackGetOrDefault("app.server.http.timeout", 60000).equals(60000));
Assert.assertTrue(nvMap3.takeStr("app.server.http.http-port").equals("8081"));
Assert.assertNull(nvMap3.take(null));
Assert.assertTrue(nvMap3.takeStr("httpPort").equals("8081"));
Assert.assertTrue(nvMap3.takeInt("http-port").equals(8081));
Assert.assertTrue(nvMap3.takeInt("port").equals(8081));
// 注意:第3层的别名p,指向了第1层的别名http-port
Assert.assertTrue(nvMap3.takeInt("p").equals(8081));
Assert.assertTrue(nvMap3.takeStr("aaa").equals("8081"));
Assert.assertTrue(nvMap3.takeInt("wsPort").equals(8888));
}
}
@@ -0,0 +1,60 @@
package fun.asgc.neutrino.core.base;
import org.junit.Test;
import java.io.IOException;
/**
* @author: aoshiguchen
* @date: 2023/3/6
*/
public class NvMapsTest {
/**
* 先给电脑设置环境变量,然后重启idea
* EUTRINO_PROXY=http-port=6000:app-name=neutrino-proxy-client
* @throws IOException
*/
@Test
public void test1() throws IOException {
// 创建NvMaps实例
NvMaps nvMaps = NvMaps.of();
// 阶段1:设置内部默认值
nvMaps.setKv("neutrino.application.name", "app-name",null);
nvMaps.setKv("neutrino.http.enable", true);
nvMaps.setKv("neutrino.http.port", "httpPort",null);
nvMaps.setKv("neutrino.http.context-path", "context-path", "/");
nvMaps.stageDone();
// 阶段2:内部配置文件
nvMaps.loadFile(NvMapsTest.class.getResource("/application.yml").getPath());
nvMaps.stageDone();
// 阶段3:环境变量
nvMaps.loadEnvironmentVariable("NEUTRINO_PROXY");
nvMaps.stageDone();
// 结算4:外部配置文件
// nvMaps.loadFile(NvMapsTest.class.getResource("/aaa.json").getPath());
nvMaps.loadFile(NvMapsTest.class.getResource("/aaa.properties").getPath());
nvMaps.stageDone();
// 阶段5:启动参数
String[] mainArgs = new String[]{
"httpPort=8100"
};
nvMaps.loadMainArgs(mainArgs);
nvMaps.stageDone();
// 获取NvMap实例
NvMap nvMap = nvMaps.getNvMap();
System.out.println(nvMap.takeInt("httpPort"));
System.out.println(nvMap.takeInt("neutrino.http.port"));
System.out.println(nvMap.takeStr("appName"));
System.out.println(nvMap.takeStr("neutrino.application.name"));
}
}
@@ -21,7 +21,7 @@
*/
package fun.asgc.neutrino.core.db.dao;
import com.alibaba.druid.pool.DruidDataSource;
import com.zaxxer.hikari.HikariDataSource;
import fun.asgc.neutrino.core.db.annotation.Column;
import fun.asgc.neutrino.core.db.annotation.Id;
import lombok.Data;
@@ -29,6 +29,7 @@ import lombok.ToString;
import lombok.experimental.Accessors;
import org.junit.Test;
import javax.activation.DataSource;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
@@ -39,12 +40,12 @@ import java.util.List;
* @date: 2022/6/28
*/
public class DaoTest {
private DruidDataSource dataSource;
private HikariDataSource dataSource;
private DBType dbType;
{
dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8");
dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8");
dataSource.setUsername("root");
dataSource.setPassword("YWasgc@10520");
dbType = DBType.MYSQL;
@@ -21,7 +21,7 @@
*/
package fun.asgc.neutrino.core.db.mapper;
import com.alibaba.druid.pool.DruidDataSource;
import com.zaxxer.hikari.HikariDataSource;
import fun.asgc.neutrino.core.annotation.Bean;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Order;
@@ -38,8 +38,8 @@ public class Configuration {
@Bean
public JdbcTemplate jdbcTemplate() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8");
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8");
dataSource.setUsername("root");
dataSource.setPassword("YWasgc@10520");
return new JdbcTemplate(dataSource);
@@ -21,7 +21,7 @@
*/
package fun.asgc.neutrino.core.db.template;
import com.alibaba.druid.pool.DruidDataSource;
import com.zaxxer.hikari.HikariDataSource;
import fun.asgc.neutrino.core.db.annotation.Id;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -42,8 +42,8 @@ public class JdbcTemplateTestForMySql {
private JdbcTemplate jdbcTemplate;
{
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8");
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8");
dataSource.setUsername("root");
dataSource.setPassword("YWasgc@10520");
jdbcTemplate = new JdbcTemplate(dataSource);
@@ -21,8 +21,7 @@
*/
package fun.asgc.neutrino.core.db.template;
import com.alibaba.druid.pool.DruidDataSource;
import com.google.common.collect.Sets;
import com.zaxxer.hikari.HikariDataSource;
import fun.asgc.neutrino.core.db.annotation.Id;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -41,9 +40,9 @@ public class JdbcTemplateTestForSqlite {
private JdbcTemplate jdbcTemplate;
{
DruidDataSource dataSource = new DruidDataSource();
HikariDataSource dataSource = new HikariDataSource();
// dataSource.setUrl("jdbc:sqlite:" + JdbcTemplateTestForSqlite.class.getResource("/sqlite.db").getPath());
dataSource.setUrl("jdbc:sqlite:../data.db");
dataSource.setJdbcUrl("jdbc:sqlite:../data.db");
dataSource.setDriverClassName("org.sqlite.JDBC");
jdbcTemplate = new JdbcTemplate(dataSource);
}
+10
View File
@@ -0,0 +1,10 @@
{
"neutrino": {
"application": {
"name": "test-app"
},
"http": {
"port": 8000
}
}
}
@@ -0,0 +1,2 @@
#neutrino.application.name=test
app-name=test1
+2 -2
View File
@@ -62,7 +62,7 @@ You need to install [node](http://nodejs.org/) and [git](https://git-scm.com/) l
- Dynamic breadcrumb
- I18n
- Customizable theme
- Tags-view(Tab page Support right-click operation)
- Tags-view(Tab pageInfo Support right-click operation)
- Rich text editor
- Markdown editor
- JSON editor
@@ -73,7 +73,7 @@ You need to install [node](http://nodejs.org/) and [git](https://git-scm.com/) l
- Mock data
- Echarts
- Clipboard
- 401/404 error page
- 401/404 error pageInfo
- Error log
- Export excel
- Export zip
@@ -47,12 +47,12 @@
</el-table>
<div class="pagination-end" v-if="isPagination">
<el-pagination
:hide-on-single-page="false"
:hide-on-single-pageInfo="false"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="PaginationData.currentPage"
:page-sizes="[10, 20, 50, 100]"
:page-size="PaginationData.pageSize"
:current-pageInfo="PaginationData.currentPage"
:pageInfo-sizes="[10, 20, 50, 100]"
:pageInfo-size="PaginationData.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="PaginationData.total"
>
@@ -26,7 +26,7 @@ export default {
},
height: {
type: String,
default: '380px'
default: '450px'
}
},
data() {
@@ -1,8 +1,11 @@
<template>
<scroll-bar>
<div class="log-div">
<div class="log-max-div" v-if="sidebar.opened">
<img :src="logCross"/>
</div>
<div class="log-mini-div" v-else>
<img :src="logMini">
</div>
<el-menu mode="vertical" :default-active="$route.path" :collapse="isCollapse" background-color="#304156" text-color="#bfcbd9" active-text-color="#409EFF">
<sidebar-item :routes="permission_routers"></sidebar-item>
</el-menu>
@@ -14,6 +17,7 @@ import { mapGetters } from 'vuex'
import SidebarItem from './SidebarItem'
import ScrollBar from '@/components/ScrollBar'
import logCross from '@/assets/logo/logo-text-cross.svg'
import logMini from '@/assets/logo/logo.svg'
export default {
components: { SidebarItem, ScrollBar },
@@ -28,17 +32,26 @@ export default {
},
data() {
return {
logCross
logCross,
logMini
}
}
}
</script>
<style lang="scss" scoped>
.log-div{
.log-max-div{
padding: 10px 0 5px 15px;
img{
height: 40px;
}
}
.log-mini-div{
text-align: center;
margin-top: 30px;
margin-bottom: 10px;
img{
height: 20px;
}
}
</style>
@@ -48,8 +48,8 @@
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.currentPage"
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.currentPage"
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
@@ -124,16 +124,16 @@ export default {
})
},
handleFilter() {
this.listQuery.currentPage = 1
this.listQuery.current = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.pageSize = val
this.listQuery.currentPage = 1
this.listQuery.size = val
this.listQuery.current = 1
this.getList()
},
handleCurrentChange(val) {
this.listQuery.currentPage = val
this.listQuery.current = val
this.getList()
},
handleLookOver(row) {
@@ -46,8 +46,8 @@
</el-table-column>-->
</el-table>
<div class="pagination-container">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.currentPage"
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.currentPage"
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
@@ -148,16 +148,16 @@ export default {
})
},
handleFilter() {
this.listQuery.currentPage = 1
this.listQuery.current = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.pageSize = val
this.listQuery.currentPage = 1
this.listQuery.size = val
this.listQuery.current = 1
this.getList()
},
handleCurrentChange(val) {
this.listQuery.currentPage = val
this.listQuery.current = val
this.getList()
},
handleShowClick(row) {
@@ -28,8 +28,8 @@
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.currentPage"
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.currentPage"
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</div>
@@ -116,16 +116,16 @@ export default {
})
},
handleFilter() {
this.listQuery.currentPage = 1
this.listQuery.current = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.pageSize = val
this.listQuery.currentPage = 1
this.listQuery.size = val
this.listQuery.current = 1
this.getList()
},
handleCurrentChange(val) {
this.listQuery.currentPage = val
this.listQuery.current = val
this.getList()
},
handleShowClick(row) {
@@ -60,8 +60,8 @@
</el-table>
<div class="pagination-container">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.currentPage"
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.currentPage"
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
@@ -213,15 +213,15 @@
})
},
handleFilter() {
this.listQuery.currentPage = 1
this.listQuery.current = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.pageSize = val
this.listQuery.size = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.currentPage = val
this.listQuery.current = val
this.getList()
},
handleModifyStatus(row, enable) {
@@ -65,8 +65,8 @@
</el-table>
<div class="pagination-container">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.currentPage"
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.currentPage"
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
@@ -264,15 +264,15 @@
})
},
handleFilter() {
this.listQuery.currentPage = 1
this.listQuery.current = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.pageSize = val
this.listQuery.size = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.currentPage = val
this.listQuery.current = val
this.getList()
},
handleModifyStatus(row, enable) {
@@ -51,8 +51,8 @@
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.currentPage"
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.currentPage"
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
@@ -171,15 +171,15 @@
})
},
handleFilter() {
this.listQuery.currentPage = 1
this.listQuery.current = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.pageSize = val
this.listQuery.size = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.currentPage = val
this.listQuery.current = val
this.getList()
},
handleModifyStatus(row, enable) {
@@ -43,8 +43,8 @@
</el-table>
<div class="pagination-container">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.currentPage"
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.currentPage"
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
@@ -173,15 +173,15 @@
})
},
handleFilter() {
this.listQuery.currentPage = 1
this.listQuery.current = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.pageSize = val
this.listQuery.size = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.currentPage = val
this.listQuery.current = val
this.getList()
},
handleModifyStatus(row, enable) {
@@ -50,8 +50,8 @@
</el-table>
<div class="pagination-container">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.currentPage"
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.currentPage"
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
@@ -197,15 +197,15 @@
})
},
handleFilter() {
this.listQuery.currentPage = 1
this.listQuery.current = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.pageSize = val
this.listQuery.size = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.currentPage = val
this.listQuery.current = val
this.getList()
},
handleModifyStatus(row, enable) {
+9
View File
@@ -14,11 +14,20 @@
<artifactId>neutrino-proxy-client</artifactId>
<dependencies>
<!-- <dependency>-->
<!-- <groupId>fun.asgc.neutrino</groupId>-->
<!-- <artifactId>neutrino-core</artifactId>-->
<!-- <version>${revision}</version>-->
<!-- </dependency>-->
<dependency>
<groupId>fun.asgc.neutrino</groupId>
<artifactId>neutrino-proxy-core</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-lib</artifactId>
</dependency>
</dependencies>
<!-- <build>-->
@@ -1,40 +1,38 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.client;
import fun.asgc.neutrino.core.annotation.NeutrinoApplication;
import fun.asgc.neutrino.core.context.NeutrinoLauncher;
import cn.hutool.core.util.StrUtil;
import org.noear.solon.Solon;
import org.noear.solon.SolonApp;
import org.noear.solon.annotation.SolonMain;
/**
*
* @author: aoshiguchen
* @date: 2022/6/16
*/
@NeutrinoApplication
@SolonMain
public class ProxyClient {
public static void main(String[] args) {
NeutrinoLauncher.run(ProxyClient.class, args);
Solon.start(ProxyClient.class, args, app -> {
setAlias("neutrino.proxy.client.serverIp", "serverIp");
setAlias("neutrino.proxy.client.serverPort", "serverPort");
setAlias("neutrino.proxy.client.sslEnable", "sslEnable");
setAlias("neutrino.proxy.client.jksPath", "jksPath");
setAlias("neutrino.proxy.client.keyStorePassword", "keyStorePassword");
setAlias("neutrino.proxy.client.licenseKey", "licenseKey");
});
}
/**
* 别名处理,支持较短的启动参数名
* @param key
* @param alias
*/
private static void setAlias(String key, String alias) {
String val = Solon.cfg().argx().get(alias);
if (StrUtil.isNotBlank(val)) {
Solon.cfg().put(key, val);
}
}
}
@@ -1,31 +1,8 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.client.config;
import fun.asgc.neutrino.core.annotation.Configuration;
import fun.asgc.neutrino.core.annotation.Init;
import fun.asgc.neutrino.core.annotation.Value;
import lombok.Data;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
/**
*
@@ -33,53 +10,33 @@ import lombok.Data;
* @date: 2022/6/16
*/
@Data
@Configuration(prefix = "neutrino.proxy")
@Component
public class ProxyConfig {
public static ProxyConfig instance;
@Inject("${neutrino.proxy.protocol}")
private Protocol protocol;
@Inject("${neutrino.proxy.client}")
private Client client;
private String licenseKey;
private CustomConfig customConfig;
public static volatile boolean authSuccess;
@Data
public static class Protocol {
@Value("max-frame-length")
private Integer maxFrameLength;
@Value("length-field-offset")
private Integer lengthFieldOffset;
@Value("length-field-length")
private Integer lengthFieldLength;
@Value("initial-bytes-to-strip")
private Integer initialBytesToStrip;
@Value("length-adjustment")
private Integer lengthAdjustment;
@Value("read-idle-time")
private Integer readIdleTime;
@Value("write-idle-time")
private Integer writeIdleTime;
@Value("all-idle-time-seconds")
private Integer allIdleTimeSeconds;
}
@Data
public static class Client {
@Value("key-store-password")
private String keyStorePassword;
@Value("jks-path")
private String jksPath;
@Value("server-ip")
private String serverIp;
@Value("server-port")
private Integer serverPort;
@Value("ssl-enable")
private Boolean sslEnable;
@Value("obtain-license-interval")
private Integer obtainLicenseInterval;
}
@Init
public void init() {
instance = this;
private String licenseKey;
}
}
@@ -1,51 +1,45 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.client.config;
import fun.asgc.neutrino.core.annotation.Bean;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Order;
import fun.asgc.neutrino.core.base.DefaultDispatcher;
import fun.asgc.neutrino.core.base.Dispatcher;
import fun.asgc.neutrino.core.base.Ordered;
import fun.asgc.neutrino.core.util.BeanManager;
import fun.asgc.neutrino.proxy.core.ProxyDataTypeEnum;
import fun.asgc.neutrino.proxy.core.ProxyMessage;
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
import fun.asgc.neutrino.proxy.core.dispatcher.DefaultDispatcher;
import fun.asgc.neutrino.proxy.core.dispatcher.Dispatcher;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.nio.NioEventLoopGroup;
import org.noear.solon.Solon;
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.core.bean.LifecycleBean;
import java.util.List;
/**
* 代理配置
* @author: aoshiguchen
* @date: 2022/10/8
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class ProxyConfiguration {
@Configuration
public class ProxyConfiguration implements LifecycleBean {
@Bean
public Dispatcher<ChannelHandlerContext, ProxyMessage> dispatcher() {
return new DefaultDispatcher<>("消息调度器",
BeanManager.getBeanListBySuperClass(ProxyMessageHandler.class),
proxyMessage -> ProxyDataTypeEnum.of((int)proxyMessage.getType()) == null ? null : ProxyDataTypeEnum.of((int)proxyMessage.getType()).getName());
@Override
public void start() throws Throwable {
List<ProxyMessageHandler> list = Solon.context().getBeansOfType(ProxyMessageHandler.class);
Dispatcher<ChannelHandlerContext, ProxyMessage> dispatcher = new DefaultDispatcher<>("消息调度器", list,
proxyMessage -> ProxyDataTypeEnum.of((int)proxyMessage.getType()) == null ?
null : ProxyDataTypeEnum.of((int)proxyMessage.getType()).getName());
Solon.context().wrapAndPut(Dispatcher.class, dispatcher);
}
@Bean("bootstrap")
public Bootstrap bootstrap() {
return new Bootstrap();
}
@Bean("realServerBootstrap")
public Bootstrap realServerBootstrap() {
return new Bootstrap();
}
}
@@ -1,55 +1,55 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.client.core;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.annotation.Subscribe;
import fun.asgc.neutrino.core.base.event.ApplicationEvent;
import fun.asgc.neutrino.core.base.event.ApplicationEventReceiver;
import fun.asgc.neutrino.core.constant.AppLifeCycleStatusEnum;
import fun.asgc.neutrino.core.constant.MetaDataConstant;
import lombok.extern.slf4j.Slf4j;
/**
* 应用生命周期事件监听器
* @author: aoshiguchen
* @date: 2022/10/10
*/
@Slf4j
@NonIntercept
@Component
@Subscribe(topic = MetaDataConstant.TOPIC_APP_LIFE_CYCLE)
public class ApplicationLifeCycleListener extends ApplicationEventReceiver<AppLifeCycleStatusEnum> {
@Autowired
private LicenseObtainService licenseObtainService;
@Override
public void receive(ApplicationEvent<AppLifeCycleStatusEnum> msg) {
log.debug("ApplicationLifeCycleListener:{}", msg.data().getDesc());
if (msg.data() == AppLifeCycleStatusEnum.APP_STARTUP) {
licenseObtainService.start();
}
}
}
///**
// * Copyright (c) 2022 aoshiguchen
// *
// * Permission is hereby granted, free of charge, to any person obtaining a copy
// * of this software and associated documentation files (the "Software"), to deal
// * in the Software without restriction, including without limitation the rights
// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// * copies of the Software, and to permit persons to whom the Software is
// * furnished to do so, subject to the following conditions:
// *
// * The above copyright notice and this permission notice shall be included in all
// * copies or substantial portions of the Software.
// *
// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// * SOFTWARE.
// */
//package fun.asgc.neutrino.proxy.client.core;
//
//import fun.asgc.neutrino.core.annotation.Autowired;
//import fun.asgc.neutrino.core.annotation.Component;
//import fun.asgc.neutrino.core.annotation.NonIntercept;
//import fun.asgc.neutrino.core.annotation.Subscribe;
//import fun.asgc.neutrino.core.base.event.ApplicationEvent;
//import fun.asgc.neutrino.core.base.event.ApplicationEventReceiver;
//import fun.asgc.neutrino.core.constant.AppLifeCycleStatusEnum;
//import fun.asgc.neutrino.core.constant.MetaDataConstant;
//import lombok.extern.slf4j.Slf4j;
//
///**
// * 应用生命周期事件监听器
// * @author: aoshiguchen
// * @date: 2022/10/10
// */
//@Slf4j
//@NonIntercept
//@Component
//@Subscribe(topic = MetaDataConstant.TOPIC_APP_LIFE_CYCLE)
//public class ApplicationLifeCycleListener extends ApplicationEventReceiver<AppLifeCycleStatusEnum> {
// @Autowired
// private LicenseObtainService licenseObtainService;
//
// @Override
// public void receive(ApplicationEvent<AppLifeCycleStatusEnum> msg) {
// log.debug("ApplicationLifeCycleListener:{}", msg.data().getDesc());
// if (msg.data() == AppLifeCycleStatusEnum.APP_STARTUP) {
// licenseObtainService.start();
// }
// }
//
//}
@@ -1,38 +1,16 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.client.core;
import fun.asgc.neutrino.core.base.Dispatcher;
import fun.asgc.neutrino.core.util.BeanManager;
import fun.asgc.neutrino.proxy.client.util.ProxyUtil;
import fun.asgc.neutrino.proxy.core.Constants;
import fun.asgc.neutrino.proxy.core.ProxyMessage;
import fun.asgc.neutrino.proxy.core.dispatcher.Dispatcher;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.Solon;
/**
* 处理与服务端之间的数据传输
@@ -42,19 +20,13 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ClientChannelHandler extends SimpleChannelInboundHandler<ProxyMessage> {
private static volatile Dispatcher<ChannelHandlerContext, ProxyMessage> dispatcher;
public ClientChannelHandler() {
dispatcher = BeanManager.getBean(Dispatcher.class);
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception {
if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType()) {
log.info("recieved proxy message, type is {}", proxyMessage.getType());
}
dispatcher.dispatch(ctx, proxyMessage);
Solon.context().getBean(Dispatcher.class).dispatch(ctx, proxyMessage);
}
@Override
@@ -19,32 +19,37 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.base.rest.config;
package fun.asgc.neutrino.proxy.client.core;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Bean;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.quartz.JobExecutor;
import fun.asgc.neutrino.proxy.server.service.JobInfoService;
import fun.asgc.neutrino.proxy.server.service.JobLogService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 定时任务配置
*
* @author: aoshiguchen
* @date: 2022/9/4
*/
@Component
public class JobConfig {
@Autowired
private JobLogService jobLogService;
@Autowired
private JobInfoService jobInfoService;
public class CustomThreadFactory implements ThreadFactory {
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
@Bean
public JobExecutor jobExecutor() {
JobExecutor executor = new JobExecutor();
executor.setJobSource(jobInfoService);
executor.setJobCallback(jobLogService);
return executor;
public CustomThreadFactory(String prefix) {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = prefix + "-thread-";
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
if (t.isDaemon()) {
t.setDaemon(false);
}
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
}
@@ -1,175 +1,166 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.client.core;
import com.alibaba.fastjson.JSONObject;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.base.CustomThreadFactory;
import fun.asgc.neutrino.core.context.Environment;
import fun.asgc.neutrino.core.util.ArrayUtil;
import fun.asgc.neutrino.core.util.FileUtil;
import fun.asgc.neutrino.core.util.StringUtil;
import fun.asgc.neutrino.proxy.client.config.CustomConfig;
import fun.asgc.neutrino.proxy.client.config.ProxyConfig;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* license获取服务
* @author: aoshiguchen
* @date: 2022/9/4
*/
@Slf4j
@NonIntercept
@Component
public class LicenseObtainService {
@Autowired
private ProxyConfig proxyConfig;
/**
* 调度器
*/
private static final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(new CustomThreadFactory("LicenseObtain"));
@Autowired
private ProxyClientService proxyClientService;
private ReentrantLock runLock = new ReentrantLock();
private Scanner scanner = new Scanner(System.in);
@Autowired
private Environment environment;
public void start() {
scheduledExecutor.scheduleWithFixedDelay(() -> {
boolean lock = runLock.tryLock();
try {
if (lock) {
this.process(this.environment.getMainArgs());
}
} finally {
if (runLock.isHeldByCurrentThread()){
runLock.unlock();
}
}
}, 0, proxyConfig.getClient().getObtainLicenseInterval(), TimeUnit.SECONDS);
}
public void stop() {
scheduledExecutor.shutdown();
log.info("licenseKey获取任务停止");
}
public void process(String[] args) {
CustomConfig customConfig = getCustomConfigByCliParams(args);
proxyConfig.getClient().setJksPath(customConfig.getJksPath());
proxyConfig.getClient().setServerIp(customConfig.getServerIp());
proxyConfig.getClient().setServerPort(customConfig.getServerPort());
proxyConfig.getClient().setSslEnable(customConfig.getSslEnable());
proxyConfig.setLicenseKey(customConfig.getLicenseKey());
proxyConfig.setCustomConfig(customConfig);
proxyClientService.start();
}
private CustomConfig getCustomConfigByCliParams(String[] args) {
CustomConfig customConfig = new CustomConfig();
// 默认无需输入
customConfig.setJksPath(environment.getMainArgsForString("jksPath", proxyConfig.getClient().getJksPath()));
customConfig.setServerIp(environment.getMainArgsForString("serverIp", proxyConfig.getClient().getServerIp()));
customConfig.setServerPort(environment.getMainArgsForInteger("serverPort", proxyConfig.getClient().getServerPort()));
customConfig.setSslEnable(environment.getMainArgsForBoolean("sslEnable", proxyConfig.getClient().getSslEnable()));
customConfig.setLicenseKey(environment.getMainArgsForString("licenseKey"));
// 启动参数指定了license,则无需后续处理
if (StringUtil.notEmpty(customConfig.getLicenseKey())) {
// FileUtil.write("./.neutrino-proxy-client.json", JSONObject.toJSONString(customConfig, SerializerFeature.PrettyFormat));
return customConfig;
}
// 启动参数未指定license,则优先读取外部配置
String config = FileUtil.readContentAsString("./.neutrino-proxy-client.json");
if (StringUtil.notEmpty(config)) {
try {
CustomConfig tmp = JSONObject.parseObject(config, CustomConfig.class);
if (!StringUtil.isEmpty(tmp.getJksPath())) {
customConfig.setJksPath(tmp.getJksPath());
}
if (!StringUtil.isEmpty(tmp.getServerIp())) {
customConfig.setServerIp(tmp.getServerIp());
}
if (null != tmp.getServerPort()) {
customConfig.setServerPort(tmp.getServerPort());
}
if (null != tmp.getSslEnable()) {
customConfig.setSslEnable(tmp.getSslEnable());
}
if (!StringUtil.isEmpty(tmp.getLicenseKey())) {
customConfig.setLicenseKey(tmp.getLicenseKey());
}
} catch (Exception e) {
log.error("file '.neutrino-proxy-client.json' config exception!", e);
}
if (StringUtil.notEmpty(customConfig.getLicenseKey())) {
// FileUtil.write("./.neutrino-proxy-client.json", JSONObject.toJSONString(customConfig, SerializerFeature.PrettyFormat));
return customConfig;
}
}
String license = "";
while (StringUtil.isEmpty(license)) {
System.out.print("Please input license:");
license = scanner.next();
}
customConfig.setLicenseKey(license);
// FileUtil.write("./.neutrino-proxy-client.json", JSONObject.toJSONString(customConfig, SerializerFeature.PrettyFormat));
return customConfig;
}
/**
* 获取命令行参数
* @param args
* @return
*/
private Map<String, String> getCliParams(String[] args) {
Map<String, String> res = new HashMap<>();
if (ArrayUtil.notEmpty(args)) {
for (String item : args) {
if (StringUtil.isEmpty(item) || !item.contains("=")) {
continue;
}
int index = item.indexOf("=");
if (index <= 0 || index == item.length() - 1) {
continue;
}
res.put(item.substring(0, index), item.substring(index + 1));
}
}
return res;
}
}
///**
// * Copyright (c) 2022 aoshiguchen
// *
// * Permission is hereby granted, free of charge, to any person obtaining a copy
// * of this software and associated documentation files (the "Software"), to deal
// * in the Software without restriction, including without limitation the rights
// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// * copies of the Software, and to permit persons to whom the Software is
// * furnished to do so, subject to the following conditions:
// *
// * The above copyright notice and this permission notice shall be included in all
// * copies or substantial portions of the Software.
// *
// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// * SOFTWARE.
// */
//package fun.asgc.neutrino.proxy.client.core;
//
//import com.alibaba.fastjson.JSONObject;
//import fun.asgc.neutrino.core.base.CustomThreadFactory;
//import fun.asgc.neutrino.core.util.ArrayUtil;
//import fun.asgc.neutrino.core.util.FileUtil;
//import fun.asgc.neutrino.core.util.StringUtil;
//import fun.asgc.neutrino.proxy.client.config.CustomConfig;
//import fun.asgc.neutrino.proxy.client.config.ProxyConfig;
//import lombok.extern.slf4j.Slf4j;
//import org.noear.solon.annotation.Component;
//import org.noear.solon.annotation.Inject;
//
//import java.util.HashMap;
//import java.util.Map;
//import java.util.Scanner;
//import java.util.concurrent.Executors;
//import java.util.concurrent.ScheduledExecutorService;
//import java.util.concurrent.TimeUnit;
//import java.util.concurrent.locks.ReentrantLock;
//
///**
// * license获取服务
// * @author: aoshiguchen
// * @date: 2022/9/4
// */
//@Slf4j
//@Component
//public class LicenseObtainService {
// /**
// * 调度器
// */
// private static final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(new CustomThreadFactory("LicenseObtain"));
// private ReentrantLock runLock = new ReentrantLock();
// private Scanner scanner = new Scanner(System.in);
// @Inject
// private ProxyConfig proxyConfig;
// @Inject
// private ProxyClientService proxyClientService;
//
// public void start() {
// scheduledExecutor.scheduleWithFixedDelay(() -> {
// boolean lock = runLock.tryLock();
// try {
// if (lock) {
// this.process();
// }
// } finally {
// if (runLock.isHeldByCurrentThread()){
// runLock.unlock();
// }
// }
// }, 0, proxyConfig.getClient().getObtainLicenseInterval(), TimeUnit.SECONDS);
// }
//
// public void stop() {
// scheduledExecutor.shutdown();
// log.info("licenseKey获取任务停止");
// }
//
// public void process() {
//
//
// proxyClientService.start();
// }
//
// private String
//
// private CustomConfig getCustomConfigByCliParams() {
// CustomConfig customConfig = new CustomConfig();
// // 默认无需输入
// customConfig.setJksPath(environment.getMainArgsForString("jksPath", proxyConfig.getClient().getJksPath()));
// customConfig.setServerIp(environment.getMainArgsForString("serverIp", proxyConfig.getClient().getServerIp()));
// customConfig.setServerPort(environment.getMainArgsForInteger("serverPort", proxyConfig.getClient().getServerPort()));
// customConfig.setSslEnable(environment.getMainArgsForBoolean("sslEnable", proxyConfig.getClient().getSslEnable()));
// customConfig.setLicenseKey(environment.getMainArgsForString("licenseKey"));
// // 启动参数指定了license,则无需后续处理
// if (StringUtil.notEmpty(customConfig.getLicenseKey())) {
//// FileUtil.write("./.neutrino-proxy-client.json", JSONObject.toJSONString(customConfig, SerializerFeature.PrettyFormat));
// return customConfig;
// }
//
// // 启动参数未指定license,则优先读取外部配置
// String config = FileUtil.readContentAsString("./.neutrino-proxy-client.json");
// if (StringUtil.notEmpty(config)) {
// try {
// CustomConfig tmp = JSONObject.parseObject(config, CustomConfig.class);
// if (!StringUtil.isEmpty(tmp.getJksPath())) {
// customConfig.setJksPath(tmp.getJksPath());
// }
// if (!StringUtil.isEmpty(tmp.getServerIp())) {
// customConfig.setServerIp(tmp.getServerIp());
// }
// if (null != tmp.getServerPort()) {
// customConfig.setServerPort(tmp.getServerPort());
// }
// if (null != tmp.getSslEnable()) {
// customConfig.setSslEnable(tmp.getSslEnable());
// }
// if (!StringUtil.isEmpty(tmp.getLicenseKey())) {
// customConfig.setLicenseKey(tmp.getLicenseKey());
// }
// } catch (Exception e) {
// log.error("file '.neutrino-proxy-client.json' config exception!", e);
// }
// if (StringUtil.notEmpty(customConfig.getLicenseKey())) {
//// FileUtil.write("./.neutrino-proxy-client.json", JSONObject.toJSONString(customConfig, SerializerFeature.PrettyFormat));
// return customConfig;
// }
// }
//
// String license = "";
// while (StringUtil.isEmpty(license)) {
// System.out.print("Please input license:");
// license = scanner.next();
// }
// customConfig.setLicenseKey(license);
//// FileUtil.write("./.neutrino-proxy-client.json", JSONObject.toJSONString(customConfig, SerializerFeature.PrettyFormat));
//
// return customConfig;
// }
//
// /**
// * 获取命令行参数
// * @param args
// * @return
// */
// private Map<String, String> getCliParams(String[] args) {
// Map<String, String> res = new HashMap<>();
// if (ArrayUtil.notEmpty(args)) {
// for (String item : args) {
// if (StringUtil.isEmpty(item) || !item.contains("=")) {
// continue;
// }
// int index = item.indexOf("=");
// if (index <= 0 || index == item.length() - 1) {
// continue;
// }
// res.put(item.substring(0, index), item.substring(index + 1));
// }
// }
//
// return res;
// }
//}
@@ -1,37 +1,12 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.client.core;
import fun.asgc.neutrino.core.annotation.*;
import fun.asgc.neutrino.core.base.CustomThreadFactory;
import fun.asgc.neutrino.core.context.Environment;
import fun.asgc.neutrino.core.util.FileUtil;
import fun.asgc.neutrino.core.util.StringUtil;
import cn.hutool.core.util.StrUtil;
import fun.asgc.neutrino.proxy.client.config.ProxyConfig;
import fun.asgc.neutrino.proxy.client.util.ProxyUtil;
import fun.asgc.neutrino.proxy.core.ProxyMessage;
import fun.asgc.neutrino.proxy.core.ProxyMessageDecoder;
import fun.asgc.neutrino.proxy.core.ProxyMessageEncoder;
import fun.asgc.neutrino.proxy.core.util.FileUtil;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
@@ -40,6 +15,10 @@ import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.Solon;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Init;
import org.noear.solon.annotation.Inject;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
@@ -57,18 +36,14 @@ import java.util.concurrent.TimeUnit;
* @date: 2022/6/16
*/
@Slf4j
@NonIntercept
@Component
public class ProxyClientService {
@Autowired
@Inject
private ProxyConfig proxyConfig;
@Autowired("bootstrap")
private static Bootstrap bootstrap;
@Autowired("realServerBootstrap")
private static Bootstrap realServerBootstrap;
private static NioEventLoopGroup workerGroup;
@Autowired
private Environment environment;
@Inject("bootstrap")
private Bootstrap bootstrap;
@Inject("realServerBootstrap")
private Bootstrap realServerBootstrap;
private volatile Channel channel;
/**
* 重连间隔(秒)
@@ -91,7 +66,7 @@ public class ProxyClientService {
public void init() {
this.reconnectExecutor.scheduleWithFixedDelay(this::reconnect, 0, RECONNECT_INTERVAL_SECONDS, TimeUnit.SECONDS);
workerGroup = new NioEventLoopGroup();
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
realServerBootstrap.group(workerGroup);
realServerBootstrap.channel(NioSocketChannel.class);
realServerBootstrap.handler(new ChannelInitializer<SocketChannel>() {
@@ -120,20 +95,39 @@ public class ProxyClientService {
ch.pipeline().addLast(new ClientChannelHandler());
}
});
this.start();
}
public void start() {
if (StringUtil.isEmpty(proxyConfig.getLicenseKey())) {
if (StrUtil.isEmpty(proxyConfig.getClient().getServerIp())) {
log.error("not found server-ip config.");
Solon.stop();
return;
}
if (null == proxyConfig.getClient().getServerPort()) {
log.error("not found server-port config.");
Solon.stop();
return;
}
if (null != proxyConfig.getClient().getSslEnable() && proxyConfig.getClient().getSslEnable()
&& StrUtil.isEmpty(proxyConfig.getClient().getJksPath())) {
log.error("not found jks-path config.");
Solon.stop();
return;
}
if (StrUtil.isEmpty(proxyConfig.getClient().getLicenseKey())) {
log.error("not found license-key config.");
Solon.stop();
return;
}
if (null == channel || !channel.isActive()) {
try {
connectProxyServer();
} catch (Exception e) {
log.error("启动异常", e);
log.error("client start error", e);
}
} else {
channel.writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getLicenseKey()));
channel.writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey()));
}
}
@@ -150,7 +144,7 @@ public class ProxyClientService {
channel = future.channel();
// 连接成功,向服务器发送客户端认证信息(licenseKey)
ProxyUtil.setCmdChannel(future.channel());
future.channel().writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getLicenseKey()));
future.channel().writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey()));
log.info("连接代理服务成功. channelId:{}", future.channel().id().asLongText());
reconnectServiceEnable = true;
@@ -199,14 +193,4 @@ public class ProxyClientService {
log.error("重连异常", e);
}
}
@Bean
public Bootstrap bootstrap() {
return new Bootstrap();
}
@Bean
public Bootstrap realServerBootstrap() {
return new Bootstrap();
}
}
@@ -1,41 +1,13 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.client.handler;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Match;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.util.FileUtil;
import fun.asgc.neutrino.proxy.client.config.ProxyConfig;
import fun.asgc.neutrino.proxy.client.core.LicenseObtainService;
import fun.asgc.neutrino.proxy.core.Constants;
import fun.asgc.neutrino.proxy.core.ExceptionEnum;
import fun.asgc.neutrino.proxy.core.ProxyMessage;
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Component;
/**
* 认证信息处理器
@@ -43,25 +15,14 @@ import lombok.extern.slf4j.Slf4j;
* @date: 2022/9/4
*/
@Slf4j
@NonIntercept
@Match(type = Constants.ProxyDataTypeName.AUTH)
@Component
public class ProxyMessageAuthHandler implements ProxyMessageHandler {
@Autowired
private LicenseObtainService licenseObtainService;
@Autowired
private ProxyConfig proxyConfig;
@Override
public void handle(ChannelHandlerContext context, ProxyMessage proxyMessage) {
String info = proxyMessage.getInfo();
JSONObject data = JSONObject.parseObject(info);
Integer code = data.getInteger("code");
log.info("认证结果:{}", info);
if (ExceptionEnum.SUCCESS.getCode().equals(code)) {
ProxyConfig.authSuccess = true;
FileUtil.write("./.neutrino-proxy-client.json", JSONObject.toJSONString(proxyConfig.getCustomConfig(), SerializerFeature.PrettyFormat));
licenseObtainService.stop();
}
}
}
@@ -1,51 +1,32 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.client.handler;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Match;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.proxy.client.config.ProxyConfig;
import fun.asgc.neutrino.proxy.client.core.ProxyChannelBorrowListener;
import fun.asgc.neutrino.proxy.client.util.ProxyUtil;
import fun.asgc.neutrino.proxy.core.*;
import fun.asgc.neutrino.proxy.core.Constants;
import fun.asgc.neutrino.proxy.core.ProxyDataTypeEnum;
import fun.asgc.neutrino.proxy.core.ProxyMessage;
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
/**
* 连接信息处理器
* @author: aoshiguchen
* @date: 2022/6/16
*/
@NonIntercept
@Match(type = Constants.ProxyDataTypeName.CONNECT)
@Component
public class ProxyMessageConnectHandler implements ProxyMessageHandler {
@Autowired("bootstrap")
@Inject("bootstrap")
private Bootstrap bootstrap;
@Autowired("realServerBootstrap")
@Inject("realServerBootstrap")
private Bootstrap realServerBootstrap;
@Inject
private ProxyConfig proxyConfig;
@Override
public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
@@ -76,7 +57,7 @@ public class ProxyMessageConnectHandler implements ProxyMessageHandler {
realServerChannel.attr(Constants.NEXT_CHANNEL).set(channel);
// 远程绑定
channel.writeAndFlush(ProxyMessage.buildConnectMessage(visitorId + "@" + ProxyConfig.instance.getLicenseKey()));
channel.writeAndFlush(ProxyMessage.buildConnectMessage(visitorId + "@" + proxyConfig.getClient().getLicenseKey()));
realServerChannel.config().setOption(ChannelOption.AUTO_READ, true);
ProxyUtil.addRealServerChannel(visitorId, realServerChannel);
@@ -1,46 +1,22 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.client.handler;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Match;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.proxy.client.util.ProxyUtil;
import fun.asgc.neutrino.proxy.core.Constants;
import fun.asgc.neutrino.proxy.core.ProxyDataTypeEnum;
import fun.asgc.neutrino.proxy.core.ProxyMessage;
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import org.noear.solon.annotation.Component;
/**
* 断开连接信息处理器
* @author: aoshiguchen
* @date: 2022/6/16
*/
@NonIntercept
@Match(type = Constants.ProxyDataTypeName.DISCONNECT)
@Component
public class ProxyMessageDisconnectHandler implements ProxyMessageHandler {
@@ -1,34 +1,11 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.client.handler;
import com.alibaba.fastjson.JSONObject;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Match;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.proxy.core.*;
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Component;
/**
* 异常信息处理器
@@ -36,7 +13,6 @@ import lombok.extern.slf4j.Slf4j;
* @date: 2022/6/16
*/
@Slf4j
@NonIntercept
@Match(type = Constants.ProxyDataTypeName.ERROR)
@Component
public class ProxyMessageErrorHandler implements ProxyMessageHandler {
@@ -1,44 +1,20 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.client.handler;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Match;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.proxy.core.Constants;
import fun.asgc.neutrino.proxy.core.ProxyDataTypeEnum;
import fun.asgc.neutrino.proxy.core.ProxyMessage;
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import org.noear.solon.annotation.Component;
/**
* 传输信息处理器
* @author: aoshiguchen
* @date: 2022/6/16
*/
@NonIntercept
@Match(type = Constants.ProxyDataTypeName.TRANSFER)
@Component
public class ProxyMessageTransferHandler implements ProxyMessageHandler {
@@ -31,6 +31,7 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import io.netty.util.AttributeKey;
import org.noear.solon.Solon;
import java.util.Iterator;
import java.util.Map;
@@ -62,15 +63,13 @@ public class ProxyUtil {
return;
}
bootstrap.connect(ProxyConfig.instance.getClient().getServerIp(), ProxyConfig.instance.getClient().getServerPort()).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
borrowListener.success(future.channel());
} else {
borrowListener.error(future.cause());
}
String serverIp = Solon.cfg().get("neutrino.proxy.client.server-ip");
Integer serverPort = Solon.cfg().getInt("neutrino.proxy.client.server-port", 9000);
bootstrap.connect(serverIp, serverPort).addListener((ChannelFutureListener) future -> {
if (future.isSuccess()) {
borrowListener.success(future.channel());
} else {
borrowListener.error(future.cause());
}
});
}
@@ -19,3 +19,4 @@ neutrino:
server-port: 9002
ssl-enable: true
obtain-license-interval: 5
license-key:
+13 -3
View File
@@ -14,9 +14,19 @@
<dependencies>
<dependency>
<groupId>fun.asgc.neutrino</groupId>
<artifactId>neutrino-core</artifactId>
<version>${revision}</version>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
<!--hutool -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>${hutool.ver}</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
@@ -1,28 +1,6 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.core;
import fun.asgc.neutrino.core.base.Handler;
import fun.asgc.neutrino.proxy.core.dispatcher.Handler;
import io.netty.channel.ChannelHandlerContext;
/**
@@ -19,19 +19,19 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.aop.Intercept;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
package fun.asgc.neutrino.proxy.core.base;
/**
*
* @author: aoshiguchen
* @date: 2022/8/31
* @date: 2022/6/16
*/
@Intercept(ignoreGlobal = true)
@Component
public interface UserConnectRecordMapper extends SqlMapper {
@FunctionalInterface
public interface CodeBlock {
/**
* 执行
*/
void execute() throws Exception;
}
@@ -0,0 +1,19 @@
package fun.asgc.neutrino.proxy.core.base;
/**
*
* @author: aoshiguchen
* @date: 2022/6/16
*/
public class InternalException extends RuntimeException {
public InternalException(String message) {
super(message);
}
public InternalException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -0,0 +1,102 @@
package fun.asgc.neutrino.proxy.core.base;
/**
*
* @author: aoshiguchen
* @date: 2022/6/16
*/
public interface MetaDataConstant {
String DEFAULT_BANNER = "\n _____ _____ _____ _____ _____ _____ _____ _______ \n" +
" /\\ \\ /\\ \\ /\\ \\ /\\ \\ /\\ \\ /\\ \\ /\\ \\ /::\\ \\ \n" +
" /::\\____\\ /::\\ \\ /::\\____\\ /::\\ \\ /::\\ \\ /::\\ \\ /::\\____\\ /::::\\ \\ \n" +
" /::::| | /::::\\ \\ /:::/ / \\:::\\ \\ /::::\\ \\ \\:::\\ \\ /::::| | /::::::\\ \\ \n" +
" /:::::| | /::::::\\ \\ /:::/ / \\:::\\ \\ /::::::\\ \\ \\:::\\ \\ /:::::| | /::::::::\\ \\ \n" +
" /::::::| | /:::/\\:::\\ \\ /:::/ / \\:::\\ \\ /:::/\\:::\\ \\ \\:::\\ \\ /::::::| | /:::/~~\\:::\\ \\ \n" +
" /:::/|::| | /:::/__\\:::\\ \\ /:::/ / \\:::\\ \\ /:::/__\\:::\\ \\ \\:::\\ \\ /:::/|::| | /:::/ \\:::\\ \\ \n" +
" /:::/ |::| | /::::\\ \\:::\\ \\ /:::/ / /::::\\ \\ /::::\\ \\:::\\ \\ /::::\\ \\ /:::/ |::| | /:::/ / \\:::\\ \\ \n" +
" /:::/ |::| | _____ /::::::\\ \\:::\\ \\ /:::/ / _____ /::::::\\ \\ /::::::\\ \\:::\\ \\ ____ /::::::\\ \\ /:::/ |::| | _____ /:::/____/ \\:::\\____\\ \n" +
" /:::/ |::| |/\\ \\ /:::/\\:::\\ \\:::\\ \\ /:::/____/ /\\ \\ /:::/\\:::\\ \\ /:::/\\:::\\ \\:::\\____\\ /\\ \\ /:::/\\:::\\ \\ /:::/ |::| |/\\ \\ |:::| | |:::| |\n" +
"/:: / |::| /::\\____\\/:::/__\\:::\\ \\:::\\____\\|:::| / /::\\____\\ /:::/ \\:::\\____\\/:::/ \\:::\\ \\:::| |/::\\ \\/:::/ \\:::\\____\\/:: / |::| /::\\____\\|:::|____| |:::| |\n" +
"\\::/ /|::| /:::/ /\\:::\\ \\:::\\ \\::/ /|:::|____\\ /:::/ / /:::/ \\::/ /\\::/ |::::\\ /:::|____|\\:::\\ /:::/ \\::/ /\\::/ /|::| /:::/ / \\:::\\ \\ /:::/ / \n" +
" \\/____/ |::| /:::/ / \\:::\\ \\:::\\ \\/____/ \\:::\\ \\ /:::/ / /:::/ / \\/____/ \\/____|:::::\\/:::/ / \\:::\\/:::/ / \\/____/ \\/____/ |::| /:::/ / \\:::\\ \\ /:::/ / \n" +
" |::|/:::/ / \\:::\\ \\:::\\ \\ \\:::\\ \\ /:::/ / /:::/ / |:::::::::/ / \\::::::/ / |::|/:::/ / \\:::\\ /:::/ / \n" +
" |::::::/ / \\:::\\ \\:::\\____\\ \\:::\\ /:::/ / /:::/ / |::|\\::::/ / \\::::/____/ |::::::/ / \\:::\\__/:::/ / \n" +
" |:::::/ / \\:::\\ \\::/ / \\:::\\__/:::/ / \\::/ / |::| \\::/____/ \\:::\\ \\ |:::::/ / \\::::::::/ / \n" +
" |::::/ / \\:::\\ \\/____/ \\::::::::/ / \\/____/ |::| ~| \\:::\\ \\ |::::/ / \\::::::/ / \n" +
" /:::/ / \\:::\\ \\ \\::::::/ / |::| | \\:::\\ \\ /:::/ / \\::::/ / \n" +
" /:::/ / \\:::\\____\\ \\::::/ / \\::| | \\:::\\____\\ /:::/ / \\::/____/ \n" +
" \\::/ / \\::/ / \\::/____/ \\:| | \\::/ / \\::/ / ~~ \n" +
" \\/____/ \\/____/ ~~ \\|___| \\/____/ \\/____/ \n" +
" ";
/**
* classpath标识符
*/
String CLASSPATH_IDENTIFIER = "classpath";
/**
* classpath资源标识
*/
String CLASSPATH_RESOURCE_IDENTIFIER = CLASSPATH_IDENTIFIER + ":";
/**
* 默认的yml配置文件名
*/
String DEFAULT_YML_CONFIG_FILE_NAME = "application.yml";
/**
* 应用banner路径
*/
String APP_BANNER_FILE_PATH = CLASSPATH_RESOURCE_IDENTIFIER.concat("/banner.txt");
/**
* 默认的http页面路径
*/
String DEFAULT_HTTP_PAGE_PATH = CLASSPATH_RESOURCE_IDENTIFIER.concat("/webapp/");
/**
* 服务版本
*/
String SERVER_VS = "Neutrino-1.0";
/**
* app生命周期主题
*/
String TOPIC_APP_LIFE_CYCLE = "TP_APP_LIFE_CYCLE";
/**
* 环境变量key
*/
String ENVIRONMENT_VARIABLE_KEY = "NEUTRINO_PROXY";
interface Config {
String NEUTRINO_APPLICATION_NAME = "neutrino.application.name";
String NEUTRINO_HTTP_ENABLE = "neutrino.http.enable";
String NEUTRINO_HTTP_PORT = "neutrino.http.port";
String NEUTRINO_HTTP_CONTEXT_PATH = "neutrino.http.context-path";
String NEUTRINO_HTTP_MAX_CONTENT_LENGTH_DESC = "neutrino.http.max-content-length-desc";
String NEUTRINO_HTTP_STATIC_RESOURCE_LOCATIONS = "neutrino.http.static-resource.locations";
String NEUTRINO_PROXY_PROTOCOL_MAX_FRAME_LENGTH = "neutrino.proxy.protocol.max-frame-length";
String NEUTRINO_PROXY_PROTOCOL_LENGTH_FIELD_OFFSET = "neutrino.proxy.protocol.length-field-offset";
String NEUTRINO_PROXY_PROTOCOL_LENGTH_FIELD_LENGTH = "neutrino.proxy.protocol.length-field-length";
String NEUTRINO_PROXY_PROTOCOL_INITIAL_BYTES_TO_STRIP = "neutrino.proxy.protocol.initial-bytes-to-strip";
String NEUTRINO_PROXY_PROTOCOL_LENGTH_ADJUSTMENT = "neutrino.proxy.protocol.length-adjustment";
String NEUTRINO_PROXY_PROTOCOL_READ_IDLE_TIME = "neutrino.proxy.protocol.read-idle-time";
String NEUTRINO_PROXY_PROTOCOL_WRITE_IDLE_TIME = "neutrino.proxy.protocol.write-idle-time";
String NEUTRINO_PROXY_PROTOCOL_ALL_IDLE_TIME_SECONDS = "neutrino.proxy.protocol.all-idle-time-seconds";
String NEUTRINO_PROXY_SERVER_PORT = "neutrino.proxy.server.port";
String NEUTRINO_PROXY_SERVER_SSL_PORT = "neutrino.proxy.server.ssl-port";
String NEUTRINO_PROXY_SERVER_KEY_STORE_PASSWORD = "neutrino.proxy.server.key-store-password";
String NEUTRINO_PROXY_SERVER_KEY_MANAGER_PASSWORD = "neutrino.proxy.server.key-manager-password";
String NEUTRINO_PROXY_SERVER_JKS_PATH = "neutrino.proxy.server.jks-path";
String NEUTRINO_PROXY_CLIENT_KEY_STORE_PASSWORD = "neutrino.proxy.client.key-store-password";
String NEUTRINO_PROXY_CLIENT_JKS_PATH = "neutrino.proxy.client.jks-path";
String NEUTRINO_PROXY_CLIENT_SERVER_IP = "neutrino.proxy.client.server-ip";
String NEUTRINO_PROXY_CLIENT_SERVER_PORT = "neutrino.proxy.client.server-port";
String NEUTRINO_PROXY_CLIENT_SSL_ENABLE = "neutrino.proxy.client.ssl-enable";
String NEUTRINO_PROXY_CLIENT_OBTAIN_LICENSE_INTERVAL = "neutrino.proxy.client.obtain-license-interval";
String NEUTRINO_DATA_DB_TYPE = "neutrino.data.db.type";
String NEUTRINO_DATA_DB_URL = "neutrino.data.db.url";
String NEUTRINO_DATA_DB_DRIVER_CLASS = "neutrino.data.db.driver-class";
String NEUTRINO_DATA_DB_USERNAME = "neutrino.data.db.username";
String NEUTRINO_DATA_DB_PASSWORD = "neutrino.data.db.password";
}
}
@@ -0,0 +1,89 @@
package fun.asgc.neutrino.proxy.core.dispatcher;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import fun.asgc.neutrino.proxy.core.util.TypeUtil;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
/**
*
* @author: aoshiguchen
* @date: 2022/6/16
*/
@Slf4j
public class DefaultDispatcher<Context, Data> implements Dispatcher<Context, Data> {
/**
* 调度器名称
*/
private String name;
/**
* 处理器映射
*/
private Map<String, Handler<Context,Data>> handlerMap;
/**
* 匹配器
*/
private Function<Data,String> matcher;
public DefaultDispatcher(String name, List<? extends Handler<Context,Data>> handlerList, Function<Data,String> matcher) {
Assert.notNull(name, "名称不能为空!");
Assert.notNull(matcher, "匹配器不能为空!");
if (CollectionUtil.isEmpty(handlerList)) {
log.error("{} 处理器列表为空.", name);
return;
}
this.name = name == null ? "" : name;
this.handlerMap = new HashMap<>();
this.matcher = matcher;
for (Handler handler : handlerList) {
Match match = handler.getClass().getAnnotation(Match.class);
if (null == match) {
log.warn("{} 类: {} 缺失Match注解", this.name, handler.getClass().getName());
continue;
}
if (StrUtil.isEmpty(match.type())) {
log.warn("{} 类: {} match注解缺失type参数!", this.name, handler.getClass().getName());
continue;
}
if (handlerMap.containsKey(match.type())) {
log.warn("{} 类: {} match注解type值{} 存在重复!", this.name, handler.getClass().getName(), match.type());
continue;
}
handlerMap.put(match.type(), handler);
}
log.info("{} 处理器初始化完成", this.name);
}
@Override
public void dispatch(Context context, Data data) {
if (CollectionUtil.isEmpty(handlerMap)) {
return;
}
String type = matcher.apply(data);
if (null == type) {
log.warn("{} 获取匹配类型失败 data:{}", this.name, JSONObject.toJSONString(data));
return;
}
Handler<Context,Data> handler = handlerMap.get(type);
if (null == handler) {
// log.debug("{} 找不到匹配的处理器 type:{}", this.name, type);
return;
}
String handlerName = handler.name();
if (StrUtil.isEmpty(handlerName)) {
handlerName = TypeUtil.getSimpleName(handler.getClass());
}
log.debug("{} 处理器[{}]执行.", this.name, handlerName);
handler.handle(context, data);
}
}
@@ -19,42 +19,20 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.util;
import io.netty.channel.Channel;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
package fun.asgc.neutrino.proxy.core.dispatcher;
/**
*
* @author: aoshiguchen
* @date: 2022/9/3
* @date: 2022/6/16
*/
public class ChannelUtil {
public interface Dispatcher<Context, Data> {
/**
* 获取ip地址
* @param channel
* @return
* 调度
* @param context
* @param data
*/
public static String getIP(Channel channel) {
if (null == channel) {
return "";
}
String ip = ((InetSocketAddress)channel.remoteAddress()).getAddress().getHostAddress();
if (ip.equals("127.0.0.1") || ip.equals("0:0:0:0:0:0:0:1")) {
//根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
ip = inet.getHostAddress();
}
return ip;
}
void dispatch(Context context, Data data);
}
@@ -19,32 +19,28 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.db.page;
import lombok.Data;
import java.util.List;
package fun.asgc.neutrino.proxy.core.dispatcher;
/**
*
* @author: aoshiguchen
* @date: 2022/8/6
* @date: 2022/6/16
*/
@Data
public class Page<T> extends PageQuery {
/**
* 数据总数
*/
private Long total;
/**
* 结果数据
*/
private List<T> records;
public interface Handler<Context, Data> {
public static <T> Page<T> create(PageQuery pageQuery) {
Page page = new Page();
page.setPageSize(pageQuery.getPageSize());
page.setCurrentPage(pageQuery.getCurrentPage());
return page;
}
/**
* 处理
* @param context
* @param data
*/
void handle(Context context, Data data);
/**
* 名称
* @return
*/
default String name() {
return "";
};
}
@@ -19,20 +19,19 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.base.rest.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
package fun.asgc.neutrino.proxy.core.dispatcher;
import java.lang.annotation.*;
/**
* 暂不做复杂权限控制仅用该注解标注部分接口禁止游客身份调用
*
* @author: aoshiguchen
* @date: 2022/8/14
* @date: 2022/6/16
*/
@Target({ElementType.METHOD})
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface OnlyAdmin {
@Documented
public @interface Match {
String type();
}
@@ -0,0 +1,56 @@
package fun.asgc.neutrino.proxy.core.type;
import java.util.ArrayList;
import java.util.List;
/**
* 抽象的匹配器组
* @author: aoshiguchen
* @date: 2022/6/29
*/
public abstract class AbstractMatcherGroup implements TypeMatcherGroup {
/**
* 最小距离
*/
protected int distanceMin;
/**
* 最大距离
*/
protected int distanceMax;
/**
* 匹配器列表
*/
private List<TypeMatcher> matchers;
public AbstractMatcherGroup(int distanceMin, int distanceMax) {
this.distanceMin = distanceMin;
this.distanceMax = distanceMax;
this.matchers = new ArrayList<>();
this.init();
}
protected abstract void init();
@Override
public List<TypeMatcher> matchers() {
return matchers;
}
public synchronized void add(TypeMatcher matcher) {
if (null != matcher) {
this.matchers.add(matcher);
}
}
@Override
public int getDistanceMin() {
return distanceMin;
}
@Override
public int getDistanceMax() {
return distanceMax;
}
}
@@ -0,0 +1,112 @@
package fun.asgc.neutrino.proxy.core.type;
import fun.asgc.neutrino.proxy.core.util.TypeUtil;
/**
* 默认的类型匹配器组
* @author: aoshiguchen
* @date: 2022/7/1
*/
public class DefaultTypeMatcherGroup extends AbstractMatcherGroup {
public DefaultTypeMatcherGroup(int distanceMin, int distanceMax) {
super(distanceMin, distanceMax);
}
@Override
protected void init() {
// 空匹配
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (null == clazz) {
matchInfo.setTypeDistance(TypeMatchLevel.NULL.getDistanceMin());
matchInfo.setTypeConverter((value, type) -> TypeUtil.getDefaultValue(type));
}
return matchInfo;
}
});
// 完美匹配
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (clazz == targetClass) {
matchInfo.setTypeDistance(TypeMatchLevel.PERFECT.getDistanceMin());
matchInfo.setTypeConverter((value, type) -> value);
}
return matchInfo;
}
});
// 装箱匹配
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (TypeUtil.isStrictBasicType(clazz) && TypeUtil.getWrapType(clazz) == targetClass) {
matchInfo.setTypeDistance(TypeMatchLevel.PACKING.getDistanceMin());
matchInfo.setTypeConverter((value, type) -> value);
}
return matchInfo;
}
});
// 拆箱匹配
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (TypeUtil.isStrictBasicType(targetClass) && TypeUtil.getWrapType(targetClass) == clazz) {
matchInfo.setTypeDistance(TypeMatchLevel.UNPACKING.getDistanceMin());
matchInfo.setTypeConverter((value, type) -> value);
}
return matchInfo;
}
});
// 类型提升匹配
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
int index1 = TypeUtil.basicTypeList.indexOf(clazz);
int index2 = TypeUtil.basicTypeList.indexOf(targetClass);
if (index2 > index1 && index1 >= 0) {
matchInfo.setTypeDistance(TypeMatchLevel.ASCENSION.getDistanceMin() + (index2 - index1));
matchInfo.setTypeConverter((value, type) -> {
if (value == type || TypeUtil.getWrapType(value.getClass()) == type) {
return value;
}
if (TypeUtil.isInteger(clazz) && TypeUtil.isLong(targetClass)) {
return Long.valueOf(String.valueOf(value));
}
if (TypeUtil.isBoolean(value.getClass())) {
return ((boolean)value) ? 1 : 0;
}
if (TypeUtil.isBoolean(type)) {
return TypeUtil.isChar(value.getClass()) ? ((char)value == 0 ? false : true) :
(((Number)value).intValue() == 0 ? false : true);
}
if (TypeUtil.isChar(type)) {
return (char)(int)value;
}
return value;
});
}
return matchInfo;
}
});
// 超类匹配
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (targetClass.isAssignableFrom(clazz)) {
int level = TypeUtil.getInheritLevel(targetClass, clazz);
matchInfo.setTypeDistance(TypeMatchLevel.SUPER.getDistanceMin() + level);
matchInfo.setTypeConverter((value, type) -> value);
}
return matchInfo;
}
});
}
}
@@ -0,0 +1,17 @@
package fun.asgc.neutrino.proxy.core.type;
/**
* 类型转换器
* @author: aoshiguchen
* @date: 2022/6/17
*/
@FunctionalInterface
public interface TypeConverter {
/**
* 类型转换
* @param value
* @param targetType
* @return
*/
Object convert(Object value, Class<?> targetType);
}
@@ -0,0 +1,55 @@
package fun.asgc.neutrino.proxy.core.type;
import lombok.Data;
import lombok.experimental.Accessors;
/**
*
* @author: aoshiguchen
* @date: 2022/6/16
*/
@Accessors(chain = true)
@Data
public class TypeMatchInfo {
/**
* 目标类型类型
*/
private Class<?> targetType;
/**
* 值类型
*/
private Class<?> valueType;
/**
* 类型距离
*/
private int typeDistance;
/**
* 类型匹配器
*/
private TypeMatcher typeMatcher;
/**
* 类型转换器
*/
private TypeConverter typeConverter;
public TypeMatchInfo(Class<?> valueType, Class<?> targetType, TypeMatcher typeMatcher) {
this.valueType = valueType;
this.targetType = targetType;
this.typeMatcher = typeMatcher;
this.typeDistance = TypeMatchLevel.NOT.getDistanceMin();
}
public boolean isNotMatch() {
return !isMatched();
}
public boolean isMatched() {
TypeMatchLevel matchLevel = TypeMatchLevel.byTypeDistance(this.typeDistance);
return matchLevel != null && matchLevel != TypeMatchLevel.NOT && typeConverter != null;
}
}
@@ -0,0 +1,68 @@
package fun.asgc.neutrino.proxy.core.type;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 类型匹配等级
* @author: aoshiguchen
* @date: 2022/6/17
*/
@Getter
@AllArgsConstructor
public enum TypeMatchLevel {
// 当且仅当匹配类为空(即匹配对象为null没有类型)时
NULL(0, 0, 0, "空匹配"),
// 当且仅当匹配类与目标类完全相等
PERFECT(1, 1, 1, "完美匹配"),
// 当且仅当匹配类为严格基本数据类型,且目标类为对应的包装类型
PACKING(2, 100, 100, "装箱匹配"),
// 当且仅当目标类为严格基本数据类型,且匹配类为对应的包装类型
UNPACKING(3, 200,200,"拆箱匹配"),
// 当且仅当匹配类和目标类均为一般基本数据类型(非严格),且目标类型的范围更加宽泛时
ASCENSION(4, 1000, 2000, "类型提升匹配"),
// 超类匹配,当且仅当目标类是匹配类的超类时
SUPER(5, 1000000, 2000000, "超类匹配"),
// 内置的扩展匹配
EXTENSION(6, 10000000, 50000000, "扩展匹配"),
// 自定义匹配
CUSTOM(7, 100000000, 500000000, "自定义匹配"),
// 不匹配
NOT(8, Integer.MAX_VALUE, Integer.MAX_VALUE, "不匹配");
private static Map<Integer,TypeMatchLevel> levelMap = Stream.of(TypeMatchLevel.values()).collect(Collectors.toMap(TypeMatchLevel::getLevel, Function.identity()));
/**
* 匹配级别
*/
private int level;
/**
* 类型距离最小值
*/
private int distanceMin;
/**
* 类型距离最大值
*/
private int distanceMax;
/**
* 描述
*/
private String desc;
public static TypeMatchLevel byLevel(int level) {
return levelMap.get(level);
}
public static TypeMatchLevel byTypeDistance(int typeDistance) {
for (TypeMatchLevel item : values()) {
if (typeDistance >= item.getDistanceMin() && typeDistance <= item.getDistanceMax()) {
return item;
}
}
return null;
}
}
@@ -0,0 +1,21 @@
package fun.asgc.neutrino.proxy.core.type;
/**
* 值类型匹配器
*
* @author: aoshiguchen
* @date: 2022/6/17
*/
@FunctionalInterface
public interface TypeMatcher {
/**
* 匹配
* @param clazz
* @param targetClass
* @return
*/
TypeMatchInfo match(Class<?> clazz, Class<?> targetClass);
}
@@ -0,0 +1,28 @@
package fun.asgc.neutrino.proxy.core.type;
import java.util.List;
/**
* 匹配器组
* @author: aoshiguchen
* @date: 2022/6/29
*/
public interface TypeMatcherGroup {
/**
* 匹配器列表
* @return
*/
List<TypeMatcher> matchers();
/**
* 获取最小距离
* @return
*/
int getDistanceMin();
/**
* 获取最大距离
* @return
*/
int getDistanceMax();
}
@@ -0,0 +1,218 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.core.type;
import cn.hutool.core.collection.CollectionUtil;
import fun.asgc.neutrino.proxy.core.type.extension.*;
import fun.asgc.neutrino.proxy.core.util.Assert;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
*
* @author: aoshiguchen
* @date: 2022/6/17
*/
public class TypeMatchers {
/**
* 默认的基本匹配器列表
*/
private static List<TypeMatcher> defaultTypeMatcherList = new ArrayList<>();
/**
* 默认内置扩展的匹配器列表
*/
private static List<TypeMatcher> extensionMatcherList = new ArrayList<>();
/**
* 内置扩展匹配器组列表
*/
private static List<TypeMatcherGroup> extensionMatcherGroupList = new ArrayList<>();
/**
* 用户自定义的匹配器列表
*/
private List<TypeMatcher> customTypeMatcherList = new ArrayList<>();
/**
* 是否启用内置扩展匹配器
*/
private volatile boolean enableExtensionMatcher = true;
static {
init();
}
/**
* 注册内置扩展匹配器组
* @param typeMatcherGroup
*/
private static synchronized void registerExtensionTypeMatcher(TypeMatcherGroup typeMatcherGroup) {
if (null == typeMatcherGroup || CollectionUtil.isEmpty(typeMatcherGroup.matchers())) {
return;
}
// 内置扩展匹配器距离区间检测
if (typeMatcherGroup.getDistanceMin() < TypeMatchLevel.EXTENSION.getDistanceMin() ||
typeMatcherGroup.getDistanceMax() > TypeMatchLevel.EXTENSION.getDistanceMax() ||
typeMatcherGroup.getDistanceMax() < typeMatcherGroup.getDistanceMin()) {
throw new RuntimeException(String.format("内置扩展匹配器:[%s] 距离区间定义有误!", typeMatcherGroup.getClass().getSimpleName()));
}
for (TypeMatcherGroup group : extensionMatcherGroupList) {
// 距离区间不能重叠
if (!(typeMatcherGroup.getDistanceMin() > group.getDistanceMax() || typeMatcherGroup.getDistanceMax() < group.getDistanceMin())) {
throw new RuntimeException(String.format("内置扩展匹配器:[%s]与[%s] 距离区间定义有重叠!", typeMatcherGroup.getClass().getSimpleName(), group.getClass().getSimpleName()));
}
}
extensionMatcherGroupList.add(typeMatcherGroup);
}
/**
* 注册默认的类型匹配器组
* @param typeMatcherGroup
*/
private static synchronized void registerDefaultTypeMatcher(TypeMatcherGroup typeMatcherGroup) {
if (null == typeMatcherGroup || CollectionUtil.isEmpty(typeMatcherGroup.matchers())) {
return;
}
// 自定义匹配器距离区间检测
if (typeMatcherGroup.getDistanceMin() < TypeMatchLevel.NULL.getDistanceMin() ||
typeMatcherGroup.getDistanceMax() > TypeMatchLevel.SUPER.getDistanceMax() ||
typeMatcherGroup.getDistanceMax() < typeMatcherGroup.getDistanceMin()) {
throw new RuntimeException(String.format("默认匹配器组器:[%s] 距离区间定义有误!", typeMatcherGroup.getClass().getSimpleName()));
}
defaultTypeMatcherList.addAll(typeMatcherGroup.matchers());
}
/**
* 注册自定义类型匹配器具
* @param typeMatcher
*/
public synchronized void registerCustomTypeMatcher(TypeMatcher typeMatcher) {
Assert.notNull(typeMatcher, "匹配器不能为空!");
customTypeMatcherList.add(typeMatcher);
}
/**
* 注册自定义匹配器组
* @param typeMatcherGroup
*/
public synchronized void registerCustomTypeMatcher(TypeMatcherGroup typeMatcherGroup) {
if (null == typeMatcherGroup || CollectionUtil.isEmpty(typeMatcherGroup.matchers())) {
return;
}
// 自定义匹配器距离区间检测
if (typeMatcherGroup.getDistanceMin() < TypeMatchLevel.CUSTOM.getDistanceMin() ||
typeMatcherGroup.getDistanceMax() > TypeMatchLevel.CUSTOM.getDistanceMax() ||
typeMatcherGroup.getDistanceMax() < typeMatcherGroup.getDistanceMin()) {
throw new RuntimeException(String.format("自定义扩展匹配器:[%s] 距离区间定义有误!", typeMatcherGroup.getClass().getSimpleName()));
}
customTypeMatcherList.addAll(typeMatcherGroup.matchers());
}
/**
* 匹配
* @param clazz
* @param targetClass
* @return
*/
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
// 先匹配自定义的
for (TypeMatcher matcher : customTypeMatcherList) {
TypeMatchInfo typeMatchInfo = matcher.match(clazz, targetClass);
if (typeMatchInfo.isMatched()) {
return typeMatchInfo;
}
}
// 再匹配内置默认的
for (TypeMatcher matcher : defaultTypeMatcherList) {
TypeMatchInfo typeMatchInfo = matcher.match(clazz, targetClass);
if (typeMatchInfo.isMatched()) {
return typeMatchInfo;
}
}
if (enableExtensionMatcher) {
// 再匹配内置扩展的
for (TypeMatcher matcher : extensionMatcherList) {
TypeMatchInfo typeMatchInfo = matcher.match(clazz, targetClass);
if (typeMatchInfo.isMatched()) {
return typeMatchInfo;
}
}
}
return null;
}
public boolean isEnableExtensionMatcher() {
return enableExtensionMatcher;
}
public void setEnableExtensionMatcher(boolean enableExtensionMatcher) {
this.enableExtensionMatcher = enableExtensionMatcher;
}
/**
* 类型转换
* @param value
* @param targetType
* @return
*/
public Object conversion(Object value, Class<?> targetType) {
Assert.notNull(targetType, "目标类型不能为空!");
TypeMatchInfo typeMatchInfo = match(value == null ? null : value.getClass(), targetType);
if (null == typeMatchInfo || typeMatchInfo.isNotMatch()) {
return null;
}
return typeMatchInfo.getTypeConverter().convert(value, targetType);
}
/**
* 初始化
*/
private static void init() {
// 注册默认的类型匹配器组
registerDefaultTypeMatcher(new DefaultTypeMatcherGroup(TypeMatchLevel.NULL.getDistanceMin(), TypeMatchLevel.SUPER.getDistanceMax()));
// 注册内置扩展匹配
int extensionMatcherGroupSize = 100000;
int extensionMatcherGroupDistance = TypeMatchLevel.EXTENSION.getDistanceMin();
registerExtensionTypeMatcher(new StringMatcherGroup(extensionMatcherGroupDistance + extensionMatcherGroupSize * 0,
extensionMatcherGroupDistance + extensionMatcherGroupSize * 1 - 1));
registerExtensionTypeMatcher(new BooleanMatcherGroup(extensionMatcherGroupDistance + extensionMatcherGroupSize * 1,
extensionMatcherGroupDistance + extensionMatcherGroupSize * 2 - 1));
registerExtensionTypeMatcher(new NumberMatcherGroup(extensionMatcherGroupDistance + extensionMatcherGroupSize * 2,
extensionMatcherGroupDistance + extensionMatcherGroupSize * 3 - 1));
registerExtensionTypeMatcher(new DateMatcherGroup(extensionMatcherGroupDistance + extensionMatcherGroupSize * 3,
extensionMatcherGroupDistance + extensionMatcherGroupSize * 4 - 1));
registerExtensionTypeMatcher(new ListMatcherGroup(extensionMatcherGroupDistance + extensionMatcherGroupSize * 4,
extensionMatcherGroupDistance + extensionMatcherGroupSize * 5 - 1));
registerExtensionTypeMatcher(new SetMatcherGroup(extensionMatcherGroupDistance + extensionMatcherGroupSize * 5,
extensionMatcherGroupDistance + extensionMatcherGroupSize * 6 - 1));
registerExtensionTypeMatcher(new MapMatcherGroup(extensionMatcherGroupDistance + extensionMatcherGroupSize * 6,
extensionMatcherGroupDistance + extensionMatcherGroupSize * 7 - 1));
registerExtensionTypeMatcher(new ArrayMatcherGroup(extensionMatcherGroupDistance + extensionMatcherGroupSize * 7,
extensionMatcherGroupDistance + extensionMatcherGroupSize * 8 - 1));
// 按照距离区间排序
extensionMatcherList = extensionMatcherGroupList.stream().sorted(Comparator.comparing(TypeMatcherGroup::getDistanceMin))
.map(TypeMatcherGroup::matchers).flatMap(List::stream).collect(Collectors.toList());
}
}
@@ -0,0 +1,50 @@
package fun.asgc.neutrino.proxy.core.type.extension;
import fun.asgc.neutrino.proxy.core.type.AbstractMatcherGroup;
import fun.asgc.neutrino.proxy.core.type.TypeMatchInfo;
import fun.asgc.neutrino.proxy.core.type.TypeMatcher;
import java.util.List;
import java.util.Set;
/**
* 数组匹配器组
* @author: aoshiguchen
* @date: 2022/6/29
*/
public class ArrayMatcherGroup extends AbstractMatcherGroup {
public ArrayMatcherGroup(int distanceMin, int distanceMax) {
super(distanceMin, distanceMax);
}
@Override
public void init() {
// List -> Object[]
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (List.class.isAssignableFrom(clazz) && targetClass.isArray()) {
matchInfo.setTypeDistance(getDistanceMin());
matchInfo.setTypeConverter((value, targetType) -> ((List)value).toArray());
}
return matchInfo;
}
});
// Set -> Object[]
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (Set.class.isAssignableFrom(clazz) && targetClass.isArray()) {
matchInfo.setTypeDistance(getDistanceMin() + 1);
matchInfo.setTypeConverter((value, targetType) -> ((Set)value).toArray());
}
return matchInfo;
}
});
}
}
@@ -0,0 +1,34 @@
package fun.asgc.neutrino.proxy.core.type.extension;
import fun.asgc.neutrino.proxy.core.type.AbstractMatcherGroup;
import fun.asgc.neutrino.proxy.core.type.TypeMatchInfo;
import fun.asgc.neutrino.proxy.core.type.TypeMatcher;
import fun.asgc.neutrino.proxy.core.util.TypeUtil;
/**
* 布尔值匹配器组
* @author: aoshiguchen
* @date: 2022/6/29
*/
public class BooleanMatcherGroup extends AbstractMatcherGroup {
public BooleanMatcherGroup(int distanceMin, int distanceMax) {
super(distanceMin, distanceMax);
}
@Override
public void init() {
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (TypeUtil.isString(clazz) && TypeUtil.isBoolean(targetClass)) {
matchInfo.setTypeDistance(getDistanceMin());
matchInfo.setTypeConverter(((value, targetType) -> ((String)value).toLowerCase().equals("true")));
}
return matchInfo;
}
});
}
}
@@ -0,0 +1,62 @@
package fun.asgc.neutrino.proxy.core.type.extension;
import fun.asgc.neutrino.proxy.core.type.AbstractMatcherGroup;
import fun.asgc.neutrino.proxy.core.type.TypeMatchInfo;
import fun.asgc.neutrino.proxy.core.type.TypeMatcher;
import fun.asgc.neutrino.proxy.core.util.TypeUtil;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
/**
* 日期匹配器组
* @author: aoshiguchen
* @date: 2022/6/29
*/
public class DateMatcherGroup extends AbstractMatcherGroup {
public DateMatcherGroup(int distanceMin, int distanceMax) {
super(distanceMin, distanceMax);
}
@Override
public void init() {
// Long -> Date
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (TypeUtil.isLong(clazz) && TypeUtil.isDate(targetClass)) {
matchInfo.setTypeDistance(getDistanceMin());
matchInfo.setTypeConverter(((value, targetType) -> {
if (targetClass == Date.class) {
return new Date((long)value);
} else {
return new java.sql.Date((long)value);
}
}));
}
return matchInfo;
}
});
// LocalDateTime -> Date
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (LocalDateTime.class.isAssignableFrom(clazz) && TypeUtil.isDate(targetClass)) {
matchInfo.setTypeDistance(getDistanceMin() + 1);
matchInfo.setTypeConverter(((value, targetType) -> {
ZoneId zone = ZoneId.systemDefault();
Instant instant = ((LocalDateTime)value).atZone(zone).toInstant();
return Date.from(instant);
}));
}
return matchInfo;
}
});
}
}
@@ -0,0 +1,37 @@
package fun.asgc.neutrino.proxy.core.type.extension;
import fun.asgc.neutrino.proxy.core.type.AbstractMatcherGroup;
import fun.asgc.neutrino.proxy.core.type.TypeMatchInfo;
import fun.asgc.neutrino.proxy.core.type.TypeMatcher;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* list匹配器组
* @author: aoshiguchen
* @date: 2022/6/29
*/
public class ListMatcherGroup extends AbstractMatcherGroup {
public ListMatcherGroup(int distanceMin, int distanceMax) {
super(distanceMin, distanceMax);
}
@Override
public void init() {
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (List.class == targetClass && clazz.isArray()) {
matchInfo.setTypeDistance(getDistanceMin());
matchInfo.setTypeConverter(((value, targetType) -> Stream.of((Object[])value).collect(Collectors.toList())));
}
return matchInfo;
}
});
}
}
@@ -0,0 +1,21 @@
package fun.asgc.neutrino.proxy.core.type.extension;
import fun.asgc.neutrino.proxy.core.type.AbstractMatcherGroup;
/**
* Map匹配器组
* @author: aoshiguchen
* @date: 2022/6/29
*/
public class MapMatcherGroup extends AbstractMatcherGroup {
public MapMatcherGroup(int distanceMin, int distanceMax) {
super(distanceMin, distanceMax);
}
@Override
public void init() {
}
}
@@ -0,0 +1,161 @@
package fun.asgc.neutrino.proxy.core.type.extension;
import fun.asgc.neutrino.proxy.core.type.AbstractMatcherGroup;
import fun.asgc.neutrino.proxy.core.type.TypeMatchInfo;
import fun.asgc.neutrino.proxy.core.type.TypeMatcher;
import fun.asgc.neutrino.proxy.core.util.TypeUtil;
/**
* 字符串匹配器组
* @author: aoshiguchen
* @date: 2022/6/29
*/
public class NumberMatcherGroup extends AbstractMatcherGroup {
public NumberMatcherGroup(int distanceMin, int distanceMax) {
super(distanceMin, distanceMax);
}
@Override
public void init() {
// String -> Byte
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (TypeUtil.isString(clazz) && TypeUtil.isByte(targetClass)) {
matchInfo.setTypeDistance(getDistanceMin());
matchInfo.setTypeConverter((value, targetType) -> {
try {
return Byte.valueOf((String)value);
} catch (Exception e) {
// ignore
}
return 0;
});
}
return matchInfo;
}
});
// String -> Short
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (TypeUtil.isString(clazz) && TypeUtil.isShort(targetClass)) {
matchInfo.setTypeDistance(getDistanceMin() + 1);
matchInfo.setTypeConverter((value, targetType) -> {
try {
return Short.valueOf((String)value);
} catch (Exception e) {
// ignore
}
return 0;
});
}
return matchInfo;
}
});
// String -> Integer
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (TypeUtil.isString(clazz) && TypeUtil.isInteger(targetClass)) {
matchInfo.setTypeDistance(getDistanceMin() + 2);
matchInfo.setTypeConverter((value, targetType) -> {
try {
return Integer.valueOf((String)value);
} catch (Exception e) {
// ignore
}
return 0;
});
}
return matchInfo;
}
});
// String -> Long
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (TypeUtil.isString(clazz) && TypeUtil.isLong(targetClass)) {
matchInfo.setTypeDistance(getDistanceMin() + 3);
matchInfo.setTypeConverter((value, targetType) -> {
try {
return Long.valueOf((String)value);
} catch (Exception e) {
// ignore
}
return 0;
});
}
return matchInfo;
}
});
// String -> Float
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (TypeUtil.isString(clazz) && TypeUtil.isFloat(targetClass)) {
matchInfo.setTypeDistance(getDistanceMin() + 4);
matchInfo.setTypeConverter((value, targetType) -> {
try {
return Float.valueOf((String)value);
} catch (Exception e) {
// ignore
}
return 0;
});
}
return matchInfo;
}
});
// String -> Double
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (TypeUtil.isString(clazz) && TypeUtil.isDouble(targetClass)) {
matchInfo.setTypeDistance(getDistanceMin() + 5);
matchInfo.setTypeConverter((value, targetType) -> {
try {
return Double.valueOf((String)value);
} catch (Exception e) {
// ignore
}
return 0;
});
}
return matchInfo;
}
});
// date -> Long
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (TypeUtil.isLong(targetClass) && TypeUtil.isDate(clazz)) {
matchInfo.setTypeDistance(getDistanceMin() + 6);
matchInfo.setTypeConverter(((value, targetType) -> ((java.util.Date)value).getTime()));
}
return matchInfo;
}
});
// Long - > int
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (TypeUtil.isInteger(targetClass) && TypeUtil.isLong(clazz)) {
matchInfo.setTypeDistance(getDistanceMin() + 7);
matchInfo.setTypeConverter(((value, targetType) -> ((Long)value).intValue()));
}
return matchInfo;
}
});
}
}
@@ -0,0 +1,49 @@
package fun.asgc.neutrino.proxy.core.type.extension;
import fun.asgc.neutrino.proxy.core.type.AbstractMatcherGroup;
import fun.asgc.neutrino.proxy.core.type.TypeMatchInfo;
import fun.asgc.neutrino.proxy.core.type.TypeMatcher;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* set匹配器组
* @author: aoshiguchen
* @date: 2022/6/29
*/
public class SetMatcherGroup extends AbstractMatcherGroup {
public SetMatcherGroup(int distanceMin, int distanceMax) {
super(distanceMin, distanceMax);
}
@Override
public void init() {
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (Set.class == targetClass && clazz.isArray()) {
matchInfo.setTypeDistance(getDistanceMin());
matchInfo.setTypeConverter(((value, targetType) -> Stream.of((Object[])value).collect(Collectors.toSet())));
}
return matchInfo;
}
});
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (Set.class == targetClass && Collection.class.isAssignableFrom(clazz)) {
matchInfo.setTypeDistance(getDistanceMin() + 1);
matchInfo.setTypeConverter(((value, targetType) -> ((Collection)value).stream().collect(Collectors.toSet())));
}
return matchInfo;
}
});
}
}
@@ -0,0 +1,47 @@
package fun.asgc.neutrino.proxy.core.type.extension;
import fun.asgc.neutrino.proxy.core.type.AbstractMatcherGroup;
import fun.asgc.neutrino.proxy.core.type.TypeMatchInfo;
import fun.asgc.neutrino.proxy.core.type.TypeMatcher;
import fun.asgc.neutrino.proxy.core.util.TypeUtil;
/**
* 字符串匹配器组
* @author: aoshiguchen
* @date: 2022/6/29
*/
public class StringMatcherGroup extends AbstractMatcherGroup {
public StringMatcherGroup(int distanceMin, int distanceMax) {
super(distanceMin, distanceMax);
}
@Override
public void init() {
// 基本类型 -> String
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (TypeUtil.isNormalBasicType(clazz) && TypeUtil.isString(targetClass)) {
matchInfo.setTypeDistance(getDistanceMin());
matchInfo.setTypeConverter(((value, targetType) -> String.valueOf(value)));
}
return matchInfo;
}
});
// String -> char
add(new TypeMatcher() {
@Override
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
if (TypeUtil.isChar(targetClass) && TypeUtil.isString(clazz)) {
matchInfo.setTypeDistance(getDistanceMin() + 1);
matchInfo.setTypeConverter(((value, targetType) -> ((String)value).charAt(0)));
}
return matchInfo;
}
});
}
}
@@ -0,0 +1,220 @@
package fun.asgc.neutrino.proxy.core.util;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import org.apache.commons.lang3.ObjectUtils;
import java.util.Collection;
import java.util.Map;
import java.util.function.Supplier;
/**
*
* @author: aoshiguchen
* @date: 2022/6/16
*/
public abstract class Assert {
/**
*
* @param expression
* @param message
*/
public static void state(boolean expression, String message) {
if (!expression) {
throw new IllegalStateException(message);
}
}
/**
*
* @param expression
* @param messageSupplier
*/
public static void state(boolean expression, Supplier<String> messageSupplier) {
if (!expression) {
throw new IllegalStateException(nullSafeGet(messageSupplier));
}
}
/**
*
* @param expression
* @param message
*/
public static void isTrue(boolean expression, String message) {
if (!expression) {
throw new IllegalArgumentException(message);
}
}
/**
*
* @param expression
* @param messageSupplier
*/
public static void isTrue(boolean expression, Supplier<String> messageSupplier) {
if (!expression) {
throw new IllegalArgumentException(nullSafeGet(messageSupplier));
}
}
/**
*
* @param object
* @param message
*/
public static void isNull(Object object, String message) {
if (object != null) {
throw new IllegalArgumentException(message);
}
}
/**
*
* @param object
* @param messageSupplier
*/
public static void isNull(Object object, Supplier<String> messageSupplier) {
if (object != null) {
throw new IllegalArgumentException(nullSafeGet(messageSupplier));
}
}
/**
*
* @param object
* @param message
*/
public static void notNull(Object object, String message) {
if (object == null) {
throw new IllegalArgumentException(message);
}
}
/**
*
* @param object
* @param messageSupplier
*/
public static void notNull(Object object, Supplier<String> messageSupplier) {
if (object == null) {
throw new IllegalArgumentException(nullSafeGet(messageSupplier));
}
}
/**
*
* @param array
* @param message
*/
public static void notEmpty(Object[] array, String message) {
if (ObjectUtils.isEmpty(array)) {
throw new IllegalArgumentException(message);
}
}
public static void notEmpty(String s, String message) {
if (StrUtil.isEmpty(s)) {
throw new IllegalArgumentException(message);
}
}
/**
*
* @param array
* @param messageSupplier
*/
public static void notEmpty(Object[] array, Supplier<String> messageSupplier) {
if (ObjectUtils.isEmpty(array)) {
throw new IllegalArgumentException(nullSafeGet(messageSupplier));
}
}
/**
*
* @param array
* @param message
*/
public static void noNullElements(Object[] array, String message) {
if (array != null) {
for (Object element : array) {
if (element == null) {
throw new IllegalArgumentException(message);
}
}
}
}
/**
*
* @param array
* @param messageSupplier
*/
public static void noNullElements(Object[] array, Supplier<String> messageSupplier) {
if (array != null) {
for (Object element : array) {
if (element == null) {
throw new IllegalArgumentException(nullSafeGet(messageSupplier));
}
}
}
}
/**
*
* @param collection
* @param message
*/
public static void notEmpty(Collection<?> collection, String message) {
if (CollectionUtil.isEmpty(collection)) {
throw new IllegalArgumentException(message);
}
}
/**
*
* @param collection
* @param messageSupplier
*/
public static void notEmpty(Collection<?> collection, Supplier<String> messageSupplier) {
if (CollectionUtil.isEmpty(collection)) {
throw new IllegalArgumentException(nullSafeGet(messageSupplier));
}
}
/**
*
* @param map
* @param message
*/
public static void notEmpty(Map<?, ?> map, String message) {
if (CollectionUtil.isEmpty(map)) {
throw new IllegalArgumentException(message);
}
}
/**
*
* @param map
* @param messageSupplier
*/
public static void notEmpty(Map<?, ?> map, Supplier<String> messageSupplier) {
if (CollectionUtil.isEmpty(map)) {
throw new IllegalArgumentException(nullSafeGet(messageSupplier));
}
}
private static boolean endsWithSeparator(String msg) {
return (msg.endsWith(":") || msg.endsWith(";") || msg.endsWith(",") || msg.endsWith("."));
}
private static String messageWithTypeName(String msg, Object typeName) {
return msg + (msg.endsWith(" ") ? "" : ": ") + typeName;
}
private static String nullSafeGet(Supplier<String> messageSupplier) {
return (messageSupplier != null ? messageSupplier.get() : null);
}
}
@@ -0,0 +1,357 @@
package fun.asgc.neutrino.proxy.core.util;
import org.apache.commons.lang3.StringUtils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Consumer;
/**
*
* @author: aoshiguchen
* @date: 2022/6/28
*/
public class DateUtil {
public static final long SECOND_LONG = 1000L;
public static final long MINUTE_LONG = 60 * SECOND_LONG;
public static final long HOUR_LONG = 60 * MINUTE_LONG;
private static final Map<String, SimpleDateFormat> sdfCache = new HashMap<>();
private static SimpleDateFormat getSimpleDateFormat(String format) {
try {
return LockUtil.doubleCheckProcess(
() -> !sdfCache.containsKey(format),
format,
() -> sdfCache.put(format, new SimpleDateFormat(format)),
() -> sdfCache.get(format)
);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 解析日期
*
* @param date 日期类
* @param pattern 日期格式
* @return 返回日期
*/
public static Date parseStr(String date, String pattern) {
if (date == null || pattern == null) {
return null;
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
Date parse = null;
try {
parse = simpleDateFormat.parse(date);
} catch (ParseException e) {
throw new RuntimeException(e);
}
return parse;
}
/**
* @param date 时间若为空则返回空串
* @param pattern 时间格式化
* @return 格式化后的时间字符串.
*/
public static String format(Date date, String pattern) {
if (date == null) {
return "";
}
return new SimpleDateFormat(pattern).format(date);
}
/**
* @param date 日期
* @param pattern 格式
* @return 日期类型
*/
public static Date parse(String date, String pattern) {
try {
return new SimpleDateFormat(pattern).parse(date);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
/**
* 是否在指定时间段之间
*
* @param judgeTime 比较时间
* @param beginTime 开始时间
* @param endTime 结束时间
* @param flag 0-[beginTime<=judgeTime<=endTime]
* 1-[beginTime<judgeTime<=endTime]
* 2-[beginTime<=judgeTime<endTime]
* 3-[beginTime<judgeTime<endTime]
* @return 判断结果
*/
public static boolean isBetweenTimes(Date judgeTime, Date beginTime, Date endTime, int flag) {
switch (flag) {
case 0:
return (beginTime.getTime() <= judgeTime.getTime() && judgeTime.getTime() <= endTime.getTime());
case 1:
return (beginTime.getTime() < judgeTime.getTime() && judgeTime.getTime() <= endTime.getTime());
case 2:
return (beginTime.getTime() <= judgeTime.getTime() && judgeTime.getTime() < endTime.getTime());
case 3:
return (beginTime.getTime() < judgeTime.getTime() && judgeTime.getTime() < endTime.getTime());
default:
return false;
}
}
/**
* 取得日期所在月的month个月同一天<br />
*
* @param date 日期
* @param month
* @return 日期
*/
public static Date getMonthDay(Date date, int month) {
Calendar cal = Calendar.getInstance();
if (date != null) {
cal.setTime(date);
}
cal.add(Calendar.MONTH, month);
return cal.getTime();
}
/**
* 获取该日期当月第一天
*
* @param date 日期
* @return 结果日期
*/
public static Date getMonthBegin(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(getDayBegin(date));
calendar.set(Calendar.DAY_OF_MONTH, 1);
return calendar.getTime();
}
/**
* 获取该日期当月最后一天
*
* @param date 日期
* @return 结果日期
*/
public static Date getMonthEnd(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(getDayBegin(date));
calendar.add(Calendar.MONTH, 1);
calendar.set(Calendar.DAY_OF_MONTH, 1);
calendar.add(Calendar.MILLISECOND, -1);
return calendar.getTime();
}
/**
* 计算当期时间相差的日期
*
* @param date 设置时间
* @param field 日历字段.<br/>eg:Calendar.MONTH,Calendar.DAY_OF_MONTH,<br/>Calendar.HOUR_OF_DAY等.
* @param amount 相差的数值
* @return 计算后的日志
*/
public static Date addDate(Date date, int field, int amount) {
Calendar c = Calendar.getInstance();
if (date != null) {
c.setTime(date);
}
c.add(field, amount);
return c.getTime();
}
/**
* 计算当期时间相差的日期
*
* @param field 日历字段.<br/>eg:Calendar.MONTH,Calendar.DAY_OF_MONTH,<br/>Calendar.HOUR_OF_DAY等.
* @param amount 相差的数值
* @return 计算后的日志
*/
public static Date addDate(int field, int amount) {
return addDate(null, field, amount);
}
/**
* 设置Calendar的小时分钟毫秒
*
* @param calendar 日历
* @param hour 小时
* @param minute 分钟
* @param second
* @param milliSecond 毫秒
* @return 结果日期
*/
public static void setCalender(Calendar calendar, int hour, int minute, int second, int milliSecond) {
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, second);
calendar.set(Calendar.MILLISECOND, milliSecond);
}
/**
* 获取某个时间段内的每天时间日期
*
* @param beginDate 开始日期
* @param endDate 结束日期
* @return 返回结果
*/
public static List<String> getBetweenTimes(String beginDate, String endDate) {
if (StringUtils.isEmpty(beginDate) || StringUtils.isEmpty(endDate)) {
return Collections.emptyList();
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date dBegin = null;
Date dEnd = null;
try {
dBegin = sdf.parse(beginDate);
dEnd = sdf.parse(endDate);
} catch (ParseException e) {
e.printStackTrace();
}
if (StringUtils.isEmpty(beginDate) || StringUtils.isEmpty(endDate)) {
return Collections.emptyList();
}
return findDates(dBegin, dEnd);
}
/**
* @param dBegin 开始时间
* @param dEnd 结束时间
* @return 结果集
*/
public static List<String> findDates(Date dBegin, Date dEnd) {
List<String> lDate = new ArrayList<>();
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
lDate.add(sd.format(dBegin));
Calendar calBegin = Calendar.getInstance();
// 使用给定的 Date 设置此 Calendar 的时间
calBegin.setTime(dBegin);
Calendar calEnd = Calendar.getInstance();
// 使用给定的 Date 设置此 Calendar 的时间
calEnd.setTime(dEnd);
// 测试此日期是否在指定日期之后
while (dEnd.after(calBegin.getTime())) {
// 根据日历的规则为给定的日历字段添加或减去指定的时间量
calBegin.add(Calendar.DAY_OF_MONTH, 1);
lDate.add(sd.format(calBegin.getTime()));
}
return lDate;
}
/**
* 取得日期所在年的下一年同一天<br />
* 若参数date为空则取得第当前年所对应的下一年
*
* @param date
* @return
*/
public static Date getNextYearDay(Date date) {
Calendar cal = Calendar.getInstance();
if (date != null) {
cal.setTime(date);
}
cal.add(Calendar.YEAR, 1);
return cal.getTime();
}
/**
* 获取指定天开始时间
*
* @param date 日期
* @return 获得该日期的开始
*/
public static Date getDayBegin(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
setCalender(calendar, 0, 0, 0, 0);
return calendar.getTime();
}
/**
* 获取指定小时开始时间
* @param date 日期
* @return 指定小时开始时间
*/
public static Date getHourBegin(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
setCalender(calendar, calendar.get(Calendar.HOUR), 0, 0, 0);
return calendar.getTime();
}
/**
* 获取指定小时结束时间
* @param date 日期
* @return 指定小时结束时间
*/
public static Date getHourEnd(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
setCalender(calendar, calendar.get(Calendar.HOUR), 59, 59, 999);
return calendar.getTime();
}
/**
* 获取当天开始时间
*
* @return 获得该日期的开始
*/
public static Date getDayBegin() {
return getDayBegin(new Date());
}
/**
* 获取指定天结束时间
*
* @param date 日期
* @return 获得该日期的结束
*/
public static Date getDayEnd(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
setCalender(calendar, 23, 59, 59, 999);
return calendar.getTime();
}
/**
* 获取指定天结束时间
*
* @param date 日期
* @return 获得该日期的结束
*/
public static Date getDayEnd2(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
setCalender(calendar, 23, 59, 59, 000);
return calendar.getTime();
}
/**
* 日期遍历接口
* @param startDate 开始日期 yyyy-MM-dd
* @param endDate 结束日期 yyyy-MM-dd
* @param consumer 执行器回调
*/
public static void dayForEach(String startDate, String endDate, Consumer<String> consumer) {
if (StringUtils.isEmpty(startDate) || StringUtils.isEmpty(endDate) || null == consumer) {
return;
}
Date current = parse(startDate, "yyyy-MM-dd");
Date end = parse(endDate, "yyyy-MM-dd");
while (!current.after(end)) {
consumer.accept(format(current, "yyyy-MM-dd"));
current = addDate(current, Calendar.DATE, 1);
}
}
}
@@ -0,0 +1,206 @@
package fun.asgc.neutrino.proxy.core.util;
import fun.asgc.neutrino.proxy.core.base.InternalException;
import fun.asgc.neutrino.proxy.core.base.MetaDataConstant;
import org.apache.commons.lang3.StringUtils;
import java.io.*;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
/**
*
* @author: aoshiguchen
* @date: 2022/6/16
*/
public class FileUtil {
/**
* 根据文件路径获取输入流
* @param path
* @return
*/
public static InputStream getInputStream(String path) throws FileNotFoundException {
if (StringUtils.isEmpty(path)) {
throw new NullPointerException("path 不能为空!");
}
if (path.startsWith(MetaDataConstant.CLASSPATH_RESOURCE_IDENTIFIER)) {
String subPath = path.substring(MetaDataConstant.CLASSPATH_RESOURCE_IDENTIFIER.length());
return FileUtil.class.getResourceAsStream(subPath);
}
return new FileInputStream(path);
}
/**
* 根据文件路径获取输出流
* @param path
* @return
*/
public static OutputStream getOutputStream(String path) throws FileNotFoundException {
if (StringUtils.isEmpty(path)) {
throw new NullPointerException("path 不能为空!");
}
if (path.startsWith(MetaDataConstant.CLASSPATH_RESOURCE_IDENTIFIER)) {
throw new InternalException("不支持路径以'" + MetaDataConstant.CLASSPATH_IDENTIFIER + "'开头");
}
return new FileOutputStream(path);
}
/**
* 读取文件内容
* @param path
* @return
* @throws IOException
*/
public static String readContentAsString(String path) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(getInputStream(path)))){
return br.lines().collect(Collectors.joining("\n"));
} catch (Exception e) {
return null;
}
}
/**
* 读取文件内容
* @param in
* @return
* @throws IOException
*/
public static String readContentAsString(InputStream in) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(in))){
return br.lines().collect(Collectors.joining("\n"));
} catch (Exception e) {
return null;
}
}
/**
* 读取文件内容
* @param path
* @return
* @throws IOException
*/
public static List<String> readContentAsStringList(String path) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(getInputStream(path)))){
return br.lines().collect(Collectors.toList());
} catch (Exception e) {
return null;
}
}
/**
* 读取字节内容
* @param path
* @return
*/
public static byte[] readBytes(String path) {
try (InputStream in = getInputStream(path)){
return readBytes(in);
} catch (Exception e) {
return null;
}
}
public static byte[] readBytes(File file) {
try (InputStream in = new FileInputStream(file)){
return readBytes(in);
} catch (Exception e) {
return null;
}
}
public static byte[] readBytes(InputStream in) throws IOException {
byte[] bytes = new byte[1024];
int length = 0;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((length = in.read(bytes)) != -1) {
baos.write(bytes, 0, length);
}
return baos.toByteArray();
}
public static void write(String path, String content) {
// try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(path), StandardCharsets.UTF_8)){
// writer.write(content);
// } catch (Exception e) {
// e.printStackTrace();
// }
try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(getOutputStream(path)))){
bw.write(content);
} catch (IOException e) {
e.printStackTrace();
}
}
public static File getDirectory(String path) {
if (path.endsWith("/./")) {
path = path.substring(0, path.length() - 2);
}
File file = new File(path);
if (file.isDirectory() || path.endsWith("/")) {
return file;
}
return file.getParentFile();
}
public static void makeDirs(String path) {
try {
File file = getDirectory(path);
if (null != file && !file.exists()) {
file.mkdirs();
}
} catch (Exception e) {
// ignore
}
}
public static File save(String path, String fileName, String content) {
if (!path.endsWith("/")) {
path += "/";
}
makeDirs(path);
write(path + fileName, content);
return new File(path + "/" + fileName);
}
public static void unzipJar(String destinationDir, String jarPath) throws IOException {
File file = new File(jarPath);
JarFile jar = new JarFile(file);
for (Enumeration<JarEntry> enums = jar.entries(); enums.hasMoreElements();) {
JarEntry entry = (JarEntry) enums.nextElement();
String fileName = destinationDir + File.separator + entry.getName();
File f = new File(fileName);
if (fileName.endsWith("/")) {
f.mkdirs();
}
}
for (Enumeration<JarEntry> enums = jar.entries(); enums.hasMoreElements();) {
JarEntry entry = (JarEntry) enums.nextElement();
String fileName = destinationDir + File.separator + entry.getName();
File f = new File(fileName);
if (!fileName.endsWith("/")) {
InputStream is = jar.getInputStream(entry);
FileOutputStream fos = new FileOutputStream(f);
while (is.available() > 0) {
fos.write(is.read());
}
fos.close();
is.close();
}
}
}
public static String getFileSuffix(String path) {
if (StringUtils.isBlank(path)) {
return "";
}
int index = path.lastIndexOf(".");
if (index >= 0) {
return path.substring(index);
}
return "";
}
}
@@ -0,0 +1,69 @@
package fun.asgc.neutrino.proxy.core.util;
import fun.asgc.neutrino.proxy.core.base.CodeBlock;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
/**
*
* @author: aoshiguchen
* @date: 2022/6/16
*/
public class LockUtil {
/**
* 双重校验处理
* @param isLock
* @param lock
* @param lockProcess
*/
public static void doubleCheckProcess(BooleanSupplier isLock, Object lock, CodeBlock lockProcess) throws Exception {
if (isLock.getAsBoolean()) {
synchronized (lock) {
if (isLock.getAsBoolean()) {
lockProcess.execute();
}
}
}
}
/**
* 双重校验处理
* @param isLock
* @param lock
* @param lockProcess
*/
public static void doubleCheckProcessForNoException(BooleanSupplier isLock, Object lock, CodeBlock lockProcess) {
try {
doubleCheckProcess(isLock, lock, lockProcess);
} catch (Exception e) {
// ignore
e.printStackTrace();
}
}
/**
* 双重校验处理
* @param isLock
* @param lock
* @param lockProcess
* @param nonLockProcess
*/
public static <T> T doubleCheckProcess(BooleanSupplier isLock, Object lock, CodeBlock lockProcess, Supplier<T> nonLockProcess) throws Exception {
doubleCheckProcess(isLock, lock, lockProcess);
return nonLockProcess.get();
}
/**
* 双重校验处理
* @param isLock
* @param lock
* @param lockProcess
* @param nonLockProcess
*/
public static <T> T doubleCheckProcessForNoException(BooleanSupplier isLock, Object lock, CodeBlock lockProcess, Supplier<T> nonLockProcess) {
doubleCheckProcessForNoException(isLock, lock, lockProcess);
return nonLockProcess.get();
}
}
@@ -0,0 +1,580 @@
package fun.asgc.neutrino.proxy.core.util;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Pair;
import com.google.common.collect.Lists;
import fun.asgc.neutrino.proxy.core.type.TypeMatchInfo;
import fun.asgc.neutrino.proxy.core.type.TypeMatchers;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
/**
*
* @author: aoshiguchen
* @date: 2022/6/16
*/
public class TypeUtil {
/**
* 严格意义上的基本数据类型
*/
private static final Set<Class<?>> strictBasicType = new HashSet<Class<?>>() {
{
this.add(byte.class);
this.add(short.class);
this.add(int.class);
this.add(long.class);
this.add(float.class);
this.add(double.class);
this.add(char.class);
this.add(boolean.class);
}
};
/**
* 一般意义上的基本数据类型
*/
private static final Set<Class<?>> normalBasicType = new HashSet<Class<?>>() {
{
this.addAll(strictBasicType);
this.add(Byte.class);
this.add(Short.class);
this.add(Integer.class);
this.add(Long.class);
this.add(Float.class);
this.add(Double.class);
this.add(Character.class);
this.add(Boolean.class);
this.add(String.class);
}
};
/**
* 基本类型的映射
*/
private static final Map<Class<?>, Class<?>> basicTypeMap = new HashMap<Class<?>, Class<?>>() {
{
this.put(byte.class, byte.class);
this.put(short.class, short.class);
this.put(int.class, int.class);
this.put(long.class, long.class);
this.put(float.class, float.class);
this.put(double.class, double.class);
this.put(char.class, char.class);
this.put(boolean.class, boolean.class);
this.put(Byte.class, byte.class);
this.put(Short.class, short.class);
this.put(Integer.class, int.class);
this.put(Long.class, long.class);
this.put(Float.class, float.class);
this.put(Double.class, double.class);
this.put(Character.class, char.class);
this.put(Boolean.class, boolean.class);
}
};
/**
* 包装类型的映射
*/
private static final Map<Class<?>, Class<?>> wrapTypeMap = new HashMap<Class<?>, Class<?>>() {
{
this.put(byte.class, Byte.class);
this.put(short.class, Short.class);
this.put(int.class, Integer.class);
this.put(long.class, Long.class);
this.put(float.class, Float.class);
this.put(double.class, Double.class);
this.put(char.class, Character.class);
this.put(boolean.class, Boolean.class);
this.put(Byte.class, Byte.class);
this.put(Short.class, Short.class);
this.put(Integer.class, Integer.class);
this.put(Long.class, Long.class);
this.put(Float.class, Float.class);
this.put(Double.class, Double.class);
this.put(Character.class, Character.class);
this.put(Boolean.class, Boolean.class);
this.put(String.class, String.class);
}
};
/**
* 基本类型列表用于计算类型提升距离
*/
public static final List<Class<?>> basicTypeList = Lists.newArrayList(
boolean.class, Boolean.class, byte.class, Byte.class, short.class, Short.class, char.class, Character.class,
int.class, Integer.class, long.class, Long.class, float.class, Float.class, double.class, Double.class
);
/**
* 默认值
*/
private static final Map<Class<?>, Object> defaultValueMap = new HashMap<Class<?>, Object>() {
{
this.put(byte.class, 0);
this.put(short.class, 0);
this.put(int.class, 0);
this.put(long.class, 0);
this.put(float.class, 0);
this.put(double.class, 0);
this.put(char.class, 0);
this.put(boolean.class, false);
}
};
/**
* 默认的类型匹配器
*/
private static final TypeMatchers defaultTypeMatchers = new TypeMatchers();
/**
* 获取字段类型
* @param field
* @return
*/
public static Class<?> getFieldType(Field field) {
return field.getType();
}
/**
* 字段类型匹配
* @param field
* @param clazz
* @return
*/
public static boolean fieldTypeMatch(Field field, Class<?> clazz) {
return getFieldType(field) == clazz;
}
/**
* 是否是严格基本类型
* @param clazz
* @return
*/
public static boolean isStrictBasicType(Class<?> clazz) {
return strictBasicType.contains(clazz);
}
/**
* 是否是严格基本类型
* @param field
* @return
*/
public static boolean isStrictBasicType(Field field) {
return isStrictBasicType(getFieldType(field));
}
/**
* 是否是一般基本类型
* @param clazz
* @return
*/
public static boolean isNormalBasicType(Class<?> clazz) {
return normalBasicType.contains(clazz);
}
/**
* 是否是数字
* @param clazz
* @return
*/
public static boolean isNumber(Class<?> clazz) {
return Number.class.isAssignableFrom(clazz);
}
/**
* 是否是一般基本类型
* @param field
* @return
*/
public static boolean isNormalBasicType(Field field) {
return isNormalBasicType(getFieldType(field));
}
/**
* 是否是包装类型
* @param clazz
* @return
*/
public static boolean isWrapType(Class<?> clazz) {
return !isStrictBasicType(clazz);
}
/**
* 是否是包装类型
* @param field
* @return
*/
public static boolean isWrapType(Field field) {
return !isStrictBasicType(field);
}
/**
* 是否是byte类型
* @param field
* @return
*/
public static boolean isByte(Field field) {
return isByte(getFieldType(field));
}
/**
* 是否是byte类型
* @param clazz
* @return
*/
public static boolean isByte(Class clazz) {
return clazz == byte.class || clazz == Byte.class;
}
/**
* 是否是short类型
* @param field
* @return
*/
public static boolean isShort(Field field) {
return isShort(getFieldType(field));
}
/**
* 是否是short类型
* @param clazz
* @return
*/
public static boolean isShort(Class clazz) {
return clazz == short.class || clazz == Short.class;
}
/**
* 是否是integer类型
* @param field
* @return
*/
public static boolean isInteger(Field field) {
return isInteger(getFieldType(field));
}
/**
* 是否是integer类型
* @param clazz
* @return
*/
public static boolean isInteger(Class clazz) {
return clazz == int.class || clazz == Integer.class;
}
/**
* 是否是long类型
* @param field
* @return
*/
public static boolean isLong(Field field) {
return isLong(getFieldType(field));
}
/**
* 是否是long类型
* @param clazz
* @return
*/
public static boolean isLong(Class<?> clazz) {
return clazz == long.class || clazz == Long.class;
}
/**
* 是否是float类型
* @param field
* @return
*/
public static boolean isFloat(Field field) {
return isFloat(getFieldType(field));
}
/**
* 是否是float类型
* @param clazz
* @return
*/
public static boolean isFloat(Class<?> clazz) {
return clazz == float.class || clazz == Float.class;
}
/**
* 是否是double类型
* @param field
* @return
*/
public static boolean isDouble(Field field) {
return isDouble(getFieldType(field));
}
/**
* 是否是double类型
* @param clazz
* @return
*/
public static boolean isDouble(Class<?> clazz) {
return clazz == double.class || clazz == Double.class;
}
/**
* 是否是char类型
* @param field
* @return
*/
public static boolean isChar(Field field) {
Class<?> clazz = getFieldType(field);
return clazz == char.class || clazz == Character.class;
}
/**
* 是否是boolean类型
* @param field
* @return
*/
public static boolean isBoolean(Field field) {
Class<?> clazz = getFieldType(field);
return clazz == boolean.class || clazz == Boolean.class;
}
/**
* 是否是String类型
* @param field
* @return
*/
public static boolean isString(Field field) {
return isString(getFieldType(field));
}
/**
* 是否是String类型
* @param clazz
* @return
*/
public static boolean isString(Class clazz) {
return clazz == String.class;
}
/**
* 是否是日期类型
* @param field
* @return
*/
public static boolean isDate(Field field) {
return isDate(getFieldType(field));
}
/**
* 是否是日期类型
* @param clazz
* @return
*/
public static boolean isDate(Class<?> clazz) {
return clazz == Date.class || clazz == java.sql.Date.class;
}
/**
* 是否是布尔值
* @param clazz
* @return
*/
public static boolean isBoolean(Class<?> clazz) {
return clazz == boolean.class || clazz == Boolean.class;
}
/**
* 是否是字符
* @param clazz
* @return
*/
public static boolean isChar(Class<?> clazz) {
return clazz == char.class || clazz == Character.class;
}
/**
* 是否是map类型
* @param clazz
* @return
*/
public static boolean isMap(Class<?> clazz) {
return Map.class.isAssignableFrom(clazz);
}
/**
* 获取包装类型
* @param clazz
* @return
*/
public static Class<?> getWrapType(Class<?> clazz) {
if (isStrictBasicType(clazz)) {
return wrapTypeMap.get(clazz);
}
return clazz;
}
/**
* 获取包装类型
* @param field
* @return
*/
public static Class<?> getWrapType(Field field) {
return getWrapType(getFieldType(field));
}
/**
* 是否是超类
* @param superClass
* @param childClass
* @return
*/
public static boolean isSupper(Class<?> superClass, Class<?> childClass) {
return superClass.isAssignableFrom(childClass);
}
/**
* 获取简单类名
* @param clazz
* @return
*/
public static String getSimpleName(Class<?> clazz) {
return clazz.getSimpleName();
}
/**
* 获取包名
* @param clazz
* @return
*/
public static String getPackageName(Class<?> clazz) {
return clazz.getPackage().getName();
}
/**
* 获取默认变量名
* @param clazz
* @return
*/
public static String getDefaultVariableName(Class<?> clazz) {
String name = getSimpleName(clazz);
return name.substring(0, 1).toLowerCase() + name.substring(1);
}
/**
* 获取默认值
* @param clazz
* @return
*/
public static Object getDefaultValue(Class<?> clazz) {
return defaultValueMap.get(clazz);
}
/**
* 是否是集合类型
* @param clazz
* @return
*/
public static boolean isCollection(Class<?> clazz) {
return Collection.class.isAssignableFrom(clazz);
}
/**
* 是否可列举
* @param clazz
* @return
*/
public static boolean isListable(Class<?> clazz) {
return clazz.isArray() || isCollection(clazz);
}
/**
* 是否是list
* @param clazz
* @return
*/
public static boolean isList(Class<?> clazz) {
return List.class.isAssignableFrom(clazz);
}
/**
* list转成其他形式
* @param list
* @param targetType
* @return
*/
public static Object listTo(List list, Class<?> targetType) {
if (null == list) {
return null;
}
if (isList(targetType)) {
return list;
}
// 数组
if (targetType.isArray()) {
return list.toArray();
}
// set
if (Set.class.isAssignableFrom(targetType)) {
return list.stream().collect(Collectors.toSet());
}
return null;
}
/**
* 获取继承层级
* 此处假定继承层级最多为100层避免计算太过耗时
* @param superClass
* @param childClass
* @return
*/
public static int getInheritLevel(Class<?> superClass, Class<?> childClass) {
if (!isSupper(superClass, childClass)) {
return -1;
}
List<Pair<Class<?>, Integer>> list = new LinkedList<>();
list.add(Pair.of(childClass, 0));
while (CollectionUtil.isNotEmpty(list) && list.get(0).getKey() != superClass && list.get(0).getValue() < 100) {
Pair<Class<?>, Integer> current = list.remove(0);
Class<?> clazz = current.getKey();
int level = current.getValue();
if (null != clazz.getSuperclass()) {
list.add(Pair.of(clazz.getSuperclass(), level + 1));
}
if (null != clazz.getInterfaces() && clazz.getInterfaces().length > 0) {
for (Class<?> inter : clazz.getInterfaces()) {
list.add(Pair.of(inter, level + 1));
}
}
}
if (list.isEmpty()) {
return 100;
}
return Math.min(list.get(0).getValue(), 100);
}
/**
* 计算一个类型的值是否可以赋值给指定类型的匹配信息
* @param fieldType
* @param valueType
* @return
*/
public static TypeMatchInfo typeMatch(Class<?> fieldType, Class<?> valueType) {
Assert.notNull(fieldType, "字段类型不能为空!");
Assert.notNull(valueType, "值类型不能为空!");
return new TypeMatchInfo(fieldType, valueType, null);
}
/**
* 类型转换
* @param value
* @param targetType
* @return
*/
public static <T> T conversion(Object value, Class<T> targetType) {
return (T)defaultTypeMatchers.conversion(value, targetType);
}
}
+32 -8
View File
@@ -13,8 +13,35 @@
<artifactId>neutrino-proxy-server</artifactId>
<dependencies>
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-api</artifactId>
</dependency>
<dependency>
<groupId>org.noear</groupId>
<artifactId>mybatis-plus-solon-plugin</artifactId>
</dependency>
<dependency>
<groupId>org.noear</groupId>
<artifactId>mybatis-pagehelper-solon-plugin</artifactId>
</dependency>
<dependency>
<groupId>org.noear</groupId>
<artifactId>activerecord-solon-plugin</artifactId>
</dependency>
<!--orika-->
<dependency>
<groupId>fun.asgc</groupId>
<artifactId>orika-solon-plugin</artifactId>
<version>2.2.2</version>
</dependency>
<!--job-->
<dependency>
<groupId>fun.asgc</groupId>
<artifactId>job-solon-plugin</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>fun.asgc.neutrino</groupId>
<artifactId>neutrino-proxy-core</artifactId>
@@ -23,17 +50,14 @@
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.39.2.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.24</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
</dependencies>
@@ -1,30 +1,9 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server;
import fun.asgc.neutrino.core.annotation.EnableJob;
import fun.asgc.neutrino.core.annotation.NeutrinoApplication;
import fun.asgc.neutrino.core.context.NeutrinoLauncher;
import fun.asgc.solon.extend.job.annotation.EnableJob;
import org.noear.solon.Solon;
import org.noear.solon.annotation.SolonMain;
import org.noear.solon.web.cors.CrossFilter;
/**
*
@@ -32,11 +11,13 @@ import fun.asgc.neutrino.core.context.NeutrinoLauncher;
* @date: 2022/6/16
*/
@EnableJob
@NeutrinoApplication
@SolonMain
public class ProxyServer {
public static void main(String[] args) {
NeutrinoLauncher.run(ProxyServer.class, args);
Solon.start(ProxyServer.class, args, app -> {
// 跨域支持-1 优先级更高
app.filter(-1, new CrossFilter().allowedOrigins("*"));
});
}
}
@@ -19,20 +19,22 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.base.rest;
package fun.asgc.neutrino.proxy.server.base.db;
import com.alibaba.druid.pool.DruidDataSource;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import fun.asgc.neutrino.core.annotation.PreLoad;
import fun.asgc.neutrino.core.db.template.JdbcTemplate;
import fun.asgc.neutrino.core.util.*;
import fun.asgc.neutrino.proxy.server.base.rest.config.DbConfig;
import com.jfinal.plugin.activerecord.Db;
import fun.asgc.neutrino.proxy.core.util.Assert;
import fun.asgc.neutrino.proxy.core.util.FileUtil;
import fun.asgc.neutrino.proxy.server.constant.DbTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.sqlite.SQLiteConfig;
import org.sqlite.SQLiteDataSource;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Init;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.event.AppLoadEndEvent;
import org.noear.solon.core.event.EventListener;
import java.sql.DriverManager;
import java.util.List;
/**
@@ -41,43 +43,48 @@ import java.util.List;
* @date: 2022/7/31
*/
@Slf4j
@PreLoad("init")
public class DBInitialize {
@Component
public class DBInitialize implements EventListener<AppLoadEndEvent> {
private static List<String> initDataTableNameList = Lists.newArrayList("user", "license", "port_pool", "port_mapping", "job_info");
private static DbConfig dbConfig;
private static JdbcTemplate jdbcTemplate;
@Inject
private DbConfig dbConfig;
private static DbTypeEnum dbTypeEnum;
private DbTypeEnum dbTypeEnum;
public static void init() throws Exception {
dbConfig = ConfigUtil.getYmlConfig(DbConfig.class);
@Init
public void init() throws Throwable {
Assert.notNull(dbConfig.getType(), "neutrino.data.db.type不能为空!");
dbTypeEnum = DbTypeEnum.of(dbConfig.getType());
Assert.notNull(dbTypeEnum, "neutrino.data.db.type取值异常!");
log.info("{}数据库初始化...", dbConfig.getType());
jdbcTemplate = getJdbcTemplate();
initDBStructure();
initDBData();
}
@Override
public void onEvent(AppLoadEndEvent appLoadEndEvent) throws Throwable {
// TODO 该事件有50%的概率不触发
System.out.println("11");
}
/**
* 初始化数据库结构
*/
private static void initDBStructure() throws Exception {
private void initDBStructure() throws Exception {
List<String> lines = FileUtil.readContentAsStringList(String.format("classpath:/sql/%s/init-structure.sql", dbConfig.getType()));
if (CollectionUtil.isEmpty(lines)) {
return;
}
String sql = "";
for (String line : lines) {
if (StringUtil.isEmpty(line) || StringUtil.isEmpty(line.trim()) || line.trim().startsWith("#")) {
if (StrUtil.isEmpty(line) || StrUtil.isEmpty(line.trim()) || line.trim().startsWith("#")) {
continue;
}
sql += "\r\n" + line.trim();
if (sql.endsWith(";")) {
log.debug("初始化数据库表 sql:{}", sql);
jdbcTemplate.update(sql);
Db.update(sql);
sql = "";
}
}
@@ -85,15 +92,17 @@ public class DBInitialize {
/**
* 初始化数据
*
* @throws Exception
*/
private static void initDBData() throws Exception {
private void initDBData() throws Exception {
if (CollectionUtil.isEmpty(initDataTableNameList)) {
return;
}
for (String tableName : initDataTableNameList) {
// 表里没有数据的时候才进行初始化操作
int count = jdbcTemplate.queryForInt(String.format("select count(1) from `%s`", tableName));
int count = Db.queryInt(String.format("select count(1) from `%s`", tableName));
if (count > 0) {
continue;
}
@@ -103,55 +112,16 @@ public class DBInitialize {
}
String sql = "";
for (String line : lines) {
if (StringUtil.isEmpty(line) || StringUtil.isEmpty(line.trim()) || line.trim().startsWith("#")) {
if (StrUtil.isEmpty(line) || StrUtil.isEmpty(line.trim()) || line.trim().startsWith("#")) {
continue;
}
sql += "\r\n" + line.trim();
if (sql.endsWith(";")) {
log.debug("初始化数据[table={}] sql:{}", tableName, sql);
jdbcTemplate.update(sql);
Db.update(sql);
sql = "";
}
}
}
}
/**
* 获取jdbcTemplate实例
* @return
* @throws Exception
*/
private static JdbcTemplate getJdbcTemplate() throws Exception {
return LockUtil.doubleCheckProcess(
() -> null == jdbcTemplate,
DBInitialize.class,
() -> {
if (DbTypeEnum.SQLITE == dbTypeEnum) {
//建立一个数据库名data.db的连接如果不存在就在当前目录下创建之
DriverManager.getConnection(dbConfig.getUrl());
// 创建数据源
SQLiteDataSource dataSource = new SQLiteDataSource();
dataSource.setUrl(dbConfig.getUrl());
dataSource.setJournalMode(SQLiteConfig.JournalMode.WAL.getValue());
// 创建jdbcTemplate
jdbcTemplate = new JdbcTemplate(dataSource);
} else if (DbTypeEnum.MYSQL == dbTypeEnum) {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(dbConfig.getDriverClass());
dataSource.setUrl(dbConfig.getUrl());
dataSource.setInitialSize(5);
dataSource.setMinIdle(5);
dataSource.setMaxActive(20);
dataSource.setMaxWait(60000);
dataSource.setPoolPreparedStatements(true);
dataSource.setUsername(dbConfig.getUsername());
dataSource.setPassword(dbConfig.getPassword());
// 创建jdbcTemplate
jdbcTemplate = new JdbcTemplate(dataSource);
}
},
() -> jdbcTemplate
);
}
}
@@ -19,13 +19,12 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.base.rest.config;
package fun.asgc.neutrino.proxy.server.base.db;
import fun.asgc.neutrino.core.annotation.Configuration;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.annotation.Value;
import fun.asgc.neutrino.proxy.server.constant.DbTypeEnum;
import lombok.Data;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
/**
* sqlite数据库配置
@@ -33,35 +32,33 @@ import lombok.Data;
* @date: 2022/7/31
*/
@Data
@NonIntercept
@Configuration(prefix = "neutrino.data.db")
@Component
public class DbConfig {
/**
* 数据库类型
* {@link DbTypeEnum}
*/
@Value("type")
@Inject("${neutrino.data.db.type}")
private String type;
/**
* 连接url
*/
@Value("url")
@Inject("${neutrino.data.db.url}")
private String url;
/**
* 驱动类
*/
@Value("driver-class")
@Inject("${neutrino.data.db.driver-class}")
private String driverClass;
/**
* 用户名
*/
@Value("username")
@Inject("${neutrino.data.db.username}")
private String username;
/**
* 密码
*/
@Value("password")
@Inject("${neutrino.data.db.password}")
private String password;
}
@@ -0,0 +1,70 @@
package fun.asgc.neutrino.proxy.server.base.db;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.zaxxer.hikari.HikariDataSource;
import fun.asgc.neutrino.proxy.server.constant.DbTypeEnum;
import org.apache.ibatis.solon.annotation.Db;
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;
import org.sqlite.SQLiteConfig;
import org.sqlite.SQLiteDataSource;
import javax.sql.DataSource;
/**
* @author: aoshiguchen
* @date: 2023/3/10
*/
@Configuration
public class DbConfiguration {
@Bean(value = "db", typed = true)
public DataSource dataSource(@Inject DbConfig dbConfig) {
DbTypeEnum dbTypeEnum = DbTypeEnum.of(dbConfig.getType());
if (DbTypeEnum.SQLITE == dbTypeEnum) {
SQLiteDataSource dataSource = new SQLiteDataSource();
dataSource.setUrl(dbConfig.getUrl());
dataSource.setJournalMode(SQLiteConfig.JournalMode.WAL.getValue());
return dataSource;
} else if (DbTypeEnum.MYSQL == dbTypeEnum) {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName(dbConfig.getDriverClass());
dataSource.setJdbcUrl(dbConfig.getUrl());
dataSource.setMinimumIdle(5);
dataSource.setMaximumPoolSize(20);
dataSource.setMaxLifetime(60000);
// dataSource.setInitialSize(5);
// dataSource.setMinIdle(5);
// dataSource.setMaxActive(20);
// dataSource.setMaxWait(60000);
// dataSource.setPoolPreparedStatements(true);
dataSource.setUsername(dbConfig.getUsername());
dataSource.setPassword(dbConfig.getPassword());
return dataSource;
}
return null;
}
@Bean
public void db1_ext(@Db("db") GlobalConfig globalConfig) {
MetaObjectHandler metaObjectHandler = new MetaObjectHandlerImpl();
globalConfig.setMetaObjectHandler(metaObjectHandler);
}
@Bean
public void db1_ext2(@Db("db") MybatisConfiguration config){
config.getTypeHandlerRegistry().register("fun.asgc.neutrino.proxy.server.dal");
config.setDefaultEnumTypeHandler(null);
}
@Bean
public MybatisSqlSessionFactoryBuilder factoryBuilderNew(){
return new MybatisSqlSessionFactoryBuilderImpl();
}
}
@@ -0,0 +1,20 @@
package fun.asgc.neutrino.proxy.server.base.db;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
/**
* @author: aoshiguchen
* @date: 2023/3/10
*/
public class MetaObjectHandlerImpl implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
}
@Override
public void updateFill(MetaObject metaObject) {
}
}
@@ -0,0 +1,11 @@
package fun.asgc.neutrino.proxy.server.base.db;
import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
/**
* @author: aoshiguchen
* @date: 2023/3/10
*/
public class MybatisSqlSessionFactoryBuilderImpl extends MybatisSqlSessionFactoryBuilder {
}
@@ -0,0 +1,111 @@
package fun.asgc.neutrino.proxy.server.base.page;
import lombok.Data;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
/**
*
* @author: aoshiguchen
* @date: 2022/8/6
*/
@Data
public class PageInfo<T> implements Serializable {
private static final long serialVersionUID = 8545996863226528797L;
private List<T> records;
private Long total;
private Integer size;
private Integer current;
public PageInfo() {
this.records = Collections.emptyList();
this.total = 0L;
this.size = 10;
this.current = 1;
}
public PageInfo(Integer current, Integer size) {
this(current, size, 0L);
}
public PageInfo(Integer current, Integer size, Long total) {
this.records = Collections.emptyList();
this.total = 0L;
this.size = 10;
this.current = 1;
if ((long)current > 1L) {
this.current = current;
}
this.size = size;
this.total = total;
}
public Long getPages() {
if ((long)this.getSize() == 0L) {
return 0L;
} else {
Long pages = this.getTotal() / (long)this.getSize();
if (this.getTotal() % (long)this.getSize() != 0L) {
pages = pages + 1L;
}
return pages;
}
}
public Long getTotal() {
return this.total;
}
public Integer getSize() {
return this.size;
}
public boolean hasPrevious() {
return (long)this.current > 1L;
}
public boolean hasNext() {
return (long)this.current < this.getPages();
}
public List<T> getRecords() {
return this.records;
}
public PageInfo<T> setRecords(List<T> records) {
this.records = records;
return this;
}
public PageInfo<T> setTotal(Long total) {
this.total = total;
return this;
}
public PageInfo<T> setSize(Integer size) {
this.size = size;
return this;
}
public Integer getCurrent() {
return this.current;
}
public PageInfo<T> setCurrent(Integer current) {
this.current = current;
return this;
}
public static <T> PageInfo<T> of(List<T> records, Long total, Integer current, Integer size) {
PageInfo<T> pageInfo = new PageInfo();
pageInfo.setRecords(records);
pageInfo.setTotal(total);
pageInfo.setCurrent(current);
pageInfo.setSize(size);
return pageInfo;
}
}
@@ -0,0 +1,22 @@
package fun.asgc.neutrino.proxy.server.base.page;
import lombok.Data;
import java.io.Serializable;
/**
*
* @author: aoshiguchen
* @date: 2022/8/6
*/
@Data
public class PageQuery implements Serializable {
/**
* 当前页
*/
private int current = 1;
/**
* 分页大小
*/
private int size = 10;
}
@@ -1,29 +1,8 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.base.proxy;
import fun.asgc.neutrino.core.annotation.Configuration;
import fun.asgc.neutrino.core.annotation.Value;
import lombok.Data;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
/**
* 服务端代理配置
@@ -31,48 +10,37 @@ import lombok.Data;
* @date: 2022/6/16
*/
@Data
@Configuration(prefix = "neutrino.proxy")
@Component
public class ProxyConfig {
/**
* 传输协议相关配置
*/
@Inject("${neutrino.proxy.protocol}")
private Protocol protocol;
/**
* 服务端配置
*/
@Inject("${neutrino.proxy.server}")
private Server server;
@Data
public static class Protocol {
@Value("max-frame-length")
private Integer maxFrameLength;
@Value("length-field-offset")
private Integer lengthFieldOffset;
@Value("length-field-length")
private Integer lengthFieldLength;
@Value("initial-bytes-to-strip")
private Integer initialBytesToStrip;
@Value("length-adjustment")
private Integer lengthAdjustment;
@Value("read-idle-time")
private Integer readIdleTime;
@Value("write-idle-time")
private Integer writeIdleTime;
@Value("all-idle-time-seconds")
private Integer allIdleTimeSeconds;
}
@Data
public static class Server {
@Value("port")
private Integer port;
@Value("ssl-port")
private Integer sslPort;
@Value("key-store-password")
private String keyStorePassword;
@Value("key-manager-password")
private String keyManagerPassword;
@Value("jks-path")
private String jksPath;
}
@@ -1,51 +1,47 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.base.proxy;
import fun.asgc.neutrino.core.annotation.Bean;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Order;
import fun.asgc.neutrino.core.base.DefaultDispatcher;
import fun.asgc.neutrino.core.base.Dispatcher;
import fun.asgc.neutrino.core.base.Ordered;
import fun.asgc.neutrino.core.util.BeanManager;
import fun.asgc.neutrino.proxy.core.ProxyDataTypeEnum;
import fun.asgc.neutrino.proxy.core.ProxyMessage;
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
import fun.asgc.neutrino.proxy.core.dispatcher.DefaultDispatcher;
import fun.asgc.neutrino.proxy.core.dispatcher.Dispatcher;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.nio.NioEventLoopGroup;
import org.noear.solon.Solon;
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.AopContext;
import org.noear.solon.core.bean.LifecycleBean;
import java.util.List;
/**
* 代理配置
* @author: aoshiguchen
* @date: 2022/10/8
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class ProxyConfiguration {
@Configuration
public class ProxyConfiguration implements LifecycleBean {
@Bean
public Dispatcher<ChannelHandlerContext, ProxyMessage> dispatcher() {
return new DefaultDispatcher<>("消息调度器",
BeanManager.getBeanListBySuperClass(ProxyMessageHandler.class),
proxyMessage -> ProxyDataTypeEnum.of((int)proxyMessage.getType()) == null ? null : ProxyDataTypeEnum.of((int)proxyMessage.getType()).getName());
@Override
public void start() throws Throwable {
List<ProxyMessageHandler> list = Solon.context().getBeansOfType(ProxyMessageHandler.class);
Dispatcher<ChannelHandlerContext, ProxyMessage> dispatcher = new DefaultDispatcher<>("消息调度器", list,
proxyMessage -> ProxyDataTypeEnum.of((int)proxyMessage.getType()) == null ?
null : ProxyDataTypeEnum.of((int)proxyMessage.getType()).getName());
Solon.context().wrapAndPut(Dispatcher.class, dispatcher);
}
@Bean("serverBossGroup")
public NioEventLoopGroup serverBossGroup() {
return new NioEventLoopGroup();
}
@Bean("serverWorkerGroup")
public NioEventLoopGroup serverWorkerGroup() {
return new NioEventLoopGroup();
}
}
@@ -35,4 +35,6 @@ import java.lang.annotation.Target;
@Target({ElementType.METHOD})
public @interface Authorization {
boolean login() default true;
boolean onlyAdmin() default false;
}
@@ -24,6 +24,7 @@ package fun.asgc.neutrino.proxy.server.base.rest;
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
import lombok.Data;
import lombok.experimental.Accessors;
import org.noear.solon.core.handle.Action;
import java.util.Date;
@@ -51,4 +52,5 @@ public class SystemContext {
* 接收请求时间
*/
private Date receiveTime;
private Action action;
}
@@ -1,75 +0,0 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.base.rest.config;
import com.alibaba.druid.pool.DruidDataSource;
import fun.asgc.neutrino.core.annotation.*;
import fun.asgc.neutrino.core.base.Ordered;
import fun.asgc.neutrino.core.db.template.JdbcTemplate;
import fun.asgc.neutrino.proxy.server.constant.DbTypeEnum;
import org.sqlite.SQLiteConfig;
import org.sqlite.SQLiteDataSource;
import javax.sql.DataSource;
/**
* 系统配置
*author: aoshiguchen
* @date: 2022/8/1
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class RestConfiguration {
@Autowired
private DbConfig dbConfig;
@Bean
public DataSource dataSource() {
DbTypeEnum dbTypeEnum = DbTypeEnum.of(dbConfig.getType());
if (DbTypeEnum.SQLITE == dbTypeEnum) {
SQLiteDataSource dataSource = new SQLiteDataSource();
dataSource.setUrl(dbConfig.getUrl());
dataSource.setJournalMode(SQLiteConfig.JournalMode.WAL.getValue());
return dataSource;
} else if (DbTypeEnum.MYSQL == dbTypeEnum) {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(dbConfig.getDriverClass());
dataSource.setUrl(dbConfig.getUrl());
dataSource.setInitialSize(5);
dataSource.setMinIdle(5);
dataSource.setMaxActive(20);
dataSource.setMaxWait(60000);
dataSource.setPoolPreparedStatements(true);
dataSource.setUsername(dbConfig.getUsername());
dataSource.setPassword(dbConfig.getPassword());
return dataSource;
}
return null;
}
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
}
@@ -1,56 +0,0 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.base.rest.config;
import fun.asgc.neutrino.core.annotation.Configuration;
import fun.asgc.neutrino.core.web.config.WebMvcConfigurer;
import fun.asgc.neutrino.core.web.interceptor.ExceptionHandlerRegistry;
import fun.asgc.neutrino.core.web.interceptor.InterceptorRegistry;
import fun.asgc.neutrino.core.web.interceptor.RestControllerAdviceHandler;
import fun.asgc.neutrino.proxy.server.base.rest.interceptor.*;
/**
* web配置
* @author: aoshiguchen
* @date: 2022/7/30
*/
@Configuration
public class WebConfigurerAdapter implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new BaseAuthInterceptor())
.addPathPatterns("/**").excludePathPatterns("/**/*.html", "/**/*.js", "/**/*.ico");
registry.addInterceptor(new CorsInterceptor());
registry.addInterceptor(new VisitLogInterceptor());
}
@Override
public RestControllerAdviceHandler adviceHandler() {
return new GlobalAdviceHandler();
}
@Override
public void addExceptionHandler(ExceptionHandlerRegistry registry) {
registry.addExceptionHandler(new GlobalExceptionHandler());
}
}
@@ -1,84 +1,95 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.base.rest.interceptor;
import fun.asgc.neutrino.core.util.BeanManager;
import fun.asgc.neutrino.core.util.HttpUtil;
import fun.asgc.neutrino.core.util.StringUtil;
import fun.asgc.neutrino.core.web.context.HttpContextHolder;
import fun.asgc.neutrino.core.web.context.HttpRequestWrapper;
import fun.asgc.neutrino.core.web.context.HttpResponseWrapper;
import fun.asgc.neutrino.core.web.interceptor.HandlerInterceptor;
import cn.hutool.core.util.StrUtil;
import fun.asgc.neutrino.proxy.server.base.rest.*;
import fun.asgc.neutrino.proxy.server.base.rest.annotation.OnlyAdmin;
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
import fun.asgc.neutrino.proxy.server.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.noear.solon.Solon;
import org.noear.solon.annotation.Component;
import org.noear.solon.core.handle.Action;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.Handler;
import org.noear.solon.core.route.RouterInterceptor;
import org.noear.solon.core.route.RouterInterceptorChain;
import java.lang.reflect.Method;
/**
* 鉴权拦截器
* @author: aoshiguchen
* @date: 2022/7/30
* @date: 2023/3/9
*/
public class BaseAuthInterceptor implements HandlerInterceptor {
@Slf4j
@Component
public class BaseAuthInterceptor implements RouterInterceptor {
@Override
public boolean preHandle(HttpRequestWrapper requestParser, HttpResponseWrapper responseWrapper, String route, Method targetMethod) throws Exception {
SystemContext systemContext = new SystemContext();
SystemContextHolder.set(systemContext);
systemContext.setIp(HttpUtil.getIP(HttpContextHolder.getChannelHandlerContext(), requestParser));
@Override
public void doIntercept(Context ctx, Handler mainHandler, RouterInterceptorChain chain) throws Throwable {
if (!(mainHandler instanceof Action)) {
chain.doIntercept(ctx, mainHandler);
return;
}
Action action = (Action) mainHandler;
Method targetMethod = action.method().getMethod();
Authorization authorization = targetMethod.getAnnotation(Authorization.class);
if (null == authorization || authorization.login()) {
String authorize = requestParser.getHeaderValue("Authorize");
if (StringUtil.isEmpty(authorize)) {
throw ServiceException.create(ExceptionConstant.USER_NOT_LOGIN);
}
UserDO userDO = BeanManager.getBean(UserService.class).findByToken(authorize);
if (null == userDO) {
throw ServiceException.create(ExceptionConstant.USER_NOT_LOGIN);
}
if (EnableStatusEnum.DISABLE.getStatus().equals(userDO.getEnable())) {
throw ServiceException.create(ExceptionConstant.USER_DISABLE);
}
if (targetMethod.isAnnotationPresent(OnlyAdmin.class) && !userDO.getLoginName().equals("admin")) {
throw ServiceException.create(ExceptionConstant.NO_PERMISSION_VISIT);
}
SystemContext systemContext = new SystemContext();
SystemContextHolder.set(systemContext);
systemContext.setIp(ctx.realIp());
systemContext.setToken(authorize);
systemContext.setUser(userDO);
Authorization authorization = targetMethod.getAnnotation(Authorization.class);
if (null == authorization || authorization.login()) {
String authorize = ctx.header("Authorize");
if (StrUtil.isEmpty(authorize)) {
throw ServiceException.create(ExceptionConstant.USER_NOT_LOGIN);
}
UserDO userDO = Solon.context().getBean(UserService.class).findByToken(authorize);
if (null == userDO) {
throw ServiceException.create(ExceptionConstant.USER_NOT_LOGIN);
}
if (EnableStatusEnum.DISABLE.getStatus().equals(userDO.getEnable())) {
throw ServiceException.create(ExceptionConstant.USER_DISABLE);
}
if (null != authorization && authorization.onlyAdmin() && !userDO.getLoginName().equals("admin")) {
throw ServiceException.create(ExceptionConstant.NO_PERMISSION_VISIT);
}
// token续期
BeanManager.getBean(UserService.class).updateTokenExpirationTime(authorize);
}
systemContext.setToken(authorize);
systemContext.setUser(userDO);
return true;
}
// token续期
Solon.context().getBean(UserService.class).updateTokenExpirationTime(authorize);
}
chain.doIntercept(ctx, mainHandler);
}
@Override
public void afterCompletion(HttpRequestWrapper requestParser, HttpResponseWrapper responseWrapper, String route, Method targetMethod) {
SystemContextHolder.remove();
}
@Override
public Object postResult(Context ctx, Object result) throws Throwable {
SystemContextHolder.remove();
if (result instanceof ResponseBody) {
return result;
}
if (result instanceof Throwable) {
log.error("全局异常", (Throwable) result);
if (result instanceof ServiceException) {
ServiceException exception = (ServiceException) result;
return new ResponseBody<>()
.setCode(exception.getCode())
.setMsg(exception.getMsg());
}
return new ResponseBody<>()
.setCode(ExceptionConstant.SYSTEM_ERROR.getCode())
.setMsg(ExceptionConstant.SYSTEM_ERROR.getMsg())
.setStack(ExceptionUtils.getStackTrace((Throwable) result));
}
return new ResponseBody<>()
.setCode(0)
.setData(result);
}
}
@@ -1,49 +0,0 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.base.rest.interceptor;
import fun.asgc.neutrino.core.web.context.HttpRequestWrapper;
import fun.asgc.neutrino.core.web.context.HttpResponseWrapper;
import fun.asgc.neutrino.core.web.interceptor.HandlerInterceptor;
import java.lang.reflect.Method;
/**
* 处理跨域问题
* @author: aoshiguchen
* @date: 2022/7/30
*/
public class CorsInterceptor implements HandlerInterceptor {
@Override
public void postHandle(HttpRequestWrapper requestParser, HttpResponseWrapper responseWrapper, String route, Method targetMethod, Object result) throws Exception {
responseWrapper.headers().add("Access-Control-Allow-Origin", "*");
responseWrapper.headers().add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
responseWrapper.headers().add("Access-Control-Max-Age", "86400");
responseWrapper.headers().add("Access-Control-Allow-Headers", "*");
responseWrapper.headers().add("Access-Control-Allow-Credentials", "true");
responseWrapper.headers().add("XDomainRequestAllowed", "1");
responseWrapper.headers().add("Access-Control-Allow-Headers","Authorize, Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type");
responseWrapper.headers().add("Access-Control-Allow-Credentials", "true");
}
}
@@ -1,48 +0,0 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.base.rest.interceptor;
import fun.asgc.neutrino.core.web.context.HttpRequestWrapper;
import fun.asgc.neutrino.core.web.context.HttpResponseWrapper;
import fun.asgc.neutrino.core.web.interceptor.RestControllerAdviceHandler;
import fun.asgc.neutrino.proxy.server.base.rest.ResponseBody;
import java.lang.reflect.Method;
/**
* 全局返回处理
* @author: aoshiguchen
* @date: 2022/7/31
*/
public class GlobalAdviceHandler implements RestControllerAdviceHandler {
@Override
public Object advice(HttpRequestWrapper requestParser, HttpResponseWrapper responseWrapper, String route, Method targetMethod, Object res) {
if (res instanceof ResponseBody) {
return res;
}
return new ResponseBody<>()
.setCode(0)
.setData(res);
}
}
@@ -0,0 +1,42 @@
package fun.asgc.neutrino.proxy.server.base.rest.interceptor;
import fun.asgc.neutrino.proxy.server.base.rest.ResponseBody;
import fun.asgc.neutrino.proxy.server.base.rest.ServiceException;
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.noear.solon.annotation.Component;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.Filter;
import org.noear.solon.core.handle.FilterChain;
/**
* @author: aoshiguchen
* @date: 2023/3/9
*/
@Slf4j
@Component
public class GlobalExceptionFilter implements Filter {
@Override
public void doFilter(Context ctx, FilterChain chain) throws Throwable {
try {
chain.doFilter(ctx);
} catch (Throwable e) {
log.error("全局异常", e);
if (e instanceof ServiceException) {
ServiceException serviceException = (ServiceException) e;
ctx.render(new ResponseBody<>()
.setCode(serviceException.getCode())
.setMsg(serviceException.getMsg()));
return;
}
ctx.render(new ResponseBody<>()
.setCode(ExceptionConstant.SYSTEM_ERROR.getCode())
.setMsg(ExceptionConstant.SYSTEM_ERROR.getMsg())
.setStack(ExceptionUtils.getStackTrace(e)));
}
}
}
@@ -1,53 +0,0 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.base.rest.interceptor;
import fun.asgc.neutrino.core.web.context.HttpRequestWrapper;
import fun.asgc.neutrino.core.web.context.HttpResponseWrapper;
import fun.asgc.neutrino.core.web.interceptor.RestControllerExceptionHandler;
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
import fun.asgc.neutrino.proxy.server.base.rest.ResponseBody;
import fun.asgc.neutrino.proxy.server.base.rest.ServiceException;
import org.apache.commons.lang3.exception.ExceptionUtils;
/**
* 全局异常处理
* @author: aoshiguchen
* @date: 2022/7/31
*/
public class GlobalExceptionHandler implements RestControllerExceptionHandler {
@Override
public Object handle(HttpRequestWrapper requestParser, HttpResponseWrapper responseWrapper, Throwable e) {
if (e instanceof ServiceException) {
ServiceException serviceException = (ServiceException)e;
return new ResponseBody<>()
.setCode(serviceException.getCode())
.setMsg(serviceException.getMsg());
}
return new ResponseBody<>()
.setCode(ExceptionConstant.SYSTEM_ERROR.getCode())
.setMsg(ExceptionConstant.SYSTEM_ERROR.getMsg())
.setStack(ExceptionUtils.getStackTrace(e));
}
}
@@ -1,70 +1,46 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.base.rest.interceptor;
import com.alibaba.fastjson.JSONObject;
import fun.asgc.neutrino.core.web.context.HttpRequestWrapper;
import fun.asgc.neutrino.core.web.context.HttpResponseWrapper;
import fun.asgc.neutrino.core.web.interceptor.HandlerInterceptor;
import fun.asgc.neutrino.proxy.server.base.rest.SystemContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Component;
import org.noear.solon.core.handle.Action;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.Handler;
import org.noear.solon.core.route.RouterInterceptor;
import org.noear.solon.core.route.RouterInterceptorChain;
import java.lang.reflect.Method;
import java.util.Date;
/**
* 访问日志拦截器
* @author: aoshiguchen
* @date: 2022/8/14
* @date: 2023/3/12
*/
@Slf4j
public class VisitLogInterceptor implements HandlerInterceptor {
@Component(index = 1)
public class VisitLogInterceptor implements RouterInterceptor {
@Override
public void doIntercept(Context ctx, Handler mainHandler, RouterInterceptorChain chain) throws Throwable {
if (!(mainHandler instanceof Action)) {
chain.doIntercept(ctx, mainHandler);
return;
}
@Override
public boolean preHandle(HttpRequestWrapper requestParser, HttpResponseWrapper responseWrapper, String route, Method targetMethod) throws Exception {
if (null != SystemContextHolder.getContext()) {
SystemContextHolder.getContext().setReceiveTime(new Date());
}
return true;
}
Date startTime = new Date();
try {
chain.doIntercept(ctx, mainHandler);
} finally {
Date now = new Date();
long elapsedTime = now.getTime() - startTime.getTime();
log.info("\n-----------------------------------------------------------------接口请求日志:\n{} url:{} 执行耗时:{}\n请求体参数:{}\n响应结果:{}\n客户端IP:{}\n",
ctx.method(), ctx.path(), getElapsedTimeStr(elapsedTime),
JSONObject.toJSONString(ctx.paramMap()),
JSONObject.toJSONString(JSONObject.toJSONString(ctx.result)),
ctx.realIp()
);
}
}
@Override
public void postHandle(HttpRequestWrapper requestParser, HttpResponseWrapper responseWrapper, String route, Method targetMethod, Object result) throws Exception {
if (null == SystemContextHolder.getContext() || null == SystemContextHolder.getContext().getReceiveTime()) {
return;
}
Date receiveTime = SystemContextHolder.getContext().getReceiveTime();
Date now = new Date();
long elapsedTime = now.getTime() - receiveTime.getTime();
log.info("\n-----------------------------------------------------------------接口请求日志:\n{} url:{} 执行耗时:{}\nURL参数:{}\n请求体参数:{}\n响应结果:{}\n客户端IP:{}\n",
requestParser.getMethod().name(), requestParser.getUrl(), getElapsedTimeStr(elapsedTime),
requestParser.getQueryString(),
requestParser.getContentAsString(),
JSONObject.toJSONString(result),
SystemContextHolder.getIp()
);
}
/**
/**
* 获取耗时描述
* @param elapsedTime
* @return
@@ -77,4 +53,5 @@ public class VisitLogInterceptor implements HandlerInterceptor {
}
return String.format("%.2f分钟", (elapsedTime * 1.0) / 1000 / 60);
}
}
@@ -21,33 +21,32 @@
*/
package fun.asgc.neutrino.proxy.server.controller;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import fun.asgc.neutrino.core.web.annotation.GetMapping;
import fun.asgc.neutrino.core.web.annotation.RequestMapping;
import fun.asgc.neutrino.core.web.annotation.RestController;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.controller.req.ClientConnectRecordListReq;
import fun.asgc.neutrino.proxy.server.controller.res.ClientConnectRecordListRes;
import fun.asgc.neutrino.proxy.server.service.ClientConnectRecordService;
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Get;
import org.noear.solon.annotation.Inject;
import org.noear.solon.annotation.Mapping;
/**
* @author: aoshiguchen
* @date: 2022/11/26
*/
@Slf4j
@NonIntercept
@RequestMapping("client-connect-record")
@RestController
@Mapping("/client-connect-record")
@Controller
public class ClientConnectRecordController {
@Autowired
@Inject
private ClientConnectRecordService clientConnectRecordService;
@GetMapping("page")
public Page<ClientConnectRecordListRes> page(PageQuery pageQuery, ClientConnectRecordListReq req) {
@Get
@Mapping("/page")
public PageInfo<ClientConnectRecordListRes> page(PageQuery pageQuery, ClientConnectRecordListReq req) {
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
return clientConnectRecordService.page(pageQuery, req);
}
@@ -21,37 +21,43 @@
*/
package fun.asgc.neutrino.proxy.server.controller;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.web.annotation.*;
import fun.asgc.neutrino.proxy.server.base.rest.Authorization;
import fun.asgc.neutrino.proxy.server.controller.req.LoginReq;
import fun.asgc.neutrino.proxy.server.controller.res.LoginRes;
import fun.asgc.neutrino.proxy.server.service.UserService;
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
import org.noear.solon.annotation.*;
import org.noear.solon.core.handle.Context;
/**
*
* @author: aoshiguchen
* @date: 2022/7/31
*/
@NonIntercept
@RequestMapping
@RestController
@Controller
public class IndexController {
@Autowired
@Inject
private UserService userService;
@Authorization(login = false)
@PostMapping("login")
public LoginRes login(@RequestBody LoginReq req) {
@Get
@Mapping("/")
public void home(Context ctx) {
ctx.forward("/index.html");
}
@Authorization(login = false)
@Post
@Mapping("/login")
public LoginRes login(LoginReq req) {
ParamCheckUtil.checkNotEmpty(req.getLoginName(), "loginName");
ParamCheckUtil.checkNotEmpty(req.getLoginPassword(), "loginPassword");
return userService.login(req);
}
@PostMapping("logout")
@Post
@Mapping("/logout")
public void logout() {
userService.logout();
}
@@ -21,18 +21,22 @@
*/
package fun.asgc.neutrino.proxy.server.controller;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import fun.asgc.neutrino.core.web.annotation.*;
import fun.asgc.neutrino.proxy.server.base.rest.annotation.OnlyAdmin;
import fun.asgc.neutrino.proxy.server.controller.req.*;
import fun.asgc.neutrino.proxy.server.controller.res.*;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.base.rest.Authorization;
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoExecuteReq;
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoListReq;
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoUpdateEnableStatusReq;
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoUpdateReq;
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoExecuteRes;
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoListRes;
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoUpdateEnableStatusRes;
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoUpdateRes;
import fun.asgc.neutrino.proxy.server.dal.entity.JobInfoDO;
import fun.asgc.neutrino.proxy.server.service.JobInfoService;
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.*;
import java.util.List;
@@ -42,44 +46,48 @@ import java.util.List;
* @date: 2022/9/5
*/
@Slf4j
@NonIntercept
@RequestMapping("job-info")
@RestController
@Mapping("/job-info")
@Controller
public class JobInfoController {
@Autowired
@Inject
private JobInfoService jobInfoService;
@GetMapping("page")
public Page<JobInfoListRes> page(PageQuery pageQuery, JobInfoListReq req) {
@Get
@Mapping("/page")
public PageInfo<JobInfoListRes> page(PageQuery pageQuery, JobInfoListReq req) {
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
return jobInfoService.page(pageQuery, req);
}
@GetMapping("findList")
@Get
@Mapping("/findList")
public List<JobInfoDO> findList() {
return jobInfoService.findList();
}
@OnlyAdmin
@PostMapping("update/enable-status")
public JobInfoUpdateEnableStatusRes updateEnableStatus(@RequestBody JobInfoUpdateEnableStatusReq req) {
@Post
@Mapping("/update/enable-status")
@Authorization(onlyAdmin = true)
public JobInfoUpdateEnableStatusRes updateEnableStatus(JobInfoUpdateEnableStatusReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getId(), "id");
ParamCheckUtil.checkNotNull(req.getEnable(), "enable");
return jobInfoService.updateEnableStatus(req);
}
@OnlyAdmin
@PostMapping("execute")
public JobInfoExecuteRes execute(@RequestBody JobInfoExecuteReq req) {
@Post
@Mapping("/execute")
@Authorization(onlyAdmin = true)
public JobInfoExecuteRes execute(JobInfoExecuteReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getId(), "id");
return jobInfoService.execute(req);
}
@PostMapping("update")
public JobInfoUpdateRes update(@RequestBody JobInfoUpdateReq req) {
@Post
@Mapping("/update")
public JobInfoUpdateRes update(JobInfoUpdateReq req) {
ParamCheckUtil.checkNotNull(req, "req");
return jobInfoService.update(req);
@@ -21,16 +21,17 @@
*/
package fun.asgc.neutrino.proxy.server.controller;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import fun.asgc.neutrino.core.web.annotation.*;
import fun.asgc.neutrino.proxy.server.controller.req.*;
import fun.asgc.neutrino.proxy.server.controller.res.*;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.controller.req.JobLogListReq;
import fun.asgc.neutrino.proxy.server.controller.res.JobLogListRes;
import fun.asgc.neutrino.proxy.server.service.JobLogService;
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Get;
import org.noear.solon.annotation.Inject;
import org.noear.solon.annotation.Mapping;
/**
*
@@ -38,15 +39,15 @@ import lombok.extern.slf4j.Slf4j;
* @date: 2022/9/25
*/
@Slf4j
@NonIntercept
@RequestMapping("job-log")
@RestController
@Mapping("/job-log")
@Controller
public class JobLogController {
@Autowired
@Inject
private JobLogService jobLogService;
@GetMapping("page")
public Page<JobLogListRes> page(PageQuery pageQuery, JobLogListReq req) {
@Get
@Mapping("/page")
public PageInfo<JobLogListRes> page(PageQuery pageQuery, JobLogListReq req) {
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
return jobLogService.page(pageQuery, req);
}
@@ -21,19 +21,14 @@
*/
package fun.asgc.neutrino.proxy.server.controller;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import fun.asgc.neutrino.core.web.annotation.*;
import fun.asgc.neutrino.proxy.server.base.rest.annotation.OnlyAdmin;
import fun.asgc.neutrino.proxy.server.controller.req.LicenseCreateReq;
import fun.asgc.neutrino.proxy.server.controller.req.LicenseListReq;
import fun.asgc.neutrino.proxy.server.controller.req.LicenseUpdateEnableStatusReq;
import fun.asgc.neutrino.proxy.server.controller.req.LicenseUpdateReq;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.base.rest.Authorization;
import fun.asgc.neutrino.proxy.server.controller.req.*;
import fun.asgc.neutrino.proxy.server.controller.res.*;
import fun.asgc.neutrino.proxy.server.service.LicenseService;
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
import org.noear.solon.annotation.*;
import java.util.List;
@@ -42,29 +37,29 @@ import java.util.List;
* @author: aoshiguchen
* @date: 2022/8/6
*/
@NonIntercept
@RequestMapping("license")
@RestController
@Mapping("/license")
@Controller
public class LicenseController {
@Autowired
@Inject
private LicenseService licenseService;
@GetMapping("page")
public Page<LicenseListRes> page(PageQuery pageQuery, LicenseListReq req) {
@Get
@Mapping("/page")
public PageInfo<LicenseListRes> page(PageQuery pageQuery, LicenseListReq req) {
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
return licenseService.page(pageQuery, req);
}
@GetMapping("list")
@Mapping("/list")
public List<LicenseListRes> list(LicenseListReq req) {
return licenseService.list(req);
}
@OnlyAdmin
@PostMapping("create")
public LicenseCreateRes create(@RequestBody LicenseCreateReq req) {
@Post
@Mapping("/create")
@Authorization(onlyAdmin = true)
public LicenseCreateRes create(LicenseCreateReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotEmpty(req.getName(), "name");
ParamCheckUtil.checkNotNull(req.getUserId(), "userId");
@@ -72,9 +67,10 @@ public class LicenseController {
return licenseService.create(req);
}
@OnlyAdmin
@PostMapping("update")
public LicenseUpdateRes update(@RequestBody LicenseUpdateReq req) {
@Post
@Mapping("/update")
@Authorization(onlyAdmin = true)
public LicenseUpdateRes update(LicenseUpdateReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getId(), "id");
ParamCheckUtil.checkNotEmpty(req.getName(), "name");
@@ -82,16 +78,19 @@ public class LicenseController {
return licenseService.update(req);
}
@GetMapping("detail")
public LicenseDetailRes detail(@RequestParam("id") Integer id) {
ParamCheckUtil.checkNotNull(id, "id");
@Post
@Mapping("/detail")
public LicenseDetailRes detail(LicenseDetailReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getId(), "id");
return licenseService.detail(id);
return licenseService.detail(req.getId());
}
@OnlyAdmin
@PostMapping("update/enable-status")
public LicenseUpdateEnableStatusRes updateEnableStatus(@RequestBody LicenseUpdateEnableStatusReq req) {
@Post
@Mapping("/update/enable-status")
@Authorization(onlyAdmin = true)
public LicenseUpdateEnableStatusRes updateEnableStatus(LicenseUpdateEnableStatusReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getId(), "id");
ParamCheckUtil.checkNotNull(req.getEnable(), "enable");
@@ -99,20 +98,24 @@ public class LicenseController {
return licenseService.updateEnableStatus(req);
}
@OnlyAdmin
@PostMapping("delete")
public void delete(@RequestParam("id") Integer id) {
ParamCheckUtil.checkNotNull(id, "id");
@Post
@Mapping("/delete")
@Authorization(onlyAdmin = true)
public void delete(LicenseDeleteReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getId(), "id");
licenseService.delete(id);
licenseService.delete(req.getId());
}
@OnlyAdmin
@PostMapping("reset")
public void reset(@RequestParam("id") Integer id) {
ParamCheckUtil.checkNotNull(id, "id");
@Post
@Mapping("/reset")
@Authorization(onlyAdmin = true)
public void reset(LicenseResetReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getId(), "id");
licenseService.reset(id);
licenseService.reset(req.getId());
}
}
@@ -1,60 +1,35 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.controller;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import fun.asgc.neutrino.core.web.annotation.*;
import fun.asgc.neutrino.proxy.server.controller.req.PortMappingCreateReq;
import fun.asgc.neutrino.proxy.server.controller.req.PortMappingListReq;
import fun.asgc.neutrino.proxy.server.controller.req.PortMappingUpdateEnableStatusReq;
import fun.asgc.neutrino.proxy.server.controller.req.PortMappingUpdateReq;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.controller.req.*;
import fun.asgc.neutrino.proxy.server.controller.res.*;
import fun.asgc.neutrino.proxy.server.service.PortMappingService;
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
import org.noear.solon.annotation.*;
/**
* 端口映射
* @author: aoshiguchen
* @date: 2022/8/8
*/
@NonIntercept
@RequestMapping("port-mapping")
@RestController
@Mapping("/port-mapping")
@Controller
public class PortMappingController {
@Autowired
@Inject
private PortMappingService portMappingService;
@GetMapping("page")
public Page<PortMappingListRes> page(PageQuery pageQuery, PortMappingListReq req) {
@Get
@Mapping("/page")
public PageInfo<PortMappingListRes> page(PageQuery pageQuery, PortMappingListReq req) {
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
return portMappingService.page(pageQuery, req);
}
@PostMapping("create")
public PortMappingCreateRes create(@RequestBody PortMappingCreateReq req) {
@Post
@Mapping("/create")
public PortMappingCreateRes create(PortMappingCreateReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getLicenseId(), "licenseId");
ParamCheckUtil.checkNotNull(req.getServerPort(), "serverPort");
@@ -64,22 +39,26 @@ public class PortMappingController {
return portMappingService.create(req);
}
@PostMapping("update")
public PortMappingUpdateRes update(@RequestBody PortMappingUpdateReq req) {
@Post
@Mapping("/update")
public PortMappingUpdateRes update(PortMappingUpdateReq req) {
ParamCheckUtil.checkNotNull(req, "req");
return portMappingService.update(req);
}
@GetMapping("detail")
public PortMappingDetailRes detail(@RequestParam("id") Integer id) {
ParamCheckUtil.checkNotNull(id, "id");
@Get
@Mapping("/detail")
public PortMappingDetailRes detail(PortMappingDetailReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getId(), "id");
return portMappingService.detail(id);
return portMappingService.detail(req.getId());
}
@PostMapping("update/enable-status")
public PortMappingUpdateEnableStatusRes updateEnableStatus(@RequestBody PortMappingUpdateEnableStatusReq req) {
@Post
@Mapping("/update/enable-status")
public PortMappingUpdateEnableStatusRes updateEnableStatus(PortMappingUpdateEnableStatusReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getId(), "id");
ParamCheckUtil.checkNotNull(req.getEnable(), "enable");
@@ -87,10 +66,12 @@ public class PortMappingController {
return portMappingService.updateEnableStatus(req);
}
@PostMapping("delete")
public void delete(@RequestParam("id") Integer id) {
ParamCheckUtil.checkNotNull(id, "id");
@Post
@Mapping("/delete")
public void delete(PortMappingDeleteReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getId(), "id");
portMappingService.delete(id);
portMappingService.delete(req.getId());
}
}
@@ -21,13 +21,11 @@
*/
package fun.asgc.neutrino.proxy.server.controller;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import fun.asgc.neutrino.core.web.annotation.*;
import fun.asgc.neutrino.proxy.server.base.rest.annotation.OnlyAdmin;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.base.rest.Authorization;
import fun.asgc.neutrino.proxy.server.controller.req.PortPoolCreateReq;
import fun.asgc.neutrino.proxy.server.controller.req.PortPoolDeleteReq;
import fun.asgc.neutrino.proxy.server.controller.req.PortPoolListReq;
import fun.asgc.neutrino.proxy.server.controller.req.PortPoolUpdateEnableStatusReq;
import fun.asgc.neutrino.proxy.server.controller.res.PortPoolCreateRes;
@@ -35,6 +33,7 @@ import fun.asgc.neutrino.proxy.server.controller.res.PortPoolListRes;
import fun.asgc.neutrino.proxy.server.controller.res.PortPoolUpdateEnableStatusRes;
import fun.asgc.neutrino.proxy.server.service.PortPoolService;
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
import org.noear.solon.annotation.*;
import java.util.List;
@@ -43,37 +42,40 @@ import java.util.List;
* @author: aoshiguchen
* @date: 2022/8/7
*/
@NonIntercept
@RequestMapping("port-pool")
@RestController
@Mapping("/port-pool")
@Controller
public class PortPoolController {
@Autowired
@Inject
private PortPoolService portPoolService;
@GetMapping("page")
public Page<PortPoolListRes> page(PageQuery pageQuery, PortPoolListReq req) {
@Get
@Mapping("/page")
public PageInfo<PortPoolListRes> page(PageQuery pageQuery, PortPoolListReq req) {
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
return portPoolService.page(pageQuery, req);
}
@GetMapping("list")
@Get
@Mapping("/list")
public List<PortPoolListRes> list(PortPoolListReq req) {
return portPoolService.list(req);
}
@OnlyAdmin
@PostMapping("create")
public PortPoolCreateRes create(@RequestBody PortPoolCreateReq req) {
@Post
@Mapping("/create")
@Authorization(onlyAdmin = true)
public PortPoolCreateRes create(PortPoolCreateReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getPort(), "port");
return portPoolService.create(req);
}
@OnlyAdmin
@PostMapping("update/enable-status")
public PortPoolUpdateEnableStatusRes updateEnableStatus(@RequestBody PortPoolUpdateEnableStatusReq req) {
@Post
@Mapping("/update/enable-status")
@Authorization(onlyAdmin = true)
public PortPoolUpdateEnableStatusRes updateEnableStatus(PortPoolUpdateEnableStatusReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getId(), "id");
ParamCheckUtil.checkNotNull(req.getEnable(), "enable");
@@ -81,11 +83,13 @@ public class PortPoolController {
return portPoolService.updateEnableStatus(req);
}
@OnlyAdmin
@PostMapping("delete")
public void delete(@RequestParam("id") Integer id) {
ParamCheckUtil.checkNotNull(id, "id");
@Post
@Mapping("/delete")
@Authorization(onlyAdmin = true)
public void delete(PortPoolDeleteReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getId(), "id");
portPoolService.delete(id);
portPoolService.delete(req.getId());
}
}
@@ -1,33 +1,7 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.controller;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import fun.asgc.neutrino.core.web.annotation.GetMapping;
import fun.asgc.neutrino.core.web.annotation.RequestMapping;
import fun.asgc.neutrino.core.web.annotation.RestController;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.controller.req.LicenseFlowReportReq;
import fun.asgc.neutrino.proxy.server.controller.req.UserFlowReportReq;
import fun.asgc.neutrino.proxy.server.controller.res.LicenseFlowReportRes;
@@ -35,18 +9,21 @@ import fun.asgc.neutrino.proxy.server.controller.res.ReportDataViewRes;
import fun.asgc.neutrino.proxy.server.controller.res.UserFlowReportRes;
import fun.asgc.neutrino.proxy.server.service.ReportService;
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Get;
import org.noear.solon.annotation.Inject;
import org.noear.solon.annotation.Mapping;
/**
* 报表管理
* @author: aoshiguchen
* @date: 2022/9/12
*/
@NonIntercept
@RequestMapping("report")
@RestController
@Mapping("/report")
@Controller
public class ReportController {
@Autowired
@Inject
private ReportService reportService;
/**
@@ -62,7 +39,8 @@ public class ReportController {
* 4点击历史流量下方展示历史流量折线图筛选项/ 日期选择展示最近30天最多跨30日展示最近12个月最多跨12个月
* @return
*/
@GetMapping("data-view")
@Get
@Mapping("/data-view")
public ReportDataViewRes dataView() {
return new ReportDataViewRes()
.setUserOnlineNumber(2).setEnableUserNumber(3).setUserNumber(5)
@@ -78,8 +56,9 @@ public class ReportController {
* @param req
* @return
*/
@GetMapping("user/flow-report/page")
public Page<UserFlowReportRes> userFlowReportPage(PageQuery pageQuery, UserFlowReportReq req) {
@Get
@Mapping("/user/flow-report/page")
public PageInfo<UserFlowReportRes> userFlowReportPage(PageQuery pageQuery, UserFlowReportReq req) {
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
return reportService.userFlowReportPage(pageQuery, req);
@@ -91,8 +70,9 @@ public class ReportController {
* @param req
* @return
*/
@GetMapping("license/flow-report/page")
public Page<LicenseFlowReportRes> licenseFlowReportPage(PageQuery pageQuery, LicenseFlowReportReq req) {
@Get
@Mapping("/license/flow-report/page")
public PageInfo<LicenseFlowReportRes> licenseFlowReportPage(PageQuery pageQuery, LicenseFlowReportReq req) {
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
return reportService.licenseFlowReportPage(pageQuery, req);
@@ -21,13 +21,10 @@
*/
package fun.asgc.neutrino.proxy.server.controller;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import fun.asgc.neutrino.core.web.annotation.*;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.base.rest.Authorization;
import fun.asgc.neutrino.proxy.server.base.rest.SystemContextHolder;
import fun.asgc.neutrino.proxy.server.base.rest.annotation.OnlyAdmin;
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
import fun.asgc.neutrino.proxy.server.controller.req.*;
import fun.asgc.neutrino.proxy.server.controller.res.*;
@@ -36,6 +33,7 @@ import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
import fun.asgc.neutrino.proxy.server.service.UserService;
import fun.asgc.neutrino.proxy.server.util.Md5Util;
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
import org.noear.solon.annotation.*;
import java.util.List;
@@ -44,36 +42,39 @@ import java.util.List;
* @author: aoshiguchen
* @date: 2022/7/31
*/
@NonIntercept
@RequestMapping("user")
@RestController
@Mapping("/user")
@Controller
public class UserController {
@Autowired
@Inject
private UserService userService;
@Autowired
@Inject
private UserMapper userMapper;
@GetMapping("page")
public Page<UserListRes> page(PageQuery pageQuery, UserListReq req) {
@Get
@Mapping("/page")
public PageInfo<UserListRes> page(PageQuery pageQuery, UserListReq req) {
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
return userService.page(pageQuery, req);
}
@GetMapping("list")
@Get
@Mapping("/list")
public List<UserListRes> list(UserListReq req) {
return userService.list(req);
}
@GetMapping("info")
@Get
@Mapping("/info")
public UserInfoRes info(UserInfoReq req) {
return userService.info(req);
}
@OnlyAdmin
@PostMapping("update/enable-status")
public UserUpdateEnableStatusRes updateEnableStatus(@RequestBody UserUpdateEnableStatusReq req) {
@Post
@Mapping("/update/enable-status")
@Authorization(onlyAdmin = true)
public UserUpdateEnableStatusRes updateEnableStatus(UserUpdateEnableStatusReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getId(), "id");
ParamCheckUtil.checkNotNull(req.getEnable(), "enable");
@@ -81,9 +82,10 @@ public class UserController {
return userService.updateEnableStatus(req);
}
@OnlyAdmin
@PostMapping("create")
public UserCreateRes create(@RequestBody UserCreateReq req) {
@Post
@Mapping("/create")
@Authorization(onlyAdmin = true)
public UserCreateRes create(UserCreateReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotEmpty(req.getName(), "name");
ParamCheckUtil.checkNotEmpty(req.getLoginName(), "loginName");
@@ -91,9 +93,10 @@ public class UserController {
return userService.create(req);
}
@OnlyAdmin
@PostMapping("update")
public UserUpdateRes update(@RequestBody UserUpdateReq req) {
@Post
@Mapping("/update")
@Authorization(onlyAdmin = true)
public UserUpdateRes update(UserUpdateReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getId(), "id");
ParamCheckUtil.checkNotEmpty(req.getName(), "name");
@@ -102,9 +105,10 @@ public class UserController {
return userService.update(req);
}
@OnlyAdmin
@PostMapping("update/password")
public UserUpdatePasswordRes updatePassword(@RequestBody UserUpdatePasswordReq req) {
@Post
@Mapping("/update/password")
@Authorization(onlyAdmin = true)
public UserUpdatePasswordRes updatePassword(UserUpdatePasswordReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getId(), "id");
ParamCheckUtil.checkNotEmpty(req.getLoginPassword(), "loginPassword");
@@ -113,8 +117,9 @@ public class UserController {
return userService.updatePassword(req);
}
@PostMapping("current-user/update/password")
public UserUpdatePasswordRes currentUserUpdatePassword(@RequestBody UserUpdatePasswordReq req) {
@Post
@Mapping("/current-user/update/password")
public UserUpdatePasswordRes currentUserUpdatePassword(UserUpdatePasswordReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotEmpty(req.getOldLoginPassword(), "oldLoginPassword");
ParamCheckUtil.checkNotEmpty(req.getLoginPassword(), "loginPassword");
@@ -128,11 +133,13 @@ public class UserController {
return userService.updatePassword(req);
}
@OnlyAdmin
@PostMapping("delete")
public void delete(@RequestParam("id") Integer id) {
ParamCheckUtil.checkNotNull(id, "id");
@Post
@Mapping("/delete")
@Authorization(onlyAdmin = true)
public void delete(UserDeleteReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getId(), "id");
userService.delete(id);
userService.delete(req.getId());
}
}
@@ -21,31 +21,30 @@
*/
package fun.asgc.neutrino.proxy.server.controller;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import fun.asgc.neutrino.core.web.annotation.GetMapping;
import fun.asgc.neutrino.core.web.annotation.RequestMapping;
import fun.asgc.neutrino.core.web.annotation.RestController;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.controller.req.UserLoginRecordListReq;
import fun.asgc.neutrino.proxy.server.controller.res.UserLoginRecordListRes;
import fun.asgc.neutrino.proxy.server.service.UserLoginRecordService;
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Get;
import org.noear.solon.annotation.Inject;
import org.noear.solon.annotation.Mapping;
/**
* @author: aoshiguchen
* @date: 2022/10/20
*/
@NonIntercept
@RequestMapping("user-login-record")
@RestController
@Mapping("/user-login-record")
@Controller
public class UserLoginRecordController {
@Autowired
@Inject
private UserLoginRecordService userLoginRecordService;
@GetMapping("page")
public Page<UserLoginRecordListRes> page(PageQuery pageQuery, UserLoginRecordListReq req) {
@Get
@Mapping("/page")
public PageInfo<UserLoginRecordListRes> page(PageQuery pageQuery, UserLoginRecordListReq req) {
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
return userLoginRecordService.page(pageQuery, req);
@@ -0,0 +1,13 @@
package fun.asgc.neutrino.proxy.server.controller.req;
import lombok.Data;
/**
* license删除请求
* @author: aoshiguchen
* @date: 2023/3/11
*/
@Data
public class LicenseDeleteReq {
private Integer id;
}
@@ -0,0 +1,12 @@
package fun.asgc.neutrino.proxy.server.controller.req;
import lombok.Data;
/**
* @author: aoshiguchen
* @date: 2023/3/11
*/
@Data
public class LicenseDetailReq {
private Integer id;
}
@@ -0,0 +1,12 @@
package fun.asgc.neutrino.proxy.server.controller.req;
import lombok.Data;
/**
* @author: aoshiguchen
* @date: 2023/3/11
*/
@Data
public class LicenseResetReq {
private Integer id;
}
@@ -0,0 +1,12 @@
package fun.asgc.neutrino.proxy.server.controller.req;
import lombok.Data;
/**
* @author: aoshiguchen
* @date: 2023/3/11
*/
@Data
public class PortMappingDeleteReq {
private Integer id;
}
@@ -30,5 +30,5 @@ import lombok.Data;
*/
@Data
public class PortMappingDetailReq {
private Integer id;
}
@@ -0,0 +1,12 @@
package fun.asgc.neutrino.proxy.server.controller.req;
import lombok.Data;
/**
* @author: aoshiguchen
* @date: 2023/3/11
*/
@Data
public class PortPoolDeleteReq {
private Integer id;
}
@@ -0,0 +1,12 @@
package fun.asgc.neutrino.proxy.server.controller.req;
import lombok.Data;
/**
* @author: aoshiguchen
* @date: 2023/3/11
*/
@Data
public class UserDeleteReq {
private Integer id;
}
@@ -1,27 +1,5 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.controller.res;
import fun.asgc.neutrino.core.db.annotation.Id;
import fun.asgc.neutrino.proxy.server.constant.OnlineStatusEnum;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -36,7 +14,6 @@ import java.util.Date;
@Accessors(chain = true)
@Data
public class LicenseListRes {
@Id
private Integer id;
/**
* 名称
@@ -1,27 +1,5 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.controller.res;
import fun.asgc.neutrino.core.db.annotation.Id;
import fun.asgc.neutrino.proxy.server.constant.OnlineStatusEnum;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -36,7 +14,6 @@ import java.util.Date;
@Accessors(chain = true)
@Data
public class PortMappingDetailRes {
@Id
private Integer id;
/**
* licenseId
@@ -1,27 +1,5 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.controller.res;
import fun.asgc.neutrino.core.db.annotation.Id;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -1,26 +1,21 @@
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.aop.Intercept;
import fun.asgc.neutrino.core.db.annotation.ResultType;
import fun.asgc.neutrino.core.db.annotation.Select;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.proxy.server.controller.req.ClientConnectRecordListReq;
import fun.asgc.neutrino.proxy.server.controller.res.ClientConnectRecordListRes;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.ClientConnectRecordDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Date;
/**
* @author: aoshiguchen
* @date: 2022/11/23
*/
@Intercept(ignoreGlobal = true)
@Component
public interface ClientConnectRecordMapper extends SqlMapper {
void add(ClientConnectRecordDO clientConnectRecordDO);
@ResultType(ClientConnectRecordListRes.class)
@Select("select * from client_connect_record order by id desc")
void page(Page page, ClientConnectRecordListReq req);
@Mapper
public interface ClientConnectRecordMapper extends BaseMapper<ClientConnectRecordDO> {
default void clean(Date date) {
this.delete(new LambdaQueryWrapper<ClientConnectRecordDO>()
.lt(ClientConnectRecordDO::getCreateTime, date)
);
}
}
@@ -1,57 +0,0 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.aop.Intercept;
import fun.asgc.neutrino.core.db.annotation.Delete;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import java.util.Date;
/**
* @author: aoshiguchen
* @date: 2022/9/17
*/
@Intercept(ignoreGlobal = true)
@Component
public interface DataCleanMapper extends SqlMapper {
@Delete("delete from `job_log` where create_time < ?")
void cleanJobLog(Date date);
@Delete("delete from `user_login_record` where create_time < ?")
void cleanUserLoginRecord(Date date);
@Delete("delete from `client_connect_record` where create_time < ?")
void cleanClientConnectRecord(Date date);
@Delete("delete from `flow_report_minute` where create_time < ?")
void cleanFlowMinuteReport(Date date);
@Delete("delete from `flow_report_hour` where create_time < ?")
void cleanFlowHourReport(Date date);
@Delete("delete from `flow_report_day` where create_time < ?")
void cleanFlowDayReport(Date date);
}
@@ -21,36 +21,32 @@
*/
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Param;
import fun.asgc.neutrino.core.aop.Intercept;
import fun.asgc.neutrino.core.db.annotation.Delete;
import fun.asgc.neutrino.core.db.annotation.Insert;
import fun.asgc.neutrino.core.db.annotation.ResultType;
import fun.asgc.neutrino.core.db.annotation.Select;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportDayDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Date;
import java.util.List;
/**
* @author: aoshiguchen
* @date: 2022/10/28
*/
@Intercept(ignoreGlobal = true)
@Component
public interface FlowReportDayMapper extends SqlMapper {
@Select("select * from flow_report_day where license_id = :licenseId and date_str = :dateStr")
FlowReportDayDO findOne(@Param("licenseId") Integer licenseId, @Param("dateStr") String dateStr);
@Mapper
public interface FlowReportDayMapper extends BaseMapper<FlowReportDayDO> {
default void clean(Date date) {
this.delete(new LambdaQueryWrapper<FlowReportDayDO>()
.lt(FlowReportDayDO::getCreateTime, date)
);
}
@Insert("insert into flow_report_day(`user_id`,`license_id`,`write_bytes`,`read_bytes`,`date`,`date_str`,`create_time`) values(:userId,:licenseId,:writeBytes,:readBytes,:date,:dateStr,:createTime)")
void add(FlowReportDayDO flowReportDayDO);
default void deleteByDateStr(String dateStr) {
this.delete(new LambdaQueryWrapper<FlowReportDayDO>()
.eq(FlowReportDayDO::getDateStr, dateStr)
);
}
@Delete("delete from flow_report_day where date_str = :dateStr")
void deleteByDateStr(@Param("dateStr") String dateStr);
@ResultType(FlowReportDayDO.class)
@Select("select * from flow_report_day where date >= :startDate and date <= :endDate")
List<FlowReportDayDO> findListByDateRange(@Param("startDate") Date startDate, @Param("endDate") Date endDate);
default List<FlowReportDayDO> findListByDateRange(Date startDate, Date endDate) {
return this.selectList(new LambdaQueryWrapper<FlowReportDayDO>()
.le(FlowReportDayDO::getDate, startDate)
.gt(FlowReportDayDO::getDate, endDate)
);
}
}
@@ -21,37 +21,33 @@
*/
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Param;
import fun.asgc.neutrino.core.aop.Intercept;
import fun.asgc.neutrino.core.db.annotation.Delete;
import fun.asgc.neutrino.core.db.annotation.Insert;
import fun.asgc.neutrino.core.db.annotation.ResultType;
import fun.asgc.neutrino.core.db.annotation.Select;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportHourDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Date;
import java.util.List;
/**
* @author: aoshiguchen
* @date: 2022/10/28
*/
@Intercept(ignoreGlobal = true)
@Component
public interface FlowReportHourMapper extends SqlMapper {
@Select("select * from flow_report_hour where license_id = :licenseId and date_str = :dateStr")
FlowReportHourDO findOne(@Param("licenseId") Integer licenseId, @Param("dateStr") String dateStr);
@Mapper
public interface FlowReportHourMapper extends BaseMapper<FlowReportHourDO> {
default void clean(Date date) {
this.delete(new LambdaQueryWrapper<FlowReportHourDO>()
.lt(FlowReportHourDO::getCreateTime, date)
);
}
@Insert("insert into flow_report_hour(`user_id`,`license_id`,`write_bytes`,`read_bytes`,`date`,`date_str`,`create_time`) values(:userId,:licenseId,:writeBytes,:readBytes,:date,:dateStr,:createTime)")
void add(FlowReportHourDO flowReportHourDO);
default void deleteByDateStr(String dateStr) {
this.delete(new LambdaQueryWrapper<FlowReportHourDO>()
.eq(FlowReportHourDO::getDateStr, dateStr)
);
}
@Delete("delete from flow_report_hour where date_str = :dateStr")
void deleteByDateStr(@Param("dateStr") String dateStr);
@ResultType(FlowReportHourDO.class)
@Select("select * from flow_report_hour where date >= :startDate and date <= :endDate")
List<FlowReportHourDO> findListByDateRange(@Param("startDate") Date startDate, @Param("endDate") Date endDate);
default List<FlowReportHourDO> findListByDateRange(Date startDate, Date endDate) {
return this.selectList(new LambdaQueryWrapper<FlowReportHourDO>()
.ge(FlowReportHourDO::getDateStr, startDate)
.le(FlowReportHourDO::getDateStr, endDate)
);
}
}
@@ -21,37 +21,35 @@
*/
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Param;
import fun.asgc.neutrino.core.aop.Intercept;
import fun.asgc.neutrino.core.db.annotation.Insert;
import fun.asgc.neutrino.core.db.annotation.ResultType;
import fun.asgc.neutrino.core.db.annotation.Select;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportMinuteDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Date;
import java.util.List;
import java.util.Set;
/**
* @author: aoshiguchen
* @date: 2022/10/24
*/
@Intercept(ignoreGlobal = true)
@Component
public interface FlowReportMinuteMapper extends SqlMapper {
@Select("select * from flow_report_minute where license_id = :licenseId and date = :date")
FlowReportMinuteDO findOne(@Param("licenseId") Integer licenseId, @Param("date") String date);
@Mapper
public interface FlowReportMinuteMapper extends BaseMapper<FlowReportMinuteDO> {
default void clean(Date date) {
this.delete(new LambdaQueryWrapper<FlowReportMinuteDO>()
.lt(FlowReportMinuteDO::getCreateTime, date)
);
}
@ResultType(FlowReportMinuteDO.class)
@Select("select * from flow_report_minute where license_id in (:licenseIds) and date = :date")
List<FlowReportMinuteDO> findList(@Param("licenseIds") Set<Integer> licenseIds, @Param("date") String date);
default List<FlowReportMinuteDO> findList(Set<Integer> licenseIds, String date) {
return this.selectList(new LambdaQueryWrapper<FlowReportMinuteDO>()
.in(FlowReportMinuteDO::getLicenseId, licenseIds)
.eq(FlowReportMinuteDO::getDate, date)
);
}
@ResultType(FlowReportMinuteDO.class)
@Select("select * from flow_report_minute where date >= :startDate and date <= :endDate")
List<FlowReportMinuteDO> findListByDateRange(@Param("startDate") Date startDate, @Param("endDate") Date endDate);
default List<FlowReportMinuteDO> findListByDateRange(Date startDate, Date endDate) {
return this.selectList(new LambdaQueryWrapper<FlowReportMinuteDO>()
.ge(FlowReportMinuteDO::getDate, startDate)
.le(FlowReportMinuteDO::getDate, endDate)
);
}
@Insert("insert into flow_report_minute(`user_id`,`license_id`,`write_bytes`,`read_bytes`,`date`,`date_str`,`create_time`) values(:userId,:licenseId,:writeBytes,:readBytes,:date,:dateStr,:createTime)")
void add(FlowReportMinuteDO flowReportMinuteDO);
}
@@ -21,28 +21,17 @@
*/
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Param;
import fun.asgc.neutrino.core.aop.Intercept;
import fun.asgc.neutrino.core.db.annotation.Delete;
import fun.asgc.neutrino.core.db.annotation.Insert;
import fun.asgc.neutrino.core.db.annotation.Select;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportMonthDO;
import org.apache.ibatis.annotations.Mapper;
/**
* @author: aoshiguchen
* @date: 2022/10/28
*/
@Intercept(ignoreGlobal = true)
@Component
public interface FlowReportMonthMapper extends SqlMapper {
@Select("select * from flow_report_month where license_id = :licenseId and date_str = :dateStr")
FlowReportMonthDO findOne(@Param("licenseId") Integer licenseId, @Param("dateStr") String dateStr);
@Mapper
public interface FlowReportMonthMapper extends BaseMapper<FlowReportMonthDO> {
@Insert("insert into flow_report_month(`user_id`,`license_id`,`write_bytes`,`read_bytes`,`date`,`date_str`,`create_time`) values(:userId,:licenseId,:writeBytes,:readBytes,:date,:dateStr,:createTime)")
void add(FlowReportMonthDO flowReportMonthDO);
@Delete("delete from flow_report_month where date_str = :dateStr")
void deleteByDateStr(@Param("dateStr") String dateStr);
default void deleteByDateStr(String dateStr) {
this.delete(new LambdaQueryWrapper<FlowReportMonthDO>()
.eq(FlowReportMonthDO::getDateStr, dateStr)
);
}
}
@@ -21,43 +21,31 @@
*/
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Param;
import fun.asgc.neutrino.core.aop.Intercept;
import fun.asgc.neutrino.core.db.annotation.ResultType;
import fun.asgc.neutrino.core.db.annotation.Select;
import fun.asgc.neutrino.core.db.annotation.Update;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoListReq;
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoListRes;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.JobInfoDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Date;
import java.util.List;
/**
*
* @author: aoshiguchen
* @date: 2022/9/5
*/
@Intercept(ignoreGlobal = true)
@Component
public interface JobInfoMapper extends SqlMapper {
@Mapper
public interface JobInfoMapper extends BaseMapper<JobInfoDO> {
@ResultType(JobInfoListRes.class)
@Select("select * from job_info")
void page(Page page, JobInfoListReq req);
default JobInfoDO findById(Integer id) {
return this.selectById(id);
}
@Select("select * from job_info where id = ?")
JobInfoDO findById(Integer id);
default void updateEnableStatus(Integer id, Integer enable, Date updateTime) {
this.update(null, new LambdaUpdateWrapper<JobInfoDO>()
.eq(JobInfoDO::getId, id)
.set(JobInfoDO::getEnable, enable)
.set(JobInfoDO::getUpdateTime, updateTime)
);
}
@Update("update `job_info` set enable = :enable,update_time = :updateTime where id = :id")
void updateEnableStatus(@Param("id") Integer id, @Param("enable") Integer enable, @Param("updateTime") Date updateTime);
@ResultType(JobInfoDO.class)
@Select("select * from job_info")
List<JobInfoDO> findList();
void update(JobInfoDO jobInfoDO);
default List<JobInfoDO> findList() {
return this.selectList(new LambdaQueryWrapper<>());
}
}
@@ -21,39 +21,25 @@
*/
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Param;
import fun.asgc.neutrino.core.aop.Intercept;
import fun.asgc.neutrino.core.db.annotation.Insert;
import fun.asgc.neutrino.core.db.annotation.ResultType;
import fun.asgc.neutrino.core.db.annotation.Select;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoListReq;
import fun.asgc.neutrino.proxy.server.controller.req.JobLogListReq;
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoListRes;
import fun.asgc.neutrino.proxy.server.controller.res.JobLogListRes;
import fun.asgc.neutrino.proxy.server.dal.entity.JobInfoDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.JobLogDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Date;
/**
*
* @author: aoshiguchen
* @date: 2022/9/5
*/
@Intercept(ignoreGlobal = true)
@Component
public interface JobLogMapper extends SqlMapper {
@Mapper
public interface JobLogMapper extends BaseMapper<JobLogDO> {
@Insert("insert into job_log(`job_id`,`handler`,`param`,`code`,`msg`,`alarm_status`,`create_time`) values(:jobId,:handler,:param,:code,:msg,:alarmStatus,:createTime)")
void add(JobLogDO jobLog);
@ResultType(JobLogListRes.class)
@Select("select * from job_log order by create_time desc")
void page(Page page, JobLogListReq req);
@ResultType(JobLogListRes.class)
@Select("select * from job_log where job_id = :jobId order by create_time desc")
void pageByJobId(Page page, JobLogListReq req);
default void clean(Date date) {
this.delete(new LambdaQueryWrapper<JobLogDO>()
.lt(JobLogDO::getCreateTime, date)
);
}
}
@@ -21,18 +21,11 @@
*/
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Param;
import fun.asgc.neutrino.core.aop.Intercept;
import fun.asgc.neutrino.core.db.annotation.Delete;
import fun.asgc.neutrino.core.db.annotation.ResultType;
import fun.asgc.neutrino.core.db.annotation.Select;
import fun.asgc.neutrino.core.db.annotation.Update;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.proxy.server.controller.req.LicenseListReq;
import fun.asgc.neutrino.proxy.server.controller.res.LicenseListRes;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.LicenseDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Date;
import java.util.List;
@@ -43,68 +36,86 @@ import java.util.Set;
* @author: aoshiguchen
* @date: 2022/8/6
*/
@Intercept(ignoreGlobal = true)
@Component
public interface LicenseMapper extends SqlMapper {
@Mapper
public interface LicenseMapper extends BaseMapper<LicenseDO> {
/**
* 查询license分页
* @param page
* @param req
*/
void page(Page page, LicenseListReq req);
default List<LicenseDO> listAll() {
return this.selectList(new LambdaQueryWrapper<>());
}
@ResultType(LicenseListRes.class)
@Select("select * from license where enable = 1")
List<LicenseListRes> list();
default List<LicenseDO> listByUserId(Integer userId) {
return this.selectList(new LambdaQueryWrapper<LicenseDO>()
.eq(LicenseDO::getUserId, userId)
);
}
@ResultType(LicenseDO.class)
@Select("select * from license")
List<LicenseDO> listAll();
default void updateEnableStatus(Integer id, Integer enable, Date updateTime) {
this.update(null, new LambdaUpdateWrapper<LicenseDO>()
.eq(LicenseDO::getId, id)
.set(LicenseDO::getEnable, enable)
.set(LicenseDO::getUpdateTime, updateTime)
);
}
@ResultType(LicenseDO.class)
@Select("select * from `license` where user_id = :userId")
List<LicenseDO> listByUserId(@Param("userId") Integer userId);
default void updateOnlineStatus(Integer id, Integer isOnline, Date updateTime) {
this.update(null, new LambdaUpdateWrapper<LicenseDO>()
.eq(LicenseDO::getId, id)
.set(LicenseDO::getIsOnline, isOnline)
.set(LicenseDO::getUpdateTime, updateTime)
);
}
/**
* 新增license
* @param license
*/
int add(LicenseDO license);
default void updateOnlineStatus(Integer isOnline, Date updateTime) {
this.update(null, new LambdaUpdateWrapper<LicenseDO>()
.set(LicenseDO::getIsOnline, updateTime)
.set(LicenseDO::getUpdateTime, updateTime)
);
}
@Update("update `license` set enable = :enable, update_time = :updateTime where id = :id")
void updateEnableStatus(@Param("id") Integer id, @Param("enable") Integer enable, @Param("updateTime") Date updateTime);
default void reset(Integer id, String key, Date updateTime) {
this.update(null, new LambdaUpdateWrapper<LicenseDO>()
.eq(LicenseDO::getId, id)
.set(LicenseDO::getKey, key)
.set(LicenseDO::getUpdateTime, updateTime)
);
}
@Update("update `license` set is_online = :isOnline, update_time = :updateTime where id = :id")
void updateOnlineStatus(@Param("id") Integer id, @Param("isOnline") Integer isOnline, @Param("updateTime") Date updateTime);
default LicenseDO findById(Integer id) {
return this.selectById(id);
}
@Update("update `license` set is_online = :isOnline, update_time = :updateTime")
void updateOnlineStatus(@Param("isOnline") Integer isOnline, @Param("updateTime") Date updateTime);
default void update(Integer id, String name, Date updateTime) {
this.update(null, new LambdaUpdateWrapper<LicenseDO>()
.eq(LicenseDO::getId, id)
.set(LicenseDO::getName, name)
.set(LicenseDO::getUpdateTime, updateTime)
);
}
@Update("update `license` set `key` = :key,update_time = :updateTime where id = :id")
void reset(@Param("id") Integer id, @Param("key") String key, @Param("updateTime") Date updateTime);
default List<LicenseDO> findByIds(Set<Integer> ids) {
return selectBatchIds(ids);
}
@Delete("delete from `license` where id = ?")
void delete(Integer id);
default LicenseDO checkRepeat(Integer userId, String name) {
return this.selectOne(new LambdaQueryWrapper<LicenseDO>()
.eq(LicenseDO::getUserId, userId)
.eq(LicenseDO::getName, name)
.last("limit 1")
);
}
@Select("select * from `license` where id = ?")
LicenseDO findById(Integer id);
default LicenseDO checkRepeat(Integer userId, String name, Set<Integer> excludeIds) {
return this.selectOne(new LambdaQueryWrapper<LicenseDO>()
.eq(LicenseDO::getUserId, userId)
.eq(LicenseDO::getName, name)
.notIn(LicenseDO::getId, excludeIds)
.last("limit 1")
);
}
@Update("update `license` set name = :name, update_time = :updateTime where id = :id")
void update(@Param("id") Integer id, @Param("name") String name, @Param("updateTime") Date updateTime);
@ResultType(LicenseDO.class)
@Select("select * from `license` where id in (:ids)")
List<LicenseDO> findByIds(@Param("ids")Set<Integer> ids);
@ResultType(LicenseDO.class)
@Select("select * from `license` where user_id = :userId and name =:name limit 0,1")
LicenseDO checkRepeat(@Param("userId") Integer userId, @Param("name") String name);
@ResultType(LicenseDO.class)
@Select("select * from `license` where user_id = :userId and name =:name and id not in (:excludeIds) limit 0,1")
LicenseDO checkRepeat(@Param("userId") Integer userId, @Param("name") String name, @Param("excludeIds") Set<Integer> excludeIds);
@Select("select * from `license` where `key` = ?")
LicenseDO findByKey(String licenseKey);
default LicenseDO findByKey(String licenseKey) {
return selectOne(new LambdaQueryWrapper<LicenseDO>()
.eq(LicenseDO::getKey, licenseKey)
);
}
}
@@ -1,38 +1,12 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Param;
import fun.asgc.neutrino.core.aop.Intercept;
import fun.asgc.neutrino.core.db.annotation.Delete;
import fun.asgc.neutrino.core.db.annotation.ResultType;
import fun.asgc.neutrino.core.db.annotation.Select;
import fun.asgc.neutrino.core.db.annotation.Update;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.proxy.server.controller.req.PortMappingListReq;
import fun.asgc.neutrino.proxy.server.controller.res.PortMappingListRes;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
import fun.asgc.neutrino.proxy.server.dal.entity.PortMappingDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Date;
import java.util.List;
@@ -43,51 +17,69 @@ import java.util.Set;
* @author: aoshiguchen
* @date: 2022/8/8
*/
@Intercept(ignoreGlobal = true)
@Component
public interface PortMappingMapper extends SqlMapper {
@Mapper
public interface PortMappingMapper extends BaseMapper<PortMappingDO> {
@ResultType(PortMappingListRes.class)
@Select("select * from port_mapping")
void page(Page page, PortMappingListReq req);
default PortMappingDO findById(Integer id) {
return this.selectById(id);
}
void add(PortMappingDO portMappingDO);
default void updateEnableStatus(Integer id, Integer enable, Date updateTime) {
this.update(null, new LambdaUpdateWrapper<PortMappingDO>()
.eq(PortMappingDO::getId, id)
.set(PortMappingDO::getEnable, enable)
.set(PortMappingDO::getUpdateTime, updateTime)
);
}
void update(PortMappingDO portMappingDO);
default PortMappingDO findByPort(Integer port, Set<Integer> excludeIds) {
return this.selectOne(new LambdaQueryWrapper<PortMappingDO>()
.eq(PortMappingDO::getServerPort, port)
.notIn(!CollectionUtil.isEmpty(excludeIds), PortMappingDO::getId, excludeIds)
.last("limit 1")
);
}
@Select("select * from port_mapping where id = ?")
PortMappingDO findById(Integer id);
default List<PortMappingDO> findEnableListByLicenseId(Integer licenseId) {
return this.selectList(new LambdaQueryWrapper<PortMappingDO>()
.eq(PortMappingDO::getLicenseId, licenseId)
.eq(PortMappingDO::getEnable, EnableStatusEnum.ENABLE.getStatus())
);
}
@Update("update `port_mapping` set enable = :enable,update_time = :updateTime where id = :id")
void updateEnableStatus(@Param("id") Integer id, @Param("enable") Integer enable, @Param("updateTime") Date updateTime);
default List<PortMappingDO> findListByServerPort(Integer serverPort) {
return this.selectList(new LambdaQueryWrapper<PortMappingDO>()
.eq(PortMappingDO::getServerPort, serverPort)
);
}
@Delete("delete from `port_mapping` where id = ?")
void delete(Integer id);
default List<PortMappingDO> findListByLicenseId(Integer licenseId) {
return this.selectList(new LambdaQueryWrapper<PortMappingDO>()
.eq(PortMappingDO::getLicenseId, licenseId)
);
}
@Select("select * from port_mapping where server_port = ?")
PortMappingDO findByPort(Integer port);
default void updateOnlineStatus(Integer licenseId,Integer serverPort, Integer isOnline, Date updateTime) {
this.update(null, new LambdaUpdateWrapper<PortMappingDO>()
.eq(PortMappingDO::getLicenseId, licenseId)
.eq(PortMappingDO::getServerPort, serverPort)
.set(PortMappingDO::getIsOnline, isOnline)
.set(PortMappingDO::getUpdateTime, updateTime)
);
}
@Select("select * from port_mapping where server_port = :port and id not in (:excludeIds)")
PortMappingDO findByPort(@Param("port") Integer port, @Param("excludeIds") Set<Integer> excludeIds);
default void updateOnlineStatus(Integer licenseId, Integer isOnline, Date updateTime) {
this.update(null, new LambdaUpdateWrapper<PortMappingDO>()
.eq(PortMappingDO::getLicenseId, licenseId)
.set(PortMappingDO::getIsOnline, isOnline)
.set(PortMappingDO::getUpdateTime, updateTime)
);
}
@ResultType(PortMappingDO.class)
@Select("select * from port_mapping where license_id = ? and enable = 1")
List<PortMappingDO> findEnableListByLicenseId(Integer licenseId);
@ResultType(PortMappingDO.class)
@Select("select * from port_mapping where server_port = :serverPort")
List<PortMappingDO> findListByServerPort(@Param("serverPort") Integer serverPort);
@ResultType(PortMappingDO.class)
@Select("select * from port_mapping where license_id = ?")
List<PortMappingDO> findListByLicenseId(Integer licenseId);
@Update("update `port_mapping` set is_online = :isOnline,update_time = :updateTime where license_id = :licenseId and server_port = :serverPort")
void updateOnlineStatus(@Param("licenseId") Integer licenseId, @Param("serverPort") Integer serverPort, @Param("isOnline") Integer isOnline, @Param("updateTime") Date updateTime);
@Update("update `port_mapping` set is_online = :isOnline,update_time = :updateTime where license_id = :licenseId")
void updateOnlineStatus(@Param("licenseId") Integer licenseId, @Param("isOnline") Integer isOnline, @Param("updateTime") Date updateTime);
@Update("update `port_mapping` set is_online = :isOnline,update_time = :updateTime")
void updateOnlineStatus(@Param("isOnline") Integer isOnline, @Param("updateTime") Date updateTime);
default void updateOnlineStatus(Integer isOnline, Date updateTime) {
this.update(null, new LambdaUpdateWrapper<PortMappingDO>()
.set(PortMappingDO::getIsOnline, isOnline)
.set(PortMappingDO::getUpdateTime, updateTime)
);
}
}
@@ -21,48 +21,36 @@
*/
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Param;
import fun.asgc.neutrino.core.aop.Intercept;
import fun.asgc.neutrino.core.db.annotation.*;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.proxy.server.controller.req.PortPoolListReq;
import fun.asgc.neutrino.proxy.server.controller.res.PortPoolListRes;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.PortPoolDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Date;
import java.util.List;
/**
*
* @author: aoshiguchen
* @date: 2022/8/7
*/
@Intercept(ignoreGlobal = true)
@Component
public interface PortPoolMapper extends SqlMapper {
@Mapper
public interface PortPoolMapper extends BaseMapper<PortPoolDO> {
default void updateEnableStatus(Integer id, Integer enable, Date updateTime) {
this.update(null, new LambdaUpdateWrapper<PortPoolDO>()
.eq(PortPoolDO::getId, id)
.set(PortPoolDO::getEnable, enable)
.set(PortPoolDO::getUpdateTime, updateTime)
);
}
@ResultType(PortPoolListRes.class)
@Select("select * from port_pool")
void page(Page<PortPoolListRes> page, PortPoolListReq req);
default PortPoolDO findByPort(Integer port) {
return this.selectOne(new LambdaQueryWrapper<PortPoolDO>()
.eq(PortPoolDO::getPort, port)
);
}
@ResultType(PortPoolListRes.class)
@Select("select * from port_pool where enable = 1")
List<PortPoolListRes> list();
@Insert("insert into port_pool(`port`,`enable`,`create_time`,`update_time`) values(:port,:enable,:createTime,:updateTime)")
void add(PortPoolDO portPool);
@Update("update `port_pool` set enable = :enable, update_time = :updateTime where id = :id")
void updateEnableStatus(@Param("id") Integer id, @Param("enable") Integer enable, @Param("updateTime") Date updateTime);
@Delete("delete from `port_pool` where id = ?")
void delete(Integer id);
@Select("select * from port_pool where port = ? limit 0,1")
PortPoolDO findByPort(Integer port);
@Select("select * from port_pool where id = ?")
PortPoolDO findById(Integer id);
default PortPoolDO findById(Integer id) {
return this.selectById(id);
}
}
@@ -21,34 +21,23 @@
*/
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.aop.Intercept;
import fun.asgc.neutrino.core.db.annotation.Insert;
import fun.asgc.neutrino.core.db.annotation.ResultType;
import fun.asgc.neutrino.core.db.annotation.Select;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.proxy.server.controller.req.UserLoginRecordListReq;
import fun.asgc.neutrino.proxy.server.controller.res.UserLoginRecordListRes;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.UserLoginRecordDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Date;
/**
*
* @author: aoshiguchen
* @date: 2022/8/2
*/
@Intercept(ignoreGlobal = true)
@Component
public interface UserLoginRecordMapper extends SqlMapper {
/**
* 新增用户登录日志
* @param userLoginRecord
* @return
*/
@Insert("insert into `user_login_record`(`user_id`,`ip`,`token`,`type`,`create_time`) values(:userId,:ip,:token,:type,:createTime)")
int add(UserLoginRecordDO userLoginRecord);
@ResultType(UserLoginRecordListRes.class)
@Select("select * from user_login_record order by create_time desc")
void page(Page page, UserLoginRecordListReq req);
@Mapper
public interface UserLoginRecordMapper extends BaseMapper<UserLoginRecordDO> {
default void clean(Date date) {
this.delete(new LambdaQueryWrapper<UserLoginRecordDO>()
.lt(UserLoginRecordDO::getCreateTime, date)
);
}
}
@@ -1,35 +1,11 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Param;
import fun.asgc.neutrino.core.aop.Intercept;
import fun.asgc.neutrino.core.db.annotation.*;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.proxy.server.controller.req.UserListReq;
import fun.asgc.neutrino.proxy.server.controller.res.UserListRes;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import java.util.Date;
import java.util.List;
@@ -40,49 +16,49 @@ import java.util.Set;
* @author: aoshiguchen
* @date: 2022/8/1
*/
@Intercept(ignoreGlobal = true)
@Component
public interface UserMapper extends SqlMapper {
@Mapper
public interface UserMapper extends BaseMapper<UserDO> {
/**
* 根据登录名查询用户记录
* @param loginName
* @return
*/
@Select("select * from user where login_name = ?")
UserDO findByLoginName(String loginName);
default UserDO findByLoginName(String loginName) {
return selectOne(new LambdaQueryWrapper<UserDO>()
.eq(UserDO::getLoginName, loginName)
.last("limit 1")
);
}
/**
* 根据id查询单条记录
* @param id
* @return
*/
@Select("select * from user where id = ?")
UserDO findById(Integer id);
default UserDO findById(Integer id) {
return selectById(id);
}
@ResultType(UserDO.class)
@Select("select * from user where id in (:ids)")
List<UserDO> findByIds(@Param("ids") Set<Integer> ids);
default List<UserDO> findByIds(Set<Integer> ids) {
return selectBatchIds(ids);
}
@ResultType(UserListRes.class)
@Select("select * from user")
void page(Page page, UserListReq req);
default void updateEnableStatus(Integer id, Integer enable, Date updateTime) {
this.update(null, new LambdaUpdateWrapper<UserDO>()
.eq(UserDO::getId, id)
.set(UserDO::getEnable, enable)
.set(UserDO::getUpdateTime, updateTime)
);
}
@ResultType(UserListRes.class)
@Select("select * from user where enable = 1")
List<UserListRes> list();
@Update("update `user` set enable = :enable,update_time = :updateTime where id = :id")
void updateEnableStatus(@Param("id") Integer id, @Param("enable") Integer enable, @Param("updateTime")Date updateTime);
@Delete("delete from `user` where id = ?")
void delete(Integer id);
@Update("update `user` set name = :name,login_name = :loginName,update_time = :updateTime where id = :id")
void update(UserDO userDO);
@Update("update `user` set login_password = :loginPassword,update_time = :updateTime where id = :id")
void updateLoginPassword(@Param("id") Integer id, @Param("loginPassword") String loginPassword, @Param("updateTime")Date updateTime);
default void updateLoginPassword(Integer id, String loginPassword, Date updateTime) {
this.update(null, new LambdaUpdateWrapper<UserDO>()
.eq(UserDO::getId, id)
.set(UserDO::getLoginPassword, loginPassword)
.set(UserDO::getUpdateTime, updateTime)
);
}
@Insert("insert into user(`name`,`login_name`,`login_password`,`enable`,`create_time`,`update_time`) values(:name,:loginName,:loginPassword,:enable,:createTime,:updateTime)")
void add(UserDO user);
@@ -1,22 +0,0 @@
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Param;
import fun.asgc.neutrino.core.aop.Intercept;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.proxy.server.controller.res.UserFlowReportRes;
import java.util.Date;
/**
* @author: aoshiguchen
* @date: 2023/1/18
*/
@Intercept(ignoreGlobal = true)
@Component
public interface UserReportMapper extends SqlMapper {
void userFlowReportPage(Page<UserFlowReportRes> page, @Param("todayBegin") Date todayBegin, @Param("todayEnd") Date todayEnd);
}
@@ -21,13 +21,11 @@
*/
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Param;
import fun.asgc.neutrino.core.aop.Intercept;
import fun.asgc.neutrino.core.db.annotation.Delete;
import fun.asgc.neutrino.core.db.annotation.Update;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.UserTokenDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Date;
@@ -36,17 +34,8 @@ import java.util.Date;
* @author: aoshiguchen
* @date: 2022/8/1
*/
@Intercept(ignoreGlobal = true)
@Component
public interface UserTokenMapper extends SqlMapper {
/**
* 新增用户token
* 支持注解 + xml配置2种方式
* @param userToken
* @return
*/
// @Insert("insert into `user_token`(`token`,`user_id`,`expiration_time`,`create_time`,`update_time`) values (:token,:userId,:expirationTime,:createTime,:updateTime)")
int add(UserTokenDO userToken);
@Mapper
public interface UserTokenMapper extends BaseMapper<UserTokenDO> {
/**
* 根据token查询单条记录
@@ -55,23 +44,37 @@ public interface UserTokenMapper extends SqlMapper {
* @param time
* @return
*/
// @Select("select * from user_token where token = ? and expiration_time > ?")
UserTokenDO findByAvailableToken(String token, Date date);
default UserTokenDO findByAvailableToken(String token, Date date) {
return selectOne(new LambdaQueryWrapper<UserTokenDO>()
.eq(UserTokenDO::getToken, token)
.gt(UserTokenDO::getExpirationTime, date)
);
}
/**
* 根据token删除记录
* @param token
*/
@Delete("delete from user_token where token = ?")
void deleteByToken(String token);
default void deleteByToken(String token) {
this.delete(new LambdaQueryWrapper<UserTokenDO>()
.eq(UserTokenDO::getToken, token)
);
}
@Update("update user_token set expiration_time = :expirationTime where token = :token")
void updateTokenExpirationTime(@Param("token") String token, @Param("expirationTime") Date expirationTime);
default void updateTokenExpirationTime(String token, Date expirationTime) {
this.update(null, new LambdaUpdateWrapper<UserTokenDO>()
.eq(UserTokenDO::getToken, token)
.set(UserTokenDO::getExpirationTime, expirationTime)
);
}
/**
* 根据userId删除token
* @param userId
*/
@Delete("delete from user_token where user_id = ?")
void deleteByUserId(Integer userId);
default void deleteByUserId(Integer userId) {
this.delete(new LambdaQueryWrapper<UserTokenDO>()
.eq(UserTokenDO::getUserId, userId)
);
}
}
@@ -1,7 +1,8 @@
package fun.asgc.neutrino.proxy.server.dal.entity;
import fun.asgc.neutrino.core.db.annotation.Id;
import fun.asgc.neutrino.core.db.annotation.Table;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
@@ -15,9 +16,9 @@ import java.util.Date;
@ToString
@Accessors(chain = true)
@Data
@Table("client_connect_record")
@TableName("client_connect_record")
public class ClientConnectRecordDO {
@Id
@TableId(type = IdType.AUTO)
private Integer id;
private String ip;
private Integer licenseId;
@@ -21,8 +21,9 @@
*/
package fun.asgc.neutrino.proxy.server.dal.entity;
import fun.asgc.neutrino.core.db.annotation.Id;
import fun.asgc.neutrino.core.db.annotation.Table;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
@@ -36,9 +37,9 @@ import java.util.Date;
@ToString
@Accessors(chain = true)
@Data
@Table("flow_report_day")
@TableName("flow_report_day")
public class FlowReportDayDO {
@Id
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 用户ID
@@ -21,8 +21,9 @@
*/
package fun.asgc.neutrino.proxy.server.dal.entity;
import fun.asgc.neutrino.core.db.annotation.Id;
import fun.asgc.neutrino.core.db.annotation.Table;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
@@ -36,9 +37,9 @@ import java.util.Date;
@ToString
@Accessors(chain = true)
@Data
@Table("flow_report_hour")
@TableName("flow_report_hour")
public class FlowReportHourDO {
@Id
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 用户ID
@@ -21,8 +21,9 @@
*/
package fun.asgc.neutrino.proxy.server.dal.entity;
import fun.asgc.neutrino.core.db.annotation.Id;
import fun.asgc.neutrino.core.db.annotation.Table;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
@@ -36,9 +37,9 @@ import java.util.Date;
@ToString
@Accessors(chain = true)
@Data
@Table("flow_report_minute")
@TableName("flow_report_minute")
public class FlowReportMinuteDO {
@Id
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 用户ID
@@ -21,8 +21,9 @@
*/
package fun.asgc.neutrino.proxy.server.dal.entity;
import fun.asgc.neutrino.core.db.annotation.Id;
import fun.asgc.neutrino.core.db.annotation.Table;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
@@ -36,9 +37,9 @@ import java.util.Date;
@ToString
@Accessors(chain = true)
@Data
@Table("flow_report_month")
@TableName("flow_report_month")
public class FlowReportMonthDO {
@Id
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 用户ID
@@ -21,8 +21,10 @@
*/
package fun.asgc.neutrino.proxy.server.dal.entity;
import fun.asgc.neutrino.core.db.annotation.Id;
import fun.asgc.neutrino.core.db.annotation.Table;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
@@ -37,11 +39,12 @@ import java.util.Date;
@ToString
@Accessors(chain = true)
@Data
@Table("job_info")
@TableName("job_info")
public class JobInfoDO {
@Id
@TableId(type = IdType.AUTO)
private Integer id;
private String cron;
@TableField("`desc`")
private String desc;
private String alarmEmail;
private String alarmDing;
@@ -21,8 +21,9 @@
*/
package fun.asgc.neutrino.proxy.server.dal.entity;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.db.annotation.Table;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
@@ -37,9 +38,9 @@ import java.util.Date;
@ToString
@Accessors(chain = true)
@Data
@Table("job_log")
@TableName("job_log")
public class JobLogDO {
@Autowired
@TableId(type = IdType.AUTO)
private Integer id;
private Integer jobId;
private String handler;
@@ -21,8 +21,10 @@
*/
package fun.asgc.neutrino.proxy.server.dal.entity;
import fun.asgc.neutrino.core.db.annotation.Id;
import fun.asgc.neutrino.core.db.annotation.Table;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import fun.asgc.neutrino.proxy.server.constant.OnlineStatusEnum;
import lombok.Data;
import lombok.ToString;
@@ -38,9 +40,9 @@ import java.util.Date;
@ToString
@Accessors(chain = true)
@Data
@Table("license")
@TableName("license")
public class LicenseDO {
@Id
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 名称
@@ -49,6 +51,7 @@ public class LicenseDO {
/**
* licenseKey
*/
@TableField("`key`")
private String key;
/**
* 用户ID
@@ -21,8 +21,9 @@
*/
package fun.asgc.neutrino.proxy.server.dal.entity;
import fun.asgc.neutrino.core.db.annotation.Id;
import fun.asgc.neutrino.core.db.annotation.Table;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import fun.asgc.neutrino.proxy.server.constant.OnlineStatusEnum;
import lombok.Data;
import lombok.ToString;
@@ -38,9 +39,9 @@ import java.util.Date;
@ToString
@Accessors(chain = true)
@Data
@Table("port_mapping")
@TableName("port_mapping")
public class PortMappingDO {
@Id
@TableId(type = IdType.AUTO)
private Integer id;
/**
* licenseId
@@ -21,8 +21,9 @@
*/
package fun.asgc.neutrino.proxy.server.dal.entity;
import fun.asgc.neutrino.core.db.annotation.Id;
import fun.asgc.neutrino.core.db.annotation.Table;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
@@ -37,9 +38,9 @@ import java.util.Date;
@ToString
@Accessors(chain = true)
@Data
@Table("port_pool")
@TableName("port_pool")
public class PortPoolDO {
@Id
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 端口
@@ -21,8 +21,9 @@
*/
package fun.asgc.neutrino.proxy.server.dal.entity;
import fun.asgc.neutrino.core.db.annotation.Id;
import fun.asgc.neutrino.core.db.annotation.Table;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.ToString;
@@ -35,9 +36,9 @@ import java.util.Date;
*/
@ToString
@Data
@Table("user")
@TableName("user")
public class UserDO {
@Id
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 用户名
@@ -12,8 +12,9 @@
*/
package fun.asgc.neutrino.proxy.server.dal.entity;
import fun.asgc.neutrino.core.db.annotation.Id;
import fun.asgc.neutrino.core.db.annotation.Table;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
@@ -28,7 +29,7 @@ import java.util.Date;
@ToString
@Data
@Accessors(chain = true)
@Table("user_login_record")
@TableName("user_login_record")
public class UserLoginRecordDO {
/**
* 类型 - 登录
@@ -39,7 +40,7 @@ public class UserLoginRecordDO {
*/
public static final Integer TYPE_LOGOUT = 2;
@Id
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 用户ID
@@ -21,8 +21,9 @@
*/
package fun.asgc.neutrino.proxy.server.dal.entity;
import fun.asgc.neutrino.core.db.annotation.Id;
import fun.asgc.neutrino.core.db.annotation.Table;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
@@ -37,10 +38,10 @@ import java.util.Date;
@ToString
@Accessors(chain = true)
@Data
@Table("user_token")
@TableName("user_token")
public class UserTokenDO {
@Id
@TableId(type = IdType.AUTO)
private Integer id;
/**
* token
@@ -1,38 +1,16 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.job;
import com.alibaba.fastjson.JSONObject;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.quartz.IJobHandler;
import fun.asgc.neutrino.core.quartz.annotation.JobHandler;
import fun.asgc.neutrino.core.util.DateUtil;
import fun.asgc.neutrino.proxy.server.dal.DataCleanMapper;
import fun.asgc.neutrino.proxy.core.util.DateUtil;
import fun.asgc.neutrino.proxy.server.dal.*;
import fun.asgc.solon.extend.job.IJobHandler;
import fun.asgc.solon.extend.job.annotation.JobHandler;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import java.text.SimpleDateFormat;
import java.util.Calendar;
@@ -44,13 +22,9 @@ import java.util.Date;
* @date: 2022/9/17
*/
@Slf4j
@NonIntercept
@Component
@JobHandler(name = "DataCleanJob", cron = "0 0 1 * * ?")
public class DataCleanJob implements IJobHandler {
@Autowired
private DataCleanMapper dataCleanMapper;
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/**
* Job日志保存天数
*/
@@ -76,6 +50,19 @@ public class DataCleanJob implements IJobHandler {
* 流量统计天报表记录保留天数
*/
private static final Integer FLOW_DAY_REPORT_KEEP_DAYS = 400;
@Inject
private JobLogMapper jobLogMapper;
@Inject
private UserLoginRecordMapper userLoginRecordMapper;
@Inject
private ClientConnectRecordMapper clientConnectRecordMapper;
@Inject
private FlowReportMinuteMapper flowReportMinuteMapper;
@Inject
private FlowReportHourMapper flowReportHourMapper;
@Inject
private FlowReportDayMapper flowReportDayMapper;
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public void execute(String s) throws Exception {
@@ -84,37 +71,37 @@ public class DataCleanJob implements IJobHandler {
{
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getJobLogKeepDays());
log.info("清理调度管理日志 date:{}", sdf.format(date));
dataCleanMapper.cleanJobLog(date);
jobLogMapper.clean(date);
}
{
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getUserLoginRecordKeepDays());
log.info("清理用户登录日志 date:{}", sdf.format(date));
dataCleanMapper.cleanUserLoginRecord(date);
userLoginRecordMapper.clean(date);
}
{
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getClientConnectRecordKeepDays());
log.info("清理客户端连接日志 date:{}", sdf.format(date));
dataCleanMapper.cleanClientConnectRecord(date);
clientConnectRecordMapper.clean(date);
}
{
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getFlowMinuteReportKeepDays());
log.info("清理流通统计分钟报表日志 date:{}", sdf.format(date));
dataCleanMapper.cleanFlowMinuteReport(date);
flowReportMinuteMapper.clean(date);
}
{
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getFlowHourReportKeepDays());
log.info("清理流通统计小时报表日志 date:{}", sdf.format(date));
dataCleanMapper.cleanFlowHourReport(date);
flowReportHourMapper.clean(date);
}
{
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getFlowDayReportKeepDays());
log.info("清理流通统计日报表日志 date:{}", sdf.format(date));
dataCleanMapper.cleanFlowDayReport(date);
flowReportDayMapper.clean(date);
}
}
@@ -1,31 +1,9 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.job;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.quartz.IJobHandler;
import fun.asgc.neutrino.core.quartz.annotation.JobHandler;
import fun.asgc.solon.extend.job.IJobHandler;
import fun.asgc.solon.extend.job.annotation.JobHandler;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Component;
/**
*
@@ -33,7 +11,6 @@ import lombok.extern.slf4j.Slf4j;
* @date: 2022/9/4
*/
@Slf4j
@NonIntercept
@Component
@JobHandler(name = "DemoJob", cron = "0/10 * * * * ?", param = "{\"a\":1}")
public class DemoJob implements IJobHandler {
@@ -21,13 +21,8 @@
*/
package fun.asgc.neutrino.proxy.server.job;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.quartz.IJobHandler;
import fun.asgc.neutrino.core.quartz.annotation.JobHandler;
import fun.asgc.neutrino.core.util.CollectionUtil;
import fun.asgc.neutrino.core.util.DateUtil;
import cn.hutool.core.collection.CollectionUtil;
import fun.asgc.neutrino.proxy.core.util.DateUtil;
import fun.asgc.neutrino.proxy.server.dal.FlowReportDayMapper;
import fun.asgc.neutrino.proxy.server.dal.FlowReportHourMapper;
import fun.asgc.neutrino.proxy.server.dal.FlowReportMinuteMapper;
@@ -35,7 +30,11 @@ import fun.asgc.neutrino.proxy.server.dal.LicenseMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportDayDO;
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportHourDO;
import fun.asgc.neutrino.proxy.server.service.FlowReportService;
import fun.asgc.solon.extend.job.IJobHandler;
import fun.asgc.solon.extend.job.annotation.JobHandler;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import java.util.*;
@@ -44,19 +43,18 @@ import java.util.*;
* @date: 2022/10/28
*/
@Slf4j
@NonIntercept
@Component
@JobHandler(name = "FlowReportForDayJob", cron = "0 0 1 * * ?", param = "")
public class FlowReportForDayJob implements IJobHandler {
@Autowired
@Inject
private FlowReportService flowReportService;
@Autowired
@Inject
private LicenseMapper licenseMapper;
@Autowired
@Inject
private FlowReportMinuteMapper flowReportMinuteMapper;
@Autowired
@Inject
private FlowReportHourMapper flowReportHourMapper;
@Autowired
@Inject
private FlowReportDayMapper flowReportDayMapper;
@Override
@@ -97,7 +95,7 @@ public class FlowReportForDayJob implements IJobHandler {
}
for (FlowReportDayDO item : map.values()) {
flowReportDayMapper.add(item);
flowReportDayMapper.insert(item);
}
}
@@ -1,40 +1,18 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.job;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.quartz.IJobHandler;
import fun.asgc.neutrino.core.quartz.annotation.JobHandler;
import fun.asgc.neutrino.core.util.CollectionUtil;
import fun.asgc.neutrino.core.util.DateUtil;
import cn.hutool.core.collection.CollectionUtil;
import fun.asgc.neutrino.proxy.core.util.DateUtil;
import fun.asgc.neutrino.proxy.server.dal.FlowReportHourMapper;
import fun.asgc.neutrino.proxy.server.dal.FlowReportMinuteMapper;
import fun.asgc.neutrino.proxy.server.dal.LicenseMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportHourDO;
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportMinuteDO;
import fun.asgc.neutrino.proxy.server.service.FlowReportService;
import fun.asgc.solon.extend.job.IJobHandler;
import fun.asgc.solon.extend.job.annotation.JobHandler;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import java.util.*;
@@ -43,17 +21,16 @@ import java.util.*;
* @date: 2022/10/28
*/
@Slf4j
@NonIntercept
@Component
@JobHandler(name = "FlowReportForHourJob", cron = "0 0 */1 * * ?", param = "")
public class FlowReportForHourJob implements IJobHandler {
@Autowired
@Inject
private FlowReportService flowReportService;
@Autowired
@Inject
private LicenseMapper licenseMapper;
@Autowired
@Inject
private FlowReportMinuteMapper flowReportMinuteMapper;
@Autowired
@Inject
private FlowReportHourMapper flowReportHourMapper;
@Override
@@ -94,7 +71,7 @@ public class FlowReportForHourJob implements IJobHandler {
}
for (FlowReportHourDO item : map.values()) {
flowReportHourMapper.add(item);
flowReportHourMapper.insert(item);
}
}
@@ -1,39 +1,17 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.job;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.quartz.IJobHandler;
import fun.asgc.neutrino.core.quartz.annotation.JobHandler;
import fun.asgc.neutrino.core.util.CollectionUtil;
import fun.asgc.neutrino.core.util.DateUtil;
import cn.hutool.core.collection.CollectionUtil;
import fun.asgc.neutrino.proxy.core.util.DateUtil;
import fun.asgc.neutrino.proxy.server.dal.FlowReportMinuteMapper;
import fun.asgc.neutrino.proxy.server.dal.LicenseMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportMinuteDO;
import fun.asgc.neutrino.proxy.server.dal.entity.LicenseDO;
import fun.asgc.neutrino.proxy.server.service.FlowReportService;
import fun.asgc.solon.extend.job.IJobHandler;
import fun.asgc.solon.extend.job.annotation.JobHandler;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import java.util.*;
import java.util.function.Function;
@@ -45,16 +23,15 @@ import java.util.stream.Collectors;
* @date: 2022/10/24
*/
@Slf4j
@NonIntercept
@Component
@JobHandler(name = "FlowReportForMinuteJob", cron = "0 */1 * * * ?", param = "")
public class FlowReportForMinuteJob implements IJobHandler {
@Autowired
@Inject
private FlowReportService flowReportService;
@Autowired
@Inject
private LicenseMapper licenseMapper;
@Autowired
@Inject
private FlowReportMinuteMapper flowReportMinuteMapper;
@Override
@@ -86,7 +63,7 @@ public class FlowReportForMinuteJob implements IJobHandler {
flowReportMinuteDO.setDate(date);
flowReportMinuteDO.setDateStr(dateStr);
flowReportMinuteDO.setCreateTime(now);
flowReportMinuteMapper.add(flowReportMinuteDO);
flowReportMinuteMapper.insert(flowReportMinuteDO);
}
}
}
@@ -1,38 +1,16 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.job;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.quartz.IJobHandler;
import fun.asgc.neutrino.core.quartz.annotation.JobHandler;
import fun.asgc.neutrino.core.util.CollectionUtil;
import fun.asgc.neutrino.core.util.DateUtil;
import cn.hutool.core.collection.CollectionUtil;
import fun.asgc.neutrino.proxy.core.util.DateUtil;
import fun.asgc.neutrino.proxy.server.dal.*;
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportDayDO;
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportMonthDO;
import fun.asgc.neutrino.proxy.server.service.FlowReportService;
import fun.asgc.solon.extend.job.IJobHandler;
import fun.asgc.solon.extend.job.annotation.JobHandler;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import java.util.*;
@@ -41,21 +19,20 @@ import java.util.*;
* @date: 2022/10/28
*/
@Slf4j
@NonIntercept
@Component
@JobHandler(name = "FlowReportForMonthJob", cron = "0 10 0 1 * ?", param = "")
public class FlowReportForMonthJob implements IJobHandler {
@Autowired
@Inject
private FlowReportService flowReportService;
@Autowired
@Inject
private LicenseMapper licenseMapper;
@Autowired
@Inject
private FlowReportMinuteMapper flowReportMinuteMapper;
@Autowired
@Inject
private FlowReportHourMapper flowReportHourMapper;
@Autowired
@Inject
private FlowReportDayMapper flowReportDayMapper;
@Autowired
@Inject
private FlowReportMonthMapper flowReportMonthMapper;
@Override
@@ -96,7 +73,7 @@ public class FlowReportForMonthJob implements IJobHandler {
}
for (FlowReportMonthDO item : map.values()) {
flowReportMonthMapper.add(item);
flowReportMonthMapper.insert(item);
}
}
@@ -1,36 +1,8 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.proxy.core;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Bean;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.context.ApplicationRunner;
import fun.asgc.neutrino.core.context.Environment;
import fun.asgc.neutrino.core.util.FileUtil;
import fun.asgc.neutrino.proxy.core.ProxyMessageDecoder;
import fun.asgc.neutrino.proxy.core.ProxyMessageEncoder;
import fun.asgc.neutrino.proxy.core.util.FileUtil;
import fun.asgc.neutrino.proxy.server.base.proxy.ProxyConfig;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelHandler;
@@ -41,8 +13,15 @@ import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.event.AppLoadEndEvent;
import org.noear.solon.core.event.EventListener;
import javax.net.ssl.*;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManager;
import java.io.InputStream;
import java.security.KeyStore;
@@ -52,24 +31,29 @@ import java.security.KeyStore;
* @date: 2022/6/16
*/
@Slf4j
@NonIntercept
@Component
public class ProxyServerRunner implements ApplicationRunner {
@Autowired
public class ProxyServerRunner implements EventListener<AppLoadEndEvent> {
@Inject
private ProxyConfig proxyConfig;
@Autowired("serverBossGroup")
@Inject("serverBossGroup")
private NioEventLoopGroup serverBossGroup;
@Autowired("serverWorkerGroup")
@Inject("serverWorkerGroup")
private NioEventLoopGroup serverWorkerGroup;
@Autowired
private Environment environment;
@Inject("${neutrino.proxy.server.port}")
private Integer port;
@Inject("${neutrino.proxy.server.ssl-port}")
private Integer sslPort;
@Inject("${neutrino.proxy.server.jks-path}")
private String jksPath;
@Inject("${neutrino.proxy.server.key-store-password}")
private String keyStorePassword;
@Inject("${neutrino.proxy.server.key-manager-password}")
private String keyManagerPassword;
@Override
public void run(String[] args) {
public void onEvent(AppLoadEndEvent appLoadEndEvent) throws Throwable {
startProxyServer();
startProxyServerForSSL();
}
/**
* 启动代理服务
*/
@@ -83,7 +67,6 @@ public class ProxyServerRunner implements ApplicationRunner {
}
});
try {
Integer port = environment.getMainArgsForInteger("neutrino.proxy.server.port", proxyConfig.getServer().getPort());
bootstrap.bind(port).sync();
log.info("代理服务启动,端口:{}", port);
} catch (Exception e) {
@@ -92,7 +75,6 @@ public class ProxyServerRunner implements ApplicationRunner {
}
private void startProxyServerForSSL() {
Integer sslPort = environment.getMainArgsForInteger("neutrino.proxy.server.ssl-port", proxyConfig.getServer().getSslPort());
if (null == sslPort) {
return;
}
@@ -115,15 +97,12 @@ public class ProxyServerRunner implements ApplicationRunner {
private ChannelHandler createSslHandler() {
try {
String jksPath = environment.getMainArgsForString("neutrino.proxy.server.jks-path", proxyConfig.getServer().getJksPath());
InputStream jksInputStream = FileUtil.getInputStream(jksPath);
SSLContext serverContext = SSLContext.getInstance("TLS");
final KeyStore ks = KeyStore.getInstance("JKS");
String keyStorePassword = environment.getMainArgsForString("neutrino.proxy.server.key-store-password", proxyConfig.getServer().getKeyStorePassword());
ks.load(jksInputStream, keyStorePassword.toCharArray());
final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
String keyManagerPassword = environment.getMainArgsForString("neutrino.proxy.server.key-manager-password", proxyConfig.getServer().getKeyManagerPassword());
kmf.init(ks, keyManagerPassword.toCharArray());
TrustManager[] trustManagers = null;
@@ -149,14 +128,4 @@ public class ProxyServerRunner implements ApplicationRunner {
ch.pipeline().addLast(new IdleStateHandler(proxyConfig.getProtocol().getReadIdleTime(), proxyConfig.getProtocol().getWriteIdleTime(), proxyConfig.getProtocol().getAllIdleTimeSeconds()));
ch.pipeline().addLast(new ServerChannelHandler());
}
@Bean
public NioEventLoopGroup serverBossGroup() {
return new NioEventLoopGroup();
}
@Bean
public NioEventLoopGroup serverWorkerGroup() {
return new NioEventLoopGroup();
}
}
@@ -22,11 +22,9 @@
package fun.asgc.neutrino.proxy.server.proxy.core;
import fun.asgc.neutrino.core.base.Dispatcher;
import fun.asgc.neutrino.core.util.BeanManager;
import fun.asgc.neutrino.core.util.ChannelUtil;
import fun.asgc.neutrino.proxy.core.Constants;
import fun.asgc.neutrino.proxy.core.ProxyMessage;
import fun.asgc.neutrino.proxy.core.dispatcher.Dispatcher;
import fun.asgc.neutrino.proxy.server.constant.ClientConnectTypeEnum;
import fun.asgc.neutrino.proxy.server.constant.SuccessCodeEnum;
import fun.asgc.neutrino.proxy.server.dal.entity.ClientConnectRecordDO;
@@ -38,7 +36,9 @@ import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.Solon;
import java.net.InetSocketAddress;
import java.util.Date;
/**
@@ -51,7 +51,7 @@ public class ServerChannelHandler extends SimpleChannelInboundHandler<ProxyMessa
private static volatile Dispatcher<ChannelHandlerContext, ProxyMessage> dispatcher;
public ServerChannelHandler() {
dispatcher = BeanManager.getBean(Dispatcher.class);
dispatcher = Solon.context().getBean(Dispatcher.class);
}
@Override
@@ -87,9 +87,9 @@ public class ServerChannelHandler extends SimpleChannelInboundHandler<ProxyMessa
} else {
CmdChannelAttachInfo cmdChannelAttachInfo = ProxyUtil.getAttachInfo(ctx.channel());
if (null != cmdChannelAttachInfo) {
BeanManager.getBean(ProxyMutualService.class).offline(cmdChannelAttachInfo);
BeanManager.getBean(ClientConnectRecordService.class).add(new ClientConnectRecordDO()
.setIp(ChannelUtil.getIP(ctx.channel()))
Solon.context().getBean(ProxyMutualService.class).offline(cmdChannelAttachInfo);
Solon.context().getBean(ClientConnectRecordService.class).add(new ClientConnectRecordDO()
.setIp(((InetSocketAddress)ctx.channel().remoteAddress()).getAddress().getHostAddress())
.setLicenseId(cmdChannelAttachInfo.getLicenseId())
.setType(ClientConnectTypeEnum.DISCONNECT.getType())
.setMsg("")
@@ -1,29 +1,6 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.proxy.core;
import fun.asgc.neutrino.core.util.BeanManager;
import fun.asgc.neutrino.core.util.StringUtil;
import cn.hutool.core.util.StrUtil;
import fun.asgc.neutrino.proxy.core.Constants;
import fun.asgc.neutrino.proxy.core.ProxyMessage;
import fun.asgc.neutrino.proxy.server.proxy.domain.VisitorChannelAttachInfo;
@@ -34,6 +11,7 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.SimpleChannelInboundHandler;
import org.noear.solon.Solon;
import java.net.InetSocketAddress;
import java.util.concurrent.atomic.AtomicLong;
@@ -72,7 +50,7 @@ public class VisitorChannelHandler extends SimpleChannelInboundHandler<ByteBuf>
// 增加流量计数
VisitorChannelAttachInfo visitorChannelAttachInfo = ProxyUtil.getAttachInfo(visitorChannel);
BeanManager.getBean(FlowReportService.class).addWriteByte(visitorChannelAttachInfo.getLicenseId(), bytes.length);
Solon.context().getBean(FlowReportService.class).addWriteByte(visitorChannelAttachInfo.getLicenseId(), bytes.length);
}
}
@@ -88,7 +66,7 @@ public class VisitorChannelHandler extends SimpleChannelInboundHandler<ByteBuf>
} else {
String visitorId = newVisitorId();
String lanInfo = ProxyUtil.getClientLanInfoByServerPort(sa.getPort());
if (StringUtil.isEmpty(lanInfo)) {
if (StrUtil.isEmpty(lanInfo)) {
ctx.channel().close();
} else {
// 用户连接到代理服务器时设置用户连接不可读等待代理后端服务器连接成功后再改变为可读状态
@@ -1,27 +1,6 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.proxy.domain;
import fun.asgc.neutrino.core.util.CollectionUtil;
import cn.hutool.core.collection.CollectionUtil;
import fun.asgc.neutrino.proxy.server.dal.entity.PortMappingDO;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -22,13 +22,9 @@
package fun.asgc.neutrino.proxy.server.proxy.handler;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Match;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.util.ChannelUtil;
import fun.asgc.neutrino.core.util.StringUtil;
import cn.hutool.core.util.StrUtil;
import fun.asgc.neutrino.proxy.core.*;
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
import fun.asgc.neutrino.proxy.server.base.proxy.ProxyConfig;
import fun.asgc.neutrino.proxy.server.constant.ClientConnectTypeEnum;
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
@@ -43,7 +39,10 @@ import fun.asgc.neutrino.proxy.server.util.ProxyUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import java.net.InetSocketAddress;
import java.util.Date;
/**
@@ -52,36 +51,35 @@ import java.util.Date;
* @date: 2022/6/16
*/
@Slf4j
@NonIntercept
@Match(type = Constants.ProxyDataTypeName.AUTH)
@Component
public class ProxyMessageAuthHandler implements ProxyMessageHandler {
@Autowired
@Inject
private ProxyConfig proxyConfig;
@Autowired
@Inject
private LicenseService licenseService;
@Autowired
@Inject
private UserService userService;
@Autowired
@Inject
private PortMappingService portMappingService;
@Autowired
@Inject
private ProxyMutualService proxyMutualService;
@Autowired
@Inject
private FlowReportService flowReportService;
@Autowired
@Inject
private ClientConnectRecordService clientConnectRecordService;
@Autowired
@Inject
private LicenseMapper licenseMapper;
@Autowired
@Inject
private VisitorChannelService visitorChannelService;
@Override
public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
String ip = ChannelUtil.getIP(ctx.channel());
String ip = ((InetSocketAddress)ctx.channel().remoteAddress()).getAddress().getHostAddress();
Date now = new Date();
String licenseKey = proxyMessage.getInfo();
if (StringUtil.isEmpty(licenseKey)) {
if (StrUtil.isEmpty(licenseKey)) {
ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "license不能为空!", licenseKey));
clientConnectRecordService.add(new ClientConnectRecordDO()
.setIp(ip)
@@ -1,33 +1,8 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.proxy.handler;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Match;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.util.StringUtil;
import cn.hutool.core.util.StrUtil;
import fun.asgc.neutrino.proxy.core.*;
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
import fun.asgc.neutrino.proxy.server.dal.entity.LicenseDO;
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
@@ -37,26 +12,26 @@ import fun.asgc.neutrino.proxy.server.util.ProxyUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
/**
*
* @author: aoshiguchen
* @date: 2022/6/16
*/
@NonIntercept
@Match(type = Constants.ProxyDataTypeName.CONNECT)
@Component
public class ProxyMessageConnectHandler implements ProxyMessageHandler {
@Autowired
@Inject
private LicenseService licenseService;
@Autowired
@Inject
private UserService userService;
@Override
public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
String info = proxyMessage.getInfo();
if (StringUtil.isEmpty(info)) {
if (StrUtil.isEmpty(info)) {
ctx.channel().writeAndFlush(ProxyMessage.buildErrMessage(ExceptionEnum.CONNECT_FAILED, "info不能为空!"));
ctx.channel().close();
return;
@@ -1,46 +1,22 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.proxy.handler;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Match;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.proxy.core.Constants;
import fun.asgc.neutrino.proxy.core.ProxyDataTypeEnum;
import fun.asgc.neutrino.proxy.core.ProxyMessage;
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
import fun.asgc.neutrino.proxy.server.util.ProxyUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import org.noear.solon.annotation.Component;
/**
*
* @author: aoshiguchen
* @date: 2022/6/16
*/
@NonIntercept
@Match(type = Constants.ProxyDataTypeName.DISCONNECT)
@Component
public class ProxyMessageDisconnectHandler implements ProxyMessageHandler {
@@ -1,42 +1,18 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.proxy.handler;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Match;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.proxy.core.Constants;
import fun.asgc.neutrino.proxy.core.ProxyDataTypeEnum;
import fun.asgc.neutrino.proxy.core.ProxyMessage;
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
import io.netty.channel.ChannelHandlerContext;
import org.noear.solon.annotation.Component;
/**
*
* @author: aoshiguchen
* @date: 2022/6/16
*/
@NonIntercept
@Match(type = Constants.ProxyDataTypeName.HEARTBEAT)
@Component
public class ProxyMessageHeartbeatHandler implements ProxyMessageHandler {
@@ -1,48 +1,24 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.proxy.handler;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Match;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.util.BeanManager;
import fun.asgc.neutrino.proxy.core.Constants;
import fun.asgc.neutrino.proxy.core.ProxyDataTypeEnum;
import fun.asgc.neutrino.proxy.core.ProxyMessage;
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
import fun.asgc.neutrino.proxy.server.proxy.domain.VisitorChannelAttachInfo;
import fun.asgc.neutrino.proxy.server.service.FlowReportService;
import fun.asgc.neutrino.proxy.server.util.ProxyUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import org.noear.solon.Solon;
import org.noear.solon.annotation.Component;
/**
*
* @author: aoshiguchen
* @date: 2022/6/16
*/
@NonIntercept
@Match(type = Constants.ProxyDataTypeName.TRANSFER)
@Component
public class ProxyMessageTransferHandler implements ProxyMessageHandler {
@@ -57,7 +33,7 @@ public class ProxyMessageTransferHandler implements ProxyMessageHandler {
// 增加流量计数
VisitorChannelAttachInfo visitorChannelAttachInfo = ProxyUtil.getAttachInfo(visitorChannel);
BeanManager.getBean(FlowReportService.class).addReadByte(visitorChannelAttachInfo.getLicenseId(), proxyMessage.getData().length);
Solon.context().getBean(FlowReportService.class).addReadByte(visitorChannelAttachInfo.getLicenseId(), proxyMessage.getData().length);
}
}
@@ -1,32 +1,12 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.service;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import fun.asgc.neutrino.core.util.CollectionUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.base.rest.SystemContextHolder;
import fun.asgc.neutrino.proxy.server.controller.req.ClientConnectRecordListReq;
import fun.asgc.neutrino.proxy.server.controller.res.ClientConnectRecordListRes;
@@ -37,6 +17,10 @@ import fun.asgc.neutrino.proxy.server.dal.entity.ClientConnectRecordDO;
import fun.asgc.neutrino.proxy.server.dal.entity.LicenseDO;
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFacade;
import org.apache.ibatis.solon.annotation.Db;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import java.util.List;
import java.util.Map;
@@ -49,40 +33,41 @@ import java.util.stream.Collectors;
* @date: 2022/11/23
*/
@Slf4j
@NonIntercept
@Component
public class ClientConnectRecordService {
@Autowired
@Inject
private MapperFacade mapperFacade;
@Db
private ClientConnectRecordMapper clientConnectRecordMapper;
@Autowired
@Db
private LicenseMapper licenseMapper;
@Autowired
@Db
private UserMapper userMapper;
public void add(ClientConnectRecordDO clientConnectRecordDO) {
clientConnectRecordMapper.add(clientConnectRecordDO);
clientConnectRecordMapper.insert(clientConnectRecordDO);
}
public Page<ClientConnectRecordListRes> page(PageQuery pageQuery, ClientConnectRecordListReq req) {
Page<ClientConnectRecordListRes> page = Page.create(pageQuery);
clientConnectRecordMapper.page(page, req);
if (CollectionUtil.isEmpty(page.getRecords())) {
return page;
}
Set<Integer> licenseIds = page.getRecords().stream().map(ClientConnectRecordListRes::getLicenseId).collect(Collectors.toSet());
if (CollectionUtil.isEmpty(licenseIds)) {
return page;
public PageInfo<ClientConnectRecordListRes> page(PageQuery pageQuery, ClientConnectRecordListReq req) {
Page<ClientConnectRecordListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
List<ClientConnectRecordDO> list = clientConnectRecordMapper.selectList(new LambdaQueryWrapper<ClientConnectRecordDO>()
.orderByDesc(ClientConnectRecordDO::getId)
);
List<ClientConnectRecordListRes> respList = mapperFacade.mapAsList(list, ClientConnectRecordListRes.class);
if (CollectionUtils.isEmpty(list)) {
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
Set<Integer> licenseIds = respList.stream().map(ClientConnectRecordListRes::getLicenseId).collect(Collectors.toSet());
List<LicenseDO> licenseList = licenseMapper.findByIds(licenseIds);
if (CollectionUtil.isEmpty(licenseList)) {
return page;
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
Set<Integer> userIds = licenseList.stream().map(LicenseDO::getUserId).collect(Collectors.toSet());
List<UserDO> userList = userMapper.findByIds(userIds);
Map<Integer, LicenseDO> licenseMap = licenseList.stream().collect(Collectors.toMap(LicenseDO::getId, Function.identity()));
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
boolean isAdmin = SystemContextHolder.isAdmin();
page.getRecords().forEach(item -> {
respList.forEach(item -> {
LicenseDO license = licenseMap.get(item.getLicenseId());
if (null == license) {
return;
@@ -99,6 +84,6 @@ public class ClientConnectRecordService {
item.setMsg("******");
}
});
return page;
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
}
@@ -21,10 +21,9 @@
*/
package fun.asgc.neutrino.proxy.server.service;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.util.LockUtil;
import fun.asgc.neutrino.proxy.core.util.LockUtil;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Component;
import java.util.HashMap;
import java.util.Map;
@@ -36,7 +35,6 @@ import java.util.concurrent.atomic.AtomicInteger;
* @date: 2022/10/26
*/
@Slf4j
@NonIntercept
@Component
public class FlowReportService {
private Map<Integer/*licenseId*/, AtomicInteger/*writeByte*/> writeByteMap = new HashMap<>();
@@ -1,45 +1,34 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.service;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import fun.asgc.neutrino.core.quartz.IJobSource;
import fun.asgc.neutrino.core.quartz.JobExecutor;
import fun.asgc.neutrino.core.quartz.JobInfo;
import fun.asgc.neutrino.core.util.BeanManager;
import fun.asgc.neutrino.core.util.CollectionUtil;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
import fun.asgc.neutrino.proxy.server.controller.req.*;
import fun.asgc.neutrino.proxy.server.controller.res.*;
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoExecuteReq;
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoListReq;
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoUpdateEnableStatusReq;
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoUpdateReq;
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoExecuteRes;
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoListRes;
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoUpdateEnableStatusRes;
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoUpdateRes;
import fun.asgc.neutrino.proxy.server.dal.JobInfoMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.JobInfoDO;
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
import fun.asgc.solon.extend.job.IJobSource;
import fun.asgc.solon.extend.job.JobInfo;
import fun.asgc.solon.extend.job.impl.JobExecutor;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFacade;
import org.apache.ibatis.solon.annotation.Db;
import org.noear.solon.Solon;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import java.util.Date;
import java.util.List;
@@ -50,17 +39,20 @@ import java.util.List;
* @date: 2022/9/5
*/
@Slf4j
@NonIntercept
@Component
public class JobInfoService implements IJobSource {
@Autowired
@Inject
private MapperFacade mapperFacade;
@Db
private JobInfoMapper jobInfoMapper;
public Page<JobInfoListRes> page(PageQuery pageQuery, JobInfoListReq req) {
Page<JobInfoListRes> page = Page.create(pageQuery);
jobInfoMapper.page(page, req);
return page;
public PageInfo<JobInfoListRes> page(PageQuery pageQuery, JobInfoListReq req) {
Page<JobInfoListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
List<JobInfoDO> list = jobInfoMapper.selectList(new LambdaQueryWrapper<JobInfoDO>()
.orderByAsc(JobInfoDO::getId)
);
List<JobInfoListRes> respList = mapperFacade.mapAsList(list, JobInfoListRes.class);
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
public List<JobInfoDO> findList() {
@@ -73,7 +65,7 @@ public class JobInfoService implements IJobSource {
ParamCheckUtil.checkNotNull(jobInfoDO, ExceptionConstant.JOB_INFO_NOT_EXIST);
jobInfoMapper.updateEnableStatus(req.getId(), req.getEnable(), new Date());
if (EnableStatusEnum.ENABLE.getStatus().equals(req.getEnable())) {
BeanManager.getBean(JobExecutor.class).add(new JobInfo()
Solon.context().getBean(JobExecutor.class).add(new JobInfo()
.setId(String.valueOf(jobInfoDO.getId()))
.setName(jobInfoDO.getHandler())
.setDesc(jobInfoDO.getDesc())
@@ -82,13 +74,13 @@ public class JobInfoService implements IJobSource {
.setEnable(true)
);
} else {
BeanManager.getBean(JobExecutor.class).remove(String.valueOf(req.getId()));
Solon.context().getBean(JobExecutor.class).remove(String.valueOf(req.getId()));
}
return new JobInfoUpdateEnableStatusRes();
}
public JobInfoExecuteRes execute(JobInfoExecuteReq req) {
BeanManager.getBean(JobExecutor.class).trigger(String.valueOf(req.getId()), req.getParam());
Solon.context().getBean(JobExecutor.class).trigger(String.valueOf(req.getId()), req.getParam());
return new JobInfoExecuteRes();
}
@@ -125,7 +117,7 @@ public class JobInfoService implements IJobSource {
jobInfo.setParam(req.getParam());
jobInfo.setUpdateTime(new Date());
jobInfoMapper.update( jobInfo);
jobInfoMapper.updateById(jobInfo);
return new JobInfoUpdateRes();
}
}
@@ -21,23 +21,26 @@
*/
package fun.asgc.neutrino.proxy.server.service;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import fun.asgc.neutrino.core.quartz.IJobCallback;
import fun.asgc.neutrino.core.quartz.JobInfo;
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoListReq;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.controller.req.JobLogListReq;
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoListRes;
import fun.asgc.neutrino.proxy.server.controller.res.JobLogListRes;
import fun.asgc.neutrino.proxy.server.dal.JobLogMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.JobLogDO;
import fun.asgc.solon.extend.job.IJobCallback;
import fun.asgc.solon.extend.job.JobInfo;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFacade;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.ibatis.solon.annotation.Db;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import java.util.Date;
import java.util.List;
/**
*
@@ -45,10 +48,11 @@ import java.util.Date;
* @date: 2022/9/4
*/
@Slf4j
@NonIntercept
@Component
public class JobLogService implements IJobCallback {
@Autowired
@Inject
private MapperFacade mapperFacade;
@Db
private JobLogMapper jobLogMapper;
@Override
@@ -63,7 +67,7 @@ public class JobLogService implements IJobCallback {
msg = "执行异常:\r\n" + ExceptionUtils.getStackTrace(throwable);
code = -1;
}
jobLogMapper.add(new JobLogDO()
jobLogMapper.insert(new JobLogDO()
.setJobId(Integer.valueOf(jobInfo.getId()))
.setHandler(jobInfo.getName())
.setParam(param)
@@ -74,15 +78,14 @@ public class JobLogService implements IJobCallback {
);
}
public Page<JobLogListRes> page(PageQuery pageQuery, JobLogListReq req) {
Page<JobLogListRes> page = Page.create(pageQuery);
if(req.getJobId() != null && req.getJobId() > 0){
jobLogMapper.pageByJobId(page, req);
} else {
jobLogMapper.page(page, req);
}
return page;
public PageInfo<JobLogListRes> page(PageQuery pageQuery, JobLogListReq req) {
Page<JobLogListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
List<JobLogDO> list = jobLogMapper.selectList(new LambdaQueryWrapper<JobLogDO>()
.eq(null != req.getJobId(), JobLogDO::getJobId, req.getJobId())
.orderByDesc(JobLogDO::getId)
);
List<JobLogListRes> respList = mapperFacade.mapAsList(list, JobLogListRes.class);
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
}
@@ -1,31 +1,13 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.service;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Sets;
import fun.asgc.neutrino.core.annotation.*;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import fun.asgc.neutrino.core.util.CollectionUtil;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.base.rest.SystemContextHolder;
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
@@ -40,6 +22,11 @@ import fun.asgc.neutrino.proxy.server.dal.UserMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.LicenseDO;
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
import ma.glasnost.orika.MapperFacade;
import org.apache.ibatis.solon.annotation.Db;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.Lifecycle;
import java.util.*;
import java.util.function.Function;
@@ -50,25 +37,31 @@ import java.util.stream.Collectors;
* @author: aoshiguchen
* @date: 2022/8/6
*/
@NonIntercept
@Component
public class LicenseService {
@Autowired
public class LicenseService implements Lifecycle {
@Inject
private MapperFacade mapperFacade;
@Db
private LicenseMapper licenseMapper;
@Autowired
@Db
private UserMapper userMapper;
@Autowired
@Inject
private VisitorChannelService visitorChannelService;
public Page<LicenseListRes> page(PageQuery pageQuery, LicenseListReq req) {
Page<LicenseListRes> page = Page.create(pageQuery);
licenseMapper.page(page, req);
if (!CollectionUtil.isEmpty(page.getRecords())) {
Set<Integer> userIds = page.getRecords().stream().map(LicenseListRes::getUserId).collect(Collectors.toSet());
public PageInfo<LicenseListRes> page(PageQuery pageQuery, LicenseListReq req) {
Page<LicenseListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
List<LicenseDO> list = licenseMapper.selectList(new LambdaQueryWrapper<LicenseDO>()
.orderByAsc(LicenseDO::getId)
);
List<LicenseListRes> respList = mapperFacade.mapAsList(list, LicenseListRes.class);
if (CollectionUtils.isEmpty(list)) {
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
if (!CollectionUtil.isEmpty(respList)) {
Set<Integer> userIds = respList.stream().map(LicenseListRes::getUserId).collect(Collectors.toSet());
List<UserDO> userList = userMapper.findByIds(userIds);
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
for (LicenseListRes item : page.getRecords()) {
for (LicenseListRes item : respList) {
UserDO userDO = userMap.get(item.getUserId());
if (null != userDO) {
item.setUserName(userDO.getName());
@@ -76,11 +69,14 @@ public class LicenseService {
item.setKey(desensitization(item.getUserId(), item.getKey()));
}
}
return page;
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
public List<LicenseListRes> list(LicenseListReq req) {
List<LicenseListRes> licenseList = licenseMapper.list();
List<LicenseDO> list = licenseMapper.selectList(new LambdaQueryWrapper<LicenseDO>()
.eq(LicenseDO::getEnable, EnableStatusEnum.ENABLE.getStatus())
);
List<LicenseListRes> licenseList = mapperFacade.mapAsList(list, LicenseListRes.class);
if (!CollectionUtil.isEmpty(licenseList)) {
Set<Integer> userIds = licenseList.stream().map(LicenseListRes::getUserId).collect(Collectors.toSet());
List<UserDO> userList = userMapper.findByIds(userIds);
@@ -108,7 +104,7 @@ public class LicenseService {
String key = UUID.randomUUID().toString().replaceAll("-", "");
Date now = new Date();
licenseMapper.add(new LicenseDO()
licenseMapper.insert(new LicenseDO()
.setName(req.getName())
.setKey(key)
.setUserId(req.getUserId())
@@ -171,7 +167,7 @@ public class LicenseService {
* @param id
*/
public void delete(Integer id) {
licenseMapper.delete(id);
licenseMapper.deleteById(id);
// 更新VisitorChannel
visitorChannelService.updateVisitorChannelByLicenseId(id, EnableStatusEnum.DISABLE.getStatus());
}
@@ -209,9 +205,16 @@ public class LicenseService {
/**
* 服务端项目停止启动时更新在线状态为离线
*/
@Init
@Destroy
public void destroy() {
@Override
public void start() throws Throwable {
licenseMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
}
/**
* 服务端项目停止启动时更新在线状态为离线
*/
@Override
public void stop() throws Throwable {
licenseMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
}
}
@@ -1,31 +1,13 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.service;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Sets;
import fun.asgc.neutrino.core.annotation.*;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import fun.asgc.neutrino.core.util.CollectionUtil;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.base.rest.SystemContextHolder;
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
@@ -44,6 +26,11 @@ import fun.asgc.neutrino.proxy.server.dal.entity.PortMappingDO;
import fun.asgc.neutrino.proxy.server.dal.entity.PortPoolDO;
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
import ma.glasnost.orika.MapperFacade;
import org.apache.ibatis.solon.annotation.Db;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.Lifecycle;
import java.util.Date;
import java.util.List;
@@ -57,39 +44,40 @@ import java.util.stream.Collectors;
* @author: aoshiguchen
* @date: 2022/8/8
*/
@NonIntercept
@Component
public class PortMappingService {
@Autowired
public class PortMappingService implements Lifecycle {
@Inject
private MapperFacade mapperFacade;
@Db
private PortMappingMapper portMappingMapper;
@Autowired
@Db
private LicenseMapper licenseMapper;
@Autowired
@Db
private UserMapper userMapper;
@Autowired
@Db
private PortPoolMapper portPoolMapper;
@Autowired
@Inject
private VisitorChannelService visitorChannelService;
public Page<PortMappingListRes> page(PageQuery pageQuery, PortMappingListReq req) {
Page<PortMappingListRes> page = Page.create(pageQuery);
portMappingMapper.page(page, req);
if (CollectionUtil.isEmpty(page.getRecords())) {
return page;
}
Set<Integer> licenseIds = page.getRecords().stream().map(PortMappingListRes::getLicenseId).collect(Collectors.toSet());
if (CollectionUtil.isEmpty(licenseIds)) {
return page;
public PageInfo<PortMappingListRes> page(PageQuery pageQuery, PortMappingListReq req) {
Page<PortMappingListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
List<PortMappingDO> list = portMappingMapper.selectList(new LambdaQueryWrapper<PortMappingDO>()
.orderByAsc(PortMappingDO::getId)
);
List<PortMappingListRes> respList = mapperFacade.mapAsList(list, PortMappingListRes.class);
if (CollectionUtils.isEmpty(list)) {
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
Set<Integer> licenseIds = respList.stream().map(PortMappingListRes::getLicenseId).collect(Collectors.toSet());
List<LicenseDO> licenseList = licenseMapper.findByIds(licenseIds);
if (CollectionUtil.isEmpty(licenseList)) {
return page;
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
Set<Integer> userIds = licenseList.stream().map(LicenseDO::getUserId).collect(Collectors.toSet());
List<UserDO> userList = userMapper.findByIds(userIds);
Map<Integer, LicenseDO> licenseMap = licenseList.stream().collect(Collectors.toMap(LicenseDO::getId, Function.identity()));
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
page.getRecords().forEach(item -> {
respList.forEach(item -> {
LicenseDO license = licenseMap.get(item.getLicenseId());
if (null == license) {
return;
@@ -102,7 +90,7 @@ public class PortMappingService {
}
item.setUserName(user.getName());
});
return page;
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
public PortMappingCreateRes create(PortMappingCreateReq req) {
@@ -114,7 +102,7 @@ public class PortMappingService {
}
PortPoolDO portPoolDO = portPoolMapper.findByPort(req.getServerPort());
ParamCheckUtil.checkNotNull(portPoolDO, ExceptionConstant.PORT_NOT_EXIST);
ParamCheckUtil.checkExpression(null == portMappingMapper.findByPort(req.getServerPort()), ExceptionConstant.PORT_CANNOT_REPEAT_MAPPING, req.getServerPort());
ParamCheckUtil.checkExpression(null == portMappingMapper.findByPort(req.getServerPort(), null), ExceptionConstant.PORT_CANNOT_REPEAT_MAPPING, req.getServerPort());
Date now = new Date();
@@ -127,7 +115,7 @@ public class PortMappingService {
portMappingDO.setEnable(EnableStatusEnum.ENABLE.getStatus());
portMappingDO.setCreateTime(now);
portMappingDO.setUpdateTime(now);
portMappingMapper.add(portMappingDO);
portMappingMapper.insert(portMappingDO);
// 更新VisitorChannel
visitorChannelService.addVisitorChannelByPortMapping(portMappingDO);
return new PortMappingCreateRes();
@@ -156,7 +144,7 @@ public class PortMappingService {
portMappingDO.setClientPort(req.getClientPort());
portMappingDO.setUpdateTime(new Date());
portMappingDO.setEnable(EnableStatusEnum.ENABLE.getStatus());
portMappingMapper.update(portMappingDO);
portMappingMapper.updateById(portMappingDO);
// 更新VisitorChannel
visitorChannelService.updateVisitorChannelByPortMapping(oldPortMappingDO, portMappingDO);
return new PortMappingUpdateRes();
@@ -198,7 +186,6 @@ public class PortMappingService {
LicenseDO licenseDO = licenseMapper.findById(portMappingDO.getLicenseId());
ParamCheckUtil.checkNotNull(licenseDO, ExceptionConstant.LICENSE_NOT_EXIST);
if (!SystemContextHolder.isAdmin()) {
// 临时处理如果当前用户不是管理员则操作userId不能为1
ParamCheckUtil.checkExpression(!licenseDO.getUserId().equals(1), ExceptionConstant.NO_PERMISSION_VISIT);
}
@@ -225,7 +212,7 @@ public class PortMappingService {
ParamCheckUtil.checkExpression(!licenseDO.getUserId().equals(1), ExceptionConstant.NO_PERMISSION_VISIT);
}
portMappingMapper.delete(id);
portMappingMapper.deleteById(id);
// 更新VisitorChannel
visitorChannelService.removeVisitorChannelByPortMapping(portMappingDO);
@@ -243,10 +230,16 @@ public class PortMappingService {
/**
* 服务端项目停止启动时更新在线状态为离线
*/
@Init
@Destroy
public void destroy() {
@Override
public void start() throws Throwable {
portMappingMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
}
/**
* 服务端项目停止启动时更新在线状态为离线
*/
@Override
public void stop() throws Throwable {
portMappingMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
}
}
@@ -21,11 +21,11 @@
*/
package fun.asgc.neutrino.proxy.server.service;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
import fun.asgc.neutrino.proxy.server.controller.req.PortPoolCreateReq;
@@ -37,6 +37,10 @@ import fun.asgc.neutrino.proxy.server.controller.res.PortPoolUpdateEnableStatusR
import fun.asgc.neutrino.proxy.server.dal.PortPoolMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.PortPoolDO;
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
import ma.glasnost.orika.MapperFacade;
import org.apache.ibatis.solon.annotation.Db;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import java.util.Date;
import java.util.List;
@@ -46,23 +50,29 @@ import java.util.List;
* @author: aoshiguchen
* @date: 2022/8/7
*/
@NonIntercept
@Component
public class PortPoolService {
@Autowired
@Inject
private MapperFacade mapperFacade;
@Db
private PortPoolMapper portPoolMapper;
@Autowired
@Inject
private VisitorChannelService visitorChannelService;
public Page<PortPoolListRes> page(PageQuery pageQuery, PortPoolListReq req) {
Page<PortPoolListRes> page = Page.create(pageQuery);
portPoolMapper.page(page, req);
return page;
public PageInfo<PortPoolListRes> page(PageQuery pageQuery, PortPoolListReq req) {
Page<PortPoolListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
List<PortPoolDO> list = portPoolMapper.selectList(new LambdaQueryWrapper<PortPoolDO>()
.orderByAsc(PortPoolDO::getId)
);
List<PortPoolListRes> respList = mapperFacade.mapAsList(list, PortPoolListRes.class);
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
public List<PortPoolListRes> list(PortPoolListReq req) {
return portPoolMapper.list();
List<PortPoolDO> list = portPoolMapper.selectList(new LambdaQueryWrapper<PortPoolDO>()
.eq(PortPoolDO::getEnable, EnableStatusEnum.ENABLE.getStatus())
);
return mapperFacade.mapAsList(list, PortPoolListRes.class);
}
public PortPoolCreateRes create(PortPoolCreateReq req) {
@@ -71,7 +81,7 @@ public class PortPoolService {
Date now = new Date();
portPoolMapper.add(new PortPoolDO()
portPoolMapper.insert(new PortPoolDO()
.setPort(req.getPort())
.setEnable(EnableStatusEnum.ENABLE.getStatus())
.setCreateTime(now)
@@ -98,7 +108,7 @@ public class PortPoolService {
PortPoolDO portPoolDO = portPoolMapper.findById(id);
ParamCheckUtil.checkNotNull(portPoolDO, ExceptionConstant.PORT_NOT_EXIST);
portPoolMapper.delete(id);
portPoolMapper.deleteById(id);
// 更新visitorChannel
visitorChannelService.updateVisitorChannelByPortPool(portPoolDO.getPort(), EnableStatusEnum.DISABLE.getStatus());
@@ -21,14 +21,13 @@
*/
package fun.asgc.neutrino.proxy.server.service;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.proxy.server.constant.OnlineStatusEnum;
import fun.asgc.neutrino.proxy.server.dal.LicenseMapper;
import fun.asgc.neutrino.proxy.server.dal.PortMappingMapper;
import fun.asgc.neutrino.proxy.server.proxy.domain.CmdChannelAttachInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.solon.annotation.Db;
import org.noear.solon.annotation.Component;
import java.util.Date;
@@ -38,12 +37,11 @@ import java.util.Date;
* @date: 2022/9/3
*/
@Slf4j
@NonIntercept
@Component
public class ProxyMutualService {
@Autowired
@Db
private PortMappingMapper portMappingMapper;
@Autowired
@Db
private LicenseMapper licenseMapper;
/**
@@ -1,57 +1,29 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.service;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.controller.req.LicenseFlowReportReq;
import fun.asgc.neutrino.proxy.server.controller.req.UserFlowReportReq;
import fun.asgc.neutrino.proxy.server.controller.res.LicenseFlowReportRes;
import fun.asgc.neutrino.proxy.server.controller.res.UserFlowReportRes;
import fun.asgc.neutrino.proxy.server.dal.UserReportMapper;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Component;
/**
* @author: aoshiguchen
* @date: 2022/12/23
*/
@Slf4j
@NonIntercept
@Component
public class ReportService {
@Autowired
private UserReportMapper userReportMapper;
/**
* 用户流量报表分页
* @param pageQuery
* @param req
* @return
*/
public Page<UserFlowReportRes> userFlowReportPage(PageQuery pageQuery, UserFlowReportReq req) {
public PageInfo<UserFlowReportRes> userFlowReportPage(PageQuery pageQuery, UserFlowReportReq req) {
// TODO
return null;
}
@@ -62,7 +34,7 @@ public class ReportService {
* @param req
* @return
*/
public Page<LicenseFlowReportRes> licenseFlowReportPage(PageQuery pageQuery, LicenseFlowReportReq req) {
public PageInfo<LicenseFlowReportRes> licenseFlowReportPage(PageQuery pageQuery, LicenseFlowReportReq req) {
// TODO
return null;
}
@@ -1,37 +1,22 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.service;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import fun.asgc.neutrino.core.util.CollectionUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.controller.req.UserLoginRecordListReq;
import fun.asgc.neutrino.proxy.server.controller.res.UserLoginRecordListRes;
import fun.asgc.neutrino.proxy.server.dal.UserLoginRecordMapper;
import fun.asgc.neutrino.proxy.server.dal.UserMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
import fun.asgc.neutrino.proxy.server.dal.entity.UserLoginRecordDO;
import ma.glasnost.orika.MapperFacade;
import org.apache.ibatis.solon.annotation.Db;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import java.util.List;
import java.util.Map;
@@ -44,28 +29,36 @@ import java.util.stream.Collectors;
* @author: aoshiguchen
* @date: 2022/10/20
*/
@NonIntercept
@Component
public class UserLoginRecordService {
@Autowired
@Inject
private MapperFacade mapperFacade;
@Db
private UserLoginRecordMapper userLoginRecordMapper;
@Autowired
@Db
private UserMapper userMapper;
public Page<UserLoginRecordListRes> page(PageQuery pageQuery, UserLoginRecordListReq req) {
Page<UserLoginRecordListRes> page = Page.create(pageQuery);
userLoginRecordMapper.page(page, req);
if (!CollectionUtil.isEmpty(page.getRecords())) {
Set<Integer> userIds = page.getRecords().stream().map(UserLoginRecordListRes::getUserId).collect(Collectors.toSet());
public PageInfo<UserLoginRecordListRes> page(PageQuery pageQuery, UserLoginRecordListReq req) {
Page<UserLoginRecordListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
List<UserLoginRecordDO> list = userLoginRecordMapper.selectList(new LambdaQueryWrapper<UserLoginRecordDO>()
.orderByDesc(UserLoginRecordDO::getCreateTime)
);
List<UserLoginRecordListRes> respList = mapperFacade.mapAsList(list, UserLoginRecordListRes.class);
if (CollectionUtils.isEmpty(list)) {
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
if (!CollectionUtil.isEmpty(respList)) {
Set<Integer> userIds = respList.stream().map(UserLoginRecordListRes::getUserId).collect(Collectors.toSet());
List<UserDO> userList = userMapper.findByIds(userIds);
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
for (UserLoginRecordListRes item : page.getRecords()) {
for (UserLoginRecordListRes item : respList) {
UserDO userDO = userMap.get(item.getUserId());
if (null != userDO) {
item.setUserName(userDO.getName());
}
}
}
return page;
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
}
@@ -1,32 +1,12 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.service;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.db.page.Page;
import fun.asgc.neutrino.core.db.page.PageQuery;
import fun.asgc.neutrino.core.util.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import fun.asgc.neutrino.proxy.core.util.DateUtil;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.base.rest.ServiceException;
import fun.asgc.neutrino.proxy.server.base.rest.SystemContextHolder;
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
@@ -41,6 +21,10 @@ import fun.asgc.neutrino.proxy.server.dal.entity.UserLoginRecordDO;
import fun.asgc.neutrino.proxy.server.dal.entity.UserTokenDO;
import fun.asgc.neutrino.proxy.server.util.Md5Util;
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
import ma.glasnost.orika.MapperFacade;
import org.apache.ibatis.solon.annotation.Db;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import java.util.Calendar;
import java.util.Date;
@@ -52,17 +36,18 @@ import java.util.UUID;
* @author: aoshiguchen
* @date: 2022/7/31
*/
@NonIntercept
@Component
public class UserService {
private static final String DEFAULT_PASSWORD = "123456";
@Autowired
@Inject
private MapperFacade mapperFacade;
@Db
private UserMapper userMapper;
@Autowired
@Db
private UserTokenMapper userTokenMapper;
@Autowired
@Db
private UserLoginRecordMapper userLoginRecordMapper;
@Autowired
@Inject
private VisitorChannelService visitorChannelService;
public LoginRes login(LoginReq req) {
@@ -79,7 +64,7 @@ public class UserService {
Date expirationTime = DateUtil.addDate(now, Calendar.HOUR, 1);
// 缓存token
userTokenMapper.add(new UserTokenDO()
userTokenMapper.insert(new UserTokenDO()
.setToken(token)
.setUserId(userDO.getId())
.setExpirationTime(expirationTime)
@@ -88,7 +73,7 @@ public class UserService {
);
// 新增用户登录日志
userLoginRecordMapper.add(new UserLoginRecordDO()
userLoginRecordMapper.insert(new UserLoginRecordDO()
.setUserId(userDO.getId())
.setIp(SystemContextHolder.getIp())
.setToken(token)
@@ -106,7 +91,7 @@ public class UserService {
userTokenMapper.deleteByToken(SystemContextHolder.getToken());
// 新增用户登录日志
userLoginRecordMapper.add(new UserLoginRecordDO()
userLoginRecordMapper.insert(new UserLoginRecordDO()
.setUserId(SystemContextHolder.getUser().getId())
.setIp(SystemContextHolder.getIp())
.setToken(SystemContextHolder.getToken())
@@ -134,15 +119,21 @@ public class UserService {
userTokenMapper.updateTokenExpirationTime(token, expirationTime);
}
public Page<UserListRes> page(PageQuery pageQuery, UserListReq req) {
Page<UserListRes> page = Page.create(pageQuery);
userMapper.page(page, req);
return page;
public PageInfo<UserListRes> page(PageQuery pageQuery, UserListReq req) {
Page<UserListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
List<UserDO> list = userMapper.selectList(new LambdaQueryWrapper<UserDO>()
.orderByAsc(UserDO::getId)
);
List<UserListRes> respList = mapperFacade.mapAsList(list, UserListRes.class);
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
public List<UserListRes> list(UserListReq req) {
List<UserListRes> list = userMapper.list();
return list;
List<UserDO> userDOList = userMapper.selectList(new LambdaQueryWrapper<UserDO>()
.eq(UserDO::getEnable, EnableStatusEnum.ENABLE.getStatus())
.orderByAsc(UserDO::getId)
);
return mapperFacade.mapAsList(userDOList, UserListRes.class);
}
public UserInfoRes info(UserInfoReq req) {
@@ -170,8 +161,6 @@ public class UserService {
}
public UserCreateRes create(UserCreateReq req) {
Date now = new Date();
UserDO userDO = new UserDO();
userDO.setName(req.getName());
@@ -180,18 +169,17 @@ public class UserService {
userDO.setEnable(EnableStatusEnum.ENABLE.getStatus());
userDO.setCreateTime(now);
userDO.setUpdateTime(now);
userMapper.add(userDO);
userMapper.insert(userDO);
return new UserCreateRes();
}
public UserUpdateRes update(UserUpdateReq req) {
UserDO userDO = new UserDO();
userDO.setId(req.getId());
userDO.setName(req.getName());
userDO.setLoginName(req.getLoginName());
userDO.setUpdateTime(new Date());
userMapper.update(userDO);
userMapper.update(null, new LambdaUpdateWrapper<UserDO>()
.eq(UserDO::getId, req.getId())
.set(UserDO::getName, req.getName())
.set(UserDO::getLoginName, req.getLoginName())
.set(UserDO::getUpdateTime, new Date())
);
return new UserUpdateRes();
}
@@ -210,7 +198,7 @@ public class UserService {
}
public void delete(Integer id) {
userMapper.delete(id);
userMapper.deleteById(id);
// 更新VisitorChannel
visitorChannelService.updateVisitorChannelByUserId(id, EnableStatusEnum.DISABLE.getStatus());
}
@@ -1,32 +1,8 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.service;
import cn.hutool.core.collection.CollectionUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.util.CollectionUtil;
import fun.asgc.neutrino.proxy.core.Constants;
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
import fun.asgc.neutrino.proxy.server.dal.LicenseMapper;
@@ -49,6 +25,9 @@ import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.solon.annotation.Db;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import java.net.BindException;
import java.util.List;
@@ -60,22 +39,21 @@ import java.util.stream.Collectors;
* @date: 2023/2/5
*/
@Slf4j
@NonIntercept
@Component
public class VisitorChannelService {
@Autowired("serverBossGroup")
@Inject("serverBossGroup")
private NioEventLoopGroup serverBossGroup;
@Autowired("serverWorkerGroup")
@Inject("serverWorkerGroup")
private NioEventLoopGroup serverWorkerGroup;
@Autowired
@Inject
private ProxyMutualService proxyMutualService;
@Autowired
@Db
private UserMapper userMapper;
@Autowired
@Db
private LicenseMapper licenseMapper;
@Autowired
@Db
private PortMappingMapper portMappingMapper;
@Autowired
@Db
private PortPoolMapper portPoolMapper;
/**
@@ -1,27 +1,6 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.util;
import fun.asgc.neutrino.core.util.StringUtil;
import cn.hutool.core.util.StrUtil;
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
import fun.asgc.neutrino.proxy.server.base.rest.ServiceException;
@@ -43,7 +22,7 @@ public class ParamCheckUtil {
}
public static void checkNotEmpty(String str, String name) {
if (StringUtil.isEmpty(str)) {
if (StrUtil.isEmpty(str)) {
throw ServiceException.create(ExceptionConstant.PARAMS_NOT_EMPTY, name);
}
}
@@ -80,7 +59,7 @@ public class ParamCheckUtil {
}
public static void checkNotEmpty(String str, ExceptionConstant constant, Object... params) {
if (StringUtil.isEmpty(str)) {
if (StrUtil.isEmpty(str)) {
throw ServiceException.create(constant, params);
}
}
@@ -1,29 +1,7 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.util;
import cn.hutool.core.collection.CollectionUtil;
import com.google.common.collect.Sets;
import fun.asgc.neutrino.core.util.ChannelUtil;
import fun.asgc.neutrino.core.util.CollectionUtil;
import fun.asgc.neutrino.proxy.core.ChannelAttribute;
import fun.asgc.neutrino.proxy.server.proxy.domain.CmdChannelAttachInfo;
import fun.asgc.neutrino.proxy.server.proxy.domain.ProxyMapping;
@@ -134,7 +112,7 @@ public class ProxyUtil {
CmdChannelAttachInfo cmdChannelAttachInfo = getAttachInfo(cmdChannel);
if (null == cmdChannelAttachInfo) {
cmdChannelAttachInfo = new CmdChannelAttachInfo()
.setIp(ChannelUtil.getIP(cmdChannel))
.setIp(((InetSocketAddress)cmdChannel.remoteAddress()).getAddress().getHostAddress())
.setLicenseId(licenseId)
.setVisitorChannelMap(new HashMap<>(16))
.setServerPorts(Sets.newHashSet());
@@ -213,7 +191,7 @@ public class ProxyUtil {
.setLanInfo(lanInfo)
.setServerPort(serverPort)
.setLicenseId(cmdChannelAttachInfo.getLicenseId())
.setIp(ChannelUtil.getIP(visitorChannel))
.setIp(((InetSocketAddress)visitorChannel.remoteAddress()).getAddress().getHostAddress())
);
userChannelMapLock.writeLock().lock();
try {
@@ -0,0 +1,49 @@
server:
port: 8888
neutrino:
proxy:
protocol:
max-frame-length: 2097152
length-field-offset: 0
length-field-length: 4
initial-bytes-to-strip: 0
length-adjustment: 0
read-idle-time: 40
write-idle-time: 10
all-idle-time-seconds: 0
server:
port: 9000
ssl-port: 9002
key-store-password: 123456
key-manager-password: 123456
jks-path: classpath:/test.jks
data:
db:
type: sqlite
url: jdbc:sqlite:data.db
driver-class: org.sqlite.JDBC
username:
password:
#添加MIME印射(如果有需要?)
#是否启用静态文件服务。(可不配,默认为启用)
solon.staticfiles.enable: true
#静态文件的304缓存时长。(可不配,默认为10分钟)
solon.staticfiles.maxAge: 600
#添加静态目录映射。(按需选择)#v1.11.0 后支持
solon.staticfiles.mappings:
- path: "/"
repository: "./neutrino-proxy-admin/dist/" #2.添加资源路径(仓库只能是目录)
mybatis.db:
typeAliases: #支持包名 或 类名(大写开头 或 *)//支持 ** 或 * 占位符
- "fun.asgc.neutrino.proxy.server.dal.entity"
mappers: #支持包名 或 类名(大写开头 或 *)或 xml(.xml结尾)//支持 ** 或 * 占位符
- "classpath:mapper/*.xml"
- "fun.asgc.neutrino.proxy.server.dal"
configuration: #扩展配置(要与 MybatisConfiguration 类的属性一一对应)
cacheEnabled: false
mapUnderscoreToCamelCase: true
globalConfig: #全局配置(要与 GlobalConfig 类的属性一一对应)
banner: true
@@ -1,38 +0,0 @@
neutrino:
application:
name: neutrino-proxy-server
http:
enable: true
port: 8888
context-path: /
max-content-length-desc: 128K
static-resource:
locations:
- "neutrino-proxy-admin/dist/"
proxy:
protocol:
max-frame-length: 2097152
length-field-offset: 0
length-field-length: 4
initial-bytes-to-strip: 0
length-adjustment: 0
read-idle-time: 40
write-idle-time: 10
all-idle-time-seconds: 0
server:
port: 9000
ssl-port: 9002
key-store-password: 123456
key-manager-password: 123456
jks-path: classpath:/test.jks
data:
db:
type: sqlite
url: jdbc:sqlite:data.db
driver-class: org.sqlite.JDBC
# type: mysql
# url: jdbc:mysql://103.163.47.16:3306/neutrino-proxy?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useAffectedRows=true&useSSL=false
# driver-class: com.mysql.jdbc.Driver
# username: "******"
# password: "******"
@@ -1,7 +0,0 @@
<mapper namespace = "fun.asgc.neutrino.proxy.server.dal.ClientConnectRecordMapper">
<update id="add">
insert into client_connect_record(`ip`,`license_id`,`type`, `msg`, `code`, `err`, `create_time`)
values(:ip,:licenseId,:type,:msg,:code,:err,:createTime)
</update>
</mapper>
@@ -1,8 +0,0 @@
<mapper namespace = "fun.asgc.neutrino.proxy.server.dal.JobInfoMapper">
<update id="update">
update `job_info`
set cron = :cron,desc = :desc,alarm_email=:alarmEmail,alarm_ding=:alarmDing,param=:param,update_time=:updateTime
where id =:id
</update>
</mapper>
@@ -1,12 +0,0 @@
<mapper namespace = "fun.asgc.neutrino.proxy.server.dal.LicenseMapper">
<select id="page" resultType="fun.asgc.neutrino.proxy.server.controller.res.LicenseListRes">
select * from `license`
</select>
<insert id="add">
insert into `license`(`name`,`key`,`user_id`,`is_online`,`enable`,`create_time`,`update_time`)
values (:name, :key, :userId, :isOnline, :enable, :createTime, :updateTime)
</insert>
</mapper>
@@ -1,13 +0,0 @@
<mapper namespace = "fun.asgc.neutrino.proxy.server.dal.PortMappingMapper">
<insert id="add">
insert into `port_mapping`(`license_id`,`server_port`,`client_ip`,`client_port`,`is_online`,`enable`,`create_time`,`update_time`)
values (:licenseId, :serverPort, :clientIp, :clientPort, :isOnline, :enable, :createTime, :updateTime)
</insert>
<update id="update">
update `port_mapping`
set license_id = :licenseId,server_port = :serverPort,client_ip=:clientIp,client_port=:clientPort,update_time=:updateTime
where id =:id
</update>
</mapper>
@@ -1,14 +0,0 @@
<mapper namespace = "fun.asgc.neutrino.proxy.server.dal.UserReportMapper">
<select id="userFlowReportPage" resultType="fun.asgc.neutrino.proxy.server.controller.res.UserFlowReportRes">
SELECT
u.id AS userId,
u.NAME AS userName,
IFNULL( SUM( frm.write_bytes ), 0 ) AS historyWriteBytes,
IFNULL( SUM( frm.read_bytes ), 0 ) AS historyReadBytes
FROM `user` u
LEFT JOIN flow_report_month frm ON u.id = frm.user_id
GROUP BY u.id
</select>
</mapper>
@@ -1,12 +0,0 @@
<mapper namespace = "fun.asgc.neutrino.proxy.server.dal.UserTokenMapper">
<insert id = "add">
insert into `user_token`(`token`,`user_id`,`expiration_time`,`create_time`,`update_time`)
values (:token, :userId, :expirationTime, :createTime, :updateTime)
</insert>
<select id = "findByAvailableToken">
select * from user_token where token = ? and expiration_time > ?
</select>
</mapper>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

@@ -1,3 +0,0 @@
function hello() {
alert("hello");
}
@@ -1,12 +0,0 @@
<html>
<head>
<title>测试页面</title>
<script type="application/javascript" src="js/test.js"></script>
<script type="application/javascript">
hello();
</script>
</head>
<body>
<h2>hello,欢迎来到<span stype="color:red;">中微子代理</span></h2>
</body>
</html>
+28 -3
View File
@@ -4,6 +4,13 @@
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>
<parent>
<groupId>org.noear</groupId>
<artifactId>solon-parent</artifactId>
<version>2.2.2</version>
<relativePath />
</parent>
<groupId>fun.asgc.neutrino</groupId>
<artifactId>neutrino-proxy</artifactId>
<packaging>pom</packaging>
@@ -14,6 +21,8 @@
<module>neutrino-proxy-core</module>
<module>neutrino-proxy-client</module>
<module>neutrino-proxy-server</module>
<module>_solon_plugin/job-solon-plugin</module>
<module>_solon_plugin/orika-solon-plugin</module>
</modules>
<properties>
@@ -25,7 +34,7 @@
<java.version>1.8</java.version>
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
<maven-flatten.version>1.1.0</maven-flatten.version>
<org.projectlombok.version>1.16.14</org.projectlombok.version>
<org.projectlombok.version>1.18.4</org.projectlombok.version>
</properties>
<dependencyManagement>
@@ -48,12 +57,12 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.0</version>
<version>${org.projectlombok.version}</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.25</version>
<version>1.33</version>
</dependency>
<dependency>
<groupId>junit</groupId>
@@ -81,6 +90,21 @@
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.39.2.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
</dependency>
</dependencies>
</dependencyManagement>
@@ -129,6 +153,7 @@
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF-8</encoding>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
+15 -1
View File
@@ -34,4 +34,18 @@
# Bug
- windows环境下直接运行发布版的jar包,日志输出乱码
- 部份用户windows环境下启动客户端,扫描类个数为0个
- 代理mysql时,使用未开启远程访问的账号走代理访问mysql,代理客户端出现断开现象
- 代理mysql时,使用未开启远程访问的账号走代理访问mysql,代理客户端出现断开现象
# 2.x规划
- 全面重构:底层更换为Solon + Mybatis Plus
- 规范协议:代理协议规范化,方便后续更好扩展、支持不同语言客户端接入
- 端口池优化:支持为license设置独占端口。方便后续开发jetbrains插件、solon插件
- 精细化控制:支持针对用户限速、限流
- 参考鹊桥,增加对域名的支持
- MGT增加服务端维护
- 支持调整服务端端口
- 支持重启
- 支持查看服务端日志
- 支持证书上传下载
- 支持客户端版本管理
- 支持原生编译
+7
View File
@@ -0,0 +1,7 @@
以下为部分使用中机构/组织/个人:
---
|单位/组织名称| 主营业务描述 |使用中微子的主要用途|
|:----|:----------|:--------|
|常州裕景信息科技有限公司| 高校数字化软件建设 |统筹管理个单位的服务器|