Compare commits
48
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a227919017 | ||
|
|
96648ea7bc | ||
|
|
507d4ebb04 | ||
|
|
c2ccb9d2c7 | ||
|
|
09424a7f07 | ||
|
|
44909e20b5 | ||
|
|
639d7d1707 | ||
|
|
8033666a70 | ||
|
|
98f855505d | ||
|
|
c79d2937cc | ||
|
|
d24ef43f45 | ||
|
|
04841dcbd9 | ||
|
|
de59752bb9 | ||
|
|
f378f9e744 | ||
|
|
13128e0a9e | ||
|
|
a212056a46 | ||
|
|
2f841ad7a5 | ||
|
|
aadee74d8e | ||
|
|
8fce7d1677 | ||
|
|
4ebc53b755 | ||
|
|
5f3cd8f60e | ||
|
|
f75a1fa57b | ||
|
|
59f8c9c042 | ||
|
|
41a9ded54a | ||
|
|
b13dbc687b | ||
|
|
92aa25940c | ||
|
|
df2ced99a0 | ||
|
|
540bedb809 | ||
|
|
7e9a4d5fad | ||
|
|
32f5e2397c | ||
|
|
bbee153491 | ||
|
|
8626917441 | ||
|
|
58504d8b49 | ||
|
|
4b8ec0b33b | ||
|
|
f71055b6ea | ||
|
|
8f46518b06 | ||
|
|
81e1efd296 | ||
|
|
87d6e0a07d | ||
|
|
7db85e6379 | ||
|
|
81b9dcf6c4 | ||
|
|
4d4aeaf8fc | ||
|
|
80573ee718 | ||
|
|
ded5e2f927 | ||
|
|
f43f46fe9e | ||
|
|
d00346a376 | ||
|
|
033196d955 | ||
|
|
47be82ba95 | ||
|
|
7fa4d6d8fa |
@@ -3,6 +3,7 @@
|
||||
*.class
|
||||
data.db*
|
||||
.neutrino-proxy.license
|
||||
.neutrino-proxy-client.json*
|
||||
lib/*
|
||||
|
||||
|
||||
|
||||
@@ -106,6 +106,7 @@ proxy:
|
||||
|
||||
# 7、技术文档
|
||||
- [Aop](./docs/Aop.MD)
|
||||
- [Channel](./docs/Channel.MD)
|
||||
|
||||
# 8、联系我们
|
||||
- 微信: yuyunshize
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# 代理实现中涉及的几类Channel
|
||||
|
||||
## 指令通道(CmdChannel)
|
||||
- 该channel负责维护客户端与服务端之间的指令通讯,由客户端启动后向服务端发起连接请求,服务端验证license成功后连接建立。
|
||||
- 服务端维护第一个CmdChannel的映射表,key为licenseId。服务端可以根据licenseId,向指定的客户端指令通道发布指令。
|
||||
- 该通道建立完成后,服务端会将该license授权的外网映射端口打开,等待用户访问。正常情况下,只要客户端不下线,该通道一直可用。
|
||||
- 然后服务端维护第二个CmdChannel的映射表,key为服务端外网端口。服务端可以根据指定的外网端口,向指定的客户端指令通道发布指令。
|
||||
|
||||
## 用户访问通道(VisitorChannel)
|
||||
- 该channel负责维护访问者与服务端端口之间的通讯,由访问者向服务端映射的外网端口发起请求开始建立,具体断开时机由实际的被代理的
|
||||
协议决定。
|
||||
- 如HTTP/1.0下,用户向该端口发起请求,响应结束后,该通道随之关闭,下一次发起请求后,重新建立新的连接。
|
||||
- 该连接建立后,服务端会向该外网端口映射的指令通道发送`Connect`指令,传输该外网端口需要代理的内网信息,
|
||||
如:`127.0.0.1:3306`。
|
||||
|
||||
## 被代理服务的实际通道(RealServerChannel)
|
||||
- 该channel负责维护客户端与实际被代理服务之间的通讯,当客户端接收到服务端的`Connect`指令后,客户端便会建立该通道。
|
||||
|
||||
## 代理数据传输的通道(ProxyChannel)
|
||||
- 该channel负责完成内网被代理服务与代理服务端之间的数据转发任务。
|
||||
- 每个客户端维护一个`ProxyChannel`的缓存队列,需要时从该队列中取,当取不到时,直接新建一个`ProxyChannel`返回。
|
||||
当一个`ProxyChannel`实例用完后,需要归还到缓存队列中(`ProxyChannel`收到`DisConnect`指令时)。
|
||||
- 当`RealServerChannel`建立完成后,就会获取相关联的`ProxyChannel`,并与其绑定。设置`RealServerChannel`为
|
||||
可读状态。然后通过`ProxyChannel`向服务端发送`Connect`指令。
|
||||
|
||||
|
||||
# 代理实现流程
|
||||
## 1、服务连接阶段
|
||||
- 1.1、客户端根据是否需要使用SSL,选择对应的服务端端口发起连接,建立`CmdChannel`。
|
||||
- 1.2、客户端根据用户输入或配置文件获取`license`,并携带`license`通过`CmdChannel`向服务端发送`Auth`指令。
|
||||
- 1.3、服务端通过`CmdChannel`接收到来自客户端的`Auth`指令。若验证`license`有效,则建立`licenseId`与`CmdChannel`的映射缓存、
|
||||
外网端口与`CmdChannel`的映射缓存。并启动服务端代理端口,等待用户连接。
|
||||
## 2、用户连接阶段
|
||||
- 2.1、用户访向服务端代理的外网端口发起请求,服务端建立`VisitorChannel`。
|
||||
- 2.2、根据外网端口查找`CmdChannel`,若不存在有效的`CmdChannel`,则关闭该`VisitorChannel`。否则,
|
||||
设置`VisitorChannel`为不可读,并携带内网映射信息(如:`127.0.0.1:3306`)通过`CmdChannel`向客户端发送`Connect`指令。
|
||||
## 3、实际被代理服务连接阶段
|
||||
- 3.1、客户端通过`CmdChannel`接收到服务端的`Connect`指令。拿到需要代理的内网IP、端口号,向实际被
|
||||
代理服务发起连接请求,若连接失败,则通过`CmdChannel`向服务端发送`DisConnect`指令。建立`RealServerChannel`成功,设置`RealServerChannel`为不可读
|
||||
状态,并进入4.1阶段
|
||||
## 4、代理通道连接阶段
|
||||
- 4.1、客户端通过`ProxyChannelQueue`获取或新建一个`ProxyChannel`,并将`RealServerChannel`与`ProxyChannel`进行绑定。
|
||||
- 4.2、客户端通过`ProxyChannel`向服务端发送`Connect`指令。
|
||||
- 4.3、服务端通过`ProxyChannel`通道收到来自客户端的`Connect`指令后,将`ProxyChannel`与对应的`VisitorChannel`进行绑定,并
|
||||
设置`VisitorChannel`为可读状态。
|
||||
## 5、数据传输阶段
|
||||
- 5.1、服务端通过`VisitorChannel`收到来自用户的请求数据,然后找到`VisitorChannel`绑定的`ProxyChannel`,
|
||||
通过`ProxyChannel`发送`Transfer`指令,并携带用户请求数据。
|
||||
- 5.2、客户端通过`ProxyChannel`收到来自服务端的`Transfer`指令,取出用户请求数据。找到`ProxyChannel`绑定的`RealServerChannel`,
|
||||
通过`RealServerChannel`向被代理服务写入用户请求数据。
|
||||
- 5.3、客户端通过`RealServerChannel`收到被代理服务响应的数据,找到`RealServerChannel`绑定的`ProxyChannel`,
|
||||
通过`ProxyChannel`向服务端发送`Transfer`指令,并携带响应数据。
|
||||
- 5.4、服务端通过`ProxyChannel`收到来自客户端的`Transfer`指令,找到`ProxyChannel`绑定的`VisitorChannel`,
|
||||
通过`VisitorChannel`向用户端写入响应数据。
|
||||
@@ -40,7 +40,6 @@ public class AsgcProxyFactory implements ProxyFactory {
|
||||
private static final String classNameTemplate = "%s" + SYMBOLIC + "%s";
|
||||
private static AtomicLong proxyClassCounter = new AtomicLong();
|
||||
private AsgcCompiler compiler = new AsgcCompiler();
|
||||
private ProxyClassLoader classLoader = new ProxyClassLoader();
|
||||
|
||||
@Override
|
||||
public <T> T get(Class<T> targetType) throws Exception {
|
||||
|
||||
@@ -1,80 +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.core.aop.proxy;
|
||||
|
||||
import fun.asgc.neutrino.core.base.GlobalConfig;
|
||||
import fun.asgc.neutrino.core.util.FileUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 代理类加载器
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/24
|
||||
*/
|
||||
public class ProxyClassLoader extends ClassLoader {
|
||||
|
||||
protected Map<String, byte[]> byteCodeMap = new ConcurrentHashMap<>();
|
||||
|
||||
static {
|
||||
registerAsParallelCapable();
|
||||
}
|
||||
|
||||
public ProxyClassLoader() {
|
||||
super(getParentClassLoader());
|
||||
}
|
||||
|
||||
protected static ClassLoader getParentClassLoader() {
|
||||
ClassLoader ret = Thread.currentThread().getContextClassLoader();
|
||||
return ret != null ? ret : ProxyClassLoader.class.getClassLoader();
|
||||
}
|
||||
|
||||
public Class<?> loadProxyClass(ProxyClass proxyClass) {
|
||||
if (null != proxyClass.getByteCode()) {
|
||||
for (Map.Entry<String, byte[]> e : proxyClass.getByteCode().entrySet()) {
|
||||
byteCodeMap.putIfAbsent(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return loadClass(proxyClass.getPkg() + "." + proxyClass.getName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
byte[] bytes = byteCodeMap.get(name);
|
||||
if (null == bytes) {
|
||||
bytes = FileUtil.readBytes( GlobalConfig.getGeneratorCodeSavePath() + name.replaceAll("\\.", "/") + ".class");
|
||||
}
|
||||
if (bytes != null) {
|
||||
Class<?> ret = defineClass(name, bytes, 0, bytes.length);
|
||||
byteCodeMap.remove(name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return super.findClass(name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.crisp;
|
||||
|
||||
/**
|
||||
* 清爽的数据库工具
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/3
|
||||
*/
|
||||
public class CrispDbKit {
|
||||
private static final JdbcManager manager = new JdbcManager();
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* 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.crisp;
|
||||
|
||||
import fun.asgc.neutrino.core.db.crisp.ds.DefaultDataSourceProvider;
|
||||
import fun.asgc.neutrino.core.db.crisp.ds.IDataSourceProvider;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/3
|
||||
*/
|
||||
public class DbConfig {
|
||||
/**
|
||||
* 数据库名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 数据源提供者
|
||||
*/
|
||||
private IDataSourceProvider dataSourceProvider;
|
||||
/**
|
||||
* 是否显示sql
|
||||
*/
|
||||
private Boolean showSql;
|
||||
/**
|
||||
* 是否开启调试模式
|
||||
*/
|
||||
private Boolean debugMode;
|
||||
/**
|
||||
* 上下文
|
||||
*/
|
||||
private DbContext context;
|
||||
/**
|
||||
* 数据库执行器
|
||||
*/
|
||||
private DbExecutor dbExecutor;
|
||||
|
||||
public DbConfig(String name, IDataSourceProvider dataSourceProvider) {
|
||||
this.name = name;
|
||||
this.dataSourceProvider = dataSourceProvider;
|
||||
this.showSql = Boolean.FALSE;
|
||||
this.debugMode = Boolean.FALSE;
|
||||
this.context = new DbContext(this);
|
||||
this.dbExecutor = new DbExecutor(this);
|
||||
}
|
||||
|
||||
public DbConfig(String name, DataSource dataSource) {
|
||||
this(name, new DefaultDataSourceProvider(dataSource));
|
||||
}
|
||||
|
||||
public DbConfig(IDataSourceProvider dataSourceProvider) {
|
||||
this("unknown", dataSourceProvider);
|
||||
}
|
||||
|
||||
public DbConfig(DataSource dataSource) {
|
||||
this(new DefaultDataSourceProvider(dataSource));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库操作实例
|
||||
* @return 数据库操作实例
|
||||
*/
|
||||
public DbExecutor getDbExecutor() {
|
||||
return dbExecutor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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.crisp;
|
||||
|
||||
import fun.asgc.neutrino.core.db.crisp.session.SqlSessionFactory;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/3
|
||||
*/
|
||||
public class DbContext {
|
||||
private DbConfig dbConfig;
|
||||
private final ThreadLocal<Connection> connectionHolder = new ThreadLocal<>();
|
||||
|
||||
public DbContext(DbConfig dbConfig) {
|
||||
this.dbConfig = dbConfig;
|
||||
}
|
||||
public SqlSessionFactory getSqlSessionFactory() {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* 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.crisp;
|
||||
|
||||
import fun.asgc.neutrino.core.db.crisp.base.DbUpdateResult;
|
||||
import fun.asgc.neutrino.core.db.crisp.ds.IDataSourceProvider;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/3
|
||||
*/
|
||||
class DbExecutor implements DbOperator {
|
||||
/**
|
||||
* 配置
|
||||
*/
|
||||
private DbConfig config;
|
||||
|
||||
|
||||
public DbExecutor(DbConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public DbExecutor(IDataSourceProvider dataSourceProvider) {
|
||||
this(new DbConfig(dataSourceProvider));
|
||||
}
|
||||
|
||||
public DbExecutor(String name, IDataSourceProvider dataSourceProvider) {
|
||||
this(new DbConfig(name, dataSourceProvider));
|
||||
}
|
||||
|
||||
public DbExecutor(DataSource dataSource) {
|
||||
this(new DbConfig(dataSource));
|
||||
}
|
||||
|
||||
public DbExecutor(String name, DataSource dataSource) {
|
||||
this(new DbConfig(name, dataSource));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> queryList(Class<T> resultType, String sql, Object... params) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T query(Class<T> resultType, String sql, Object... params) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DbUpdateResult update(String sql, Object... params) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DbUpdateResult insert(String sql, Object... params) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DbUpdateResult delete(String sql, Object... params) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 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.crisp;
|
||||
|
||||
import fun.asgc.neutrino.core.db.crisp.base.DbUpdateResult;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/3
|
||||
*/
|
||||
public interface DbOperator {
|
||||
/**
|
||||
* 查询数据列表
|
||||
* @param resultType 结果类型
|
||||
* @param sql sql
|
||||
* @param params 参数列表
|
||||
* @return 查询结果列表
|
||||
* @param <T>
|
||||
*/
|
||||
<T> List<T> queryList(Class<T> resultType, String sql, Object... params);
|
||||
|
||||
/**
|
||||
* 查询单条记录
|
||||
* @param resultType 结果类型
|
||||
* @param sql sql
|
||||
* @param params 参数列表
|
||||
* @return 查询结果
|
||||
* @param <T>
|
||||
*/
|
||||
<T> T query(Class<T> resultType, String sql, Object... params);
|
||||
|
||||
/**
|
||||
* 更新
|
||||
* @param sql sql
|
||||
* @param params 参数列表
|
||||
* @return 更新结果
|
||||
*/
|
||||
DbUpdateResult update(String sql, Object... params);
|
||||
|
||||
/**
|
||||
* 新增
|
||||
* @param sql sql
|
||||
* @param params 参数列表
|
||||
* @return 新增结果
|
||||
*/
|
||||
DbUpdateResult insert(String sql, Object... params);
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param sql sql
|
||||
* @param params 参数列表
|
||||
* @return 删除结果
|
||||
*/
|
||||
DbUpdateResult delete(String sql, Object... params);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package fun.asgc.neutrino.core.db.crisp;
|
||||
|
||||
import fun.asgc.neutrino.core.exception.InternalException;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/7
|
||||
*/
|
||||
public class JdbcException extends InternalException {
|
||||
|
||||
public JdbcException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public JdbcException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* 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.crisp;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/4
|
||||
*/
|
||||
public class JdbcManager {
|
||||
/**
|
||||
* 数据源缓存
|
||||
*/
|
||||
private Map<String, DbConfig> dbConfigMap = new HashMap<>();
|
||||
/**
|
||||
* 默认数据库的key
|
||||
*/
|
||||
private final String DEFAULT_KEY = "default";
|
||||
|
||||
/**
|
||||
* 设置默认数据库配置
|
||||
* @param config 数据库配置
|
||||
*/
|
||||
public void setConfig(DbConfig config) {
|
||||
setConfig(DEFAULT_KEY, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置数据库配置
|
||||
* @param key 键
|
||||
* @param config 数据库配置
|
||||
*/
|
||||
public void setConfig(String key, DbConfig config) {
|
||||
dbConfigMap.put(key, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称获取数据库配置
|
||||
* @param key 键
|
||||
* @return 数据库配置
|
||||
*/
|
||||
public DbConfig getConfig(String key) {
|
||||
return dbConfigMap.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认数据库配置
|
||||
* @return 数据库配置
|
||||
*/
|
||||
public DbConfig getConfig() {
|
||||
return getConfig(DEFAULT_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认数据库操作实例
|
||||
* @return
|
||||
*/
|
||||
private DbExecutor getDbExecutor(String key) {
|
||||
DbConfig dbConfig = getConfig(key);
|
||||
return null == dbConfig ? null : dbConfig.getDbExecutor();
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换数据源
|
||||
* @param name 数据源名称
|
||||
* @return 数据库操作实例
|
||||
*/
|
||||
public DbExecutor use(String name) {
|
||||
return getDbExecutor(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换为默认数据源
|
||||
* @return 默认数据库操作实例
|
||||
*/
|
||||
public DbExecutor useDefault() {
|
||||
return getDbExecutor(DEFAULT_KEY);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* 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.crisp.base;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/4
|
||||
*/
|
||||
public class BatchResult {
|
||||
|
||||
private final MappedStatement mappedStatement;
|
||||
private final String sql;
|
||||
private final List<Object> parameterObjects;
|
||||
|
||||
private int[] updateCounts;
|
||||
|
||||
public BatchResult(MappedStatement mappedStatement, String sql) {
|
||||
super();
|
||||
this.mappedStatement = mappedStatement;
|
||||
this.sql = sql;
|
||||
this.parameterObjects = new ArrayList<>();
|
||||
}
|
||||
|
||||
public BatchResult(MappedStatement mappedStatement, String sql, Object parameterObject) {
|
||||
this(mappedStatement, sql);
|
||||
addParameterObject(parameterObject);
|
||||
}
|
||||
|
||||
public MappedStatement getMappedStatement() {
|
||||
return mappedStatement;
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Object getParameterObject() {
|
||||
return parameterObjects.get(0);
|
||||
}
|
||||
|
||||
public List<Object> getParameterObjects() {
|
||||
return parameterObjects;
|
||||
}
|
||||
|
||||
public int[] getUpdateCounts() {
|
||||
return updateCounts;
|
||||
}
|
||||
|
||||
public void setUpdateCounts(int[] updateCounts) {
|
||||
this.updateCounts = updateCounts;
|
||||
}
|
||||
|
||||
public void addParameterObject(Object parameterObject) {
|
||||
this.parameterObjects.add(parameterObject);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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.crisp.base;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/3
|
||||
*/
|
||||
public class DbUpdateResult {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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.crisp.base;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/4
|
||||
*/
|
||||
public class MappedStatement {
|
||||
// TODO
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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.crisp.base;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/4
|
||||
*/
|
||||
public class RowBounds {
|
||||
|
||||
public static final int NO_ROW_OFFSET = 0;
|
||||
public static final int NO_ROW_LIMIT = Integer.MAX_VALUE;
|
||||
public static final RowBounds DEFAULT = new RowBounds();
|
||||
|
||||
private final int offset;
|
||||
private final int limit;
|
||||
|
||||
public RowBounds() {
|
||||
this.offset = NO_ROW_OFFSET;
|
||||
this.limit = NO_ROW_LIMIT;
|
||||
}
|
||||
|
||||
public RowBounds(int offset, int limit) {
|
||||
this.offset = offset;
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
public int getLimit() {
|
||||
return limit;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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.crisp.base;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/4
|
||||
*/
|
||||
public enum SqlExecutorType {
|
||||
SIMPLE, REUSE, BATCH
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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.crisp.ds;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/3
|
||||
*/
|
||||
public class DefaultDataSourceProvider implements IDataSourceProvider {
|
||||
/**
|
||||
* 数据源
|
||||
*/
|
||||
private DataSource dataSource;
|
||||
|
||||
public DefaultDataSourceProvider(DataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSource getDataSource() {
|
||||
return dataSource;
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 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.crisp.ds;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* 数据源提供商
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/3
|
||||
*/
|
||||
public interface IDataSourceProvider {
|
||||
/**
|
||||
* 获取数据源
|
||||
* @return
|
||||
*/
|
||||
DataSource getDataSource();
|
||||
}
|
||||
+95
@@ -0,0 +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.core.db.crisp.session;
|
||||
|
||||
import fun.asgc.neutrino.core.db.crisp.DbConfig;
|
||||
import fun.asgc.neutrino.core.db.crisp.base.SqlExecutorType;
|
||||
import fun.asgc.neutrino.core.db.crisp.tx.TransactionIsolationLevel;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/4
|
||||
*/
|
||||
public class DefaultSqlSessionFactory implements SqlSessionFactory {
|
||||
|
||||
private final DbConfig config;
|
||||
|
||||
public DefaultSqlSessionFactory(DbConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlSession openSession() {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlSession openSession(boolean autoCommit) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlSession openSession(Connection connection) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlSession openSession(TransactionIsolationLevel level) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlSession openSession(SqlExecutorType execType) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlSession openSession(SqlExecutorType execType, boolean autoCommit) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlSession openSession(SqlExecutorType execType, TransactionIsolationLevel level) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlSession openSession(SqlExecutorType execType, Connection connection) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DbConfig getDbConfig() {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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.crisp.session;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/23
|
||||
*/
|
||||
public interface ResultContext<T> {
|
||||
T getResultObject();
|
||||
|
||||
int getResultCount();
|
||||
|
||||
boolean isStopped();
|
||||
|
||||
void stop();
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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.crisp.session;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/23
|
||||
*/
|
||||
public interface ResultHandler<T> {
|
||||
void handleResult(ResultContext<? extends T> resultContext);
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
/**
|
||||
* 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.crisp.session;
|
||||
|
||||
import fun.asgc.neutrino.core.db.crisp.DbConfig;
|
||||
import fun.asgc.neutrino.core.db.crisp.base.BatchResult;
|
||||
import fun.asgc.neutrino.core.db.crisp.base.RowBounds;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/4
|
||||
*/
|
||||
public interface SqlSession extends Closeable {
|
||||
|
||||
/**
|
||||
* Retrieve a single row mapped from the statement key.
|
||||
* @param <T> the returned object type
|
||||
* @param statement
|
||||
* @return Mapped object
|
||||
*/
|
||||
<T> T selectOne(String statement);
|
||||
|
||||
/**
|
||||
* Retrieve a single row mapped from the statement key and parameter.
|
||||
* @param <T> the returned object type
|
||||
* @param statement Unique identifier matching the statement to use.
|
||||
* @param parameter A parameter object to pass to the statement.
|
||||
* @return Mapped object
|
||||
*/
|
||||
<T> T selectOne(String statement, Object parameter);
|
||||
|
||||
/**
|
||||
* Retrieve a list of mapped objects from the statement key and parameter.
|
||||
* @param <E> the returned list element type
|
||||
* @param statement Unique identifier matching the statement to use.
|
||||
* @return List of mapped object
|
||||
*/
|
||||
<E> List<E> selectList(String statement);
|
||||
|
||||
/**
|
||||
* Retrieve a list of mapped objects from the statement key and parameter.
|
||||
* @param <E> the returned list element type
|
||||
* @param statement Unique identifier matching the statement to use.
|
||||
* @param parameter A parameter object to pass to the statement.
|
||||
* @return List of mapped object
|
||||
*/
|
||||
<E> List<E> selectList(String statement, Object parameter);
|
||||
|
||||
/**
|
||||
* Retrieve a list of mapped objects from the statement key and parameter,
|
||||
* within the specified row bounds.
|
||||
* @param <E> the returned list element type
|
||||
* @param statement Unique identifier matching the statement to use.
|
||||
* @param parameter A parameter object to pass to the statement.
|
||||
* @param rowBounds Bounds to limit object retrieval
|
||||
* @return List of mapped object
|
||||
*/
|
||||
<E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);
|
||||
|
||||
/**
|
||||
* The selectMap is a special case in that it is designed to convert a list
|
||||
* of results into a Map based on one of the properties in the resulting
|
||||
* objects.
|
||||
* Eg. Return a of Map[Integer,Author] for selectMap("selectAuthors","id")
|
||||
* @param <K> the returned Map keys type
|
||||
* @param <V> the returned Map values type
|
||||
* @param statement Unique identifier matching the statement to use.
|
||||
* @param mapKey The property to use as key for each value in the list.
|
||||
* @return Map containing key pair data.
|
||||
*/
|
||||
<K, V> Map<K, V> selectMap(String statement, String mapKey);
|
||||
|
||||
/**
|
||||
* The selectMap is a special case in that it is designed to convert a list
|
||||
* of results into a Map based on one of the properties in the resulting
|
||||
* objects.
|
||||
* @param <K> the returned Map keys type
|
||||
* @param <V> the returned Map values type
|
||||
* @param statement Unique identifier matching the statement to use.
|
||||
* @param parameter A parameter object to pass to the statement.
|
||||
* @param mapKey The property to use as key for each value in the list.
|
||||
* @return Map containing key pair data.
|
||||
*/
|
||||
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);
|
||||
|
||||
/**
|
||||
* The selectMap is a special case in that it is designed to convert a list
|
||||
* of results into a Map based on one of the properties in the resulting
|
||||
* objects.
|
||||
* @param <K> the returned Map keys type
|
||||
* @param <V> the returned Map values type
|
||||
* @param statement Unique identifier matching the statement to use.
|
||||
* @param parameter A parameter object to pass to the statement.
|
||||
* @param mapKey The property to use as key for each value in the list.
|
||||
* @param rowBounds Bounds to limit object retrieval
|
||||
* @return Map containing key pair data.
|
||||
*/
|
||||
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);
|
||||
|
||||
/**
|
||||
* Retrieve a single row mapped from the statement key and parameter
|
||||
* using a {@code ResultHandler}.
|
||||
*
|
||||
* @param statement Unique identifier matching the statement to use.
|
||||
* @param parameter A parameter object to pass to the statement.
|
||||
* @param handler ResultHandler that will handle each retrieved row
|
||||
*/
|
||||
default void select(String statement, Object parameter, ResultHandler handler) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a single row mapped from the statement
|
||||
* using a {@code ResultHandler}.
|
||||
* @param statement Unique identifier matching the statement to use.
|
||||
* @param handler ResultHandler that will handle each retrieved row
|
||||
*/
|
||||
void select(String statement, ResultHandler handler);
|
||||
|
||||
/**
|
||||
* Retrieve a single row mapped from the statement key and parameter
|
||||
* using a {@code ResultHandler} and {@code RowBounds}.
|
||||
* @param statement Unique identifier matching the statement to use.
|
||||
* @param rowBounds RowBound instance to limit the query results
|
||||
* @param handler ResultHandler that will handle each retrieved row
|
||||
*/
|
||||
void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);
|
||||
|
||||
/**
|
||||
* Execute an insert statement.
|
||||
* @param statement Unique identifier matching the statement to execute.
|
||||
* @return int The number of rows affected by the insert.
|
||||
*/
|
||||
int insert(String statement);
|
||||
|
||||
/**
|
||||
* Execute an insert statement with the given parameter object. Any generated
|
||||
* autoincrement values or selectKey entries will modify the given parameter
|
||||
* object properties. Only the number of rows affected will be returned.
|
||||
* @param statement Unique identifier matching the statement to execute.
|
||||
* @param parameter A parameter object to pass to the statement.
|
||||
* @return int The number of rows affected by the insert.
|
||||
*/
|
||||
int insert(String statement, Object parameter);
|
||||
|
||||
/**
|
||||
* Execute an update statement. The number of rows affected will be returned.
|
||||
* @param statement Unique identifier matching the statement to execute.
|
||||
* @return int The number of rows affected by the update.
|
||||
*/
|
||||
int update(String statement);
|
||||
|
||||
/**
|
||||
* Execute an update statement. The number of rows affected will be returned.
|
||||
* @param statement Unique identifier matching the statement to execute.
|
||||
* @param parameter A parameter object to pass to the statement.
|
||||
* @return int The number of rows affected by the update.
|
||||
*/
|
||||
int update(String statement, Object parameter);
|
||||
|
||||
/**
|
||||
* Execute a delete statement. The number of rows affected will be returned.
|
||||
* @param statement Unique identifier matching the statement to execute.
|
||||
* @return int The number of rows affected by the delete.
|
||||
*/
|
||||
int delete(String statement);
|
||||
|
||||
/**
|
||||
* Execute a delete statement. The number of rows affected will be returned.
|
||||
* @param statement Unique identifier matching the statement to execute.
|
||||
* @param parameter A parameter object to pass to the statement.
|
||||
* @return int The number of rows affected by the delete.
|
||||
*/
|
||||
int delete(String statement, Object parameter);
|
||||
|
||||
/**
|
||||
* Flushes batch statements and commits database connection.
|
||||
* Note that database connection will not be committed if no updates/deletes/inserts were called.
|
||||
* To force the commit call {@link SqlSession#commit(boolean)}
|
||||
*/
|
||||
void commit();
|
||||
|
||||
/**
|
||||
* Flushes batch statements and commits database connection.
|
||||
* @param force forces connection commit
|
||||
*/
|
||||
void commit(boolean force);
|
||||
|
||||
/**
|
||||
* Discards pending batch statements and rolls database connection back.
|
||||
* Note that database connection will not be rolled back if no updates/deletes/inserts were called.
|
||||
* To force the rollback call {@link SqlSession#rollback(boolean)}
|
||||
*/
|
||||
void rollback();
|
||||
|
||||
/**
|
||||
* Discards pending batch statements and rolls database connection back.
|
||||
* Note that database connection will not be rolled back if no updates/deletes/inserts were called.
|
||||
* @param force forces connection rollback
|
||||
*/
|
||||
void rollback(boolean force);
|
||||
|
||||
/**
|
||||
* Flushes batch statements.
|
||||
* @return BatchResult list of updated records
|
||||
* @since 3.0.6
|
||||
*/
|
||||
List<BatchResult> flushStatements();
|
||||
|
||||
/**
|
||||
* Closes the session.
|
||||
*/
|
||||
@Override
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Clears local session cache.
|
||||
*/
|
||||
void clearCache();
|
||||
|
||||
/**
|
||||
* Retrieves current configuration.
|
||||
* @return DbConfig
|
||||
*/
|
||||
DbConfig getDbConfig();
|
||||
|
||||
/**
|
||||
* Retrieves a mapper.
|
||||
* @param <T> the mapper type
|
||||
* @param type Mapper interface class
|
||||
* @return a mapper bound to this SqlSession
|
||||
*/
|
||||
<T> T getMapper(Class<T> type);
|
||||
|
||||
/**
|
||||
* Retrieves inner database connection.
|
||||
* @return Connection
|
||||
*/
|
||||
Connection getConnection();
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 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.crisp.session;
|
||||
|
||||
import fun.asgc.neutrino.core.db.crisp.DbConfig;
|
||||
import fun.asgc.neutrino.core.db.crisp.base.SqlExecutorType;
|
||||
import fun.asgc.neutrino.core.db.crisp.tx.TransactionIsolationLevel;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/4
|
||||
*/
|
||||
public interface SqlSessionFactory {
|
||||
|
||||
SqlSession openSession();
|
||||
|
||||
SqlSession openSession(boolean autoCommit);
|
||||
|
||||
SqlSession openSession(Connection connection);
|
||||
|
||||
SqlSession openSession(TransactionIsolationLevel level);
|
||||
|
||||
SqlSession openSession(SqlExecutorType execType);
|
||||
|
||||
SqlSession openSession(SqlExecutorType execType, boolean autoCommit);
|
||||
|
||||
SqlSession openSession(SqlExecutorType execType, TransactionIsolationLevel level);
|
||||
|
||||
SqlSession openSession(SqlExecutorType execType, Connection connection);
|
||||
|
||||
DbConfig getDbConfig();
|
||||
}
|
||||
+34
@@ -0,0 +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.core.db.crisp.session;
|
||||
|
||||
import fun.asgc.neutrino.core.db.crisp.DbConfig;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/7
|
||||
*/
|
||||
public class SqlSessionFactoryBuilder {
|
||||
public SqlSessionFactory build(DbConfig config) {
|
||||
return new DefaultSqlSessionFactory(config);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package fun.asgc.neutrino.core.db.crisp.tx;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/7
|
||||
*/
|
||||
@Slf4j
|
||||
public class JdbcTransaction implements Transaction {
|
||||
|
||||
protected Connection connection;
|
||||
protected DataSource dataSource;
|
||||
protected TransactionIsolationLevel level;
|
||||
protected boolean autoCommit;
|
||||
|
||||
public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
|
||||
dataSource = ds;
|
||||
level = desiredLevel;
|
||||
autoCommit = desiredAutoCommit;
|
||||
}
|
||||
|
||||
public JdbcTransaction(Connection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
if (connection == null) {
|
||||
openConnection();
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit() throws SQLException {
|
||||
if (connection != null && !connection.getAutoCommit()) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Committing JDBC Connection [" + connection + "]");
|
||||
}
|
||||
connection.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() throws SQLException {
|
||||
if (connection != null && !connection.getAutoCommit()) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Rolling back JDBC Connection [" + connection + "]");
|
||||
}
|
||||
connection.rollback();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws SQLException {
|
||||
if (connection != null) {
|
||||
resetAutoCommit();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Closing JDBC Connection [" + connection + "]");
|
||||
}
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTimeout() throws SQLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void openConnection() throws SQLException {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Opening JDBC Connection");
|
||||
}
|
||||
connection = dataSource.getConnection();
|
||||
if (level != null) {
|
||||
connection.setTransactionIsolation(level.getLevel());
|
||||
}
|
||||
setDesiredAutoCommit(autoCommit);
|
||||
}
|
||||
|
||||
protected void setDesiredAutoCommit(boolean desiredAutoCommit) {
|
||||
try {
|
||||
if (connection.getAutoCommit() != desiredAutoCommit) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + connection + "]");
|
||||
}
|
||||
connection.setAutoCommit(desiredAutoCommit);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
// Only a very poorly implemented driver would fail here,
|
||||
// and there's not much we can do about that.
|
||||
throw new TransactionException("Error configuring AutoCommit. "
|
||||
+ "Your driver may not support getAutoCommit() or setAutoCommit(). "
|
||||
+ "Requested setting: " + desiredAutoCommit + ". Cause: " + e, e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void resetAutoCommit() {
|
||||
try {
|
||||
if (!connection.getAutoCommit()) {
|
||||
// MyBatis does not call commit/rollback on a connection if just selects were performed.
|
||||
// Some databases start transactions with select statements
|
||||
// and they mandate a commit/rollback before closing the connection.
|
||||
// A workaround is setting the autocommit to true before closing the connection.
|
||||
// Sybase throws an exception here.
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Resetting autocommit to true on JDBC Connection [" + connection + "]");
|
||||
}
|
||||
connection.setAutoCommit(true);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Error resetting autocommit to true "
|
||||
+ "before closing the connection. Cause: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* 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.crisp.tx;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/7
|
||||
*/
|
||||
public interface Transaction {
|
||||
|
||||
/**
|
||||
* Retrieve inner database connection.
|
||||
* @return DataBase connection
|
||||
* @throws SQLException
|
||||
*/
|
||||
Connection getConnection() throws SQLException;
|
||||
|
||||
/**
|
||||
* Commit inner database connection.
|
||||
* @throws SQLException
|
||||
*/
|
||||
void commit() throws SQLException;
|
||||
|
||||
/**
|
||||
* Rollback inner database connection.
|
||||
* @throws SQLException
|
||||
*/
|
||||
void rollback() throws SQLException;
|
||||
|
||||
/**
|
||||
* Close inner database connection.
|
||||
* @throws SQLException
|
||||
*/
|
||||
void close() throws SQLException;
|
||||
|
||||
/**
|
||||
* Get transaction timeout if set.
|
||||
* @throws SQLException
|
||||
*/
|
||||
Integer getTimeout() throws SQLException;
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package fun.asgc.neutrino.core.db.crisp.tx;
|
||||
|
||||
import fun.asgc.neutrino.core.db.crisp.JdbcException;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/7
|
||||
*/
|
||||
public class TransactionException extends JdbcException {
|
||||
|
||||
public TransactionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public TransactionException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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.crisp.tx;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/4
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum TransactionIsolationLevel {
|
||||
NONE(Connection.TRANSACTION_NONE),
|
||||
READ_COMMITTED(Connection.TRANSACTION_READ_COMMITTED),
|
||||
READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),
|
||||
REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),
|
||||
SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE);
|
||||
|
||||
private final int level;
|
||||
}
|
||||
@@ -36,6 +36,10 @@ import java.util.function.Consumer;
|
||||
* @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 Cache<String, SimpleDateFormat> sdfCache = new MemoryCache<>();
|
||||
private static SimpleDateFormat getSimpleDateFormat(String format) {
|
||||
try {
|
||||
@@ -284,6 +288,30 @@ public class DateUtil {
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当天开始时间
|
||||
*
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function fetchList(query) {
|
||||
return request({
|
||||
url: '/user-login-record/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
@@ -52,7 +52,9 @@ export default {
|
||||
license: 'License管理',
|
||||
portMapping: '端口映射',
|
||||
jobManager: '调度管理',
|
||||
jobLog: '调度日志'
|
||||
jobLog: '调度日志',
|
||||
log: '日志管理',
|
||||
loginLog: '登录日志'
|
||||
},
|
||||
navbar: {
|
||||
logOut: '退出登录',
|
||||
@@ -135,7 +137,9 @@ export default {
|
||||
alarmDing: '任务报警钉钉',
|
||||
jobLogCode: '执行结果',
|
||||
jobLogMsg: '执行日志',
|
||||
alarmStatus: '报警状态'
|
||||
alarmStatus: '报警状态',
|
||||
ip: 'IP',
|
||||
happendTime: '发生时间'
|
||||
},
|
||||
errorLog: {
|
||||
tips: '请点击右上角bug小图标',
|
||||
|
||||
@@ -277,8 +277,21 @@ export const asyncRouterMap = [
|
||||
children: [
|
||||
{ path: 'user', component: _import('system/user'), name: 'user', meta: { title: 'user' }},
|
||||
{ path: 'portPool', component: _import('system/portPool'), name: 'portPool', meta: { title: 'portPool' }},
|
||||
{ path: 'jobManager', component: _import('system/jobManager'), name: 'jobManager', meta: { title: 'jobManager' }},
|
||||
{ path: 'jobLog', component: _import('system/jobLog'), name: 'jobLog', meta: { title: 'jobLog' }}
|
||||
{ path: 'jobManager', component: _import('system/jobManager'), name: 'jobManager', meta: { title: 'jobManager' }}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/log',
|
||||
component: Layout,
|
||||
redirect: 'noredirect',
|
||||
name: 'log',
|
||||
meta: {
|
||||
title: 'log',
|
||||
icon: 'component'
|
||||
},
|
||||
children: [
|
||||
{ path: 'jobLog', component: _import('log/jobLog'), name: 'jobLog', meta: { title: 'jobLog' }},
|
||||
{ path: 'loginLog', component: _import('log/loginLog'), name: 'loginLog', meta: { title: 'loginLog' }}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ export default {
|
||||
listLoading: false,
|
||||
listQuery: {
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
pageSize: 10,
|
||||
jobId: undefined
|
||||
},
|
||||
jobList: []
|
||||
@@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
<div class="filter-container">
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">{{$t('table.search')}}</el-button>
|
||||
</div>
|
||||
|
||||
<el-table :key='tableKey' :data="list" v-loading="listLoading" element-loading-text="给我一点时间" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column type="index" width="100" :label="$t('table.id')"></el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.userName')" min-width="200">
|
||||
<template slot-scope="scope">
|
||||
<span>{{scope.row.userName}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.ip')" min-width="200">
|
||||
<template slot-scope="scope">
|
||||
<span>{{scope.row.ip}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.type')" min-width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.type | typeFilter">{{scope.row.type | typeName}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.happendTime')" min-width="150">
|
||||
<template slot-scope="scope">
|
||||
<span>{{scope.row.createTime | parseTime('{y}-{m}-{d} {h}:{i}')}}</span>
|
||||
</template>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fetchList } from '@/api/loginLog'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
|
||||
export default {
|
||||
name: 'loginLog',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableKey: 0,
|
||||
list: null,
|
||||
total: null,
|
||||
listLoading: false,
|
||||
listQuery: {
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
jobId: undefined
|
||||
}
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
statusName(status) {
|
||||
const statusMap = {
|
||||
0: '成功',
|
||||
1: '失败'
|
||||
}
|
||||
return statusMap[status]
|
||||
},
|
||||
statusFilter(status) {
|
||||
const statusMap = {
|
||||
0: 'success',
|
||||
1: 'danger'
|
||||
}
|
||||
return statusMap[status]
|
||||
},
|
||||
typeName(type) {
|
||||
const typeMap = {
|
||||
1: '登录',
|
||||
2: '登出'
|
||||
}
|
||||
return typeMap[type]
|
||||
},
|
||||
typeFilter(type) {
|
||||
const typeMap = {
|
||||
1: 'success',
|
||||
2: 'danger'
|
||||
}
|
||||
return typeMap[type]
|
||||
},
|
||||
alarmStatusFilter(status) {
|
||||
const statusMap = {
|
||||
0: 'success',
|
||||
1: 'warning',
|
||||
2: 'success',
|
||||
3: 'danger'
|
||||
}
|
||||
return statusMap[status]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
activated() {
|
||||
if (this.$route.query.jobId) {
|
||||
this.listQuery.jobId = this.$route.query.jobId
|
||||
console.log(this.listQuery.jobId, this.$route.query.jobId)
|
||||
this.getList()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.listLoading = true
|
||||
fetchList(this.listQuery).then(response => {
|
||||
this.list = response.data.data.records
|
||||
this.total = response.data.data.total
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.currentPage = 1
|
||||
this.getList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.pageSize = val
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.listQuery.currentPage = val
|
||||
this.getList()
|
||||
},
|
||||
handleShowClick(row) {
|
||||
console.log(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -133,7 +133,7 @@
|
||||
listLoading: true,
|
||||
listQuery: {
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
pageSize: 10,
|
||||
importance: undefined,
|
||||
title: undefined,
|
||||
type: undefined
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
listLoading: true,
|
||||
listQuery: {
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
pageSize: 10,
|
||||
importance: undefined,
|
||||
title: undefined,
|
||||
type: undefined
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<el-button size="mini" type="text" @click="handleLogClick(scope.row)">查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.actions')" width="230" class-name="small-padding fixed-width">
|
||||
<el-table-column align="center" :label="$t('table.actions')" min-width="230" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="primary" @click="handleEditClick(scope.row)">编辑</el-button>
|
||||
<el-button size="mini" type="primary" @click="handleExecuteClick(scope.row)">执行</el-button>
|
||||
@@ -115,7 +115,7 @@
|
||||
listLoading: true,
|
||||
listQuery: {
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
pageSize: 10,
|
||||
importance: undefined,
|
||||
title: undefined,
|
||||
type: undefined
|
||||
@@ -225,7 +225,7 @@
|
||||
})
|
||||
},
|
||||
handleLogClick(row) {
|
||||
this.$router.push({ path: '/system/jobLog', query: { jobId: row.id }})
|
||||
this.$router.push({ path: '/log/jobLog', query: { jobId: row.id }})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<el-table :key='tableKey' :data="list" v-loading="listLoading" element-loading-text="给我一点时间" border fit highlight-current-row
|
||||
style="width: 100%">
|
||||
<el-table-column align="center" :label="$t('table.id')" width="100">
|
||||
<el-table-column align="center" :label="$t('table.id')" width="120">
|
||||
<template slot-scope="scope">
|
||||
<span>{{scope.row.id}}</span>
|
||||
</template>
|
||||
@@ -17,22 +17,22 @@
|
||||
<span>{{scope.row.port}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="150px" align="center" :label="$t('table.createTime')">
|
||||
<el-table-column width="200" align="center" :label="$t('table.createTime')">
|
||||
<template slot-scope="scope">
|
||||
<span>{{scope.row.createTime | parseTime('{y}-{m}-{d} {h}:{i}')}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="150px" align="center" :label="$t('table.updateTime')">
|
||||
<el-table-column width="200" align="center" :label="$t('table.updateTime')">
|
||||
<template slot-scope="scope">
|
||||
<span>{{scope.row.updateTime | parseTime('{y}-{m}-{d} {h}:{i}')}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column class-name="status-col" :label="$t('table.enableStatus')" width="100">
|
||||
<el-table-column class-name="status-col" :label="$t('table.enableStatus')" width="150">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.enable | statusFilter">{{scope.row.enable | statusName}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.actions')" width="230" class-name="small-padding fixed-width">
|
||||
<el-table-column align="center" :label="$t('table.actions')" width="250" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button v-if="scope.row.enable =='1'" size="mini" type="danger" @click="handleModifyStatus(scope.row,2)">{{$t('table.disable')}}</el-button>
|
||||
<el-button v-if="scope.row.enable =='2'" size="mini" type="success" @click="handleModifyStatus(scope.row,1)">{{$t('table.enable')}}</el-button>
|
||||
@@ -108,7 +108,7 @@
|
||||
listLoading: true,
|
||||
listQuery: {
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
pageSize: 10,
|
||||
importance: undefined,
|
||||
title: undefined,
|
||||
type: undefined
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
listLoading: true,
|
||||
listQuery: {
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
pageSize: 10,
|
||||
importance: undefined,
|
||||
title: undefined,
|
||||
type: undefined
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 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 lombok.Data;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/18
|
||||
*/
|
||||
@Data
|
||||
public class CustomConfig {
|
||||
private String jksPath;
|
||||
private String serverIp;
|
||||
private Integer serverPort;
|
||||
private Boolean sslEnable;
|
||||
private String licenseKey;
|
||||
}
|
||||
+1
@@ -39,6 +39,7 @@ public class ProxyConfig {
|
||||
private Protocol protocol;
|
||||
private Client client;
|
||||
private String licenseKey;
|
||||
private CustomConfig customConfig;
|
||||
public static volatile boolean authSuccess;
|
||||
|
||||
@Data
|
||||
|
||||
+1
@@ -32,6 +32,7 @@ import fun.asgc.neutrino.core.constant.MetaDataConstant;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 应用生命周期事件监听器
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/10
|
||||
*/
|
||||
|
||||
+79
-15
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
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;
|
||||
@@ -29,9 +30,12 @@ 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;
|
||||
@@ -39,7 +43,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
*
|
||||
* license获取服务
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/4
|
||||
*/
|
||||
@@ -82,29 +86,89 @@ public class LicenseObtainService {
|
||||
}
|
||||
|
||||
public void process(String[] args) {
|
||||
String licenseKey = getLicenseKey(args);
|
||||
proxyClientService.start(licenseKey);
|
||||
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 String getLicenseKey(String[] args) {
|
||||
String license = "";
|
||||
if (null != args && ArrayUtil.notEmpty(args)) {
|
||||
for (String s : args) {
|
||||
if (s.startsWith("license=") && s.length() > 8) {
|
||||
license = s.substring(8).trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
private CustomConfig getCustomConfigByCliParams(String[] args) {
|
||||
CustomConfig customConfig = new CustomConfig();
|
||||
// 默认无需输入
|
||||
customConfig.setJksPath(proxyConfig.getClient().getJksPath());
|
||||
customConfig.setServerIp(proxyConfig.getClient().getServerIp());
|
||||
customConfig.setServerPort(proxyConfig.getClient().getServerPort());
|
||||
customConfig.setSslEnable(proxyConfig.getClient().getSslEnable());
|
||||
// 从cli参数中取
|
||||
Map<String, String> cliParams = getCliParams(args);
|
||||
if (cliParams.containsKey("jksPath")) {
|
||||
customConfig.setJksPath(cliParams.get("jksPath"));
|
||||
}
|
||||
if (StringUtil.isEmpty(license)) {
|
||||
license = FileUtil.readContentAsString("./.neutrino-proxy.license");
|
||||
if (cliParams.containsKey("serverIp")) {
|
||||
customConfig.setServerIp(cliParams.get("serverIp"));
|
||||
}
|
||||
if (cliParams.containsKey("serverPort")) {
|
||||
customConfig.setServerPort(Integer.valueOf(cliParams.get("serverPort")));
|
||||
}
|
||||
if (cliParams.containsKey("sslEnable")) {
|
||||
customConfig.setSslEnable(Boolean.valueOf(cliParams.get("sslEnable")));
|
||||
}
|
||||
if (cliParams.containsKey("licenseKey")) {
|
||||
customConfig.setLicenseKey(cliParams.get("licenseKey"));
|
||||
}
|
||||
if (StringUtil.notEmpty(customConfig.getLicenseKey())) {
|
||||
// FileUtil.write("./.neutrino-proxy-client.json", JSONObject.toJSONString(customConfig, SerializerFeature.PrettyFormat));
|
||||
return customConfig;
|
||||
}
|
||||
|
||||
String config = FileUtil.readContentAsString("./.neutrino-proxy-client.json");
|
||||
if (StringUtil.notEmpty(config)) {
|
||||
try {
|
||||
customConfig = JSONObject.parseObject(config, CustomConfig.class);
|
||||
} catch (Exception e) {
|
||||
log.error("配置异常!", 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("请输入license:");
|
||||
license = scanner.next();
|
||||
}
|
||||
customConfig.setLicenseKey(license);
|
||||
// FileUtil.write("./.neutrino-proxy-client.json", JSONObject.toJSONString(customConfig, SerializerFeature.PrettyFormat));
|
||||
|
||||
return license;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
+70
-27
@@ -22,17 +22,16 @@
|
||||
|
||||
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.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.context.ApplicationRunner;
|
||||
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 fun.asgc.neutrino.proxy.client.config.ProxyConfig;
|
||||
import fun.asgc.neutrino.proxy.client.util.ProxyUtil;
|
||||
import fun.asgc.neutrino.proxy.core.*;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessage;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessageDecoder;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessageEncoder;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
@@ -48,10 +47,12 @@ import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyStore;
|
||||
import java.util.Scanner;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
*
|
||||
* 客户端服务
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@@ -69,23 +70,27 @@ public class ProxyClientService {
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
private volatile Channel channel;
|
||||
|
||||
public void start(String licenseKey) {
|
||||
if (StringUtil.isEmpty(licenseKey)) {
|
||||
return;
|
||||
}
|
||||
proxyConfig.setLicenseKey(licenseKey);
|
||||
if (null == channel || !channel.isActive()) {
|
||||
connectProxyServer();
|
||||
} else {
|
||||
channel.writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getLicenseKey()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接代理服务器
|
||||
* 重连间隔(秒)
|
||||
*/
|
||||
private void connectProxyServer() {
|
||||
private static final long RECONNECT_INTERVAL_SECONDS = 5;
|
||||
/**
|
||||
* 重连次数
|
||||
*/
|
||||
private volatile int reconnectCount = 0;
|
||||
/**
|
||||
* 启用重连服务
|
||||
*/
|
||||
private volatile boolean reconnectServiceEnable = false;
|
||||
/**
|
||||
* 重连服务执行器
|
||||
*/
|
||||
private static final ScheduledExecutorService reconnectExecutor = Executors.newSingleThreadScheduledExecutor(new CustomThreadFactory("ClientReconnect"));
|
||||
|
||||
@Init
|
||||
public void init() {
|
||||
this.reconnectExecutor.scheduleWithFixedDelay(this::reconnect, 0, RECONNECT_INTERVAL_SECONDS, TimeUnit.SECONDS);
|
||||
|
||||
workerGroup = new NioEventLoopGroup();
|
||||
realServerBootstrap.group(workerGroup);
|
||||
realServerBootstrap.channel(NioSocketChannel.class);
|
||||
@@ -108,13 +113,34 @@ public class ProxyClientService {
|
||||
}
|
||||
|
||||
ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(),
|
||||
proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(),
|
||||
proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip()));
|
||||
proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(),
|
||||
proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip()));
|
||||
ch.pipeline().addLast(new ProxyMessageEncoder());
|
||||
ch.pipeline().addLast(new IdleStateHandler(proxyConfig.getProtocol().getReadIdleTime(), proxyConfig.getProtocol().getWriteIdleTime(), proxyConfig.getProtocol().getAllIdleTimeSeconds()));
|
||||
ch.pipeline().addLast(new ClientChannelHandler());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (StringUtil.isEmpty(proxyConfig.getLicenseKey())) {
|
||||
return;
|
||||
}
|
||||
if (null == channel || !channel.isActive()) {
|
||||
try {
|
||||
connectProxyServer();
|
||||
} catch (Exception e) {
|
||||
log.error("启动异常", e);
|
||||
}
|
||||
} else {
|
||||
channel.writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getLicenseKey()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接代理服务器
|
||||
*/
|
||||
private void connectProxyServer() throws InterruptedException {
|
||||
bootstrap.connect(proxyConfig.getClient().getServerIp(), proxyConfig.getClient().getServerPort())
|
||||
.addListener(new ChannelFutureListener() {
|
||||
|
||||
@@ -126,12 +152,14 @@ public class ProxyClientService {
|
||||
ProxyUtil.setCmdChannel(future.channel());
|
||||
future.channel().writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getLicenseKey()));
|
||||
log.info("连接代理服务成功. channelId:{}", future.channel().id().asLongText());
|
||||
|
||||
reconnectServiceEnable = true;
|
||||
reconnectCount = 0;
|
||||
} else {
|
||||
log.info("连接代理服务失败!");
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}).sync();
|
||||
}
|
||||
|
||||
private ChannelHandler createSslHandler() {
|
||||
@@ -157,6 +185,21 @@ public class ProxyClientService {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected synchronized void reconnect() {
|
||||
if (!reconnectServiceEnable) {
|
||||
return;
|
||||
}
|
||||
if (null != channel && channel.isActive()) {
|
||||
return;
|
||||
}
|
||||
log.info("客户端重连 seq:{}", ++reconnectCount);
|
||||
try {
|
||||
connectProxyServer();
|
||||
} catch (Exception e) {
|
||||
log.error("重连异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Bootstrap bootstrap() {
|
||||
return new Bootstrap();
|
||||
|
||||
+5
-5
@@ -42,15 +42,15 @@ public class RealServerChannelHandler extends SimpleChannelInboundHandler<ByteBu
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf buf) throws Exception {
|
||||
Channel realServerChannel = ctx.channel();
|
||||
Channel channel = realServerChannel.attr(Constants.NEXT_CHANNEL).get();
|
||||
if (channel == null) {
|
||||
Channel proxyChannel = realServerChannel.attr(Constants.NEXT_CHANNEL).get();
|
||||
if (null == proxyChannel) {
|
||||
// 代理客户端连接断开
|
||||
ctx.channel().close();
|
||||
} else {
|
||||
byte[] bytes = new byte[buf.readableBytes()];
|
||||
buf.readBytes(bytes);
|
||||
String visitorId = ProxyUtil.getRealServerChannelVisitorId(realServerChannel);
|
||||
channel.writeAndFlush(ProxyMessage.buildTransferMessage(visitorId, bytes));
|
||||
String visitorId = ProxyUtil.getVisitorIdByRealServerChannel(realServerChannel);
|
||||
proxyChannel.writeAndFlush(ProxyMessage.buildTransferMessage(visitorId, bytes));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ public class RealServerChannelHandler extends SimpleChannelInboundHandler<ByteBu
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
Channel realServerChannel = ctx.channel();
|
||||
String visitorId = ProxyUtil.getRealServerChannelVisitorId(realServerChannel);
|
||||
String visitorId = ProxyUtil.getVisitorIdByRealServerChannel(realServerChannel);
|
||||
ProxyUtil.removeRealServerChannel(visitorId);
|
||||
Channel channel = realServerChannel.attr(Constants.NEXT_CHANNEL).get();
|
||||
if (channel != null) {
|
||||
|
||||
+5
-3
@@ -22,6 +22,7 @@
|
||||
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;
|
||||
@@ -37,7 +38,7 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
*
|
||||
* 认证信息处理器
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/4
|
||||
*/
|
||||
@@ -48,17 +49,18 @@ import lombok.extern.slf4j.Slf4j;
|
||||
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");
|
||||
String licenseKey = data.getString("licenseKey");
|
||||
log.info("认证结果:{}", info);
|
||||
if (ExceptionEnum.SUCCESS.getCode().equals(code)) {
|
||||
ProxyConfig.authSuccess = true;
|
||||
FileUtil.write("./.neutrino-proxy.license", licenseKey);
|
||||
FileUtil.write("./.neutrino-proxy-client.json", JSONObject.toJSONString(proxyConfig.getCustomConfig(), SerializerFeature.PrettyFormat));
|
||||
licenseObtainService.stop();
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -34,7 +34,7 @@ import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* 连接信息处理器
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@@ -54,6 +54,7 @@ public class ProxyMessageConnectHandler implements ProxyMessageHandler {
|
||||
String[] serverInfo = new String(proxyMessage.getData()).split(":");
|
||||
String ip = serverInfo[0];
|
||||
int port = Integer.parseInt(serverInfo[1]);
|
||||
// 连接真实的、被代理的服务
|
||||
realServerBootstrap.connect(ip, port).addListener(new ChannelFutureListener() {
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
/**
|
||||
*
|
||||
* 断开连接信息处理器
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
*
|
||||
* 异常信息处理器
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
/**
|
||||
*
|
||||
* 传输信息处理器
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
|
||||
+2
-2
@@ -38,7 +38,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
/**
|
||||
*
|
||||
* 代理工具
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/31
|
||||
*/
|
||||
@@ -101,7 +101,7 @@ public class ProxyUtil {
|
||||
realServerChannel.attr(Constants.VISITOR_ID).set(visitorId);
|
||||
}
|
||||
|
||||
public static String getRealServerChannelVisitorId(Channel realServerChannel) {
|
||||
public static String getVisitorIdByRealServerChannel(Channel realServerChannel) {
|
||||
return realServerChannel.attr(Constants.VISITOR_ID).get();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -115,9 +114,9 @@ public class ProxyMessage {
|
||||
.setInfo(data.toJSONString());
|
||||
}
|
||||
|
||||
public static ProxyMessage buildConnectMessage(String info) {
|
||||
public static ProxyMessage buildConnectMessage(String visitorId) {
|
||||
return create().setType(TYPE_CONNECT)
|
||||
.setInfo(info);
|
||||
.setInfo(visitorId);
|
||||
}
|
||||
|
||||
public static ProxyMessage buildDisconnectMessage(String info) {
|
||||
@@ -125,9 +124,9 @@ public class ProxyMessage {
|
||||
.setInfo(info);
|
||||
}
|
||||
|
||||
public static ProxyMessage buildTransferMessage(String info, byte[] data) {
|
||||
public static ProxyMessage buildTransferMessage(String visitorId, byte[] data) {
|
||||
return create().setType(TYPE_TRANSFER)
|
||||
.setInfo(info)
|
||||
.setInfo(visitorId)
|
||||
.setData(data);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ 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.base.GlobalConfig;
|
||||
import fun.asgc.neutrino.core.context.NeutrinoLauncher;
|
||||
|
||||
/**
|
||||
|
||||
+7
-1
@@ -40,7 +40,13 @@ public class SystemContextHolder {
|
||||
}
|
||||
|
||||
public static UserDO getUser() {
|
||||
return systemContextHolder.get().getUser();
|
||||
SystemContext context = getContext();
|
||||
return (null == context) ? null : context.getUser();
|
||||
}
|
||||
|
||||
public static Integer getUserId() {
|
||||
UserDO userDO = getUser();
|
||||
return (null == userDO) ? null : userDO.getId();
|
||||
}
|
||||
|
||||
public static String getToken() {
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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.constant;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/23
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ClientConnectTypeEnum {
|
||||
CONNECT(1, "连接"),
|
||||
DISCONNECT(2, "断开连接");
|
||||
|
||||
private Integer type;
|
||||
private String desc;
|
||||
}
|
||||
+3
@@ -45,6 +45,9 @@ public enum ExceptionConstant {
|
||||
// license管理(12000)
|
||||
LICENSE_NAME_CANNOT_REPEAT(12000, "license名称不能重复"),
|
||||
LICENSE_NOT_EXIST(12001, "license数据不存在"),
|
||||
ORIGIN_PASSWORD_CHECK_FAIL(12002, "原密码验证失败"),
|
||||
LOGIN_PASSWORD_LENGTH_CHECK_FAIL(12003, "登录密码不能小于6位数"),
|
||||
LOGIN_PASSWORD_NO_CHANGE_MODIFY_FAIL(12004, "密码没有变化,修改失败"),
|
||||
// 端口池管理(13000)
|
||||
PORT_CANNOT_REPEAT(13000,"端口不能重复"),
|
||||
PORT_NOT_EXIST(13001, "该端口在端口池中不存在,不允许映射"),
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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.constant;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/23
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum SuccessCodeEnum {
|
||||
SUCCESS(1, "成功"),
|
||||
FAIL(2, "失败");
|
||||
|
||||
private Integer code;
|
||||
private String desc;
|
||||
}
|
||||
+13
@@ -37,6 +37,19 @@ import fun.asgc.neutrino.proxy.server.controller.res.ReportDataViewRes;
|
||||
@RestController
|
||||
public class ReportController {
|
||||
|
||||
/**
|
||||
* 数据一览:
|
||||
* 在线用户数 查询token有效的用户ID数
|
||||
* 在线Client数 查询license表,状态为在线的数量
|
||||
* 今日流量 上行/下行/总计
|
||||
* 历史流量 上行/下行/总计
|
||||
*
|
||||
* 1、点击在线用户数:下方展示在线的用户列表,带分页
|
||||
* 2、点击在线client数:下方展示在线的license列表,带分页
|
||||
* 3、点击今日流量:下方展示今日的流量折线图(小时)。 筛选项:全部/用户列表
|
||||
* 4、点击历史流量:下方展示历史流量折线图。筛选项:日/月 日期选择:日(展示最近30天,最多跨30日),月(展示最近12个月,最多跨12个月)
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("data-view")
|
||||
public ReportDataViewRes dataView() {
|
||||
return new ReportDataViewRes()
|
||||
|
||||
+23
@@ -26,10 +26,15 @@ 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.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.*;
|
||||
import fun.asgc.neutrino.proxy.server.dal.UserMapper;
|
||||
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 java.util.List;
|
||||
@@ -45,6 +50,8 @@ import java.util.List;
|
||||
public class UserController {
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
@Autowired
|
||||
private UserMapper userMapper;
|
||||
|
||||
@GetMapping("page")
|
||||
public Page<UserListRes> page(PageQuery pageQuery, UserListReq req) {
|
||||
@@ -101,6 +108,22 @@ public class UserController {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getId(), "id");
|
||||
ParamCheckUtil.checkNotEmpty(req.getLoginPassword(), "loginPassword");
|
||||
ParamCheckUtil.checkExpression(req.getLoginPassword().length() >= 6, ExceptionConstant.LOGIN_PASSWORD_LENGTH_CHECK_FAIL);
|
||||
|
||||
return userService.updatePassword(req);
|
||||
}
|
||||
|
||||
@PostMapping("current-user/update/password")
|
||||
public UserUpdatePasswordRes currentUserUpdatePassword(@RequestBody UserUpdatePasswordReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotEmpty(req.getOldLoginPassword(), "oldLoginPassword");
|
||||
ParamCheckUtil.checkNotEmpty(req.getLoginPassword(), "loginPassword");
|
||||
req.setId(SystemContextHolder.getUserId());
|
||||
ParamCheckUtil.checkExpression(req.getLoginPassword().length() >= 6, ExceptionConstant.LOGIN_PASSWORD_LENGTH_CHECK_FAIL);
|
||||
// 验证原密码
|
||||
Integer userId = req.getId();
|
||||
UserDO userDO = userMapper.findById(userId);
|
||||
ParamCheckUtil.checkExpression(Md5Util.encode(req.getOldLoginPassword()).equals(userDO.getLoginPassword()), ExceptionConstant.ORIGIN_PASSWORD_CHECK_FAIL);
|
||||
|
||||
return userService.updatePassword(req);
|
||||
}
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 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.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;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/20
|
||||
*/
|
||||
@NonIntercept
|
||||
@RequestMapping("user-login-record")
|
||||
@RestController
|
||||
public class UserLoginRecordController {
|
||||
@Autowired
|
||||
private UserLoginRecordService userLoginRecordService;
|
||||
|
||||
@GetMapping("page")
|
||||
public Page<UserLoginRecordListRes> page(PageQuery pageQuery, UserLoginRecordListReq req) {
|
||||
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
|
||||
|
||||
return userLoginRecordService.page(pageQuery, req);
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +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.controller.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 用户登录日志列表请求
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/20
|
||||
*/
|
||||
@Data
|
||||
public class UserLoginRecordListReq {
|
||||
|
||||
}
|
||||
+1
@@ -31,5 +31,6 @@ import lombok.Data;
|
||||
@Data
|
||||
public class UserUpdatePasswordReq {
|
||||
private Integer id;
|
||||
private String oldLoginPassword;
|
||||
private String loginPassword;
|
||||
}
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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 lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户登录日志列表响应
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/20
|
||||
*/
|
||||
@Data
|
||||
public class UserLoginRecordListRes {
|
||||
private Integer id;
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Integer userId;
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String userName;
|
||||
/**
|
||||
* ip
|
||||
*/
|
||||
private String ip;
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private Integer type;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
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;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.ClientConnectRecordDO;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/23
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface ClientConnectRecordMapper extends SqlMapper {
|
||||
|
||||
void add(ClientConnectRecordDO clientConnectRecordDO);
|
||||
}
|
||||
+26
-2
@@ -1,3 +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.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
@@ -5,8 +26,6 @@ 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
|
||||
@@ -18,4 +37,9 @@ public interface DataCleanMapper extends SqlMapper {
|
||||
@Delete("delete from `job_log` where create_time < ?")
|
||||
void cleanJobLog(long date);
|
||||
|
||||
@Delete("delete from `user_login_record` where create_time < ?")
|
||||
void cleanUserLoginRecord(long date);
|
||||
|
||||
@Delete("delete from `client_connect_record` where create_time < ?")
|
||||
void cleanClientConnectRecord(long date);
|
||||
}
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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.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.proxy.server.dal.entity.FlowReportDayDO;
|
||||
|
||||
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);
|
||||
|
||||
@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);
|
||||
|
||||
@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);
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* 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.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.proxy.server.dal.entity.FlowReportHourDO;
|
||||
|
||||
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);
|
||||
|
||||
@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);
|
||||
|
||||
@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);
|
||||
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* 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.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.proxy.server.dal.entity.FlowReportMinuteDO;
|
||||
|
||||
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);
|
||||
|
||||
@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);
|
||||
|
||||
@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);
|
||||
|
||||
@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);
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 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.Insert;
|
||||
import fun.asgc.neutrino.core.db.annotation.Select;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportMonthDO;
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
@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);
|
||||
}
|
||||
+7
-1
@@ -30,7 +30,6 @@ 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.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.LicenseListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.LicenseListRes;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.LicenseDO;
|
||||
@@ -59,6 +58,10 @@ public interface LicenseMapper extends SqlMapper {
|
||||
@Select("select * from license where enable = 1")
|
||||
List<LicenseListRes> list();
|
||||
|
||||
@ResultType(LicenseDO.class)
|
||||
@Select("select * from license")
|
||||
List<LicenseDO> listAll();
|
||||
|
||||
/**
|
||||
* 新增license
|
||||
* @param license
|
||||
@@ -71,6 +74,9 @@ public interface LicenseMapper extends SqlMapper {
|
||||
@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);
|
||||
|
||||
@Update("update `license` set is_online = :isOnline, update_time = :updateTime")
|
||||
void updateOnlineStatus(@Param("isOnline") Integer isOnline, @Param("updateTime") Date 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);
|
||||
|
||||
|
||||
+3
@@ -79,4 +79,7 @@ public interface PortMappingMapper extends SqlMapper {
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
+9
@@ -24,7 +24,12 @@ 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 fun.asgc.neutrino.proxy.server.dal.entity.UserLoginRecordDO;
|
||||
|
||||
/**
|
||||
@@ -42,4 +47,8 @@ public interface UserLoginRecordMapper extends SqlMapper {
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ 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 fun.asgc.neutrino.proxy.server.dal.entity.PortPoolDO;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
+7
-2
@@ -25,8 +25,6 @@ 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.annotation.Update;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.UserTokenDO;
|
||||
@@ -69,4 +67,11 @@ public interface UserTokenMapper extends SqlMapper {
|
||||
|
||||
@Update("update user_token set expiration_time = :expirationTime where token = :token")
|
||||
void updateTokenExpirationTime(@Param("token") String token, @Param("expirationTime") Date expirationTime);
|
||||
|
||||
/**
|
||||
* 根据userId删除token
|
||||
* @param userId
|
||||
*/
|
||||
@Delete("delete from user_token where user_id = ?")
|
||||
void deleteByUserId(Integer userId);
|
||||
}
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
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 lombok.Data;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/23
|
||||
*/
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
@Table("client_connect_record")
|
||||
public class ClientConnectRecordDO {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String ip;
|
||||
private Integer licenseId;
|
||||
private Integer type;
|
||||
private String msg;
|
||||
/**
|
||||
* 1、成功
|
||||
* 2、失败
|
||||
*/
|
||||
private Integer code;
|
||||
private String err;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
}
|
||||
+37
-49
@@ -21,64 +21,52 @@
|
||||
*/
|
||||
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 lombok.Data;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/31
|
||||
* @date: 2022/10/24
|
||||
*/
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
@Table("user_connect_record")
|
||||
public class UserConnectRecordDO {
|
||||
private Integer id;
|
||||
/**
|
||||
* 服务端端口号
|
||||
*/
|
||||
private Integer serverPort;
|
||||
/**
|
||||
* userIp
|
||||
*/
|
||||
private String userIp;
|
||||
/**
|
||||
* 客户端IP
|
||||
*/
|
||||
private String clientIp;
|
||||
/**
|
||||
* 客户端信息
|
||||
*/
|
||||
private String clientLanInfo;
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private String userId;
|
||||
/**
|
||||
* licenseId
|
||||
*/
|
||||
private Integer licenseId;
|
||||
/**
|
||||
* licenseKey
|
||||
*/
|
||||
private String licenseKey;
|
||||
/**
|
||||
* writeBytes
|
||||
*/
|
||||
private Integer writeBytes;
|
||||
/**
|
||||
* readBytes
|
||||
*/
|
||||
private Integer readBytes;
|
||||
/**
|
||||
* type
|
||||
*/
|
||||
private Integer type;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
@Table("flow_report_day")
|
||||
public class FlowReportDayDO {
|
||||
@Id
|
||||
private Integer id;
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Integer userId;
|
||||
/**
|
||||
* licenseId
|
||||
*/
|
||||
private Integer licenseId;
|
||||
/**
|
||||
* 写入字节数
|
||||
*/
|
||||
private Long writeBytes;
|
||||
/**
|
||||
* 读取字节数
|
||||
*/
|
||||
private Long readBytes;
|
||||
/**
|
||||
* 报表统计时间
|
||||
*/
|
||||
private Date date;
|
||||
/**
|
||||
* 报表统计时间
|
||||
* yyyy-MM-dd
|
||||
*/
|
||||
private String dateStr;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 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.entity;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import fun.asgc.neutrino.core.db.annotation.Table;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/24
|
||||
*/
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
@Table("flow_report_hour")
|
||||
public class FlowReportHourDO {
|
||||
@Id
|
||||
private Integer id;
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Integer userId;
|
||||
/**
|
||||
* licenseId
|
||||
*/
|
||||
private Integer licenseId;
|
||||
/**
|
||||
* 写入字节数
|
||||
*/
|
||||
private Long writeBytes;
|
||||
/**
|
||||
* 读取字节数
|
||||
*/
|
||||
private Long readBytes;
|
||||
/**
|
||||
* 报表统计时间
|
||||
*/
|
||||
private Date date;
|
||||
/**
|
||||
* 报表统计时间
|
||||
* yyyy-MM-dd HH
|
||||
*/
|
||||
private String dateStr;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 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.entity;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import fun.asgc.neutrino.core.db.annotation.Table;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/24
|
||||
*/
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
@Table("flow_report_minute")
|
||||
public class FlowReportMinuteDO {
|
||||
@Id
|
||||
private Integer id;
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Integer userId;
|
||||
/**
|
||||
* licenseId
|
||||
*/
|
||||
private Integer licenseId;
|
||||
/**
|
||||
* 写入字节数
|
||||
*/
|
||||
private Integer writeBytes;
|
||||
/**
|
||||
* 读取字节数
|
||||
*/
|
||||
private Integer readBytes;
|
||||
/**
|
||||
* 报表统计时间
|
||||
*/
|
||||
private Date date;
|
||||
/**
|
||||
* 报表统计时间
|
||||
* yyyy-MM-dd HH:mm
|
||||
*/
|
||||
private String dateStr;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 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.entity;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import fun.asgc.neutrino.core.db.annotation.Table;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/24
|
||||
*/
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
@Table("flow_report_month")
|
||||
public class FlowReportMonthDO {
|
||||
@Id
|
||||
private Integer id;
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Integer userId;
|
||||
/**
|
||||
* licenseId
|
||||
*/
|
||||
private Integer licenseId;
|
||||
/**
|
||||
* 写入字节数
|
||||
*/
|
||||
private Long writeBytes;
|
||||
/**
|
||||
* 读取字节数
|
||||
*/
|
||||
private Long readBytes;
|
||||
/**
|
||||
* 报表统计时间
|
||||
*/
|
||||
private Date date;
|
||||
/**
|
||||
* 报表统计时间
|
||||
* yyyy-MM
|
||||
*/
|
||||
private String dateStr;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
}
|
||||
+51
-4
@@ -1,3 +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.job;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
@@ -34,14 +55,36 @@ public class DataCleanJob implements IJobHandler {
|
||||
* Job日志保存天数
|
||||
*/
|
||||
private static final Integer JOB_LOG_KEEP_DAYS = 7;
|
||||
/**
|
||||
* 用户登录日志保留天数
|
||||
*/
|
||||
private static final Integer USER_LOGIN_RECORD_KEEP_DAYS = 30;
|
||||
/**
|
||||
* 客户端连接记录保留天数
|
||||
*/
|
||||
private static final Integer CLIENT_CONNECT_RECORD_KEEP_DAYS = 30;
|
||||
|
||||
@Override
|
||||
public void execute(String s) throws Exception {
|
||||
JobParams jobParams = getParams(s);
|
||||
|
||||
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getJobLogKeepDays());
|
||||
log.info("清理调度管理日志 date:{}", sdf.format(date));
|
||||
dataCleanMapper.cleanJobLog(date.getTime());
|
||||
{
|
||||
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getJobLogKeepDays());
|
||||
log.info("清理调度管理日志 date:{}", sdf.format(date));
|
||||
dataCleanMapper.cleanJobLog(date.getTime());
|
||||
}
|
||||
|
||||
{
|
||||
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getUserLoginRecordKeepDays());
|
||||
log.info("清理用户登录日志 date:{}", sdf.format(date));
|
||||
dataCleanMapper.cleanUserLoginRecord(date.getTime());
|
||||
}
|
||||
|
||||
{
|
||||
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getClientConnectRecordKeepDays());
|
||||
log.info("清理客户端连接日志 date:{}", sdf.format(date));
|
||||
dataCleanMapper.cleanClientConnectRecord(date.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
public static JobParams getParams(String s) {
|
||||
@@ -53,12 +96,16 @@ public class DataCleanJob implements IJobHandler {
|
||||
// ignore
|
||||
}
|
||||
return new JobParams()
|
||||
.setJobLogKeepDays(JOB_LOG_KEEP_DAYS);
|
||||
.setJobLogKeepDays(JOB_LOG_KEEP_DAYS)
|
||||
.setUserLoginRecordKeepDays(USER_LOGIN_RECORD_KEEP_DAYS)
|
||||
.setClientConnectRecordKeepDays(CLIENT_CONNECT_RECORD_KEEP_DAYS);
|
||||
}
|
||||
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
public static class JobParams {
|
||||
private Integer jobLogKeepDays;
|
||||
private Integer userLoginRecordKeepDays;
|
||||
private Integer clientConnectRecordKeepDays;
|
||||
}
|
||||
}
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* 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 fun.asgc.neutrino.proxy.server.dal.FlowReportDayMapper;
|
||||
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.FlowReportDayDO;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportHourDO;
|
||||
import fun.asgc.neutrino.proxy.server.service.FlowReportService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/28
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
@JobHandler(name = "FlowReportForDayJob", cron = "0 0 1 * * ?", param = "")
|
||||
public class FlowReportForDayJob implements IJobHandler {
|
||||
@Autowired
|
||||
private FlowReportService flowReportService;
|
||||
@Autowired
|
||||
private LicenseMapper licenseMapper;
|
||||
@Autowired
|
||||
private FlowReportMinuteMapper flowReportMinuteMapper;
|
||||
@Autowired
|
||||
private FlowReportHourMapper flowReportHourMapper;
|
||||
@Autowired
|
||||
private FlowReportDayMapper flowReportDayMapper;
|
||||
|
||||
@Override
|
||||
public void execute(String param) throws Exception {
|
||||
Date now = new Date();
|
||||
String dateStr = DateUtil.format(DateUtil.addDate(now, Calendar.DATE, -1), "yyyy-MM-dd");
|
||||
Date date = DateUtil.parse(dateStr, "yyyy-MM-dd");
|
||||
Date startHourDate = DateUtil.getDayBegin(date);
|
||||
Date endHourDate = DateUtil.getDayEnd(date);
|
||||
|
||||
// 删除原来的记录
|
||||
flowReportDayMapper.deleteByDateStr(dateStr);
|
||||
|
||||
// 查询前一天的小时级别统计数据
|
||||
List<FlowReportHourDO> flowReportHourDOList = flowReportHourMapper.findListByDateRange(startHourDate, endHourDate);
|
||||
if (CollectionUtil.isEmpty(flowReportHourDOList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 汇总前一个天的天级别统计数据
|
||||
Map<Integer, FlowReportDayDO> map = new HashMap<>();
|
||||
for (FlowReportHourDO item : flowReportHourDOList) {
|
||||
FlowReportDayDO report = map.get(item.getLicenseId());
|
||||
if (null == report) {
|
||||
report = new FlowReportDayDO();
|
||||
map.put(item.getLicenseId(), report);
|
||||
}
|
||||
Long writeBytes = report.getWriteBytes() == null ? 0 : report.getWriteBytes();
|
||||
Long readBytes = report.getReadBytes() == null ? 0 : report.getReadBytes();
|
||||
|
||||
report.setUserId(item.getUserId());
|
||||
report.setLicenseId(item.getLicenseId());
|
||||
report.setWriteBytes(writeBytes + item.getWriteBytes());
|
||||
report.setReadBytes(readBytes + item.getReadBytes());
|
||||
report.setDate(date);
|
||||
report.setDateStr(dateStr);
|
||||
report.setCreateTime(now);
|
||||
}
|
||||
|
||||
for (FlowReportDayDO item : map.values()) {
|
||||
flowReportDayMapper.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* 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 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 lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/28
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
@JobHandler(name = "FlowReportForHourJob", cron = "0 0 */1 * * ?", param = "")
|
||||
public class FlowReportForHourJob implements IJobHandler {
|
||||
@Autowired
|
||||
private FlowReportService flowReportService;
|
||||
@Autowired
|
||||
private LicenseMapper licenseMapper;
|
||||
@Autowired
|
||||
private FlowReportMinuteMapper flowReportMinuteMapper;
|
||||
@Autowired
|
||||
private FlowReportHourMapper flowReportHourMapper;
|
||||
|
||||
@Override
|
||||
public void execute(String param) throws Exception {
|
||||
Date now = new Date();
|
||||
String dateStr = DateUtil.format(DateUtil.addDate(now, Calendar.HOUR, -1), "yyyy-MM-dd HH");
|
||||
Date date = DateUtil.parse(dateStr, "yyyy-MM-dd HH");
|
||||
Date startHourDate = DateUtil.getHourBegin(date);
|
||||
Date endHourDate = DateUtil.getHourEnd(date);
|
||||
|
||||
// 删除原来的记录
|
||||
flowReportHourMapper.deleteByDateStr(dateStr);
|
||||
|
||||
// 查询前一个小时的分钟级别统计数据
|
||||
List<FlowReportMinuteDO> flowReportMinuteDOList = flowReportMinuteMapper.findListByDateRange(startHourDate, endHourDate);
|
||||
if (CollectionUtil.isEmpty(flowReportMinuteDOList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 汇总前一个小时的小时级别统计数据
|
||||
Map<Integer, FlowReportHourDO> map = new HashMap<>();
|
||||
for (FlowReportMinuteDO item : flowReportMinuteDOList) {
|
||||
FlowReportHourDO report = map.get(item.getLicenseId());
|
||||
if (null == report) {
|
||||
report = new FlowReportHourDO();
|
||||
map.put(item.getLicenseId(), report);
|
||||
}
|
||||
Long writeBytes = report.getWriteBytes() == null ? 0 : report.getWriteBytes();
|
||||
Long readBytes = report.getReadBytes() == null ? 0 : report.getReadBytes();
|
||||
|
||||
report.setUserId(item.getUserId());
|
||||
report.setLicenseId(item.getLicenseId());
|
||||
report.setWriteBytes(writeBytes + item.getWriteBytes());
|
||||
report.setReadBytes(readBytes + item.getReadBytes());
|
||||
report.setDate(date);
|
||||
report.setDateStr(dateStr);
|
||||
report.setCreateTime(now);
|
||||
}
|
||||
|
||||
for (FlowReportHourDO item : map.values()) {
|
||||
flowReportHourMapper.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+95
@@ -0,0 +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.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 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 lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 流量统计报表 - 分钟级别
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/24
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
@JobHandler(name = "FlowReportForMinuteJob", cron = "0 */1 * * * ?", param = "")
|
||||
public class FlowReportForMinuteJob implements IJobHandler {
|
||||
|
||||
@Autowired
|
||||
private FlowReportService flowReportService;
|
||||
@Autowired
|
||||
private LicenseMapper licenseMapper;
|
||||
@Autowired
|
||||
private FlowReportMinuteMapper flowReportMinuteMapper;
|
||||
|
||||
@Override
|
||||
public void execute(String param) throws Exception {
|
||||
List<LicenseDO> list = licenseMapper.listAll();
|
||||
if (CollectionUtil.isEmpty(list)) {
|
||||
return;
|
||||
}
|
||||
Set<Integer> licenseIds = list.stream().map(LicenseDO::getId).collect(Collectors.toSet());
|
||||
Date now = new Date();
|
||||
String dateStr = DateUtil.format(DateUtil.addDate(now, Calendar.MINUTE, -1), "yyyy-MM-dd HH:mm");
|
||||
Date date = DateUtil.parse(dateStr, "yyyy-MM-dd HH:mm");
|
||||
List<FlowReportMinuteDO> oldList = flowReportMinuteMapper.findList(licenseIds, dateStr);
|
||||
Map<Integer, FlowReportMinuteDO> oldMap = CollectionUtil.isEmpty(oldList) ? new HashMap<>() :
|
||||
oldList.stream().collect(Collectors.toMap(FlowReportMinuteDO::getLicenseId, Function.identity(), (a,b) -> a));
|
||||
|
||||
for (LicenseDO item : list) {
|
||||
// 避免job重复执行导致数据重复
|
||||
if (oldMap.containsKey(item.getId())) {
|
||||
continue;
|
||||
}
|
||||
Integer writeBytes = flowReportService.getAndResetWriteByte(item.getId());
|
||||
Integer readBytes = flowReportService.getAndResetReadByte(item.getId());
|
||||
if (writeBytes == 0 && readBytes == 0) {
|
||||
continue;
|
||||
}
|
||||
FlowReportMinuteDO flowReportMinuteDO = new FlowReportMinuteDO();
|
||||
flowReportMinuteDO.setUserId(item.getUserId());
|
||||
flowReportMinuteDO.setLicenseId(item.getId());
|
||||
flowReportMinuteDO.setWriteBytes(writeBytes);
|
||||
flowReportMinuteDO.setReadBytes(readBytes);
|
||||
flowReportMinuteDO.setDate(date);
|
||||
flowReportMinuteDO.setDateStr(dateStr);
|
||||
flowReportMinuteDO.setCreateTime(now);
|
||||
flowReportMinuteMapper.add(flowReportMinuteDO);
|
||||
}
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* 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 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 lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/28
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
@JobHandler(name = "FlowReportForMonthJob", cron = "0 10 0 1 * ?", param = "")
|
||||
public class FlowReportForMonthJob implements IJobHandler {
|
||||
@Autowired
|
||||
private FlowReportService flowReportService;
|
||||
@Autowired
|
||||
private LicenseMapper licenseMapper;
|
||||
@Autowired
|
||||
private FlowReportMinuteMapper flowReportMinuteMapper;
|
||||
@Autowired
|
||||
private FlowReportHourMapper flowReportHourMapper;
|
||||
@Autowired
|
||||
private FlowReportDayMapper flowReportDayMapper;
|
||||
@Autowired
|
||||
private FlowReportMonthMapper flowReportMonthMapper;
|
||||
|
||||
@Override
|
||||
public void execute(String param) throws Exception {
|
||||
Date now = new Date();
|
||||
String dateStr = DateUtil.format(DateUtil.addDate(now, Calendar.MONTH, -1), "yyyy-MM");
|
||||
Date date = DateUtil.parse(dateStr, "yyyy-MM");
|
||||
Date startDayDate = DateUtil.getDayBegin(date);
|
||||
Date endEndDate = DateUtil.getDayEnd(date);
|
||||
|
||||
// 删除原来的记录
|
||||
flowReportDayMapper.deleteByDateStr(dateStr);
|
||||
|
||||
// 查询上个月的天级别统计数据
|
||||
List<FlowReportDayDO> flowReportDayList = flowReportDayMapper.findListByDateRange(startDayDate, endEndDate);
|
||||
if (CollectionUtil.isEmpty(flowReportDayList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 汇总前一个天的天级别统计数据
|
||||
Map<Integer, FlowReportMonthDO> map = new HashMap<>();
|
||||
for (FlowReportDayDO item : flowReportDayList) {
|
||||
FlowReportMonthDO report = map.get(item.getLicenseId());
|
||||
if (null == report) {
|
||||
report = new FlowReportMonthDO();
|
||||
map.put(item.getLicenseId(), report);
|
||||
}
|
||||
Long writeBytes = report.getWriteBytes() == null ? 0 : report.getWriteBytes();
|
||||
Long readBytes = report.getReadBytes() == null ? 0 : report.getReadBytes();
|
||||
|
||||
report.setUserId(item.getUserId());
|
||||
report.setLicenseId(item.getLicenseId());
|
||||
report.setWriteBytes(writeBytes + item.getWriteBytes());
|
||||
report.setReadBytes(readBytes + item.getReadBytes());
|
||||
report.setDate(date);
|
||||
report.setDateStr(dateStr);
|
||||
report.setCreateTime(now);
|
||||
}
|
||||
|
||||
for (FlowReportMonthDO item : map.values()) {
|
||||
flowReportMonthMapper.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -43,7 +43,7 @@ public class BytesMetricsHandler extends ChannelDuplexHandler {
|
||||
MetricsCollector metricsCollector = MetricsCollector.getCollector(sa.getPort());
|
||||
metricsCollector.incrementReadBytes(((ByteBuf) msg).readableBytes());
|
||||
metricsCollector.incrementReadMsgs(1);
|
||||
System.out.println("字节数:" + metricsCollector.getMetrics().getReadBytes());
|
||||
// System.out.println("字节数:" + metricsCollector.getMetrics().getReadBytes());
|
||||
ctx.fireChannelRead(msg);
|
||||
}
|
||||
|
||||
|
||||
+15
@@ -24,9 +24,14 @@ 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.server.constant.ClientConnectTypeEnum;
|
||||
import fun.asgc.neutrino.proxy.server.constant.SuccessCodeEnum;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.ClientConnectRecordDO;
|
||||
import fun.asgc.neutrino.proxy.server.proxy.domain.CmdChannelAttachInfo;
|
||||
import fun.asgc.neutrino.proxy.server.service.ClientConnectRecordService;
|
||||
import fun.asgc.neutrino.proxy.server.service.ProxyMutualService;
|
||||
import fun.asgc.neutrino.proxy.server.util.ProxyUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
@@ -34,6 +39,8 @@ import io.netty.channel.*;
|
||||
import io.netty.handler.timeout.IdleStateEvent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
@@ -81,6 +88,14 @@ public class ServerChannelHandler extends SimpleChannelInboundHandler<ProxyMessa
|
||||
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()))
|
||||
.setLicenseId(cmdChannelAttachInfo.getLicenseId())
|
||||
.setType(ClientConnectTypeEnum.DISCONNECT.getType())
|
||||
.setMsg("")
|
||||
.setCode(SuccessCodeEnum.SUCCESS.getCode())
|
||||
.setCreateTime(new Date())
|
||||
);
|
||||
}
|
||||
ProxyUtil.removeCmdChannel(ctx.channel());
|
||||
}
|
||||
|
||||
+20
-13
@@ -22,8 +22,11 @@
|
||||
|
||||
package fun.asgc.neutrino.proxy.server.proxy.core;
|
||||
|
||||
import fun.asgc.neutrino.core.util.BeanManager;
|
||||
import fun.asgc.neutrino.proxy.core.Constants;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessage;
|
||||
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;
|
||||
@@ -41,7 +44,7 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
*/
|
||||
public class VisitorChannelHandler extends SimpleChannelInboundHandler<ByteBuf> {
|
||||
|
||||
private static AtomicLong userIdProducer = new AtomicLong(0);
|
||||
private static AtomicLong visitorIdProducer = new AtomicLong(0);
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
@@ -63,27 +66,31 @@ public class VisitorChannelHandler extends SimpleChannelInboundHandler<ByteBuf>
|
||||
} else {
|
||||
byte[] bytes = new byte[buf.readableBytes()];
|
||||
buf.readBytes(bytes);
|
||||
String userId = ProxyUtil.getVisitorChannelUserId(visitorChannel);
|
||||
proxyChannel.writeAndFlush(ProxyMessage.buildTransferMessage(userId, bytes));
|
||||
String visitorId = ProxyUtil.getVisitorIdByChannel(visitorChannel);
|
||||
proxyChannel.writeAndFlush(ProxyMessage.buildTransferMessage(visitorId, bytes));
|
||||
|
||||
// 增加流量计数
|
||||
VisitorChannelAttachInfo visitorChannelAttachInfo = ProxyUtil.getAttachInfo(visitorChannel);
|
||||
BeanManager.getBean(FlowReportService.class).addWriteByte(visitorChannelAttachInfo.getLicenseId(), bytes.length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
Channel userChannel = ctx.channel();
|
||||
InetSocketAddress sa = (InetSocketAddress) userChannel.localAddress();
|
||||
Channel visitorChannel = ctx.channel();
|
||||
InetSocketAddress sa = (InetSocketAddress) visitorChannel.localAddress();
|
||||
Channel cmdChannel = ProxyUtil.getCmdChannelByServerPort(sa.getPort());
|
||||
|
||||
if (cmdChannel == null) {
|
||||
// 该端口还没有代理客户端
|
||||
ctx.channel().close();
|
||||
} else {
|
||||
String userId = newUserId();
|
||||
String visitorId = newVisitorId();
|
||||
String lanInfo = ProxyUtil.getClientLanInfoByServerPort(sa.getPort());
|
||||
// 用户连接到代理服务器时,设置用户连接不可读,等待代理后端服务器连接成功后再改变为可读状态
|
||||
userChannel.config().setOption(ChannelOption.AUTO_READ, false);
|
||||
ProxyUtil.addUserChannelToCmdChannel(cmdChannel, userId, userChannel);
|
||||
cmdChannel.writeAndFlush(ProxyMessage.buildConnectMessage(userId).setData(lanInfo.getBytes()));
|
||||
visitorChannel.config().setOption(ChannelOption.AUTO_READ, false);
|
||||
ProxyUtil.addVisitorChannelToCmdChannel(cmdChannel, visitorId, visitorChannel);
|
||||
cmdChannel.writeAndFlush(ProxyMessage.buildConnectMessage(visitorId).setData(lanInfo.getBytes()));
|
||||
}
|
||||
|
||||
super.channelActive(ctx);
|
||||
@@ -104,7 +111,7 @@ public class VisitorChannelHandler extends SimpleChannelInboundHandler<ByteBuf>
|
||||
} else {
|
||||
|
||||
// 用户连接断开,从控制连接中移除
|
||||
String userId = ProxyUtil.getVisitorChannelUserId(userChannel);
|
||||
String userId = ProxyUtil.getVisitorIdByChannel(userChannel);
|
||||
ProxyUtil.removeVisitorChannelFromCmdChannel(cmdChannel, userId);
|
||||
|
||||
Channel proxyChannel = userChannel.attr(Constants.NEXT_CHANNEL).get();
|
||||
@@ -144,11 +151,11 @@ public class VisitorChannelHandler extends SimpleChannelInboundHandler<ByteBuf>
|
||||
}
|
||||
|
||||
/**
|
||||
* 为用户连接产生ID
|
||||
* 为访问者连接产生ID
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private static String newUserId() {
|
||||
return String.valueOf(userIdProducer.incrementAndGet());
|
||||
private static String newVisitorId() {
|
||||
return String.valueOf(visitorIdProducer.incrementAndGet());
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -34,6 +34,10 @@ import lombok.experimental.Accessors;
|
||||
public class VisitorChannelAttachInfo {
|
||||
private String visitorId;
|
||||
private String lanInfo;
|
||||
/**
|
||||
* licenseId
|
||||
*/
|
||||
private Integer licenseId;
|
||||
/**
|
||||
* ip地址
|
||||
*/
|
||||
|
||||
+65
-13
@@ -26,22 +26,23 @@ 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.CollectionUtil;
|
||||
import fun.asgc.neutrino.core.util.StringUtil;
|
||||
import fun.asgc.neutrino.proxy.core.*;
|
||||
import fun.asgc.neutrino.proxy.server.constant.*;
|
||||
import fun.asgc.neutrino.proxy.server.base.proxy.ProxyConfig;
|
||||
import fun.asgc.neutrino.proxy.server.proxy.core.BytesMetricsHandler;
|
||||
import fun.asgc.neutrino.proxy.server.proxy.core.VisitorChannelHandler;
|
||||
import fun.asgc.neutrino.proxy.server.constant.ClientConnectTypeEnum;
|
||||
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
|
||||
import fun.asgc.neutrino.proxy.server.constant.SuccessCodeEnum;
|
||||
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.PortMappingDO;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
|
||||
import fun.asgc.neutrino.proxy.server.proxy.core.BytesMetricsHandler;
|
||||
import fun.asgc.neutrino.proxy.server.proxy.core.VisitorChannelHandler;
|
||||
import fun.asgc.neutrino.proxy.server.proxy.domain.CmdChannelAttachInfo;
|
||||
import fun.asgc.neutrino.proxy.server.proxy.domain.ProxyMapping;
|
||||
import fun.asgc.neutrino.proxy.server.service.LicenseService;
|
||||
import fun.asgc.neutrino.proxy.server.service.PortMappingService;
|
||||
import fun.asgc.neutrino.proxy.server.service.ProxyMutualService;
|
||||
import fun.asgc.neutrino.proxy.server.service.UserService;
|
||||
import fun.asgc.neutrino.proxy.server.service.*;
|
||||
import fun.asgc.neutrino.proxy.server.util.ProxyUtil;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
@@ -53,6 +54,7 @@ import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.net.BindException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -80,41 +82,91 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
|
||||
private PortMappingService portMappingService;
|
||||
@Autowired
|
||||
private ProxyMutualService proxyMutualService;
|
||||
@Autowired
|
||||
private FlowReportService flowReportService;
|
||||
@Autowired
|
||||
private ClientConnectRecordService clientConnectRecordService;
|
||||
|
||||
@Override
|
||||
public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
|
||||
String ip = ChannelUtil.getIP(ctx.channel());
|
||||
Date now = new Date();
|
||||
|
||||
String licenseKey = proxyMessage.getInfo();
|
||||
if (StringUtil.isEmpty(licenseKey)) {
|
||||
ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "license不能为空!", licenseKey));
|
||||
// ctx.channel().close();
|
||||
clientConnectRecordService.add(new ClientConnectRecordDO()
|
||||
.setIp(ip)
|
||||
.setType(ClientConnectTypeEnum.CONNECT.getType())
|
||||
.setMsg(licenseKey)
|
||||
.setCode(SuccessCodeEnum.FAIL.getCode())
|
||||
.setErr("license不能为空!")
|
||||
.setCreateTime(now)
|
||||
);
|
||||
return;
|
||||
}
|
||||
LicenseDO licenseDO = licenseService.findByKey(licenseKey);
|
||||
if (null == licenseDO) {
|
||||
ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "license不存在!", licenseKey));
|
||||
// ctx.channel().close();
|
||||
clientConnectRecordService.add(new ClientConnectRecordDO()
|
||||
.setIp(ip)
|
||||
.setType(ClientConnectTypeEnum.CONNECT.getType())
|
||||
.setMsg(licenseKey)
|
||||
.setCode(SuccessCodeEnum.FAIL.getCode())
|
||||
.setErr("license不存在!")
|
||||
.setCreateTime(now)
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (EnableStatusEnum.DISABLE.getStatus().equals(licenseDO.getEnable())) {
|
||||
ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "当前license已被禁用!", licenseKey));
|
||||
// ctx.channel().close();
|
||||
clientConnectRecordService.add(new ClientConnectRecordDO()
|
||||
.setIp(ip)
|
||||
.setLicenseId(licenseDO.getId())
|
||||
.setType(ClientConnectTypeEnum.CONNECT.getType())
|
||||
.setMsg(licenseKey)
|
||||
.setCode(SuccessCodeEnum.FAIL.getCode())
|
||||
.setErr("当前license已被禁用!")
|
||||
.setCreateTime(now));
|
||||
return;
|
||||
}
|
||||
UserDO userDO = userService.findById(licenseDO.getId());
|
||||
UserDO userDO = userService.findById(licenseDO.getUserId());
|
||||
if (null == userDO || EnableStatusEnum.DISABLE.getStatus().equals(userDO.getEnable())) {
|
||||
ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "当前license无效!", licenseKey));
|
||||
// ctx.channel().close();
|
||||
clientConnectRecordService.add(new ClientConnectRecordDO()
|
||||
.setIp(ip)
|
||||
.setLicenseId(licenseDO.getId())
|
||||
.setType(ClientConnectTypeEnum.CONNECT.getType())
|
||||
.setMsg(licenseKey)
|
||||
.setCode(SuccessCodeEnum.FAIL.getCode())
|
||||
.setErr("当前license无效!")
|
||||
.setCreateTime(now));
|
||||
return;
|
||||
}
|
||||
Channel cmdChannel = ProxyUtil.getCmdChannelByLicenseId(licenseDO.getId());
|
||||
if (null != cmdChannel) {
|
||||
ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "当前license已被另一节点使用!", licenseKey));
|
||||
// ctx.channel().close();
|
||||
clientConnectRecordService.add(new ClientConnectRecordDO()
|
||||
.setIp(ip)
|
||||
.setLicenseId(licenseDO.getId())
|
||||
.setType(ClientConnectTypeEnum.CONNECT.getType())
|
||||
.setMsg(licenseKey)
|
||||
.setCode(SuccessCodeEnum.FAIL.getCode())
|
||||
.setErr("当前license已被另一节点使用!")
|
||||
.setCreateTime(now));
|
||||
return;
|
||||
}
|
||||
// 发送认证成功消息
|
||||
ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.SUCCESS.getCode(), "认证成功!", licenseKey));
|
||||
|
||||
clientConnectRecordService.add(new ClientConnectRecordDO()
|
||||
.setIp(ip)
|
||||
.setLicenseId(licenseDO.getId())
|
||||
.setType(ClientConnectTypeEnum.CONNECT.getType())
|
||||
.setMsg(licenseKey)
|
||||
.setCode(SuccessCodeEnum.SUCCESS.getCode())
|
||||
.setCreateTime(now));
|
||||
|
||||
List<PortMappingDO> portMappingList = portMappingService.findEnableListByLicenseId(licenseDO.getId());
|
||||
// 没有端口映射仍然保持连接
|
||||
if (!CollectionUtil.isEmpty(portMappingList)) {
|
||||
|
||||
+6
-6
@@ -82,7 +82,7 @@ public class ProxyMessageConnectHandler implements ProxyMessageHandler {
|
||||
ctx.channel().close();
|
||||
return;
|
||||
}
|
||||
UserDO userDO = userService.findById(licenseDO.getId());
|
||||
UserDO userDO = userService.findById(licenseDO.getUserId());
|
||||
if (null == userDO || EnableStatusEnum.DISABLE.getStatus().equals(userDO.getEnable())) {
|
||||
ctx.channel().writeAndFlush(ProxyMessage.buildErrMessage(ExceptionEnum.CONNECT_FAILED, "当前license无效!"));
|
||||
ctx.channel().close();
|
||||
@@ -97,14 +97,14 @@ public class ProxyMessageConnectHandler implements ProxyMessageHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
Channel userChannel = ProxyUtil.getUserChannel(cmdChannel, visitorId);
|
||||
if (userChannel != null) {
|
||||
Channel visitorChannel = ProxyUtil.getVisitorChannel(cmdChannel, visitorId);
|
||||
if (visitorChannel != null) {
|
||||
ctx.channel().attr(Constants.VISITOR_ID).set(visitorId);
|
||||
ctx.channel().attr(Constants.LICENSE_ID).set(licenseDO.getId());
|
||||
ctx.channel().attr(Constants.NEXT_CHANNEL).set(userChannel);
|
||||
userChannel.attr(Constants.NEXT_CHANNEL).set(ctx.channel());
|
||||
ctx.channel().attr(Constants.NEXT_CHANNEL).set(visitorChannel);
|
||||
visitorChannel.attr(Constants.NEXT_CHANNEL).set(ctx.channel());
|
||||
// 代理客户端与后端服务器连接成功,修改用户连接为可读状态
|
||||
userChannel.config().setOption(ChannelOption.AUTO_READ, true);
|
||||
visitorChannel.config().setOption(ChannelOption.AUTO_READ, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-3
@@ -25,10 +25,14 @@ 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.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;
|
||||
@@ -45,11 +49,15 @@ public class ProxyMessageTransferHandler implements ProxyMessageHandler {
|
||||
|
||||
@Override
|
||||
public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
|
||||
Channel userChannel = ctx.channel().attr(Constants.NEXT_CHANNEL).get();
|
||||
if (null != userChannel) {
|
||||
Channel visitorChannel = ctx.channel().attr(Constants.NEXT_CHANNEL).get();
|
||||
if (null != visitorChannel) {
|
||||
ByteBuf buf = ctx.alloc().buffer(proxyMessage.getData().length);
|
||||
buf.writeBytes(proxyMessage.getData());
|
||||
userChannel.writeAndFlush(buf);
|
||||
visitorChannel.writeAndFlush(buf);
|
||||
|
||||
// 增加流量计数
|
||||
VisitorChannelAttachInfo visitorChannelAttachInfo = ProxyUtil.getAttachInfo(visitorChannel);
|
||||
BeanManager.getBean(FlowReportService.class).addReadByte(visitorChannelAttachInfo.getLicenseId(), proxyMessage.getData().length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+45
@@ -0,0 +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.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.dal.ClientConnectRecordMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.ClientConnectRecordDO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/23
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class ClientConnectRecordService {
|
||||
@Autowired
|
||||
private ClientConnectRecordMapper clientConnectRecordMapper;
|
||||
|
||||
public void add(ClientConnectRecordDO clientConnectRecordDO) {
|
||||
clientConnectRecordMapper.add(clientConnectRecordDO);
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* 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.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.util.LockUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 流量报表服务
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/26
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class FlowReportService {
|
||||
private Map<Integer/*licenseId*/, AtomicInteger/*writeByte*/> writeByteMap = new HashMap<>();
|
||||
private Map<Integer/*licenseId*/, AtomicInteger/*readByte*/> readByteMap = new HashMap<>();
|
||||
|
||||
private AtomicInteger getWriteByte(Integer licenseId) {
|
||||
return LockUtil.doubleCheckProcessForNoException(() -> !writeByteMap.containsKey(licenseId),
|
||||
licenseId,
|
||||
() -> {
|
||||
writeByteMap.put(licenseId, new AtomicInteger());
|
||||
},
|
||||
() -> writeByteMap.get(licenseId));
|
||||
}
|
||||
|
||||
private AtomicInteger getReadByte(Integer licenseId) {
|
||||
return LockUtil.doubleCheckProcessForNoException(() -> !readByteMap.containsKey(licenseId),
|
||||
licenseId,
|
||||
() -> {
|
||||
readByteMap.put(licenseId, new AtomicInteger());
|
||||
},
|
||||
() -> readByteMap.get(licenseId));
|
||||
}
|
||||
|
||||
public void addWriteByte(Integer licenseId, Integer writeByte) {
|
||||
getWriteByte(licenseId).addAndGet(writeByte);
|
||||
}
|
||||
|
||||
public void addReadByte(Integer licenseId, Integer readByte) {
|
||||
getReadByte(licenseId).addAndGet(readByte);
|
||||
}
|
||||
|
||||
public Integer getAndResetWriteByte(Integer licenseId) {
|
||||
return getWriteByte(licenseId).getAndSet(0);
|
||||
}
|
||||
|
||||
public Integer getAndResetReadByte(Integer licenseId) {
|
||||
return getReadByte(licenseId).getAndSet(0);
|
||||
}
|
||||
|
||||
}
|
||||
+11
-4
@@ -22,9 +22,7 @@
|
||||
package fun.asgc.neutrino.proxy.server.service;
|
||||
|
||||
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.annotation.*;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.util.CollectionUtil;
|
||||
@@ -125,7 +123,7 @@ public class LicenseService {
|
||||
ParamCheckUtil.checkNotNull(oldLicenseDO, ExceptionConstant.LICENSE_NOT_EXIST);
|
||||
|
||||
LicenseDO licenseCheck = licenseMapper.checkRepeat(oldLicenseDO.getUserId(), req.getName(), Sets.newHashSet(oldLicenseDO.getId()));
|
||||
ParamCheckUtil.checkNotNull(licenseCheck, ExceptionConstant.LICENSE_NAME_CANNOT_REPEAT);
|
||||
ParamCheckUtil.checkMustNull(licenseCheck, ExceptionConstant.LICENSE_NAME_CANNOT_REPEAT);
|
||||
|
||||
licenseMapper.update(req.getId(), req.getName(), new Date());
|
||||
return new LicenseUpdateRes();
|
||||
@@ -202,4 +200,13 @@ public class LicenseService {
|
||||
}
|
||||
return licenseKey.substring(0, 10) + "****" + licenseKey.substring(licenseKey.length() - 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务端项目停止、启动时,更新在线状态为离线
|
||||
*/
|
||||
@Init
|
||||
@Destroy
|
||||
public void destroy() {
|
||||
licenseMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
|
||||
}
|
||||
}
|
||||
|
||||
+11
-4
@@ -22,9 +22,7 @@
|
||||
package fun.asgc.neutrino.proxy.server.service;
|
||||
|
||||
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.annotation.*;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.util.CollectionUtil;
|
||||
@@ -140,7 +138,7 @@ public class PortMappingService {
|
||||
}
|
||||
PortPoolDO portPoolDO = portPoolMapper.findByPort(req.getServerPort());
|
||||
ParamCheckUtil.checkNotNull(portPoolDO, ExceptionConstant.PORT_NOT_EXIST);
|
||||
ParamCheckUtil.checkNotNull(portMappingMapper.findByPort(req.getServerPort(), Sets.newHashSet(req.getId())), ExceptionConstant.PORT_CANNOT_REPEAT_MAPPING, req.getServerPort());
|
||||
ParamCheckUtil.checkExpression(null == portMappingMapper.findByPort(req.getServerPort(), Sets.newHashSet(req.getId())), ExceptionConstant.PORT_CANNOT_REPEAT_MAPPING, req.getServerPort());
|
||||
|
||||
PortMappingDO portMappingDO = new PortMappingDO();
|
||||
portMappingDO.setId(req.getId());
|
||||
@@ -220,4 +218,13 @@ public class PortMappingService {
|
||||
return portMappingMapper.findEnableListByLicenseId(licenseId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务端项目停止、启动时,更新在线状态为离线
|
||||
*/
|
||||
@Init
|
||||
@Destroy
|
||||
public void destroy() {
|
||||
portMappingMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* 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 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 java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 用户登录日志
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/20
|
||||
*/
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class UserLoginRecordService {
|
||||
@Autowired
|
||||
private UserLoginRecordMapper userLoginRecordMapper;
|
||||
@Autowired
|
||||
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());
|
||||
List<UserDO> userList = userMapper.findByIds(userIds);
|
||||
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
|
||||
for (UserLoginRecordListRes item : page.getRecords()) {
|
||||
UserDO userDO = userMap.get(item.getUserId());
|
||||
if (null != userDO) {
|
||||
item.setUserName(userDO.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return page;
|
||||
}
|
||||
}
|
||||
+11
-2
@@ -27,10 +27,10 @@ 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 fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
|
||||
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
|
||||
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;
|
||||
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.dal.UserLoginRecordMapper;
|
||||
@@ -40,6 +40,7 @@ import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
|
||||
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 java.util.Calendar;
|
||||
import java.util.Date;
|
||||
@@ -192,8 +193,16 @@ public class UserService {
|
||||
}
|
||||
|
||||
public UserUpdatePasswordRes updatePassword(UserUpdatePasswordReq req) {
|
||||
UserDO userDO = userMapper.findById(req.getId());
|
||||
// 更新密码
|
||||
String loginPassword = Md5Util.encode(req.getLoginPassword());
|
||||
ParamCheckUtil.checkExpression(!userDO.getLoginPassword().equals(loginPassword), ExceptionConstant.LOGIN_PASSWORD_NO_CHANGE_MODIFY_FAIL);
|
||||
|
||||
userMapper.updateLoginPassword(req.getId(), loginPassword, new Date());
|
||||
|
||||
// 删除该用户所有token
|
||||
userTokenMapper.deleteByUserId(req.getId());
|
||||
|
||||
return new UserUpdatePasswordRes();
|
||||
}
|
||||
|
||||
|
||||
+7
@@ -66,6 +66,13 @@ public class ParamCheckUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkMustNull(Object obj, ExceptionConstant constant, Object... params) {
|
||||
if (null != obj) {
|
||||
throw ServiceException.create(constant, params);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void checkNotNull(Object obj, ExceptionConstant constant, Object... params) {
|
||||
if (null == obj) {
|
||||
throw ServiceException.create(constant, params);
|
||||
|
||||
+16
-13
@@ -171,20 +171,23 @@ public class ProxyUtil {
|
||||
/**
|
||||
* 增加用户连接与代理客户端连接关系
|
||||
*
|
||||
* @param userId
|
||||
* @param userChannel
|
||||
* @param visitorId
|
||||
* @param visitorChannel
|
||||
*/
|
||||
public static void addUserChannelToCmdChannel(Channel cmdChannel, String userId, Channel userChannel) {
|
||||
InetSocketAddress sa = (InetSocketAddress) userChannel.localAddress();
|
||||
public static void addVisitorChannelToCmdChannel(Channel cmdChannel, String visitorId, Channel visitorChannel) {
|
||||
InetSocketAddress sa = (InetSocketAddress) visitorChannel.localAddress();
|
||||
String lanInfo = getClientLanInfoByServerPort(sa.getPort());
|
||||
setAttachInfo(userChannel, new VisitorChannelAttachInfo()
|
||||
.setVisitorId(userId)
|
||||
CmdChannelAttachInfo cmdChannelAttachInfo = getAttachInfo(cmdChannel);
|
||||
|
||||
setAttachInfo(visitorChannel, new VisitorChannelAttachInfo()
|
||||
.setVisitorId(visitorId)
|
||||
.setLanInfo(lanInfo)
|
||||
.setIp(ChannelUtil.getIP(userChannel))
|
||||
.setLicenseId(cmdChannelAttachInfo.getLicenseId())
|
||||
.setIp(ChannelUtil.getIP(visitorChannel))
|
||||
);
|
||||
userChannelMapLock.writeLock().lock();
|
||||
try {
|
||||
((CmdChannelAttachInfo)getAttachInfo(cmdChannel)).getVisitorChannelMap().put(userId, userChannel);
|
||||
cmdChannelAttachInfo.getVisitorChannelMap().put(visitorId, visitorChannel);
|
||||
} finally {
|
||||
userChannelMapLock.writeLock().unlock();
|
||||
}
|
||||
@@ -206,23 +209,23 @@ public class ProxyUtil {
|
||||
/**
|
||||
* 根据代理客户端连接与用户编号获取用户连接
|
||||
*
|
||||
* @param userId
|
||||
* @param visitorId
|
||||
* @return
|
||||
*/
|
||||
public static Channel getUserChannel(Channel cmdChannel, String userId) {
|
||||
public static Channel getVisitorChannel(Channel cmdChannel, String visitorId) {
|
||||
if (null == cmdChannel || null == getAttachInfo(cmdChannel)) {
|
||||
return null;
|
||||
}
|
||||
return ((CmdChannelAttachInfo)getAttachInfo(cmdChannel)).getVisitorChannelMap().get(userId);
|
||||
return ((CmdChannelAttachInfo)getAttachInfo(cmdChannel)).getVisitorChannelMap().get(visitorId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户编号
|
||||
* 获取访问者ID
|
||||
*
|
||||
* @param visitorChannel
|
||||
* @return
|
||||
*/
|
||||
public static String getVisitorChannelUserId(Channel visitorChannel) {
|
||||
public static String getVisitorIdByChannel(Channel visitorChannel) {
|
||||
if (null == visitorChannel || null == getAttachInfo(visitorChannel)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<property name="LOG_FILE" value="/work/project/neutrino-proxy/server.log"/>
|
||||
<property name="LOG_FILE" value="/work/project/neutrino-proxy/server.log"/>
|
||||
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{50} - %msg%n"/>
|
||||
<property name="ENCODE" value="utf8" />
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="console"/>
|
||||
<appender-ref ref="file"/>
|
||||
</root>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<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,3 +1,4 @@
|
||||
#############################系统管理相关表#############################
|
||||
#用户表
|
||||
CREATE TABLE IF NOT EXISTS `user` (
|
||||
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
@@ -8,20 +9,7 @@ CREATE TABLE IF NOT EXISTS `user` (
|
||||
`create_time` INTEGER(20) NOT NULL,
|
||||
`update_time` INTEGER(20) NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS I_login_name ON `user` (login_name ASC);
|
||||
|
||||
#license表
|
||||
CREATE TABLE IF NOT EXISTS `license` (
|
||||
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
`name` VARCHAR(50) NOT NULL,
|
||||
`key` VARCHAR(100) NOT NULL,
|
||||
`user_id` INTEGER NOT NULL,
|
||||
`is_online` INTEGER(2) NOT NULL,
|
||||
`enable` INTEGER(2) NOT NULL,
|
||||
`create_time` INTEGER(20) NOT NULL,
|
||||
`update_time` INTEGER(20) NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS I_key ON `license` (`key` ASC);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS I_user_login_name ON `user` (login_name ASC);
|
||||
|
||||
#用户token表
|
||||
CREATE TABLE IF NOT EXISTS `user_token` (
|
||||
@@ -32,16 +20,9 @@ CREATE TABLE IF NOT EXISTS `user_token` (
|
||||
`create_time` INTEGER NOT NULL,
|
||||
`update_time` INTEGER NOT NULL
|
||||
);
|
||||
|
||||
#用户登录记录表
|
||||
CREATE TABLE IF NOT EXISTS `user_login_record` (
|
||||
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
`user_id` INTEGER NOT NULL,
|
||||
`ip` VARCHAR(50) NOT NULL,
|
||||
`token` VARCHAR(100) NOT NULL,
|
||||
`type` INTEGER(2) NOT NULL,
|
||||
`create_time` INTEGER(20) NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS I_user_token_user_id ON user_token(user_id);
|
||||
CREATE INDEX IF NOT EXISTS I_user_token_token ON user_token(token);
|
||||
CREATE INDEX IF NOT EXISTS I_user_token_expiration_time ON user_token(expiration_time);
|
||||
|
||||
#端口池
|
||||
CREATE TABLE IF NOT EXISTS `port_pool` (
|
||||
@@ -51,7 +32,21 @@ CREATE TABLE IF NOT EXISTS `port_pool` (
|
||||
`update_time` INTEGER(20) NOT NULL,
|
||||
`create_time` INTEGER(20) NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS I_port ON port_pool (port ASC);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS I_port_pool_port ON port_pool (port ASC);
|
||||
|
||||
#############################代理配置相关表#############################
|
||||
#license表
|
||||
CREATE TABLE IF NOT EXISTS `license` (
|
||||
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
`name` VARCHAR(50) NOT NULL,
|
||||
`key` VARCHAR(100) NOT NULL,
|
||||
`user_id` INTEGER NOT NULL,
|
||||
`is_online` INTEGER(2) NOT NULL,
|
||||
`enable` INTEGER(2) NOT NULL,
|
||||
`create_time` INTEGER(20) NOT NULL,
|
||||
`update_time` INTEGER(20) NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS I_license_key ON `license` (`key` ASC);
|
||||
|
||||
#端口映射表
|
||||
CREATE TABLE IF NOT EXISTS `port_mapping` (
|
||||
@@ -65,37 +60,29 @@ CREATE TABLE IF NOT EXISTS `port_mapping` (
|
||||
`create_time` INTEGER(20) NOT NULL,
|
||||
`update_time` INTEGER(20) NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS I_server_port ON port_mapping (server_port ASC);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS I_port_mapping_server_port ON port_mapping (server_port ASC);
|
||||
|
||||
#客户端链接记录表
|
||||
#############################日志管理相关表#############################
|
||||
#用户登录记录表
|
||||
CREATE TABLE IF NOT EXISTS `user_login_record` (
|
||||
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
`user_id` INTEGER NOT NULL,
|
||||
`ip` VARCHAR(50) NOT NULL,
|
||||
`token` VARCHAR(100) NOT NULL,
|
||||
`type` INTEGER(2) NOT NULL,
|
||||
`create_time` INTEGER(20) NOT NULL
|
||||
);
|
||||
#客户端连接记录表
|
||||
CREATE TABLE IF NOT EXISTS `client_connect_record` (
|
||||
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
`user_id` INTEGER NOT NULL,
|
||||
`ip` VARCHAR(50) NOT NULL,
|
||||
`license_id` INTEGER(20) NOT NULL,
|
||||
`license_key` VARCHAR(100) NOT NULL,
|
||||
`write_bytes` INTEGER(20) DEFAULT NULL,
|
||||
`read_bytes` INTEGER(20) DEFAULT NULL,
|
||||
`type` INTEGER(2) NOT NULL,
|
||||
`create_time` INTEGER(20) NOT NULL
|
||||
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
`ip` VARCHAR(50) NOT NULL,
|
||||
`license_id` INTEGER(20) DEFAULT NULL,
|
||||
`type` INTEGER(2) NOT NULL,
|
||||
`msg` VARCHAR(512) DEFAULT NULL,
|
||||
`code` INTEGER(2) NOT NULL,
|
||||
`err` VARCHAR(512) DEFAULT NULL,
|
||||
`create_time` INTEGER(20) NOT NULL
|
||||
);
|
||||
|
||||
#用户连接记录表
|
||||
CREATE TABLE IF NOT EXISTS `user_connect_record` (
|
||||
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
`server_port` INTEGER NOT NULL,
|
||||
`user_ip` VARCHAR(50) NOT NULL,
|
||||
`client_ip` VARCHAR(50) NOT NULL,
|
||||
`client_lan_info` VARCHAR(50) NOT NULL,
|
||||
`user_id` INTEGER NOT NULL,
|
||||
`license_id` INTEGER(20) NOT NULL,
|
||||
`license_key` VARCHAR(100) NOT NULL,
|
||||
`write_bytes` INTEGER(20) DEFAULT NULL,
|
||||
`read_bytes` INTEGER(20) DEFAULT NULL,
|
||||
`type` INTEGER(2) NOT NULL,
|
||||
`create_time` INTEGER(20) NOT NULL
|
||||
);
|
||||
|
||||
#############################调度管理相关表#############################
|
||||
#触发器信息表
|
||||
CREATE TABLE IF NOT EXISTS `job_info` (
|
||||
@@ -110,7 +97,7 @@ CREATE TABLE IF NOT EXISTS `job_info` (
|
||||
`create_time` INTEGER(20) NOT NULL,
|
||||
`update_time` INTEGER(20) NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS I_handler ON `job_info` (`handler` ASC);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS I_job_info_handler ON `job_info` (`handler` ASC);
|
||||
|
||||
#触发器日志表
|
||||
CREATE TABLE IF NOT EXISTS `job_log` (
|
||||
@@ -123,5 +110,70 @@ CREATE TABLE IF NOT EXISTS `job_log` (
|
||||
`alarm_status` INTEGER(2) NOT NULL DEFAULT '0',
|
||||
`create_time` INTEGER(20) NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS I_create_time ON job_log(create_time);
|
||||
CREATE INDEX IF NOT EXISTS I_code ON job_log(code);
|
||||
CREATE INDEX IF NOT EXISTS I_job_log_create_time ON job_log(create_time);
|
||||
CREATE INDEX IF NOT EXISTS I_job_log_code ON job_log(code);
|
||||
|
||||
#############################报表管理相关表#############################
|
||||
#流量统计报表-分钟(保留24小时)
|
||||
CREATE TABLE IF NOT EXISTS `flow_report_minute` (
|
||||
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
`user_id` INTEGER(20) NOT NULL,
|
||||
`license_id` INTEGER(20) NOT NULL,
|
||||
`write_bytes` INTEGER(20) NOT NULL,
|
||||
`read_bytes` INTEGER(20) NOT NULL,
|
||||
`date` INTEGER(20) NOT NULL,
|
||||
`date_str` VARCHAR(20) NOT NULL,
|
||||
`create_time` INTEGER(20) NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS I_flow_report_minute_create_time ON flow_report_minute(create_time);
|
||||
CREATE INDEX IF NOT EXISTS I_flow_report_minute_date ON flow_report_minute(`date`);
|
||||
CREATE INDEX IF NOT EXISTS I_flow_report_minute_user_id ON flow_report_minute(`user_id`);
|
||||
CREATE INDEX IF NOT EXISTS I_flow_report_minute_license_id ON flow_report_minute(`license_id`);
|
||||
|
||||
#流量统计报表-小时(保留60天)
|
||||
CREATE TABLE IF NOT EXISTS `flow_report_hour` (
|
||||
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
`user_id` INTEGER(20) NOT NULL,
|
||||
`license_id` INTEGER(20) NOT NULL,
|
||||
`write_bytes` INTEGER(20) NOT NULL,
|
||||
`read_bytes` INTEGER(20) NOT NULL,
|
||||
`date` INTEGER(20) NOT NULL,
|
||||
`date_str` VARCHAR(20) NOT NULL,
|
||||
`create_time` INTEGER(20) NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS I_flow_report_hour_create_time ON flow_report_hour(create_time);
|
||||
CREATE INDEX IF NOT EXISTS I_flow_report_hour_date ON flow_report_hour(`date`);
|
||||
CREATE INDEX IF NOT EXISTS I_flow_report_hour_user_id ON flow_report_hour(`user_id`);
|
||||
CREATE INDEX IF NOT EXISTS I_flow_report_hour_license_id ON flow_report_hour(`license_id`);
|
||||
|
||||
#流量统计报表-天(保留1年)
|
||||
CREATE TABLE IF NOT EXISTS `flow_report_day` (
|
||||
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
`user_id` INTEGER(20) NOT NULL,
|
||||
`license_id` INTEGER(20) NOT NULL,
|
||||
`write_bytes` INTEGER(20) NOT NULL,
|
||||
`read_bytes` INTEGER(20) NOT NULL,
|
||||
`date` INTEGER(20) NOT NULL,
|
||||
`date_str` VARCHAR(20) NOT NULL,
|
||||
`create_time` INTEGER(20) NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS I_flow_report_day_create_time ON flow_report_day(create_time);
|
||||
CREATE INDEX IF NOT EXISTS I_flow_report_day_date ON flow_report_day(`date`);
|
||||
CREATE INDEX IF NOT EXISTS I_flow_report_day_user_id ON flow_report_day(`user_id`);
|
||||
CREATE INDEX IF NOT EXISTS I_flow_report_day_license_id ON flow_report_day(`license_id`);
|
||||
|
||||
#流量统计报表-月(全量保留)
|
||||
CREATE TABLE IF NOT EXISTS `flow_report_month` (
|
||||
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
`user_id` INTEGER(20) NOT NULL,
|
||||
`license_id` INTEGER(20) NOT NULL,
|
||||
`write_bytes` INTEGER(20) NOT NULL,
|
||||
`read_bytes` INTEGER(20) NOT NULL,
|
||||
`date` INTEGER(20) NOT NULL,
|
||||
`date_str` VARCHAR(20) NOT NULL,
|
||||
`create_time` INTEGER(20) NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS I_flow_report_month_create_time ON flow_report_month(create_time);
|
||||
CREATE INDEX IF NOT EXISTS I_flow_report_month_date ON flow_report_month(`date`);
|
||||
CREATE INDEX IF NOT EXISTS I_flow_report_month_user_id ON flow_report_month(`user_id`);
|
||||
CREATE INDEX IF NOT EXISTS I_flow_report_month_license_id ON flow_report_month(`license_id`);
|
||||
@@ -1,5 +1,13 @@
|
||||
#job_qrtz_trigger_info
|
||||
insert into job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(1, '示例Job', 'DemoJob', '0/10 * * * * ?', '{"a":101}', 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) values
|
||||
(2, '数据清理任务', 'DataCleanJob', '0 0 1 * * ?', '', 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(2, '数据清理任务', 'DataCleanJob', '0 0 1 * * ?', '', 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(3, '流量统计报表-分钟', 'FlowReportForMinuteJob', '0 */1 * * * ?', '', 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(4, '流量统计报表-小时', 'FlowReportForHourJob', '0 0 */1 * * ?', '', 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(5, '流量统计报表-天', 'FlowReportForDayJob', '0 0 1 * * ?', '', 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(6, '流量统计报表-月', 'FlowReportForMonthJob', '0 30 1 1 * ?', '', 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
@@ -1,3 +1,3 @@
|
||||
#license
|
||||
insert into license(`id`, `name`, `key`, `user_id`, `is_online`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO license(`id`, `name`, `key`, `user_id`, `is_online`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(1, '我的mac', 'b0a907332b474b25897c4dcb31fc7eb6', 1, 2, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#port_mapping
|
||||
insert into port_mapping(`id`, `license_id`, `server_port`, `client_ip`, `client_port`, `is_online`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_mapping(`id`, `license_id`, `server_port`, `client_ip`, `client_port`, `is_online`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(1, 1, 9101, '127.0.0.1', 8080, 2, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_mapping(`id`, `license_id`, `server_port`, `client_ip`, `client_port`, `is_online`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_mapping(`id`, `license_id`, `server_port`, `client_ip`, `client_port`, `is_online`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(2, 1, 9102, '127.0.0.1', 3306, 2, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
#端口池
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(1, 9101, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(2, 9102, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(3, 9103, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(4, 9104, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(5, 9105, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(6, 9106, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(7, 9107, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(8, 9108, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(9, 9109, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(10, 9110, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(11, 9111, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(12, 9112, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(13, 9113, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(14, 9114, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(15, 9115, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(16, 9116, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(17, 9117, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(18, 9118, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(19, 9119, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) values
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(20, 9120, 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#用户表 6613b92b77056faeb72068f184ed4c4f
|
||||
insert into `user`(`id`, `name`,`login_name`,`login_password`,`enable`,`create_time`, `update_time`) values
|
||||
INSERT INTO `user`(`id`, `name`,`login_name`,`login_password`,`enable`,`create_time`, `update_time`) VALUES
|
||||
(1, '管理员', 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
insert into `user`(`id`, `name`,`login_name`,`login_password`,`enable`,`create_time`, `update_time`) values
|
||||
INSERT INTO `user`(`id`, `name`,`login_name`,`login_password`,`enable`,`create_time`, `update_time`) VALUES
|
||||
(2, '游客', 'visitor', 'e10adc3949ba59abbe56e057f20f883e', 1, STRFTIME('%s000', 'NOW'), STRFTIME('%s000', 'NOW'));
|
||||
|
||||
+7
-7
@@ -1,7 +1,7 @@
|
||||
- 测试及优化代理稳定性
|
||||
- 完成剩余的调度管理日志功能
|
||||
- 增加日志管理(登录日志、客户端连接日志、调度执行日志)
|
||||
- 增加简单的流量统计
|
||||
- 基于用户粒度的上下行流量累计
|
||||
- 完善补充代码文档
|
||||
- 优化底层框架
|
||||
# BUG
|
||||
- neutrino-proxy-admin 打包后启动,token失效不会跳回登录页面
|
||||
|
||||
# 优化
|
||||
- 调度管理,增加查看按钮,解决异常情况下,列表展示堆栈异常信息不全,不方便查看的问题
|
||||
- 用户列表增加修改密码入口,管理员可以修改指定用户密码,无需验证原密码(仅管理员操作
|
||||
- 增加当前登录用户修改自己密码的功能,需要验证原密码
|
||||
Reference in New Issue
Block a user