定时任务流量上报
This commit is contained in:
parent
a850899638
commit
73852fc5bd
|
|
@ -16,28 +16,28 @@ dataSources:
|
|||
|
||||
rules:
|
||||
- !SHARDING
|
||||
tables: # 数据分片规则配置
|
||||
# 节点流量记录表(按天分表)
|
||||
tables:
|
||||
net_node_flow_record:
|
||||
actualDataNodes: net_flow_record.net_node_flow_record_${['20260323']}
|
||||
actualDataNodes: net_flow_record.net_node_flow_record_${['20260324','20260325','20260326','20260327','20260328','20260329','20260330','20260331','20260401','20260402','20260403','20260404','20260405','20260406','20260407','20260408','20260409','20260410','20260411','20260412','20260413','20260414','20260415','20260416','20260417','20260418','20260419','20260420','20260421','20260422','20260423','20260424','20260425','20260426','20260427','20260428','20260429','20260430','20260501','20260502','20260503','20260504','20260505','20260506','20260507','20260508','20260509','20260510','20260511','20260512','20260513','20260514','20260515','20260516','20260517','20260518','20260519','20260520','20260521','20260522','20260523','20260524','20260525','20260526','20260527','20260528','20260529','20260530','20260531','20260601','20260602','20260603','20260604','20260605','20260606','20260607','20260608','20260609','20260610','20260611','20260612','20260613','20260614','20260615','20260616','20260617','20260618','20260619','20260620','20260621','20260622','20260623','20260624','20260625','20260626','20260627','20260628','20260629','20260630','20260701','20260702','20260703','20260704','20260705','20260706','20260707','20260708','20260709','20260710','20260711','20260712','20260713','20260714','20260715','20260716','20260717','20260718','20260719','20260720','20260721','20260722','20260723','20260724','20260725','20260726','20260727','20260728','20260729','20260730','20260731','20260801','20260802','20260803','20260804','20260805','20260806','20260807','20260808','20260809','20260810','20260811','20260812','20260813','20260814','20260815','20260816','20260817','20260818','20260819','20260820','20260821','20260822','20260823','20260824','20260825','20260826','20260827','20260828','20260829','20260830','20260831','20260901','20260902','20260903','20260904','20260905','20260906','20260907','20260908','20260909','20260910','20260911','20260912','20260913','20260914','20260915','20260916','20260917','20260918','20260919','20260920','20260921','20260922','20260923','20260924','20260925','20260926','20260927','20260928','20260929','20260930','20261001','20261002','20261003','20261004','20261005','20261006','20261007','20261008','20261009','20261010','20261011','20261012','20261013','20261014','20261015','20261016','20261017','20261018','20261019','20261020','20261021','20261022','20261023','20261024','20261025','20261026','20261027','20261028','20261029','20261030','20261031','20261101','20261102','20261103','20261104','20261105','20261106','20261107','20261108','20261109','20261110','20261111','20261112','20261113','20261114','20261115','20261116','20261117','20261118','20261119','20261120','20261121','20261122','20261123','20261124','20261125','20261126','20261127','20261128','20261129','20261130','20261201','20261202','20261203','20261204','20261205','20261206','20261207','20261208','20261209','20261210','20261211','20261212','20261213','20261214','20261215','20261216','20261217','20261218','20261219','20261220','20261221','20261222','20261223','20261224','20261225','20261226','20261227','20261228','20261229','20261230','20261231','20270101','20270102','20270103','20270104','20270105','20270106','20270107','20270108','20270109','20270110','20270111','20270112','20270113','20270114','20270115','20270116','20270117','20270118','20270119','20270120','20270121','20270122','20270123','20270124','20270125','20270126','20270127','20270128','20270129','20270130','20270131','20270201','20270202','20270203','20270204','20270205','20270206','20270207','20270208','20270209','20270210','20270211','20270212','20270213','20270214','20270215','20270216','20270217','20270218','20270219','20270220','20270221','20270222','20270223','20270224','20270225','20270226','20270227','20270228','20270301','20270302','20270303','20270304','20270305','20270306','20270307','20270308','20270309','20270310','20270311','20270312','20270313','20270314','20270315','20270316','20270317','20270318','20270319','20270320','20270321','20270322','20270323','20270324']}
|
||||
tableStrategy:
|
||||
standard:
|
||||
shardingColumn: create_time
|
||||
shardingAlgorithmName: daily_sharding
|
||||
|
||||
# 用户流量记录表(按天分表)
|
||||
net_user_flow_record:
|
||||
actualDataNodes: net_flow_record.net_user_flow_record_${['20260323']}
|
||||
actualDataNodes: net_flow_record.net_user_flow_record_${['20260324','20260325','20260326','20260327','20260328','20260329','20260330','20260331','20260401','20260402','20260403','20260404','20260405','20260406','20260407','20260408','20260409','20260410','20260411','20260412','20260413','20260414','20260415','20260416','20260417','20260418','20260419','20260420','20260421','20260422','20260423','20260424','20260425','20260426','20260427','20260428','20260429','20260430','20260501','20260502','20260503','20260504','20260505','20260506','20260507','20260508','20260509','20260510','20260511','20260512','20260513','20260514','20260515','20260516','20260517','20260518','20260519','20260520','20260521','20260522','20260523','20260524','20260525','20260526','20260527','20260528','20260529','20260530','20260531','20260601','20260602','20260603','20260604','20260605','20260606','20260607','20260608','20260609','20260610','20260611','20260612','20260613','20260614','20260615','20260616','20260617','20260618','20260619','20260620','20260621','20260622','20260623','20260624','20260625','20260626','20260627','20260628','20260629','20260630','20260701','20260702','20260703','20260704','20260705','20260706','20260707','20260708','20260709','20260710','20260711','20260712','20260713','20260714','20260715','20260716','20260717','20260718','20260719','20260720','20260721','20260722','20260723','20260724','20260725','20260726','20260727','20260728','20260729','20260730','20260731','20260801','20260802','20260803','20260804','20260805','20260806','20260807','20260808','20260809','20260810','20260811','20260812','20260813','20260814','20260815','20260816','20260817','20260818','20260819','20260820','20260821','20260822','20260823','20260824','20260825','20260826','20260827','20260828','20260829','20260830','20260831','20260901','20260902','20260903','20260904','20260905','20260906','20260907','20260908','20260909','20260910','20260911','20260912','20260913','20260914','20260915','20260916','20260917','20260918','20260919','20260920','20260921','20260922','20260923','20260924','20260925','20260926','20260927','20260928','20260929','20260930','20261001','20261002','20261003','20261004','20261005','20261006','20261007','20261008','20261009','20261010','20261011','20261012','20261013','20261014','20261015','20261016','20261017','20261018','20261019','20261020','20261021','20261022','20261023','20261024','20261025','20261026','20261027','20261028','20261029','20261030','20261031','20261101','20261102','20261103','20261104','20261105','20261106','20261107','20261108','20261109','20261110','20261111','20261112','20261113','20261114','20261115','20261116','20261117','20261118','20261119','20261120','20261121','20261122','20261123','20261124','20261125','20261126','20261127','20261128','20261129','20261130','20261201','20261202','20261203','20261204','20261205','20261206','20261207','20261208','20261209','20261210','20261211','20261212','20261213','20261214','20261215','20261216','20261217','20261218','20261219','20261220','20261221','20261222','20261223','20261224','20261225','20261226','20261227','20261228','20261229','20261230','20261231','20270101','20270102','20270103','20270104','20270105','20270106','20270107','20270108','20270109','20270110','20270111','20270112','20270113','20270114','20270115','20270116','20270117','20270118','20270119','20270120','20270121','20270122','20270123','20270124','20270125','20270126','20270127','20270128','20270129','20270130','20270131','20270201','20270202','20270203','20270204','20270205','20270206','20270207','20270208','20270209','20270210','20270211','20270212','20270213','20270214','20270215','20270216','20270217','20270218','20270219','20270220','20270221','20270222','20270223','20270224','20270225','20270226','20270227','20270228','20270301','20270302','20270303','20270304','20270305','20270306','20270307','20270308','20270309','20270310','20270311','20270312','20270313','20270314','20270315','20270316','20270317','20270318','20270319','20270320','20270321','20270322','20270323','20270324']}
|
||||
tableStrategy:
|
||||
standard:
|
||||
shardingColumn: create_time
|
||||
shardingAlgorithmName: daily_sharding
|
||||
|
||||
shardingAlgorithms:
|
||||
|
||||
# 新增: 按天分表算法
|
||||
daily_sharding:
|
||||
type: CLASS_BASED
|
||||
props:
|
||||
strategy: standard
|
||||
algorithmClassName: org.dromara.common.mybatis.sharding.DailyShardingAlgorithm
|
||||
|
||||
props:
|
||||
sql-show: true
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
package org.dromara.common.mybatis.sharding;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.google.common.collect.Range;
|
||||
import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
|
||||
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
|
||||
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 按天分表算法
|
||||
* 表名后缀格式: _yyyyMMdd
|
||||
*
|
||||
* @author lys
|
||||
* @date 2025-03-23
|
||||
*/
|
||||
public class DailyShardingAlgorithm implements StandardShardingAlgorithm<Comparable<?>> {
|
||||
|
||||
|
||||
private static final String DATE_PATTERN = "yyyyMMdd";
|
||||
|
||||
@Override
|
||||
public void init(Properties props) {
|
||||
// 无需初始化
|
||||
}
|
||||
|
||||
/**
|
||||
* 从分片值中提取日期
|
||||
*
|
||||
* @param shardingValue 分片值
|
||||
* @return 日期
|
||||
*/
|
||||
private Date extractDate(Comparable<?> shardingValue) {
|
||||
if (shardingValue instanceof Date) {
|
||||
return (Date) shardingValue;
|
||||
}
|
||||
throw new UnsupportedOperationException("分片值必须是 Date 类型,当前值: " + shardingValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从可用表名集合中获取逻辑表名
|
||||
*
|
||||
* @param availableTargetNames 可用表名集合
|
||||
* @return 逻辑表名(不带后缀)
|
||||
*/
|
||||
private String getLogicTableName(Collection<String> availableTargetNames) {
|
||||
// 从第一个可用表名中提取逻辑表名
|
||||
String firstTableName = availableTargetNames.iterator().next();
|
||||
if (firstTableName != null) {
|
||||
int underscoreIndex = firstTableName.lastIndexOf('_');
|
||||
if (underscoreIndex > 0) {
|
||||
return firstTableName.substring(0, underscoreIndex);
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("无法从可用表名中提取逻辑表名");
|
||||
}
|
||||
@Override
|
||||
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Comparable<?>> shardingValue) {
|
||||
// 获取分片值对应的日期
|
||||
Date date = extractDate(shardingValue.getValue());
|
||||
// 格式化为 yyyyMMdd
|
||||
String suffix = DateUtil.format(date, DATE_PATTERN);
|
||||
// 构建目标表名
|
||||
String logicTableName = getLogicTableName(availableTargetNames);
|
||||
return logicTableName + "_" + suffix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Comparable<?>> shardingValue) {
|
||||
// 获取范围查询的日期范围
|
||||
Range<Comparable<?>> range = shardingValue.getValueRange();
|
||||
Date lower = extractDate(range.lowerEndpoint());
|
||||
Date upper = extractDate(range.upperEndpoint());
|
||||
String logicTableName = getLogicTableName(availableTargetNames);
|
||||
// 生成日期范围内的所有表名
|
||||
Set<String> result = new LinkedHashSet<>();
|
||||
Date current = lower;
|
||||
while (!current.after(upper)) {
|
||||
result.add(logicTableName + "_" + DateUtil.format(current, DATE_PATTERN));
|
||||
current = DateUtil.offsetDay(current, 1);
|
||||
}
|
||||
// 包含上边界
|
||||
result.add(logicTableName + "_" + DateUtil.format(upper, DATE_PATTERN));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package org.dromara.net.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 节点流量记录表 net_node_flow_record
|
||||
* 记录每个节点的流量汇总数据
|
||||
*
|
||||
* @author lys
|
||||
* @date 2025-03-23
|
||||
*/
|
||||
@Data
|
||||
@TableName("net_node_flow_record")
|
||||
public class NetNodeFlowRecord implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 节点ID
|
||||
*/
|
||||
private Long nodeId;
|
||||
|
||||
/**
|
||||
* 上传流量(字节)
|
||||
*/
|
||||
private Long upNum;
|
||||
|
||||
/**
|
||||
* 下载流量(字节)
|
||||
*/
|
||||
private Long downNum;
|
||||
|
||||
/**
|
||||
* 总流量(字节)
|
||||
*/
|
||||
private Long totalNum;
|
||||
|
||||
/**
|
||||
* 记录时间
|
||||
*/
|
||||
private Date createTime;
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package org.dromara.net.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户流量记录表 net_user_flow_record
|
||||
* 记录每个用户的流量汇总数据
|
||||
*
|
||||
* @author lys
|
||||
* @date 2025-03-23
|
||||
*/
|
||||
@Data
|
||||
@TableName("net_user_flow_record")
|
||||
public class NetUserFlowRecord implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 上传流量(字节)
|
||||
*/
|
||||
private Long upNum;
|
||||
|
||||
/**
|
||||
* 下载流量(字节)
|
||||
*/
|
||||
private Long downNum;
|
||||
|
||||
/**
|
||||
* 总流量(字节)
|
||||
*/
|
||||
private Long totalNum;
|
||||
|
||||
/**
|
||||
* 记录时间
|
||||
*/
|
||||
private Date createTime;
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
package org.dromara.net.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 添加用户到节点请求DTO
|
||||
* 对应 POST /node/handler/add-user 接口
|
||||
*
|
||||
* @author lys
|
||||
* @date 2025-03-20
|
||||
*/
|
||||
@Data
|
||||
public class AddUserToNodeRequest {
|
||||
|
||||
/**
|
||||
* 用户数据列表
|
||||
*/
|
||||
private List<InboundData> data;
|
||||
|
||||
/**
|
||||
* 哈希数据
|
||||
*/
|
||||
private HashData hashData;
|
||||
|
||||
/**
|
||||
* 入站数据 - 基类
|
||||
*/
|
||||
@Data
|
||||
public static class InboundData {
|
||||
/**
|
||||
* 协议类型: vless, trojan, shadowsocks
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 入站标签
|
||||
*/
|
||||
private String tag;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String username;
|
||||
}
|
||||
|
||||
/**
|
||||
* VLESS入站数据
|
||||
*/
|
||||
@Data
|
||||
public static class VlessInboundData extends InboundData {
|
||||
/**
|
||||
* UUID
|
||||
*/
|
||||
private String uuid;
|
||||
|
||||
/**
|
||||
* 流控: xtls-rprx-vision 或空字符串
|
||||
*/
|
||||
private String flow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trojan入站数据
|
||||
*/
|
||||
@Data
|
||||
public static class TrojanInboundData extends InboundData {
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
private String password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shadowsocks入站数据
|
||||
*/
|
||||
@Data
|
||||
public static class ShadowsocksInboundData extends InboundData {
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 加密类型
|
||||
* 5 = AES_128_GCM
|
||||
* 6 = AES_256_GCM
|
||||
* 7 = CHACHA20_POLY1305
|
||||
*/
|
||||
private Integer cipherType;
|
||||
|
||||
/**
|
||||
* IV检查
|
||||
*/
|
||||
private Boolean ivCheck;
|
||||
}
|
||||
|
||||
/**
|
||||
* 哈希数据
|
||||
*/
|
||||
@Data
|
||||
public static class HashData {
|
||||
/**
|
||||
* VLESS UUID
|
||||
*/
|
||||
private String vlessUuid;
|
||||
|
||||
/**
|
||||
* 上一个VLESS UUID(可选)
|
||||
*/
|
||||
private String prevVlessUuid;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package org.dromara.net.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 添加用户到节点响应DTO
|
||||
* 对应 POST /node/handler/add-user 接口响应
|
||||
*
|
||||
* @author lys
|
||||
* @date 2025-03-20
|
||||
*/
|
||||
@Data
|
||||
public class AddUserToNodeResponse {
|
||||
|
||||
/**
|
||||
* 响应数据
|
||||
*/
|
||||
private ResponseData response;
|
||||
|
||||
@Data
|
||||
public static class ResponseData {
|
||||
/**
|
||||
* 是否成功
|
||||
*/
|
||||
private Boolean success;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String error;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package org.dromara.net.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 节点用户流量统计请求DTO
|
||||
* 对应 POST /node/stats/get-users-stats 接口的请求体
|
||||
*
|
||||
* @author lys
|
||||
* @date 2025-03-23
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class NodeUserStatsRequest {
|
||||
|
||||
/**
|
||||
* 是否重置统计数据
|
||||
* true - 获取数据后重置节点上的流量统计
|
||||
*/
|
||||
private Boolean reset;
|
||||
|
||||
public NodeUserStatsRequest(Boolean reset) {
|
||||
this.reset = reset;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package org.dromara.net.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 节点用户流量统计响应DTO
|
||||
* 对应 POST /node/stats/get-users-stats 接口的响应
|
||||
*
|
||||
* @author lys
|
||||
* @date 2025-03-23
|
||||
*/
|
||||
@Data
|
||||
public class NodeUserStatsResponse {
|
||||
|
||||
/**
|
||||
* 响应数据
|
||||
*/
|
||||
private ResponseData response;
|
||||
|
||||
@Data
|
||||
public static class ResponseData {
|
||||
/**
|
||||
* 用户流量列表
|
||||
*/
|
||||
private List<UserFlowData> users;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户流量数据
|
||||
*/
|
||||
@Data
|
||||
public static class UserFlowData {
|
||||
/**
|
||||
* 用户名(用户ID字符串形式)
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 下载流量(字节)
|
||||
*/
|
||||
private Long downlink;
|
||||
|
||||
/**
|
||||
* 上传流量(字节)
|
||||
*/
|
||||
private Long uplink;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package org.dromara.net.mapper;
|
||||
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.dromara.net.domain.NetNodeFlowRecord;
|
||||
|
||||
/**
|
||||
* 节点流量记录Mapper接口
|
||||
*
|
||||
* @author lys
|
||||
* @date 2025-03-23
|
||||
*/
|
||||
@Mapper
|
||||
@DS(value = "net_flow_record")
|
||||
public interface NetNodeFlowRecordMapper extends BaseMapper<NetNodeFlowRecord> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package org.dromara.net.mapper;
|
||||
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.dromara.net.domain.NetUserFlowRecord;
|
||||
|
||||
/**
|
||||
* 用户流量记录Mapper接口
|
||||
*
|
||||
* @author lys
|
||||
* @date 2025-03-23
|
||||
*/
|
||||
@Mapper
|
||||
@DS(value = "net_flow_record")
|
||||
public interface NetUserFlowRecordMapper extends BaseMapper<NetUserFlowRecord> {
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue