feat():合并车辆网管

dev
liuyibo 2024-10-11 22:01:16 +08:00
commit a63d614a23
16 changed files with 765 additions and 75 deletions

View File

@ -16,5 +16,25 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
public class CloudVehicleGatewayApplication { public class CloudVehicleGatewayApplication {
public static void main (String[] args) { public static void main (String[] args) {
SpringApplication.run(CloudVehicleGatewayApplication.class, args); SpringApplication.run(CloudVehicleGatewayApplication.class, args);
System.out.println(" _ooOoo_\n" +
" o8888888o\n" +
" 88\" . \"88\n" +
" (| -_- |)\n" +
" O\\ = /O\n" +
" ____/`---'\\____\n" +
" .' \\\\| |// `.\n" +
" / \\\\||| : |||// \\\n" +
" / _||||| -:- |||||- \\\n" +
" | | \\\\\\ - /// | |\n" +
" | \\_| ''\\---/'' | |\n" +
" \\ .-\\__ `-` ___/-. /\n" +
" ___`. .' /--.--\\ `. . __\n" +
" .\"\" '< `.___\\_<|>_/___.' >'\"\".\n" +
" | | : `- \\`.;`\\ _ /`;.`/ - ` : | |\n" +
" \\ \\ `-. \\_ __\\ /__ _/ .-` / /\n" +
" ======`-.____`-.___\\_____/___.-`____.-'======\n" +
" `=---='\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
" // 佛祖保佑 永不宕机 永无BUG //");
} }
} }

View File

@ -1,7 +1,8 @@
package com.muyu.vehiclegateway.instance; package com.muyu.vehiclegateway.aliyun;
import com.aliyun.ecs20140526.Client; import com.aliyun.ecs20140526.Client;
import com.aliyun.teaopenapi.models.Config; import com.aliyun.teaopenapi.models.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**

View File

