commit 4eabb493da653519a772c96a31ff01cd5e592e31 Author: 31353 <31353751672@qq.com> Date: Sat Apr 13 13:31:41 2024 +0800 11 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..0f996d3 --- /dev/null +++ b/pom.xml @@ -0,0 +1,231 @@ + + + 4.0.0 + com.muyu + mqtt + 0.0.1-SNAPSHOT + mqtt + Demo project for Spring Boot + + 1.8 + UTF-8 + UTF-8 + 2.6.13 + + + + + + + + com.aliyun + darabonba-string + 0.0.3 + + + com.aliyun + tea + [1.0.3, 2.0.0) + + + + com.aliyun + ecs20140526 + 3.1.2 + + + com.aliyun + tea-openapi + 0.3.2 + + + com.aliyun + tea-util + 0.2.21 + + + com.aliyun + tea-console + 0.0.1 + + + com.aliyun + darabonba-env + 0.1.1 + + + com.aliyun + tea + 1.1.14 + + + + + com.aliyun + credentials-java + LATEST + + + com.aliyun + tea-openapi + 0.2.8 + + + com.aliyun + dysmsapi20170525 + 2.0.24 + + + + com.aliyun + ecs20140526 + 3.1.12 + + + + com.aliyun + aliyun-java-sdk-core + 4.6.3 + + + com.aliyun + aliyun-java-sdk-ecs + 4.24.59 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.projectlombok + lombok + + + org.springframework.boot + spring-boot-starter-data-redis + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + 1.2.5 + + + + com.alibaba.fastjson2 + fastjson2 + 2.0.47 + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework + spring-tx + 5.3.31 + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + 16 + 16 + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.3 + true + + sonatype-nexus-staging + https://s01.oss.sonatype.org/ + true + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.1.1 + + UTF-8 + none + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.1 + + + org.apache.maven.plugins + maven-assembly-plugin + 2.4.1 + + + jar-with-dependencies + + + + true + com.aliyun.sample.Sample + + + + + + make-assembly + package + + single + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/com/muyu/MqttApplication.java b/src/main/java/com/muyu/MqttApplication.java new file mode 100644 index 0000000..f59e26d --- /dev/null +++ b/src/main/java/com/muyu/MqttApplication.java @@ -0,0 +1,15 @@ +package com.muyu; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; + +@EnableScheduling +@SpringBootApplication +public class MqttApplication { + + public static void main(String[] args) { + SpringApplication.run(MqttApplication.class, args); + } + +} diff --git a/src/main/java/com/muyu/common/RedisService.java b/src/main/java/com/muyu/common/RedisService.java new file mode 100644 index 0000000..f4ecc1a --- /dev/null +++ b/src/main/java/com/muyu/common/RedisService.java @@ -0,0 +1,270 @@ +package com.muyu.common; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.*; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * spring redis 工具类 + * + * @author muyu + **/ +@SuppressWarnings(value = {"unchecked", "rawtypes"}) +@Component +public class RedisService { + @Autowired + public RedisTemplate redisTemplate; + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + */ + public void setCacheObject (final String key, final T value) { + redisTemplate.opsForValue().set(key, value); + } + + + // 判断 key 是否存在 + public boolean exists(String key) { + return redisTemplate.hasKey(key); + } + public ZSetOperations opsForZSet() { + return redisTemplate.opsForZSet(); + } + + public ValueOperations opsForValue() { + return redisTemplate.opsForValue(); + } + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + * @param timeout 时间 + * @param timeUnit 时间颗粒度 + */ + public void setCacheObject (final String key, final T value, final Long timeout, final TimeUnit timeUnit) { + redisTemplate.opsForValue().set(key, value, timeout, timeUnit); + } + + /** + * 设置有效时间 + * + * @param key Redis键 + * @param timeout 超时时间 + * + * @return true=设置成功;false=设置失败 + */ + public boolean expire (final String key, final long timeout) { + return expire(key, timeout, TimeUnit.SECONDS); + } + + /** + * 设置有效时间 + * + * @param key Redis键 + * @param timeout 超时时间 + * @param unit 时间单位 + * + * @return true=设置成功;false=设置失败 + */ + public boolean expire (final String key, final long timeout, final TimeUnit unit) { + return redisTemplate.expire(key, timeout, unit); + } + + /** + * 获取有效时间 + * + * @param key Redis键 + * + * @return 有效时间 + */ + public long getExpire (final String key) { + return redisTemplate.getExpire(key); + } + + /** + * 判断 key是否存在 + * + * @param key 键 + * + * @return true 存在 false不存在 + */ + public Boolean hasKey (String key) { + return redisTemplate.hasKey(key); + } + + /** + * 获得缓存的基本对象。 + * + * @param key 缓存键值 + * + * @return 缓存键值对应的数据 + */ + public T getCacheObject (final String key) { + ValueOperations operation = redisTemplate.opsForValue(); + return operation.get(key); + } + + /** + * 删除单个对象 + * + * @param key + */ + public boolean deleteObject (final String key) { + return redisTemplate.delete(key); + } + + /** + * 删除集合对象 + * + * @param collection 多个对象 + * + * @return + */ + public boolean deleteObject (final Collection collection) { + return redisTemplate.delete(collection) > 0; + } + + /** + * 缓存List数据 + * + * @param key 缓存的键值 + * @param dataList 待缓存的List数据 + * + * @return 缓存的对象 + */ + public long setCacheList (final String key, final List dataList) { + Long count = redisTemplate.opsForList().rightPushAll(key, dataList); + return count == null ? 0 : count; + } + + /** + * 获得缓存的list对象 + * + * @param key 缓存的键值 + * + * @return 缓存键值对应的数据 + */ + public List getCacheList (final String key) { + return redisTemplate.opsForList().range(key, 0, -1); + } + + /** + * 缓存Set + * + * @param key 缓存键值 + * @param dataSet 缓存的数据 + * + * @return 缓存数据的对象 + */ + public BoundSetOperations setCacheSet (final String key, final Set dataSet) { + BoundSetOperations setOperation = redisTemplate.boundSetOps(key); + Iterator it = dataSet.iterator(); + while (it.hasNext()) { + setOperation.add(it.next()); + } + return setOperation; + } + + + + + /** + * 获得缓存的set + * + * @param key + * + * @return + */ + public Set getCacheSet (final String key) { + return redisTemplate.opsForSet().members(key); + } + + /** + * 缓存Map + * + * @param key + * @param dataMap + */ + public void setCacheMap (final String key, final Map dataMap) { + if (dataMap != null) { + redisTemplate.opsForHash().putAll(key, dataMap); + } + } + + /** + * 获得缓存的Map + * + * @param key + * + * @return + */ + public Map getCacheMap (final String key) { + return redisTemplate.opsForHash().entries(key); + } + + /** + * 往Hash中存入数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @param value 值 + */ + public void setCacheMapValue (final String key, final String hKey, final T value) { + redisTemplate.opsForHash().put(key, hKey, value); + } + + /** + * 获取Hash中的数据 + * + * @param key Redis键 + * @param hKey Hash键 + * + * @return Hash中的对象 + */ + public T getCacheMapValue (final String key, final String hKey) { + HashOperations opsForHash = redisTemplate.opsForHash(); + return opsForHash.get(key, hKey); + } + + /** + * 获取多个Hash中的数据 + * + * @param key Redis键 + * @param hKeys Hash键集合 + * + * @return Hash对象集合 + */ + public List getMultiCacheMapValue (final String key, final Collection hKeys) { + return redisTemplate.opsForHash().multiGet(key, hKeys); + } + + /** + * 删除Hash中的某条数据 + * + * @param key Redis键 + * @param hKey Hash键 + * + * @return 是否成功 + */ + public boolean deleteCacheMapValue (final String key, final String hKey) { + return redisTemplate.opsForHash().delete(key, hKey) > 0; + } + + /** + * 获得缓存的基本对象列表 + * + * @param pattern 字符串前缀 + * + * @return 对象列表 + */ + public Collection keys (final String pattern) { + return redisTemplate.keys(pattern); + } +} diff --git a/src/main/java/com/muyu/common/Result.java b/src/main/java/com/muyu/common/Result.java new file mode 100644 index 0000000..783f4ba --- /dev/null +++ b/src/main/java/com/muyu/common/Result.java @@ -0,0 +1,111 @@ +package com.muyu.common; + + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 响应信息主体 + * + * @author muyu + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Result implements Serializable { + /** + * 成功 + */ + public static final int SUCCESS = 200; + /** + * 失败 + */ + public static final int FAIL = 500; + /** + * 警告 + */ + public static final int WARN = 800; + + private static final long serialVersionUID = 1L; + private int code; + + private String msg; + + private T data; + + public static Result success () { + return restResult(null, SUCCESS, null); + } + + public static Result success (T data) { + return restResult(data, SUCCESS, null); + } + + public static Result success (T data, String msg) { + return restResult(data, SUCCESS, msg); + } + + public static Result error () { + return restResult(null, FAIL, null); + } + + public static Result error (String msg) { + return restResult(null, FAIL, msg); + } + + public static Result error (T data) { + return restResult(data, FAIL, null); + } + + public static Result error (T data, String msg) { + return restResult(data, FAIL, msg); + } + + public static Result error (int code, String msg) { + return restResult(null, code, msg); + } + + + + public static Result warn () { + return restResult(null, WARN, null); + } + + public static Result warn (String msg) { + return restResult(null, WARN, msg); + } + + public static Result warn (T data) { + return restResult(data, WARN, null); + } + + public static Result warn (T data, String msg) { + return restResult(data, WARN, msg); + } + + public static Result warn (int code, String msg) { + return restResult(null, code, msg); + } + + private static Result restResult (T data, int code, String msg) { + return Result.builder() + .code(code) + .data(data) + .msg(msg) + .build(); + } + + public static Boolean isError (Result ret) { + return !isSuccess(ret); + } + + public static Boolean isSuccess (Result ret) { + return Result.SUCCESS == ret.getCode(); + } + +} diff --git a/src/main/java/com/muyu/common/contents/CreateContents.java b/src/main/java/com/muyu/common/contents/CreateContents.java new file mode 100644 index 0000000..77d5462 --- /dev/null +++ b/src/main/java/com/muyu/common/contents/CreateContents.java @@ -0,0 +1,14 @@ +package com.muyu.common.contents; + +/** + * @author gxb + * @description TODO + * @date 2024-04-12 16:22 + */ +public class CreateContents { + + //AccessKey ID值 + public static final String ACCESSKEYIDDATA = "LTAI5tS15R28wsYmgZ8uZonR"; + //您的AccessKey Secret + public static final String ACCESSKEYSECRETDATA = "ETEMZeUhPSb1M6d0kR0XVBaIkzshqB"; +} diff --git a/src/main/java/com/muyu/common/contents/MessageConstant.java b/src/main/java/com/muyu/common/contents/MessageConstant.java new file mode 100644 index 0000000..10f8745 --- /dev/null +++ b/src/main/java/com/muyu/common/contents/MessageConstant.java @@ -0,0 +1,86 @@ +package com.muyu.common.contents; + +import org.springframework.stereotype.Component; + +/** + * @author gxb + * @description TODO + * @date 2024-04-06 8:57 + */ +@Component +public class MessageConstant { + /** + * 车辆状态 + */ + public static final Integer VEHICLE_STATUS = 1; + + /** + * 充电状态 + */ + public static final Integer CHARGING_STATUS = 1; + + /** + * 运行状态 + */ + public static final Integer OPERATING_STATUS = 1; + + /** + * soc状态 + */ + public static final Integer SOC_STATUS = 1; + + /** + * 可充电储能装置工作状态 + */ + public static final Integer CHARGING_ENERGY_STORAGE_STATUS = 1; + + /** + * 驱动电机状态 + */ + public static final Integer DRIVE_MOTOR_STATUS = 1; + + /** + * 定位是否有效 + */ + public static final Integer POSITION_STATUS = 1; + + /** + * EAS(汽车防盗系统)状态 + */ + public static final Integer EAS_STATUS = 1; + + /** + * PTC(电动加热器)状态 + */ + public static final Integer PTC_STATUS = 1; + + /** + * ABS(防抱死)状态 + */ + public static final Integer ABS_STATUS = 1; + + /** + * MCU(电机/逆变器)状态 + */ + public static final Integer MCU_STATUS = 1; + /** + * 动力电池加热状态 + */ + public static final Integer HEATING_STATUS = 1; + /** + * 动力电池当前状态 + */ + public static final Integer BATTERY_STATUS = 1; + /** + * 动力电池保温状态 + */ + public static final Integer BATTERY_INSULATION_STATUS = 1; + /** + * DCDC(电力交换系统) 状态 + */ + public static final Integer DCDC_STATUS = 1; + /** + * CHG(充电机)状态 + */ + public static final Integer CHG_STATUS = 1; +} diff --git a/src/main/java/com/muyu/common/domain/ApifoxModel.java b/src/main/java/com/muyu/common/domain/ApifoxModel.java new file mode 100644 index 0000000..d8d23ec --- /dev/null +++ b/src/main/java/com/muyu/common/domain/ApifoxModel.java @@ -0,0 +1,55 @@ +package com.muyu.common.domain; + +import lombok.Data; + +@Data +public class ApifoxModel { + /** + * 节点ID + */ + private String clusterId; + /** + * CPU使用信息 + */ + private CPUInfo cpuInfo; + /** + * 节点状态 + */ + private FlowInfo flowInfo; + /** + * HTTP请求地址 + */ + private String httpUrl; + /** + * JVM使用信息 + */ + private JVMInfo jvmInfo; + /** + * MQTT事件信息 + */ + private MqttInfo mqttInfo; + /** + * MQTTS请求地址 + */ + private String mqttsUrl; + /** + * MQTT请求地址 + */ + private String mqttUrl; + /** + * 节点名称 + */ + private String nodeName; + /** + * 启动时间 + */ + private String startJvmTime; + /** + * 节点版本 + */ + private String version; + /** + * websocket请求地址 + */ + private String websocketUrl; +} diff --git a/src/main/java/com/muyu/common/domain/CPUInfo.java b/src/main/java/com/muyu/common/domain/CPUInfo.java new file mode 100644 index 0000000..10d27f3 --- /dev/null +++ b/src/main/java/com/muyu/common/domain/CPUInfo.java @@ -0,0 +1,30 @@ +package com.muyu.common.domain; + +import lombok.Data; + +/** + * CPU使用信息 + */ +@Data +public class CPUInfo { + /** + * CPU核数 + */ + private long cpuNum; + /** + * 内核态使用率 + */ + private String cSys; + /** + * 空闲率 + */ + private String idle; + /** + * I/O等待 + */ + private String iowait; + /** + * 用户态使用率 + */ + private String user; +} diff --git a/src/main/java/com/muyu/common/domain/CreateVo.java b/src/main/java/com/muyu/common/domain/CreateVo.java new file mode 100644 index 0000000..26f9371 --- /dev/null +++ b/src/main/java/com/muyu/common/domain/CreateVo.java @@ -0,0 +1,32 @@ +package com.muyu.common.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author gxb + * @description TODO + * @date 2024-04-12 16:17 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class CreateVo { + + //地域ID + private String redionId = "cn-shanghai"; + + //查询资源类型,取值范围 + private String destinationResource = "InstanceType"; + + //是否为I/O优化实例 + private String ioOptimized = "optimized"; + + //实例规格 + private String instanceType = "ecs.u1-c1m1.large"; + + private String instanceId; +} diff --git a/src/main/java/com/muyu/common/domain/DeleteServer.java b/src/main/java/com/muyu/common/domain/DeleteServer.java new file mode 100644 index 0000000..8bbb643 --- /dev/null +++ b/src/main/java/com/muyu/common/domain/DeleteServer.java @@ -0,0 +1,32 @@ +package com.muyu.common.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author gxb + * @description TODO + * @date 2024-04-12 19:14 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class DeleteServer { + //区域ID + private String regionId = "cn-shanghai"; + + //多个实例ID,英文逗号隔开 + private String instanceIds; + + //实例名称,支持模糊查 + private String instanceName; + + //是否强制删除有删除保护的机器 默认 true + private String deleteProtected="true"; + + //是否强制删除运行中的机器 默认 true + private String force = "true"; +} diff --git a/src/main/java/com/muyu/common/domain/FlowInfo.java b/src/main/java/com/muyu/common/domain/FlowInfo.java new file mode 100644 index 0000000..ada9422 --- /dev/null +++ b/src/main/java/com/muyu/common/domain/FlowInfo.java @@ -0,0 +1,28 @@ +package com.muyu.common.domain; + +import lombok.Data; /** + * 节点状态 + */ +@Data +public class FlowInfo { + /** + * 上次读取吞吐量 + */ + private String lastReadThroughput; + /** + * 上次写入吞吐量 + */ + private String lastWriteThroughput; + /** + * 读取总吞吐量 + */ + private String readBytesHistory; + /** + * 实写字节 + */ + private String realWriteBytes; + /** + * 写入总吞吐量 + */ + private String writeBytesHistory; +} diff --git a/src/main/java/com/muyu/common/domain/Icreate.java b/src/main/java/com/muyu/common/domain/Icreate.java new file mode 100644 index 0000000..b3c6287 --- /dev/null +++ b/src/main/java/com/muyu/common/domain/Icreate.java @@ -0,0 +1,48 @@ +package com.muyu.common.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author gxb + * @description TODO + * @date 2024-04-12 16:25 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class Icreate { + + //地域ID + private String rehionId = "cn-shanghai"; + + //镜像ID + private String imageId = "m-uf6elrscl3c9wk6o762l"; + + //实例规格 + private String instanceType = "ecs.e-c1m1.large"; + + //安全组ID + private String securityGroupId = "sg-uf6bj6vxp8ruhvffdsau"; + + //虚拟交换机ID + private String vSwitchId = "vsw-uf6sfq669js64lwke0isv"; + + //公网出带宽最大值,单位为 Mbit/s。取值范围:0~100。 默认值:0。 + private String internetMaxBandwidthOut = "2"; + + //网络计费类型,取值范围 + private String internetChargeType = "PayByTraffic"; + + //系统盘大小 + private String size = "20"; + + //系统盘的云盘种类 + private String category = "cloud_essd"; + + //ECS实例的计费方式 + private String instanceChargeType = "PostPaid"; +} diff --git a/src/main/java/com/muyu/common/domain/JVMInfo.java b/src/main/java/com/muyu/common/domain/JVMInfo.java new file mode 100644 index 0000000..76dc8bf --- /dev/null +++ b/src/main/java/com/muyu/common/domain/JVMInfo.java @@ -0,0 +1,58 @@ +package com.muyu.common.domain; + +import lombok.Data; + +/** + * JVM使用信息 + */ +@Data +public class JVMInfo { + /** + * 文件描述(句柄) + */ + private String fileDescriptors; + /** + * 堆内存 + */ + private String heapCommit; + /** + * 堆初始化空间 + */ + private String heapInit; + /** + * 堆最大内存 + */ + private String heapMax; + /** + * 堆使用空间 + */ + private String heapUsed; + /** + * JAVA目录 + */ + private String jdkHome; + /** + * JDK版本 + */ + private String jdkVersion; + /** + * 非堆空间 + */ + private String noHeapCommit; + /** + * 非堆初始化空间 + */ + private String noHeapInit; + /** + * 非堆最大空间 + */ + private String noHeapMax; + /** + * 非堆使用空间 + */ + private String noHeapUsed; + /** + * 线程数量 + */ + private long threadCount; +} diff --git a/src/main/java/com/muyu/common/domain/MqttInfo.java b/src/main/java/com/muyu/common/domain/MqttInfo.java new file mode 100644 index 0000000..073413f --- /dev/null +++ b/src/main/java/com/muyu/common/domain/MqttInfo.java @@ -0,0 +1,63 @@ +package com.muyu.common.domain;// ApifoxModel.java + + +import lombok.Data; + + +// JVMInfo.java + + +// MqttInfo.java + + + +/** + * MQTT事件信息 + */ +@Data +public class MqttInfo { + /** + * 关闭事件数量 + */ + private long closeEventSize; + /** + * 连接事件数量 + */ + private long connectEventSize; + /** + * 链接总数 + */ + private long connectSize; + /** + * 断开链接数量 + */ + private long disconnectEventSize; + /** + * 推送数量 + */ + private long publishEventSize; + /** + * 发布重试事件数量 + */ + private long publishRetryEventSize; + /** + * 保留消息数量 + */ + private long retainSize; + /** + * 订阅事件数量 + */ + private long subscribeEventSize; + /** + * 订阅数量 + */ + private long subscribeSize; + /** + * 主题数量 + */ + private long topicSize; + /** + * 取消订阅数量 + */ + private long unSubscribeEventSize; +} diff --git a/src/main/java/com/muyu/common/domain/NodeRegReq.java b/src/main/java/com/muyu/common/domain/NodeRegReq.java new file mode 100644 index 0000000..37c2e65 --- /dev/null +++ b/src/main/java/com/muyu/common/domain/NodeRegReq.java @@ -0,0 +1,28 @@ +package com.muyu.common.domain; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author gxb + * @description TODO + * @date 2024-04-13 8:33 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class NodeRegReq { + + /** + * 客户端ID + */ + private String clientId; + + /** + * token + */ + private String token; +} diff --git a/src/main/java/com/muyu/common/ip/IpUtils.java b/src/main/java/com/muyu/common/ip/IpUtils.java new file mode 100644 index 0000000..0fd1f5d --- /dev/null +++ b/src/main/java/com/muyu/common/ip/IpUtils.java @@ -0,0 +1,362 @@ +package com.muyu.common.ip; + +import org.springframework.util.StringUtils; + +import javax.servlet.http.HttpServletRequest; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * 获取IP方法 + * + * @author muyu + */ +public class IpUtils { + public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)"; + // 匹配 ip + public final static String REGX_IP = "((" + REGX_0_255 + "\\.){3}" + REGX_0_255 + ")"; + // 匹配网段 + public final static String REGX_IP_SEG = "(" + REGX_IP + "\\-" + REGX_IP + ")"; + public final static String REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + REGX_0_255 + "(\\.\\*){3})|(" + REGX_0_255 + "\\." + REGX_0_255 + ")(\\.\\*){2}" + "|((" + REGX_0_255 + "\\.){3}\\*))"; + + + /** + * 获取客户端IP + * + * @param request 请求对象 + * + * @return IP地址 + */ + public static String getIpAddr (HttpServletRequest request) { + if (request == null) { + return "unknown"; + } + String ip = request.getHeader("x-forwarded-for"); + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("X-Forwarded-For"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("X-Real-IP"); + } + + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + + return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip); + } + + /** + * 检查是否为内部IP地址 + * + * @param ip IP地址 + * + * @return 结果 + */ + public static boolean internalIp (String ip) { + byte[] addr = textToNumericFormatV4(ip); + return internalIp(addr) || "127.0.0.1".equals(ip); + } + + /** + * 检查是否为内部IP地址 + * + * @param addr byte地址 + * + * @return 结果 + */ + private static boolean internalIp (byte[] addr) { + if (addr == null || addr.length < 2) { + return true; + } + final byte b0 = addr[0]; + final byte b1 = addr[1]; + // 10.x.x.x/8 + final byte SECTION_1 = 0x0A; + // 172.16.x.x/12 + final byte SECTION_2 = (byte) 0xAC; + final byte SECTION_3 = (byte) 0x10; + final byte SECTION_4 = (byte) 0x1F; + // 192.168.x.x/16 + final byte SECTION_5 = (byte) 0xC0; + final byte SECTION_6 = (byte) 0xA8; + switch (b0) { + case SECTION_1: + return true; + case SECTION_2: + if (b1 >= SECTION_3 && b1 <= SECTION_4) { + return true; + } + case SECTION_5: + switch (b1) { + case SECTION_6: + return true; + } + default: + return false; + } + } + + /** + * 将IPv4地址转换成字节 + * + * @param text IPv4地址 + * + * @return byte 字节 + */ + public static byte[] textToNumericFormatV4 (String text) { + if (text.length() == 0) { + return null; + } + + byte[] bytes = new byte[4]; + String[] elements = text.split("\\.", -1); + try { + long l; + int i; + switch (elements.length) { + case 1: + l = Long.parseLong(elements[0]); + if ((l < 0L) || (l > 4294967295L)) { + return null; + } + bytes[0] = (byte) (int) (l >> 24 & 0xFF); + bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF); + bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 2: + l = Integer.parseInt(elements[0]); + if ((l < 0L) || (l > 255L)) { + return null; + } + bytes[0] = (byte) (int) (l & 0xFF); + l = Integer.parseInt(elements[1]); + if ((l < 0L) || (l > 16777215L)) { + return null; + } + bytes[1] = (byte) (int) (l >> 16 & 0xFF); + bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 3: + for (i = 0; i < 2 ; ++i) { + l = Integer.parseInt(elements[i]); + if ((l < 0L) || (l > 255L)) { + return null; + } + bytes[i] = (byte) (int) (l & 0xFF); + } + l = Integer.parseInt(elements[2]); + if ((l < 0L) || (l > 65535L)) { + return null; + } + bytes[2] = (byte) (int) (l >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 4: + for (i = 0; i < 4 ; ++i) { + l = Integer.parseInt(elements[i]); + if ((l < 0L) || (l > 255L)) { + return null; + } + bytes[i] = (byte) (int) (l & 0xFF); + } + break; + default: + return null; + } + } catch (NumberFormatException e) { + return null; + } + return bytes; + } + + /** + * 获取IP地址 + * + * @return 本地IP地址 + */ + public static String getHostIp () { + try { + return InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + } + return "127.0.0.1"; + } + + /** + * 获取主机名 + * + * @return 本地主机名 + */ + public static String getHostName () { + try { + return InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + } + return "未知"; + } + + /** + * 从多级反向代理中获得第一个非unknown IP地址 + * + * @param ip 获得的IP地址 + * + * @return 第一个非unknown IP地址 + */ + public static String getMultistageReverseProxyIp (String ip) { + // 多级反向代理检测 + if (ip != null && ip.indexOf(",") > 0) { + final String[] ips = ip.trim().split(","); + for (String subIp : ips) { + if (false == isUnknown(subIp)) { + ip = subIp; + break; + } + } + } + return substring(ip, 0, 255); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @param end 结束 + * + * @return 结果 + */ + public static String substring (final String str, int start, int end) { + if (str == null) { + return ""; + } + + if (end < 0) { + end = str.length() + end; + } + if (start < 0) { + start = str.length() + start; + } + + if (end > str.length()) { + end = str.length(); + } + + if (start > end) { + return ""; + } + + if (start < 0) { + start = 0; + } + if (end < 0) { + end = 0; + } + + return str.substring(start, end); + } + + + /** + * 检测给定字符串是否为未知,多用于检测HTTP请求相关 + * + * @param checkString 被检测的字符串 + * + * @return 是否未知 + */ + public static boolean isUnknown (String checkString) { + return checkString == null || "unknown".equalsIgnoreCase(checkString); + } + + /** + * 是否为IP + */ + public static boolean isIP (String ip) { + return ip!=null && ip.matches(REGX_IP); + } + + /** + * 是否为IP,或 *为间隔的通配符地址 + */ + public static boolean isIpWildCard (String ip) { + return ip!=null && ip.matches(REGX_IP_WILDCARD); + } + + /** + * 检测参数是否在ip通配符里 + */ + public static boolean ipIsInWildCardNoCheck (String ipWildCard, String ip) { + String[] s1 = ipWildCard.split("\\."); + String[] s2 = ip.split("\\."); + boolean isMatchedSeg = true; + for (int i = 0 ; i < s1.length && !s1[i].equals("*") ; i++) { + if (!s1[i].equals(s2[i])) { + isMatchedSeg = false; + break; + } + } + return isMatchedSeg; + } + + /** + * 是否为特定格式如:“10.10.10.1-10.10.10.99”的ip段字符串 + */ + public static boolean isIPSegment (String ipSeg) { + return ipSeg!=null && ipSeg.matches(REGX_IP_SEG); + } + + /** + * 判断ip是否在指定网段中 + */ + public static boolean ipIsInNetNoCheck (String iparea, String ip) { + int idx = iparea.indexOf('-'); + String[] sips = iparea.substring(0, idx).split("\\."); + String[] sipe = iparea.substring(idx + 1).split("\\."); + String[] sipt = ip.split("\\."); + long ips = 0L, ipe = 0L, ipt = 0L; + for (int i = 0 ; i < 4 ; ++i) { + ips = ips << 8 | Integer.parseInt(sips[i]); + ipe = ipe << 8 | Integer.parseInt(sipe[i]); + ipt = ipt << 8 | Integer.parseInt(sipt[i]); + } + if (ips > ipe) { + long t = ips; + ips = ipe; + ipe = t; + } + return ips <= ipt && ipt <= ipe; + } + + /** + * 校验ip是否符合过滤串规则 + * + * @param filter 过滤IP列表,支持后缀'*'通配,支持网段如:`10.10.10.1-10.10.10.99` + * @param ip 校验IP地址 + * + * @return boolean 结果 + */ + public static boolean isMatchedIp (String filter, String ip) { + if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(ip)) { + return false; + } + String[] ips = filter.split(";"); + for (String iStr : ips) { + if (isIP(iStr) && iStr.equals(ip)) { + return true; + } else if (isIpWildCard(iStr) && ipIsInWildCardNoCheck(iStr, ip)) { + return true; + } else if (isIPSegment(iStr) && ipIsInNetNoCheck(iStr, ip)) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/com/muyu/controller/LoadCenterController.java b/src/main/java/com/muyu/controller/LoadCenterController.java new file mode 100644 index 0000000..8e58e64 --- /dev/null +++ b/src/main/java/com/muyu/controller/LoadCenterController.java @@ -0,0 +1,129 @@ +package com.muyu.controller; + +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.aliyun.ecs20140526.models.DescribeInstancesResponse; +import com.aliyun.ecs20140526.models.DescribeInstancesResponseBody; +import com.aliyun.ecs20140526.models.RunInstancesResponse; +import com.aliyun.tea.TeaException; +import com.muyu.common.RedisService; +import com.muyu.common.domain.Icreate; +import com.muyu.instance.ClientConfig; +import com.muyu.instance.CreateAn; +import lombok.extern.log4j.Log4j2; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author gxb + * @description TODO + * @date 2024-04-13 12:46 + */ +@Component +@Log4j2 +public class LoadCenterController { + + //定义一个值 + int a=1; + + + @Autowired + private RedisService redisService; + + /** + * 定时器扫描 + * @throws Exception + */ + @Scheduled(cron = "0/30 * * * * ?") + public void scheduleECS() throws Exception { + //获取FluxMQ运行信息 + String URL = "http://43.143.161.183:8080/public/cluster"; + //假设这里出现了超出预设连接数大于80%,则进行扩容 + OkHttpClient client = new OkHttpClient(); + + Request request = new Request.Builder() + .url(URL) + .get() + .addHeader("User-Agent", "Apifox/1.0.0 (https://apifox.com)") + .addHeader("Accesstoken", "") + .build(); + + try { + Response response = client.newCall(request).execute(); + + JSONArray jsonArray = JSONArray.parseArray(response.body().string()); + JSONObject jsonObject = jsonArray.getJSONObject(0); + JSONObject mqttInfo = jsonObject.getJSONObject("mqttInfo"); + int connectSize = mqttInfo.getIntValue("connectSize"); + //获取连接数 + System.out.println("连接数"+connectSize); + + //判断是否达到连接数80 + if (connectSize>=250){ + //节点扩容 + try { + Icreate icreate = new Icreate(); + String anServer = CreateAn.createAnServer(icreate); + log.info("扩容成功,实例ID为:{}",anServer); + selectECS("Myname"); + } catch (Exception e) { + throw new RuntimeException("扩容失败:"+e.getMessage()); + } + + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + + public void selectECS(String instanceName) throws Exception { + com.aliyun.ecs20140526.Client client = ClientConfig.createClient(); + com.aliyun.ecs20140526.models.DescribeInstancesRequest describeInstancesRequest = new com.aliyun.ecs20140526.models.DescribeInstancesRequest() + .setRegionId("cn-zhangjiakou") + .setInstanceName(instanceName) + .setPageSize(10); + + com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions(); + + try { + // 复制代码运行请自行打印 API 的返回值 + DescribeInstancesResponse describeInstancesResponse = client.describeInstancesWithOptions(describeInstancesRequest, runtime); + DescribeInstancesResponseBody body = describeInstancesResponse.getBody(); + DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstances instances = body.getInstances(); + List instance = instances.getInstance(); + instance.stream().forEach(item->{ + + System.out.println("实例的ID:" + item.getInstanceId()); + System.out.println("名称:" + item.getInstanceName()); + System.out.println("公网IP:" + item.getPublicIpAddress().getIpAddress()); + System.out.println("私网IP:" + item.getVpcAttributes().getPrivateIpAddress().ipAddress); + + + + }); + } catch (TeaException error) { + // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 + // 错误 message + System.out.println(error.getMessage()); + // 诊断地址 + System.out.println(error.getData().get("Recommend")); + com.aliyun.teautil.Common.assertAsString(error.message); + } catch (Exception _error) { + TeaException error = new TeaException(_error.getMessage(), _error); + // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 + // 错误 message + System.out.println(error.getMessage()); + // 诊断地址 + System.out.println(error.getData().get("Recommend")); + com.aliyun.teautil.Common.assertAsString(error.message); + } + } + +} diff --git a/src/main/java/com/muyu/controller/VehicleController.java b/src/main/java/com/muyu/controller/VehicleController.java new file mode 100644 index 0000000..aab9764 --- /dev/null +++ b/src/main/java/com/muyu/controller/VehicleController.java @@ -0,0 +1,43 @@ +package com.muyu.controller; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author gxb + * @description TODO + * @date 2024-04-01 20:56 + */ +@RestController +public class VehicleController { + + @PostMapping("/vehicle/online") + public ResponseEntity vahiclieOnline( + @RequestParam String vin, + @RequestParam String time, + @RequestParam String randomString + ){ + //将请求发送到fluxmq节点 + boolean connected = sendRequestToFluxMQ(vin, time, randomString); + + if (connected){ + //如果成功连接,则返回成功响应 + return ResponseEntity.ok("成功连接"); + } + //连接失败,返回错误响应,客户端需要重新走流程 + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body("链接失败"); + } + + //将请求发送到fluxmq节点的方法 + private boolean sendRequestToFluxMQ(String vin,String time,String randomString){ + // 在这里实现将请求发送到 fluxmq 节点的逻辑 + // 可以使用相应的消息队列客户端来发送消息 + + // 这里只是一个示例,假设连接成功 + return true; + } +} diff --git a/src/main/java/com/muyu/demos/web/BasicController.java b/src/main/java/com/muyu/demos/web/BasicController.java new file mode 100644 index 0000000..65e8908 --- /dev/null +++ b/src/main/java/com/muyu/demos/web/BasicController.java @@ -0,0 +1,67 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.muyu.demos.web; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * @author theonefx + */ +@Controller +public class BasicController { + + // http://127.0.0.1:8080/hello?name=lisi + @RequestMapping("/hello") + @ResponseBody + public String hello(@RequestParam(name = "name", defaultValue = "unknown user") String name) { + return "Hello " + name; + } + + // http://127.0.0.1:8080/user + @RequestMapping("/user") + @ResponseBody + public User user() { + User user = new User(); + user.setName("theonefx"); + user.setAge(666); + return user; + } + + // http://127.0.0.1:8080/save_user?name=newName&age=11 + @RequestMapping("/save_user") + @ResponseBody + public String saveUser(User u) { + return "user will save: name=" + u.getName() + ", age=" + u.getAge(); + } + + // http://127.0.0.1:8080/html + @RequestMapping("/html") + public String html(){ + return "index.html"; + } + + @ModelAttribute + public void parseUser(@RequestParam(name = "name", defaultValue = "unknown user") String name + , @RequestParam(name = "age", defaultValue = "12") Integer age, User user) { + user.setName("zhangsan"); + user.setAge(18); + } +} diff --git a/src/main/java/com/muyu/demos/web/PathVariableController.java b/src/main/java/com/muyu/demos/web/PathVariableController.java new file mode 100644 index 0000000..e3024a9 --- /dev/null +++ b/src/main/java/com/muyu/demos/web/PathVariableController.java @@ -0,0 +1,44 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.muyu.demos.web; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * @author theonefx + */ +@Controller +public class PathVariableController { + + // http://127.0.0.1:8080/user/123/roles/222 + @RequestMapping(value = "/user/{userId}/roles/{roleId}", method = RequestMethod.GET) + @ResponseBody + public String getLogin(@PathVariable("userId") String userId, @PathVariable("roleId") String roleId) { + return "User Id : " + userId + " Role Id : " + roleId; + } + + // http://127.0.0.1:8080/javabeat/somewords + @RequestMapping(value = "/javabeat/{regexp1:[a-z-]+}", method = RequestMethod.GET) + @ResponseBody + public String getRegExp(@PathVariable("regexp1") String regexp1) { + return "URI Part : " + regexp1; + } +} diff --git a/src/main/java/com/muyu/demos/web/User.java b/src/main/java/com/muyu/demos/web/User.java new file mode 100644 index 0000000..8e07afb --- /dev/null +++ b/src/main/java/com/muyu/demos/web/User.java @@ -0,0 +1,43 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.muyu.demos.web; + +/** + * @author theonefx + */ +public class User { + + private String name; + + private Integer age; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } +} diff --git a/src/main/java/com/muyu/instance/ClientConfig.java b/src/main/java/com/muyu/instance/ClientConfig.java new file mode 100644 index 0000000..312c6e1 --- /dev/null +++ b/src/main/java/com/muyu/instance/ClientConfig.java @@ -0,0 +1,23 @@ +package com.muyu.instance; + +/** + * @author gxb + * @description TODO + * @date 2024-04-13 12:40 + */ +public class ClientConfig { + + public static com.aliyun.ecs20140526.Client createClient() throws Exception { + // 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考。 + // 建议使用更安全的 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378657.html。 + com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config() + // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。 + .setAccessKeyId("LTAI5tS15R28wsYmgZ8uZonR") + // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。 + .setAccessKeySecret("ETEMZeUhPSb1M6d0kR0XVBaIkzshqB"); + // Endpoint 请参考 https://api.aliyun.com/product/Ecs + config.endpoint = "ecs.cn-shanghai.aliyuncs.com"; + return new com.aliyun.ecs20140526.Client(config); + } + +} diff --git a/src/main/java/com/muyu/instance/CreateAn.java b/src/main/java/com/muyu/instance/CreateAn.java new file mode 100644 index 0000000..8845f73 --- /dev/null +++ b/src/main/java/com/muyu/instance/CreateAn.java @@ -0,0 +1,330 @@ +package com.muyu.instance; + +import com.aliyun.ecs20140526.Client; +import com.aliyun.ecs20140526.models.*; +import com.aliyun.tea.TeaException; +import com.aliyun.tea.TeaModel; +import com.aliyun.teaopenapi.models.Config; + +import com.muyu.common.Result; +import com.muyu.common.contents.CreateContents; +import com.muyu.common.domain.CreateVo; +import com.muyu.common.domain.DeleteServer; +import com.muyu.common.domain.Icreate; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author gxb + * @description 实例创建-查询-删除 + * @date 2024-04-12 15:10 + */ +@Component +public class CreateAn { + + + /** + * Initialization 初始化公共请求参数 + */ + public static Client Initialization(String regionId) throws Exception { + Config config = new Config(); + // 您的AccessKey ID + config.accessKeyId = CreateContents.ACCESSKEYIDDATA; + // 您的AccessKey Secret + config.accessKeySecret = CreateContents.ACCESSKEYSECRETDATA; + // 您的可用区ID + config.regionId = regionId; + return new Client(config); + } + + + + static int i = 1; + + public static void main(String[] args_) throws Exception { + System.setOut(new java.io.PrintStream(System.out, true, "UTF-8")); + List args = java.util.Arrays.asList(args_); + Client client = ClientConfig.createClient(); + com.aliyun.ecs20140526.models.DescribeInstancesRequest describeInstancesRequest = new com.aliyun.ecs20140526.models.DescribeInstancesRequest() + .setRegionId("cn-shanghai") + .setInstanceName("Test-server") + .setPageSize(10); + + com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions(); + + try { + // 复制代码运行请自行打印 API 的返回值 + DescribeInstancesResponse describeInstancesResponse = client.describeInstancesWithOptions(describeInstancesRequest, runtime); + DescribeInstancesResponseBody body = describeInstancesResponse.getBody(); + DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstances instances = body.getInstances(); + List instance = instances.getInstance(); + instance.stream().forEach(item->{ + System.out.println("实例{" + i + "}的ID:" + item.getInstanceId()); + System.out.println("名称:" + item.getInstanceName()); + System.out.println("地域ID:" + item.getRegionId()); + System.out.println("状态:" + item.getStatus()); + System.out.println("类型:" + item.getInstanceType()); + System.out.println("CPU核心数:" + item.getCpu()); + System.out.println("内存大小:" + item.getMemory() + "MB"); + System.out.println("磁盘大小:" + item.getLocalStorageCapacity() + "G"); + System.out.println("操作系统:" + item.getOSName()); + System.out.println("网络类型:" + item.getInstanceNetworkType()); + System.out.println("公网出带宽值:" + item.getInternetMaxBandwidthOut() + "Mbit/s"); + System.out.println("公网入带宽值:" + item.getInternetMaxBandwidthIn() + "Mbit/s"); + System.out.println("公网IP:" + item.getPublicIpAddress().getIpAddress()); + System.out.println("私网IP:" + item.getVpcAttributes().getPrivateIpAddress().ipAddress); + System.out.println("专有网络VPCID:" + item.getVpcAttributes().getVpcId()); + System.out.println("安全组ID:" + item.getSecurityGroupIds().getSecurityGroupId()); + System.out.println("创建时间:" + item.getCreationTime()); + System.out.println("到期时间:" + item.getExpiredTime()); + System.out.println("是否可以回收:" + (item.getRecyclable()?"是":"否") + "\n\n"); + i++; + + }); + } catch (TeaException error) { + // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 + // 错误 message + System.out.println(error.getMessage()); + // 诊断地址 + System.out.println(error.getData().get("Recommend")); + com.aliyun.teautil.Common.assertAsString(error.message); + } catch (Exception _error) { + TeaException error = new TeaException(_error.getMessage(), _error); + // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 + // 错误 message + System.out.println(error.getMessage()); + // 诊断地址 + System.out.println(error.getData().get("Recommend")); + com.aliyun.teautil.Common.assertAsString(error.message); + } + } + + + + /** + * 查询实例方法 + * @throws Exception + */ + public static void findByCreate(CreateVo createVo) throws Exception { + //java.util.List args = java.util.Arrays.asList(args_); + // 地域Id + //String regionId = "cn-shanghai"; + String regionId = createVo.getRedionId(); + // 要查询的资源类型。取值范围: + // Zone:可用区。 + // IoOptimized:I/O 优化。 + // InstanceType:实例规格。 + // SystemDisk:系统盘。 + // DataDisk:数据盘。 + // Network:网络类型。 + // ddh:专有宿主机。 + //String destinationResource = "InstanceType"; + String destinationResource = createVo.getDestinationResource(); + // 是否为I/O优化实例 + // optimized:I/O优化 + // none:非IO优化 + //String ioOptimized = "optimized"; + String ioOptimized = createVo.getIoOptimized(); + // 实例规格 + //说明: 如果您指定了InstanceType,则无法指定Cores或者Memory。 + //String instanceType = "ecs.u1-c1m1.large"; + String instanceType = createVo.getInstanceType(); + Client client = CreateAn.Initialization(regionId); + // 查询指定地域下所有可用区的库存供应情况 + CreateAn.DescribeAvailableResource(client, regionId, destinationResource, ioOptimized, instanceType); + } + + + /** + * DescribeAvailableResource 查询指定地域下所有可用区的库存供应情况 + */ + public static void DescribeAvailableResource(Client client, String regionId, String destinationResource, String ioOptimized, String instanceType) throws Exception { + System.setOut(new java.io.PrintStream(System.out, true, "UTF-8")); + DescribeAvailableResourceRequest request = new DescribeAvailableResourceRequest() + .setRegionId(regionId) + .setDestinationResource(destinationResource) + .setIoOptimized(ioOptimized) + .setInstanceType(instanceType); + try { + com.aliyun.teaconsole.Client.log("--------------------查询" + regionId + "地域下所有可用区的" + instanceType + "库存供应情况:--------------------"); + DescribeAvailableResourceResponse responces = client.describeAvailableResource(request); + com.aliyun.teaconsole.Client.log("--------------------查询结果:" + com.aliyun.teautil.Common.toJSONString(TeaModel.buildMap(responces.body.availableZones)) + "--------------------"); + } catch (TeaException error) { + com.aliyun.teaconsole.Client.log("--------------------查询失败:" + com.aliyun.teautil.Common.toJSONString(error.code) + "--------------------"); + + } catch (Exception _error) { + TeaException error = new TeaException(_error.getMessage(), _error); + com.aliyun.teaconsole.Client.log("--------------------查询失败:" + com.aliyun.teautil.Common.toJSONString(error.code) + "--------------------"); + + } + } + + + /** + * 创建实例方法 + * @param icreate + * @throws Exception + */ + public static String createAnServer(Icreate icreate) throws Exception { +// java.util.List args = java.util.Arrays.asList(args_); + // 地域Id + //String regionId = "cn-shanghai"; + String regionId = icreate.getRehionId(); + // 镜像 ID,启动实例时选择的镜像资源。 + // String imageId = "m-uf6elrscl3c9wk6o762l"; + String imageId = icreate.getImageId(); + // 实例规格 + //String instanceType = "ecs.u1-c1m1.large"; + String instanceType = icreate.getInstanceType(); + // 新创建实例所属于的安全组 ID。 + //String securityGroupId = "sg-uf6bj6vxp8ruhvffdsau"; + String securityGroupId = icreate.getSecurityGroupId(); + // 虚拟交换机 ID。 + //String vSwitchId = "vsw-uf66jtgij0ptqxf1ix6l7 "; + String vSwitchId = icreate.getVSwitchId(); + // 公网出带宽最大值,单位为 Mbit/s。取值范围:0~100。 默认值:0。 + //Integer internetMaxBandwidthOut = Integer.parseInt("2"); + Integer internetMaxBandwidthOut = Integer.parseInt(icreate.getInternetMaxBandwidthOut()); + // 网络计费类型。取值范围: + // PayByBandwidth: 按固定带宽计费。 + // PayByTraffic: 按使用流量计费。 + // 默认值:PayByTraffic。 + //String internetChargeType = "PayByTraffic"; + String internetChargeType = icreate.getInternetChargeType(); + // 系统盘大小 + //String size = "20"; + String size = icreate.getSize(); + // 系统盘的云盘种类 + //String category = "cloud_essd"; + String category = icreate.getCategory(); + // ECS实例的计费方式 + // PrePaid:包年包月 + // PostPaid:按量付费 + //String instanceChargeType = "PostPaid"; + String instanceChargeType = icreate.getInstanceChargeType(); + Client client = CreateAn.Initialization(regionId); + // 批量创建实例 + String instances = CreateAn.RunInstances(client, regionId, imageId, instanceType, securityGroupId, vSwitchId, internetMaxBandwidthOut, internetChargeType, size, category, instanceChargeType); + + return instances; + + } + + /** + * RunInstances 通过备选实例规格创建ECS实例最佳实践 + * 该场景中,在调用RunInstances创建ECS实例时判断是否发生库存不足等错误,如果发生错误,将调用DescribeRecommendInstanceType查询备选实例,然后通过备选实例规格重新创建ECS实例。 + */ + public static String RunInstances(Client client, String regionId, String imageId, String instanceType, String securityGroupId, String vSwitchId, Integer internetMaxBandwidthOut, String internetChargeType, String size, String category, String instanceChargeType) throws Exception { + System.setOut(new java.io.PrintStream(System.out, true, "UTF-8")); + RunInstancesRequest request1 = new RunInstancesRequest() + .setRegionId(regionId) + .setImageId(imageId) + .setInstanceType(instanceType) + .setSecurityGroupId(securityGroupId) + .setVSwitchId(vSwitchId) + .setInstanceName("Myname") + .setDescription("Myprocure") + .setInternetMaxBandwidthOut(internetMaxBandwidthOut) + .setInternetChargeType(internetChargeType) + .setInstanceChargeType(instanceChargeType) + // 批量创建五台ECS实例,如果不设置该参数,默认创建一台ECS实例。 + // amount = 5, + // 如果缺少库存可以接受的最低创建数量。 + // minAmount = 2, + // 打开预检参数功能,不会实际创建ECS实例,只检查参数正确性、用户权限或者ECS库存等问题。 + // 实际情况下,设置了DryRun参数后,Amount必须为1,MinAmount必须为空,您可以根据实际需求修改代码。 + .setDryRun(false) + .setSystemDisk(new RunInstancesRequest.RunInstancesRequestSystemDisk() + .setSize(size) + .setCategory(category)); + RunInstancesResponse responces = client.runInstances(request1); + try { + com.aliyun.teaconsole.Client.log("--------------------批量创建实例开始--------------------"); + + com.aliyun.teaconsole.Client.log("--------------------创建实例成功,实例ID:" + com.aliyun.teautil.Common.toJSONString(responces.body.instanceIdSets.instanceIdSet) + "--------------------"); + } catch (TeaException error) { + com.aliyun.teaconsole.Client.log("--------------------创建实例失败:" + error+ "--------------------"); + } catch (Exception _error) { + TeaException error = new TeaException(_error.getMessage(), _error); + com.aliyun.teaconsole.Client.log("--------------------创建实例失败:" +error + "--------------------"); + + + } + return com.aliyun.teautil.Common.toJSONString(responces.body.instanceIdSets.instanceIdSet); + } + + public static DescribeInstancesResponse DescribeInstances(Client client, String regionId, String instanceIds, String instanceName) throws Exception { + DescribeInstancesRequest req = new DescribeInstancesRequest() + .setRegionId(regionId) + .setInstanceName(instanceName); + if (!com.aliyun.teautil.Common.empty(instanceIds)) { + req.instanceIds = com.aliyun.teautil.Common.toJSONString(com.aliyun.darabonbastring.Client.split(instanceIds, ",", 50)); + } + + DescribeInstancesResponse resp = client.describeInstances(req); + com.aliyun.teaconsole.Client.log("--------------------查询需要删除的实例--------------------"); + return resp; + } + + public static void ModifyInstanceAttribute(Client client, String instatnceId) throws Exception { + ModifyInstanceAttributeRequest req = new ModifyInstanceAttributeRequest() + .setInstanceId(instatnceId) + .setDeletionProtection(false); + client.modifyInstanceAttribute(req); + com.aliyun.teaconsole.Client.log("--------------------" + instatnceId + "释放保护取消成功--------------------"); + } + + public static void DeleteInstances(Client client, String regionId, String instanceIds, String force) throws Exception { + DeleteInstancesRequest req = new DeleteInstancesRequest() + .setRegionId(regionId) + .setInstanceId(com.aliyun.darabonbastring.Client.split(instanceIds, ",", 50)) + .setForce(com.aliyun.teautil.Common.equalString(force, "true")); + DeleteInstancesResponse resp = client.deleteInstances(req); + com.aliyun.teaconsole.Client.log("--------------------实例释放成功--------------------"); + com.aliyun.teaconsole.Client.log(com.aliyun.teautil.Common.toJSONString(com.aliyun.teautil.Common.toMap(resp))); + } + + /** + * 批量删除实力 + * @param deleteServer + * @throws Exception + */ + public static void DeleServerCreateAn(DeleteServer deleteServer) throws Exception { + // 区域ID + //String regionId = "cn-shanghai"; + String regionId = deleteServer.getRegionId(); + // 多个实例ID,用英文逗号分隔 + //String instanceIds = "i-uf6h4s0jtpvobykd7vzc"; + String instanceIds = deleteServer.getInstanceIds(); + // 实例名称,支持使用通配符*进行模糊搜索 + //String instanceName = "MyFirstEcsInstance"; + String instanceName = deleteServer.getInstanceName(); + // 强制删除有删除保护的机器 + //String deleteProtected = "true"; + String deleteProtected = deleteServer.getDeleteProtected(); + // 强制删除运行中的机器 + //String force = "true"; + String force = deleteServer.getForce(); + Client client = CreateAn.Initialization(regionId); + if (com.aliyun.teautil.Common.equalString(deleteProtected, force)) { + DescribeInstancesResponse describeInstancesResp = CreateAn.DescribeInstances(client, regionId, instanceIds, instanceName); + instanceIds = ""; + for (DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance instance : describeInstancesResp.body.instances.instance) { + instanceIds = "" + instance.instanceId + "," + instanceIds + ""; + if (instance.deletionProtection) { + CreateAn.ModifyInstanceAttribute(client, instance.instanceId); + } + + } + instanceIds = com.aliyun.darabonbastring.Client.subString(instanceIds, 0, -1); + } + + if (com.aliyun.teautil.Common.empty(instanceIds)) { + com.aliyun.teaconsole.Client.log("--------------------无有效实例可删除--------------------"); + return ; + } + + CreateAn.DeleteInstances(client, regionId, instanceIds, force); + } +} diff --git a/src/main/java/com/muyu/instance/test.java b/src/main/java/com/muyu/instance/test.java new file mode 100644 index 0000000..29bfd9a --- /dev/null +++ b/src/main/java/com/muyu/instance/test.java @@ -0,0 +1,16 @@ +package com.muyu.instance; + + +import com.muyu.common.domain.CreateVo; +import com.muyu.common.domain.Icreate; + +/** + * @author gxb + * @description TODO + * @date 2024-04-12 15:47 + */ +public class test { + public static void main(String[] args) throws Exception { + CreateAn.findByCreate(new CreateVo()); + } +} diff --git a/src/main/java/com/muyu/server/ClientRegController.java b/src/main/java/com/muyu/server/ClientRegController.java new file mode 100644 index 0000000..285230f --- /dev/null +++ b/src/main/java/com/muyu/server/ClientRegController.java @@ -0,0 +1,113 @@ +package com.muyu.server; + +import com.muyu.common.RedisService; +import com.muyu.common.Result; +import com.muyu.common.ip.IpUtils; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.data.redis.core.ZSetOperations; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletRequest; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author gxb + * @description TODO + * @date 2024-03-27 16:21 + * + * + * guoxubao.e3.luyouxia.net:12867 ->内网事件 + * + * http://guoxubao.w1.luyouxia.net -》外网事件 + */ +@RestController +@RequestMapping("reg") +@Log4j2 +public class ClientRegController { + + @Autowired + private HttpServletRequest request; + + @Autowired + private RedisService redisService; + + private Set tokenset = new HashSet<>(); + + /** + * 申请注册接口 获取到token值 + * 申请走内网:guoxubao.e3.luyouxia.net:12867/reg/apply + * @return + */ + @PostMapping("/apply") + public Result applicationRegistartion(){ + //生成令牌 只能使用一次 + String token = UUID.randomUUID().toString().replaceAll("-",""); + + tokenset.add(token); //到时候存redis + + log.info("程序生成令牌:{}",token); + + return Result.success(token); + } + + + + /** + * 注册收集节点 + * @return + */ + @PostMapping + public Result reg(@RequestBody NodeRegReq nodeRegReq) + { + log.info("客户端注册:[{}] 注册:{}", IpUtils.getIpAddr(request),nodeRegReq); + + //后期负载均衡 + ZSetOperations zSetOperations = redisService.opsForZSet(); + + zSetOperations.add("LocadKey",nodeRegReq.getClientId(),0.0); + + + + //基本信息的存储 + ValueOperations opsedForValue = redisService.opsForValue(); + + opsedForValue.set(nodeRegReq.getClientId(),"存储客户端基本信息:ip,端口,负载"); + + return Result.success(); +} + + /** + * 获取用户基本信息 + * @param token + * @return + */ + public Result getConnectionOption(@RequestParam("token")String token){ + //token验证检查令牌是否有效 + if (!tokenset.contains(token)){ + + //令牌无效,返回错误信息 + log.warn("无效的令牌:{}",token); + + return Result.error("无效的令牌"); + } + + //通过负载key拿到客户端ID + ZSetOperations zSetOperations = redisService.opsForZSet(); + + ZSetOperations.TypedTuple fuzaiKey = zSetOperations.popMin("fuzaiKey"); + + //获取客户端ID + String cliendId = (String) fuzaiKey.getValue(); + + //根据客户端ID获取存储的基本信息 + ValueOperations opsedForValue = redisService.opsForValue(); + + //客户端的基本信息 + String s = opsedForValue.get(cliendId); + + return Result.success(s); + } +} diff --git a/src/main/java/com/muyu/server/MttClient.java b/src/main/java/com/muyu/server/MttClient.java new file mode 100644 index 0000000..513481e --- /dev/null +++ b/src/main/java/com/muyu/server/MttClient.java @@ -0,0 +1,45 @@ +package com.muyu.server; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import java.lang.reflect.Type; +import java.util.List; + +public class MttClient { + /** + * 查询连接数量 + */ +// private static final String URL = "http://43.143.161.183:8080/public/cluster"; +// +// public static void main(String[] args) { +// +// OkHttpClient client = new OkHttpClient(); +// +// Request request = new Request.Builder() +// .url(URL) +// .get() +// .addHeader("User-Agent", "Apifox/1.0.0 (https://apifox.com)") +// .addHeader("Accesstoken", "") +// .build(); +// +// try { +// Response response = client.newCall(request).execute(); +// +// JSONArray jsonArray = JSONArray.parseArray(response.body().string()); +// JSONObject jsonObject = jsonArray.getJSONObject(0); +// JSONObject mqttInfo = jsonObject.getJSONObject("mqttInfo"); +// int connectSize = mqttInfo.getIntValue("connectSize"); +// System.out.println(connectSize); +// +// } catch (Exception e) { +// e.printStackTrace(); +// } +// +// } +} diff --git a/src/main/java/com/muyu/server/NodeRegReq.java b/src/main/java/com/muyu/server/NodeRegReq.java new file mode 100644 index 0000000..25961b2 --- /dev/null +++ b/src/main/java/com/muyu/server/NodeRegReq.java @@ -0,0 +1,24 @@ +package com.muyu.server; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 注册模型请求对象 + * @author gxb + * @description TODO + * @date 2024-03-27 17:27 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class NodeRegReq { + /** + * 客户端ID + */ + private String clientId; + private String token; +} diff --git a/src/main/java/com/muyu/test/fluxmqTest.java b/src/main/java/com/muyu/test/fluxmqTest.java new file mode 100644 index 0000000..63502f6 --- /dev/null +++ b/src/main/java/com/muyu/test/fluxmqTest.java @@ -0,0 +1,115 @@ +package com.muyu.test; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +/** + * @author gxb + * @description TODO + * @date 2024-04-13 9:39 + */ +public class fluxmqTest { + public static void main(String[] args) { + // FluxMQ 注册接口 URL + String fluxMQRegisterUrl = "http://43.143.161.183/register"; + + // 第一个请求获取 token 的 URL + String getTokenUrl = "http://43.143.161.183/getToken"; + + try { + // 发起第一个请求获取 token + String token = getToken(getTokenUrl); + + // 构建注册请求参数,包括 token + Map params = new HashMap<>(); + params.put("username", "your_username"); + params.put("email", "your_email@example.com"); + params.put("token", token); + + // 发起注册请求 + String response = register(fluxMQRegisterUrl, params); + + // 处理注册响应结果 + System.out.println("Response from FluxMQ registration: " + response); + } catch (Exception e) { + e.printStackTrace(); + } + } + + // 发起第一个请求获取 token + private static String getToken(String url) throws Exception { + HttpURLConnection conn = null; + try { + URL tokenUrl = new URL(url); + conn = (HttpURLConnection) tokenUrl.openConnection(); + conn.setRequestMethod("GET"); + + BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8")); + String line; + StringBuilder response = new StringBuilder(); + while ((line = reader.readLine()) != null) { + response.append(line); + } + reader.close(); + + // 解析 JSON 响应获取 token + // 这里假设 JSON 响应格式为 {"token": "your_token_value"} + String jsonResponse = response.toString(); + return jsonResponse.substring(jsonResponse.indexOf(':') + 2, jsonResponse.lastIndexOf('"')); + } finally { + if (conn != null) { + conn.disconnect(); + } + } + } + + // 发起注册请求 + private static String register(String url, Map params) throws Exception { + HttpURLConnection conn = null; + try { + URL registerUrl = new URL(url); + conn = (HttpURLConnection) registerUrl.openConnection(); + + // 设置请求方法为 POST + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + conn.setRequestProperty("Accept", "application/json"); + conn.setDoInput(true); + conn.setDoOutput(true); + + // 构建请求参数 + StringBuilder postData = new StringBuilder(); + for (Map.Entry param : params.entrySet()) { + if (postData.length() != 0) { + postData.append('&'); + } + postData.append(param.getKey()); + postData.append('='); + postData.append(param.getValue()); + } + + // 将参数写入请求体 + byte[] postDataBytes = postData.toString().getBytes("UTF-8"); + conn.getOutputStream().write(postDataBytes); + + // 获取注册响应 + BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8")); + String line; + StringBuilder response = new StringBuilder(); + while ((line = reader.readLine()) != null) { + response.append(line); + } + reader.close(); + + return response.toString(); + } finally { + if (conn != null) { + conn.disconnect(); + } + } + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..61546e7 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,9 @@ +server: + port: 9209 + +spring: + application: + name: mqtt + + + diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html new file mode 100644 index 0000000..e2d94a2 --- /dev/null +++ b/src/main/resources/static/index.html @@ -0,0 +1,6 @@ + + +

hello word!!!

+

this is a html page

+ + \ No newline at end of file diff --git a/src/test/java/com/muyu/MqttApplicationTests.java b/src/test/java/com/muyu/MqttApplicationTests.java new file mode 100644 index 0000000..762c9d5 --- /dev/null +++ b/src/test/java/com/muyu/MqttApplicationTests.java @@ -0,0 +1,13 @@ +package com.muyu; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class MqttApplicationTests { + + @Test + void contextLoads() { + } + +}