@ -0,0 +1,165 @@
package com.muyu.vehiclegateway.config;
import com.aliyun.ecs20140526.Client;
import com.aliyun.ecs20140526.models.*;
import com.aliyun.tea.TeaException;
import com.aliyun.teautil.Common;
import com.aliyun.teautil.models.RuntimeOptions;
import com.muyu.common.redis.service.RedisService;
import com.muyu.vehiclegateway.aliyun.CreateClient;
import com.muyu.vehiclegateway.domain.Instance;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName AddClientConfig
* @Description
* @Author YiBo.Liu
* @Date 2024/10/8 16:13
*/
@Log4j2
@Component
public class ClientConfig {
@Autowired
private static StringRedisTemplate redisTemplate;
@Autowired
private static RedisService redisService;
public static String addServer() throws Exception {
// 创建阿里云ECS客户端
Client client = CreateClient.createClient();
// 配置系统盘参数
RunInstancesRequest.RunInstancesRequestSystemDisk systemDisk = new RunInstancesRequest.RunInstancesRequestSystemDisk()
.setSize("40") // 设置系统盘大小为40GB
.setCategory("cloud_essd"); // 设置系统盘类型为cloud_essd
// 创建创建实例请求对象并设置参数
RunInstancesRequest runInstancesRequest = new RunInstancesRequest()
// 设置地域ID
.setRegionId("cn-shanghai")
// 设置镜像ID
.setImageId("m-uf6f7atj16s3cjn9q5l8")
// 设置实例类型
.setInstanceType("ecs.t6-c1m1.large")
// 设置安全组ID
.setSecurityGroupId("sg-uf6f6dvazjqv127a4yyt")
// 设置虚拟交换机ID
.setVSwitchId("vsw-uf6htez4ox9k2c4cs8505")
// 设置实例名称
.setInstanceName("server-mqtt")
// 设置实例付费类型为后付费按量付费
.setInstanceChargeType("PostPaid")
// 设置互联网最大出带宽为1 Mbps
.setInternetMaxBandwidthOut(1)
// 设置系统盘配置
.setSystemDisk(systemDisk)
// 设置主机名
.setHostName("root")
// 设置实例密码
.setPassword("Six@211206")
// 设置创建实例的数量
.setAmount(1);
// 创建运行时选项对象
RuntimeOptions runtime = new RuntimeOptions();
// 尝试执行创建实例请求
try {
RunInstancesResponse runInstancesResponse = client.runInstancesWithOptions(runInstancesRequest, runtime);
RunInstancesResponseBody body = runInstancesResponse.getBody();
RunInstancesResponseBody.RunInstancesResponseBodyInstanceIdSets instanceIdSets = body.getInstanceIdSets();
List<Instance> instanceList = new ArrayList<>();
List<String> instanceIps = new ArrayList<>();
Thread.sleep(20000);
DescribeInstancesResponse describeInstancesResponse = queryInstanceDetails(client);
// 获取实例的ID、公网IP和状态
String ip = "";
List<DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance> bodyInstancesInstances = describeInstancesResponse.getBody().getInstances().getInstance();
for (DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance instance : bodyInstancesInstances) {
String id = instance.getInstanceId();
String ipAddress = instance.getPublicIpAddress().getIpAddress().toString();
String status = instance.getStatus();
Instance instance1 = new Instance(id,ipAddress,status);
instanceList.add(instance1);
instanceIps.add(ipAddress);
log.info("实例id为:{}",instance.getInstanceId());
log.info("实例ip为:{}",instance.getPublicIpAddress().ipAddress.get(0));
log.info("实例状态为{}",instance.getStatus());
ip = instance.getPublicIpAddress().ipAddress.get(0);
//每个 实例ip对应的绑定数量
redisTemplate.opsForHash().put("serverBindings", ipAddress, 0);
}
log.info("====>创建的实例集合:"+instanceList);
//把实例信息存入redis
redisService.setCacheList("instanceList",instanceList);
//实例ip存入redis方便做轮询
redisService.setCacheList("ipList",instanceIps);
return ip;
} catch (TeaException error) {
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
log.error(error.getMessage());
// 诊断地址
log.error(error.getData().get("Recommend"));
Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
log.error(error.getMessage());
// 诊断地址
log.error(error.getData().get("Recommend"));
Common.assertAsString(error.message);
}
return null;
}
private static DescribeInstancesResponse queryInstanceDetails(Client client) {
// 创建查询实例请求对象并设置参数
DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest()
.setInstanceName("server-mqtt")
.setRegionId("cn-shanghai"); // 设置地域ID // 设置实例ID
// 创建运行时选项对象
RuntimeOptions runtime = new RuntimeOptions();
// 尝试执行查询实例请求
try {
return client.describeInstancesWithOptions(describeInstancesRequest, runtime);
} catch (TeaException e) {
// 捕获特定的TeaException并打印详细信息
log.info("TeaException occurred: " + e.getMessage());
e.printStackTrace();
} catch (Exception e) {
// 捕获其他所有异常
log.info("An error occurred: " + e.getMessage());
e.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,15 @@
package com.muyu.vehiclegateway.config;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;
/**
* @ClassName ConnectWeight
* @Description
* @Author YiBo.Liu
* @Date 2024/10/8 19:21
*/
@Log4j2
@Component
public class ConnectWeight {
}

View File

@ -0,0 +1,169 @@
package com.muyu.vehiclegateway.config;
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.ExchangeBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Log4j2
@Configuration
public class RabbitmqConfig {
// 日志
private static final Logger logger = LoggerFactory.getLogger(RabbitmqConfig.class);
/**
* 线
*/
public static final String GO_ONLINE_QUEUE = "GO_ONLINE";
/**
* 线
*/
public static final String GO_OFFLINE_QUEUE = "GO_OFFLINE";
/**
*
*/
public static final String SEND_OFFLINE_QUEUE = "GO_LINE";
/**
* 线
*/
public static final String ONLINE_EXCHANGE = "ONLINE_EXCHANGE";
/**
* 线
*/
public static final String OFFLINE_EXCHANGE = "OFFLINE_EXCHANGE";
/**
*
*/
public static final String LINE_EXCHANGE = "LINE_EXCHANGE";
/**
* 线key
*/
public static final String GO_OFFLINE_ROUTING_KEY = "GO_OFFLINE";
/**
* 线key
*/
public static final String GO_ONLINE_ROUTING_KEY = "GO_ONLINE";
/**
* key
*/
public static final String SEND_ONLINE_ROUTING_KEY = "GO_LINE";
/**
* ,
*/
@Bean(ONLINE_EXCHANGE)
public Exchange exchangeTopicsInformON() {
try {
Exchange exchange = ExchangeBuilder.topicExchange(ONLINE_EXCHANGE).durable(true).build();
log.info("创建的交换机为: {}", ONLINE_EXCHANGE);
return exchange;
} catch (Exception e) {
log.error("创建该: {} 交换机失败", ONLINE_EXCHANGE, e);
throw e;
}
}
/**
* ,
*/
@Bean(OFFLINE_EXCHANGE)
public Exchange exchangeTopicsInformOFF() {
try {
Exchange exchange = ExchangeBuilder.topicExchange(OFFLINE_EXCHANGE).durable(true).build();
log.info("创建的交换机为: {}", OFFLINE_EXCHANGE);
return exchange;
} catch (Exception e) {
log.error("创建该: {} 交换机失败", OFFLINE_EXCHANGE, e);
throw e;
}
}
/**
* ,
*/
@Bean(LINE_EXCHANGE)
public Exchange exchangeTopicsInform() {
try {
Exchange exchange = ExchangeBuilder.topicExchange(LINE_EXCHANGE).durable(true).build();
log.info("创建的交换机为: {}", LINE_EXCHANGE);
return exchange;
} catch (Exception e) {
log.error("创建该: {} 交换机失败", LINE_EXCHANGE, e);
throw e;
}
}
// 声明QUEUE_INFORM_EMAIL队列
@Bean(GO_OFFLINE_QUEUE)
public Queue queueInformEmail() {
try {
Queue queue = new Queue(GO_OFFLINE_QUEUE);
log.info("创建的队列为: {}", GO_OFFLINE_QUEUE);
return queue;
} catch (Exception e) {
log.error("创建该: {} 队列失败", GO_OFFLINE_QUEUE, e);
throw e;
}
}
// 声明QUEUE_INFORM_SMS队列
@Bean(GO_ONLINE_QUEUE)
public Queue queueInformSms() {
try {
Queue queue = new Queue(GO_ONLINE_QUEUE);
log.info("创建的队列为: {}", GO_ONLINE_QUEUE);
return queue;
} catch (Exception e) {
log.error("创建该: {} 队列失败", GO_ONLINE_QUEUE, e);
throw e;
}
}
// 声明QUEUE_INFORM_SMS队列
@Bean(SEND_OFFLINE_QUEUE)
public Queue queueInformSend() {
try {
Queue queue = new Queue(SEND_OFFLINE_QUEUE);
log.info("创建的队列为: {}", SEND_OFFLINE_QUEUE);
return queue;
} catch (Exception e) {
log.error("创建该: {} 队列失败", SEND_OFFLINE_QUEUE, e);
throw e;
}
}
//ROUTINGKEY_EMAIL队列绑定交换机指定routingKey
@Bean
public Binding bindingQueueInformEmail(@Qualifier(GO_OFFLINE_QUEUE) Queue queue,
@Qualifier(OFFLINE_EXCHANGE) Exchange exchange){
return BindingBuilder.bind(queue).to(exchange).with(GO_OFFLINE_ROUTING_KEY).noargs();
}
//ROUTINGKEY_SMS队列绑定交换机指定routingKey
@Bean
public Binding bindingRoutingKeySms(@Qualifier(GO_ONLINE_QUEUE) Queue queue,
@Qualifier(ONLINE_EXCHANGE) Exchange exchange){
return BindingBuilder.bind(queue).to(exchange).with(GO_ONLINE_ROUTING_KEY).noargs();
}
//ROUTINGKEY_SMS队列绑定交换机指定routingKey
@Bean
public Binding bindingRoutingKeySend(@Qualifier(SEND_OFFLINE_QUEUE) Queue queue,
@Qualifier(LINE_EXCHANGE) Exchange exchange){
return BindingBuilder.bind(queue).to(exchange).with(SEND_ONLINE_ROUTING_KEY).noargs();
}
}

View File

@ -1,6 +1,7 @@
package com.muyu.vehiclegateway.controller; package com.muyu.vehiclegateway.controller;
import com.muyu.common.core.domain.Result; import com.muyu.common.core.domain.Result;
import com.muyu.vehiclegateway.domain.MqttServerModel;
import com.muyu.vehiclegateway.domain.req.VehicleConnectionReq; import com.muyu.vehiclegateway.domain.req.VehicleConnectionReq;
import com.muyu.vehiclegateway.service.ConnectService; import com.muyu.vehiclegateway.service.ConnectService;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@ -27,15 +28,15 @@ public class ConnectController {
private ConnectService connectService; private ConnectService connectService;
/** /**
* *
* @param vehicleConnectionReq * @param vehicleConnectionReq
* @return * @return
*/ */
@PostMapping("/receiveMsg/connect") @PostMapping("/receiveMsg/connect")
private Result receiveMsg(@RequestBody VehicleConnectionReq vehicleConnectionReq){ private Result<MqttServerModel> receiveMsg(@RequestBody VehicleConnectionReq vehicleConnectionReq) throws Exception {
log.info("=======>" + vehicleConnectionReq); log.info("=======>" + vehicleConnectionReq);
connectService.receiveMsg(vehicleConnectionReq); Result<MqttServerModel> mqttServerModelResult = connectService.receiveMsg(vehicleConnectionReq);
return Result.success(); return mqttServerModelResult;
} }
/** /**

View File

@ -0,0 +1,33 @@
package com.muyu.vehiclegateway.domain;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @ClassName ConnectWegight
* @Description
* @Author YiBo.Liu
* @Date 2024/10/6 16:27
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Tag(name = "连接权重")
public class ConnectWeight {
/**
* ip
*/
private String carServerIp;
/**
*
*/
private String weightValue;
}

View File

@ -0,0 +1,49 @@
package com.muyu.vehiclegateway.domain;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @ClassName MqttProperties
* @Description
* @Author YiBo.Liu
* @Date 2024/10/10 20:04
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class MqttProperties {
/**
* MQTT
*/
private String broker;
/**
* MQTT
*/
private String topic;
/**
*
*/
private String username;
/**
*
*/
private String password;
/**
* id
*/
private String clientId;
/**
*
*/
private int qos = 0;
}

View File

@ -0,0 +1,24 @@
package com.muyu.vehiclegateway.domain;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @ClassName VinIp
* @Description
* @Author YiBo.Liu
* @Date 2024/10/6 20:33
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class VinIp {
private String vin;
private String ip;
}

View File

@ -32,7 +32,7 @@ public class VehicleConnectionReq {
private String vehicleVin; private String vehicleVin;
/** /**
* *
*/ */
private String timestamp; private String timestamp;
@ -41,4 +41,17 @@ public class VehicleConnectionReq {
*/ */
private String nonce; private String nonce;
/**
*
*/
@JSONField(name = "username")
private String username;
/**
*
*/
@JSONField(name = "password")
private String password;
} }

View File

@ -9,16 +9,23 @@ import com.aliyun.ecs20140526.models.DescribeInstancesResponseBody;
import com.aliyun.tea.*; import com.aliyun.tea.*;
import com.aliyun.teautil.Common; import com.aliyun.teautil.Common;
import com.aliyun.teautil.models.RuntimeOptions; import com.aliyun.teautil.models.RuntimeOptions;
import com.muyu.common.redis.service.RedisService;
import com.muyu.vehiclegateway.aliyun.CreateClient;
import com.muyu.vehiclegateway.service.ConnectService;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
/** /**
* @ClassName GenerateInstance * @ClassName GenerateInstance
* @Description * @Description ECS
* @Author YiBo.Liu * @Author YiBo.Liu
* @Date 2024/9/28 19:39 * @Date 2024/9/28 19:39
*/ */
@ -27,6 +34,7 @@ import java.util.ArrayList;
@Tag(name = "停止程序时删除ECS服务器实例") @Tag(name = "停止程序时删除ECS服务器实例")
public class DelInstance implements DisposableBean { public class DelInstance implements DisposableBean {
public static void delInstance() throws Exception { public static void delInstance() throws Exception {
// 创建ECS客户端对象用于后续调用ECS相关API // 创建ECS客户端对象用于后续调用ECS相关API
@ -75,9 +83,9 @@ public class DelInstance implements DisposableBean {
} catch (TeaException error) { } catch (TeaException error) {
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message // 错误 message
System.out.println(error.getMessage()); log.info(error.getMessage());
// 诊断地址 // 诊断地址
System.out.println(error.getData().get("Recommend")); log.info(error.getData().get("Recommend"));
Common.assertAsString(error.message); Common.assertAsString(error.message);
} catch (Exception _error) { } catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error); TeaException error = new TeaException(_error.getMessage(), _error);
@ -91,12 +99,12 @@ public class DelInstance implements DisposableBean {
} }
@Override @Override
public void destroy() throws Exception { public void destroy() throws Exception {
System.out.println("删除中======================="); System.out.println("删除中=======================");
delInstance(); delInstance();
} }
} }

View File

@ -1,20 +1,19 @@
package com.muyu.vehiclegateway.instance; package com.muyu.vehiclegateway.instance;
import com.aliyun.ecs20140526.Client; import com.aliyun.ecs20140526.Client;
import com.aliyun.ecs20140526.models.DescribeInstancesRequest; import com.aliyun.ecs20140526.models.*;
import com.aliyun.ecs20140526.models.DescribeInstancesResponse;
import com.aliyun.ecs20140526.models.DescribeInstancesResponseBody;
import com.aliyun.ecs20140526.models.RunInstancesRequest;
import com.aliyun.tea.TeaException; import com.aliyun.tea.TeaException;
import com.aliyun.teautil.Common; import com.aliyun.teautil.Common;
import com.aliyun.teautil.models.RuntimeOptions; import com.aliyun.teautil.models.RuntimeOptions;
import com.muyu.common.redis.service.RedisService; import com.muyu.common.redis.service.RedisService;
import com.muyu.vehiclegateway.aliyun.CreateClient;
import com.muyu.vehiclegateway.domain.Instance; import com.muyu.vehiclegateway.domain.Instance;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner; import org.springframework.boot.ApplicationRunner;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.ArrayList;
@ -35,18 +34,27 @@ public class GenerateInstance implements ApplicationRunner {
@Autowired @Autowired
private RedisService redisService; private RedisService redisService;
@Autowired
private StringRedisTemplate redisTemplate;
/** /**
* *
* @throws Exception * @throws Exception
*/ */
public List<Instance> generateInstance() throws Exception { public void generateInstance() throws Exception {
// 创建ECS客户端对象用于后续调用ECS相关API redisService.deleteObject("vinIp");
redisService.deleteObject("ipList");
redisService.deleteObject("instanceList");
redisService.deleteObject("count");
// 创建阿里云ECS客户端
Client client = CreateClient.createClient(); Client client = CreateClient.createClient();
// 配置系统盘参数
RunInstancesRequest.RunInstancesRequestSystemDisk systemDisk = new RunInstancesRequest.RunInstancesRequestSystemDisk() RunInstancesRequest.RunInstancesRequestSystemDisk systemDisk = new RunInstancesRequest.RunInstancesRequestSystemDisk()
.setSize("40") .setSize("40") // 设置系统盘大小为40GB
.setCategory("cloud_essd"); .setCategory("cloud_essd"); // 设置系统盘类型为cloud_essd
// 创建创建实例请求对象并设置参数
RunInstancesRequest runInstancesRequest = new RunInstancesRequest() RunInstancesRequest runInstancesRequest = new RunInstancesRequest()
// 设置地域ID // 设置地域ID
.setRegionId("cn-shanghai") .setRegionId("cn-shanghai")
@ -71,68 +79,104 @@ public class GenerateInstance implements ApplicationRunner {
// 设置实例密码 // 设置实例密码
.setPassword("Six@211206") .setPassword("Six@211206")
// 设置创建实例的数量 // 设置创建实例的数量
.setAmount(1); .setAmount(2);
// 创建运行时选项对象
RuntimeOptions runtime = new RuntimeOptions(); RuntimeOptions runtime = new RuntimeOptions();
// 尝试执行创建实例请求
try { try {
// 复制代码运行请自行打印 API 的返回值
client.runInstancesWithOptions(runInstancesRequest, runtime); RunInstancesResponse runInstancesResponse = client.runInstancesWithOptions(runInstancesRequest, runtime);
RunInstancesResponseBody body = runInstancesResponse.getBody();
RunInstancesResponseBody.RunInstancesResponseBodyInstanceIdSets instanceIdSets = body.getInstanceIdSets();
List<Instance> instanceList = new ArrayList<>();
List<String> instanceIps = new ArrayList<>();
Thread.sleep(20000);
DescribeInstancesResponse describeInstancesResponse = queryInstanceDetails(client);
// 获取实例的ID、公网IP和状态
List<DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance> bodyInstancesInstances = describeInstancesResponse.getBody().getInstances().getInstance();
for (DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance instance : bodyInstancesInstances) {
String id = instance.getInstanceId();
String ipAddress = instance.getPublicIpAddress().getIpAddress().get(0);
String status = instance.getStatus();
Instance instance1 = new Instance(id,ipAddress,status);
instanceList.add(instance1);
instanceIps.add(ipAddress);
log.info("实例id为:{}",instance.getInstanceId());
log.info("实例ip为:{}",instance.getPublicIpAddress().ipAddress.get(0));
log.info("实例状态为{}",instance.getStatus());
}
log.info("====>创建的实例集合:"+instanceList);
//把实例信息存入redis
redisService.setCacheList("instanceList",instanceList);
//实例ip存入redis方便做轮询
redisService.setCacheList("ipList",instanceIps);
} catch (TeaException error) { } catch (TeaException error) {
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message // 错误 message
System.out.println(error.getMessage()); log.error(error.getMessage());
// 诊断地址 // 诊断地址
System.out.println(error.getData().get("Recommend")); log.error(error.getData().get("Recommend"));
Common.assertAsString(error.message); Common.assertAsString(error.message);
} catch (Exception _error) { } catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error); TeaException error = new TeaException(_error.getMessage(), _error);
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message // 错误 message
System.out.println(error.getMessage()); log.error(error.getMessage());
// 诊断地址 // 诊断地址
System.out.println(error.getData().get("Recommend")); log.error(error.getData().get("Recommend"));
Common.assertAsString(error.message); Common.assertAsString(error.message);
} }
}
private static DescribeInstancesResponse queryInstanceDetails(Client client) {
// 创建查询实例请求对象并设置参数
DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest() DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest()
.setRegionId("cn-shanghai"); .setInstanceName("server-mqtt")
.setRegionId("cn-shanghai"); // 设置地域ID // 设置实例ID
// 创建运行时选项对象
RuntimeOptions runtime = new RuntimeOptions();
//创建运行时选择对象,用于配置运行时的选项参数 // 尝试执行查询实例请求
RuntimeOptions runtimeOptions = new RuntimeOptions(); try {
return client.describeInstancesWithOptions(describeInstancesRequest, runtime);
//获取实例列表 } catch (TeaException e) {
DescribeInstancesResponse describeInstancesResponse = client.describeInstancesWithOptions(describeInstancesRequest, runtimeOptions); // 捕获特定的TeaException并打印详细信息
log.info("TeaException occurred: " + e.getMessage());
//提取实例ID集合 e.printStackTrace();
List<Instance> list = new ArrayList<>(); } catch (Exception e) {
// 捕获其他所有异常
DescribeInstancesResponseBody body = describeInstancesResponse.getBody(); log.info("An error occurred: " + e.getMessage());
e.printStackTrace();
for (DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance instance : body.getInstances().getInstance()) {
log.info("实例id为:"+instance.getInstanceId());
log.info("实例ip为:"+instance.getPublicIpAddress().ipAddress.get(0));
log.info("实例状态为:"+instance.getStatus());
Instance instance1 = new Instance(instance.getInstanceId(), instance.getPublicIpAddress().ipAddress.get(0), instance.getStatus());
list.add(instance1);
} }
return null;
// Thread.sleep(20000);
// redisService.setCacheList("aaa",list);
return list;
} }
@Override @Override
public void run(ApplicationArguments args) throws Exception { public void run(ApplicationArguments args) throws Exception {
log.info("===============>开始执行创建实例方法");
generateInstance(); generateInstance();
System.out.println("创建实例成功");
} }
} }

View File

@ -3,8 +3,13 @@ package com.muyu.vehiclegateway.mapper;
import com.muyu.vehiclegateway.domain.req.VehicleConnectionReq; import com.muyu.vehiclegateway.domain.req.VehicleConnectionReq;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper @Mapper
public interface ConnectMapper { public interface ConnectMapper {
void addVehicle(VehicleConnectionReq vehicleConnectionReq); void addVehicle(VehicleConnectionReq vehicleConnectionReq);
List<String> selectVehicleVin(String vehicleVin);
} }

View File

@ -1,7 +1,11 @@
package com.muyu.vehiclegateway.service; package com.muyu.vehiclegateway.service;
import com.muyu.common.core.domain.Result;
import com.muyu.vehiclegateway.domain.MqttServerModel;
import com.muyu.vehiclegateway.domain.req.VehicleConnectionReq; import com.muyu.vehiclegateway.domain.req.VehicleConnectionReq;
import java.util.List;
public interface ConnectService { public interface ConnectService {
/** /**
@ -11,11 +15,12 @@ public interface ConnectService {
void createConnect() throws Exception; void createConnect() throws Exception;
/** /**
* *
* @param vehicleConnectionReq * @param vehicleConnectionReq
* @return * @return
*/ */
void receiveMsg(VehicleConnectionReq vehicleConnectionReq); Result<MqttServerModel> receiveMsg(VehicleConnectionReq vehicleConnectionReq) throws Exception;
} }

View File

@ -1,19 +1,26 @@
package com.muyu.vehiclegateway.service.impl; package com.muyu.vehiclegateway.service.impl;
import cn.hutool.json.JSON; import com.muyu.common.core.domain.Result;
import com.alibaba.fastjson2.JSONObject; import com.muyu.common.redis.service.RedisService;
import com.muyu.common.core.constant.GenConstants; import com.muyu.vehiclegateway.config.ClientConfig;
import com.muyu.common.core.utils.uuid.UUID; import com.muyu.vehiclegateway.domain.MqttProperties;
import com.muyu.vehiclegateway.domain.MqttServerModel;
import com.muyu.vehiclegateway.domain.VinIp;
import com.muyu.vehiclegateway.domain.req.VehicleConnectionReq; import com.muyu.vehiclegateway.domain.req.VehicleConnectionReq;
import com.muyu.vehiclegateway.instance.GenerateInstance; import com.muyu.vehiclegateway.instance.GenerateInstance;
import com.muyu.vehiclegateway.mapper.ConnectMapper; import com.muyu.vehiclegateway.mapper.ConnectMapper;
import com.muyu.vehiclegateway.service.ConnectService; import com.muyu.vehiclegateway.service.ConnectService;
import org.springframework.amqp.core.Message; import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import static io.lettuce.core.pubsub.PubSubOutput.Type.message; import java.util.List;
import static com.muyu.vehiclegateway.config.RabbitmqConfig.LINE_EXCHANGE;
import static com.muyu.vehiclegateway.config.RabbitmqConfig.SEND_ONLINE_ROUTING_KEY;
/** /**
* @ClassName ConnectServiceImpl * @ClassName ConnectServiceImpl
@ -22,15 +29,24 @@ import static io.lettuce.core.pubsub.PubSubOutput.Type.message;
* @Date 2024/10/2 16:25 * @Date 2024/10/2 16:25
*/ */
@Service @Service
@Log4j2
public class ConnectServiceImpl implements ConnectService { public class ConnectServiceImpl implements ConnectService {
@Autowired @Autowired
private RabbitTemplate rabbitTemplate; private RabbitTemplate rabbitTemplate;
@Autowired @Autowired
private ConnectMapper connectMapper; private ConnectMapper connectMapper;
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private ClientConfig clientConfig;
@Autowired
private RedisService redisService;
/** /**
* *
* @throws Exception * @throws Exception
@ -47,11 +63,128 @@ public class ConnectServiceImpl implements ConnectService {
* @return * @return
*/ */
@Override @Override
public void receiveMsg(VehicleConnectionReq vehicleConnectionReq) { public Result<MqttServerModel> receiveMsg(VehicleConnectionReq vehicleConnectionReq) throws Exception {
rabbitTemplate.convertAndSend("GO_OFFLINE", vehicleConnectionReq.getVehicleVin(),message1 -> {
message1.getMessageProperties().setMessageId(UUID.fastUUID().toString()); log.info("车辆连接请求:{}", vehicleConnectionReq);
return message1;
}); //生成密码
vehicleConnectionReq.setPassword(vehicleConnectionReq.getVehicleVin() + vehicleConnectionReq.getTimestamp()
+ vehicleConnectionReq.getNonce());
//查询有没有这辆车的vin码
List<String> selectVehicle = connectMapper.selectVehicleVin(vehicleConnectionReq.getVehicleVin());
if(selectVehicle.isEmpty()){
connectMapper.addVehicle(vehicleConnectionReq); connectMapper.addVehicle(vehicleConnectionReq);
log.info("车辆预上线成功");
}else {
log.info("车辆无法重复预上线");
} }
//先判断vin码
// String vin = redisTemplate.opsForValue().get(vehicleConnectionReq.getVehicleVin());
if(redisTemplate.hasKey(vehicleConnectionReq.getVehicleVin())){
log.info("车辆绑定ip失败已经存在");
throw new RuntimeException("车辆已经绑定过了");
}
//判断redis有没有count键
if(redisTemplate.hasKey("count")){
//取出count
Integer count = Integer.valueOf(redisTemplate.opsForValue().get("count"));
if(count == 1){
redisTemplate.opsForValue().set("count",String.valueOf(0));
}else {
redisTemplate.opsForValue().set("count",String.valueOf(count+1));
}
//根据游标count获取服务IP
Object ip = redisService.redisTemplate.opsForList().index("ipList", count);
//关联车辆和服务
this.insertVinIp(new VinIp(vehicleConnectionReq.getVehicleVin(),ip.toString()));
//响应信息
log.info("车辆:"+vehicleConnectionReq.getVehicleVin()+"成功绑定到:"+ip);
//发送mq到协议解析
MqttProperties mqttProperties = new MqttProperties();
mqttProperties.setBroker("tcp://" + ip + ":1883");
mqttProperties.setTopic("vehicle");
mqttProperties.setUsername(vehicleConnectionReq.getUsername());
mqttProperties.setPassword(vehicleConnectionReq.getPassword());
mqttProperties.setClientId(ip.toString());
mqttProperties.setQos(0);
rabbitTemplate.convertAndSend(LINE_EXCHANGE,SEND_ONLINE_ROUTING_KEY,mqttProperties);
return Result.success(new MqttServerModel("tcp://"+ip+":1883","vehicle"));
}else {
redisTemplate.opsForValue().set("count",String.valueOf(0));
//根据游标count获取服务器Ip
Object ip = redisService.redisTemplate.opsForList().index("ipList", 0);
log.info("ip为:{}",ip);
//关联车辆和服务
this.insertVinIp(new VinIp(vehicleConnectionReq.getVehicleVin(),ip.toString()));
//响应信息
log.info("车辆:{}",vehicleConnectionReq.getVehicleVin(),"成功绑定到:{}",ip);
return Result.success(new MqttServerModel("tcp://"+ip+":1883","vehicle"));
}
}
/**
* ip redis
*/
private void insertVinIp(VinIp vinIp){
if (vinIp == null || vinIp.getVin() == null || vinIp.getVin().isEmpty() || vinIp.getIp() == null || vinIp.getIp().isEmpty()) {
throw new IllegalArgumentException("vin 或 ip 不能为空或无效");
}
redisTemplate.opsForValue().set(vinIp.getVin(),vinIp.getIp());
}
/**
*
*/
private String addNewServer() throws Exception {
// 这里调用你已经写好的方法来新增服务器
// 假设新增服务器的方法是addServer返回新服务器的IP
String newIp = clientConfig.addServer();
// 将新服务器的IP添加到ipList中
redisTemplate.opsForList().rightPush("ipList", newIp);
// 将新服务器的绑定数量初始化为0
redisTemplate.opsForHash().put("serverBindings", newIp, 0);
return newIp;
}
/**
*
*/
private boolean isServerFull(String ip) {
Integer bindingCount = (Integer)redisTemplate.opsForHash().get("serverBindings", ip);
return bindingCount >= 6;
}
/**
*
*/
private String findAvailableServer() {
List<String> ipList = redisTemplate.opsForList().range("ipList", 0, -1);
for (String ip : ipList) {
if (!isServerFull(ip)) {
return ip;
}
}
return null; // 如果所有服务器都满了返回null
}
/**
*
*/
private void incrementServerBindingCount(String ip) {
// 获取当前服务器的绑定数量
Integer bindingCount = (Integer)redisTemplate.opsForHash().get("serverBindings", ip);
// 更新绑定数量
redisTemplate.opsForHash().put("serverBindings", ip, bindingCount + 1);
}
} }

View File

@ -4,7 +4,12 @@
<mapper namespace="com.muyu.vehiclegateway.mapper.ConnectMapper"> <mapper namespace="com.muyu.vehiclegateway.mapper.ConnectMapper">
<insert id="addVehicle"> <insert id="addVehicle">
insert into connect(id,vehicle_vin,timestamp,nonce) insert into connect(id,vehicle_vin,username,password)
values (#{id},#{vehicleVin},#{timestamp},#{nonce}) values (#{id},#{vehicleVin},#{username},#{password})
</insert> </insert>
<select id="selectVehicleVin" resultType="java.lang.String">
select connect.vehicle_vin from connect
where connect.vehicle_vin = #{vehicleVin}
</select>
</mapper> </mapper>