feat():车辆模拟+根据请求中的车辆ID为车辆分配一个模拟的服务器节点

master
Yunfei Du 2024-05-27 14:20:23 +08:00
commit b27d094f93
88 changed files with 5410 additions and 0 deletions

38
.gitignore vendored 100644
View File

@ -0,0 +1,38 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

8
.idea/.gitignore vendored 100644
View File

@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
<file url="file://$PROJECT_DIR$/VehicleSimulation/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/VehicleSimulation/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
<file url="PROJECT" charset="UTF-8" />
</component>
</project>

View File

@ -0,0 +1,5 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
</profile>
</component>

14
.idea/misc.xml 100644
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

6
.idea/vcs.xml 100644
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<relativePath>org.springframework.boot</relativePath>
<version>2.7.15</version>
</parent>
<groupId>com.muyu</groupId>
<artifactId>VehicleSimulation</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<mybatisplus.version>3.5.1</mybatisplus.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- mqtt3 -->
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- mybatis-plus 所需依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatisplus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatisplus.version}</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
<!-- 使用h2内存数据库 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.42</version>
</dependency>
<!-- http调用框架 -->
<dependency>
<groupId>com.dtflys.forest</groupId>
<artifactId>forest-spring-boot-starter</artifactId>
<version>1.5.33</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.73</version>
</dependency>
<!--常用工具类 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,20 @@
package com.muyu;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author DongZeLiang
* @version 1.0
* @description
* @date 2023/11/9
*/
@SpringBootApplication
@MapperScan(value = "com.muyu.mapper")
public class VehicleSimulationApplication {
public static void main(String[] args) {
SpringApplication.run(VehicleSimulationApplication.class, args);
}
}

View File

@ -0,0 +1,93 @@
package com.muyu.common;
/**
*
*
* @author ruoyi
*/
public class HttpStatus {
/**
*
*/
public static final int SUCCESS = 200;
/**
*
*/
public static final int CREATED = 201;
/**
*
*/
public static final int ACCEPTED = 202;
/**
*
*/
public static final int NO_CONTENT = 204;
/**
*
*/
public static final int MOVED_PERM = 301;
/**
*
*/
public static final int SEE_OTHER = 303;
/**
*
*/
public static final int NOT_MODIFIED = 304;
/**
*
*/
public static final int BAD_REQUEST = 400;
/**
*
*/
public static final int UNAUTHORIZED = 401;
/**
* 访
*/
public static final int FORBIDDEN = 403;
/**
*
*/
public static final int NOT_FOUND = 404;
/**
* http
*/
public static final int BAD_METHOD = 405;
/**
*
*/
public static final int CONFLICT = 409;
/**
*
*/
public static final int UNSUPPORTED_TYPE = 415;
/**
*
*/
public static final int ERROR = 500;
/**
*
*/
public static final int NOT_IMPLEMENTED = 501;
/**
*
*/
public static final int WARN = 601;
}

View File

@ -0,0 +1,31 @@
package com.muyu.common;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @Author: DongZeLiang
* @date: 2023/12/2
* @Description:
* @Version: 1.0
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PageList<T> {
/**
*
*/
private List<T> rows;
/**
*
*/
private long total;
}

View File

@ -0,0 +1,101 @@
package com.muyu.common;
import lombok.Data;
import java.io.Serializable;
/**
*
*
* @author ruoyi
*/
@Data
public class Result<T> implements Serializable {
/**
*
*/
public static final int SUCCESS = HttpStatus.SUCCESS;
/**
*
*/
public static final int FAIL = HttpStatus.ERROR;
private static final long serialVersionUID = 1L;
/**
*
*/
private static final int WARN = HttpStatus.WARN;
private int code;
private String msg;
private T data;
public static <T> Result<T> success () {
return restResult(null, SUCCESS, "操作成功");
}
public static <T> Result<T> success (T data) {
return restResult(data, SUCCESS, "操作成功");
}
public static <T> Result<T> success (T data, String msg) {
return restResult(data, SUCCESS, msg);
}
public static <T> Result<T> error () {
return restResult(null, FAIL, "操作失败");
}
public static <T> Result<T> error (String msg) {
return restResult(null, FAIL, msg);
}
public static <T> Result<T> error (T data) {
return restResult(data, FAIL, "操作失败");
}
public static <T> Result<T> error (T data, String msg) {
return restResult(data, FAIL, msg);
}
public static <T> Result<T> error (int code, String msg) {
return restResult(null, code, msg);
}
public static <T> Result<T> warn () {
return restResult(null, WARN, "操作失败");
}
public static <T> Result<T> warn (String msg) {
return restResult(null, WARN, msg);
}
public static <T> Result<T> warn (T data) {
return restResult(data, WARN, "操作失败");
}
public static <T> Result<T> warn (T data, String msg) {
return restResult(data, WARN, msg);
}
public static <T> Result<T> warn (int code, String msg) {
return restResult(null, code, msg);
}
private static <T> Result<T> restResult (T data, int code, String msg) {
Result<T> apiResult = new Result<>();
apiResult.setCode(code);
apiResult.setData(data);
apiResult.setMsg(msg);
return apiResult;
}
public static <T> Boolean isError (Result<T> ret) {
return !isSuccess(ret);
}
public static <T> Boolean isSuccess (Result<T> ret) {
return Result.SUCCESS == ret.getCode();
}
}

View File

@ -0,0 +1,30 @@
package com.muyu.common;
import java.math.BigDecimal;
import java.math.BigInteger;
/**
* @author DongZeLiang
* @version 1.0
* @description
* @date 2023/11/15
*/
public class SystemConstant {
/**
*
*/
public final static BigDecimal powerConsumption = new BigDecimal(10000);
public final static BigDecimal hundredKilometers = new BigDecimal(100);
/**
*
*/
public static final String MSG_START = "7E ";
/**
*
*/
public static final String MSG_END = "7E";
}

View File

@ -0,0 +1,34 @@
package com.muyu.common.pool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* @author DongZl
* @description: 线
* @Date 2023-12-5 01:51
*/
public class FixedThreadPool {
/**
* 线
*/
private final static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(15);
/**
* 线
* @param thread 线
*/
public static Future<?> submit(Thread thread){
return fixedThreadPool.submit(thread);
}
/**
* 线
*/
public static void shutDown(){
fixedThreadPool.shutdown();
}
}

View File

@ -0,0 +1,37 @@
package com.muyu.common.pool;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* @author DongZl
* @description: 线
* @Date 2023-11-17 09:16
*/
public class ScheduledThreadPool {
/**
* 线 CPU * 2 + 1
*/
private static final ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(
Runtime.getRuntime().availableProcessors() * 2 + 1);
public static ScheduledFuture<?> submit (Runnable thread){
// 参数分别是: 任务, 多久后开始执行, 每隔多久执行一次(周期),时间单位
return submit(thread, 1);
}
public static ScheduledFuture<?> submit (Runnable thread, long period){
// 参数分别是: 任务, 多久后开始执行, 每隔多久执行一次(周期),时间单位
return scheduledThreadPool.scheduleAtFixedRate(thread, 0, period, TimeUnit.SECONDS);
}
/**
* 线
*/
public static void shutdown() {
scheduledThreadPool.shutdown();
}
}

View File

@ -0,0 +1,25 @@
package com.muyu.config;
import com.muyu.common.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @author DongZeLiang
* @version 1.0
* @description
* @date 2023/11/15
*/
@RestControllerAdvice
public class ExceptionAdvice {
/**
*
* @param runtimeException
* @return
*/
@ExceptionHandler(value = RuntimeException.class)
public Result<String> runtimeExceptionHandler(RuntimeException runtimeException){
return Result.error(runtimeException.getMessage());
}
}

View File

@ -0,0 +1,29 @@
package com.muyu.config;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
*
*
*/
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill...");
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill...");
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}

View File

@ -0,0 +1,34 @@
package com.muyu.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* mybatisplus
*/
@Configuration
public class MybatisPlusConfig {
/**
*
* @return
*/
/**@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
return paginationInterceptor;
}*/
/**
* ,mybatis,
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
}

View File

@ -0,0 +1,22 @@
package com.muyu.controller;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author DongZeLiang
* @version 1.0
* @description index
* @date 2023/12/1
*/
@Log4j2
@Controller
public class IndexController {
@RequestMapping("/")
public String hello(){
log.debug("重定向到 - /static/index 页面");
return "forward:/static/index.html";
}
}

View File

@ -0,0 +1,70 @@
package com.muyu.controller;
import com.muyu.common.Result;
import com.muyu.domain.ServerNode;
import com.muyu.domain.Vehicle;
import com.muyu.domain.req.VehicleCreateAddReq;
import com.muyu.service.VehicleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author DongZeLiang
* @version 1.0
* @description
* @date 2023/11/9
*/
@RestController
@RequestMapping("/vehicle")
public class VehicleController {
@Autowired
private VehicleService vehicleService;
@GetMapping("/list")
public Result<List<Vehicle>> list(){
return Result.success(vehicleService.list());
}
@PostMapping("/assign")
public ResponseEntity< ServerNode > assignServerNode(@RequestParam String vehicleId) {
ServerNode serverNode = vehicleService.assignServerNode(vehicleId);
return ResponseEntity.ok(serverNode);
}
/**
*
* @param sum
* @return
*/
@GetMapping("/gen/{sum}")
public Result<String> generate(@PathVariable(value = "sum") Integer sum){
vehicleService.generate(sum);
return Result.success();
}
/**
*
* @param vehicleCreateAddReq
* @return
*/
@PostMapping("/create")
public Result<String> create(@RequestBody VehicleCreateAddReq vehicleCreateAddReq){
vehicleService.create(vehicleCreateAddReq.getVinStr());
return Result.success();
}
/**
*
* @param vin
* @return
*/
@DeleteMapping("/{vin}")
public Result<String> delete(@PathVariable("vin") String vin){
this.vehicleService.delete(vin);
return Result.success(null,"删除成功");
}
}

View File

@ -0,0 +1,119 @@
package com.muyu.controller;
import com.muyu.common.PageList;
import com.muyu.common.Result;
import com.muyu.domain.req.CheckPositionReq;
import com.muyu.domain.req.GearReq;
import com.muyu.domain.req.MsgReq;
import com.muyu.domain.req.VehicleInstanceListReq;
import com.muyu.domain.resp.UnifiedTaskResp;
import com.muyu.domain.resp.VehicleInstanceResp;
import com.muyu.service.VehicleInstanceService;
import com.muyu.vehicle.core.LocalContainer;
import com.muyu.vehicle.model.VehicleData;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @author DongZl
* @description:
* @Date 2023-11-25 10:01
*/
@Log4j2
@RestController
@RequestMapping("/vehicle/instance")
public class VehicleInstanceController {
@Autowired
private VehicleInstanceService vehicleInstanceService;
/**
*
* @param vehicleInstanceListReq
* @return
*/
@PostMapping("/list")
public Result<PageList<VehicleInstanceResp>> list(@RequestBody VehicleInstanceListReq vehicleInstanceListReq){
PageList<VehicleInstanceResp> pageList = vehicleInstanceService.queryList(vehicleInstanceListReq);
return Result.success(pageList);
}
/**
* VIN
* @param vin VIN
* @return
*/
@GetMapping("/data/{vin}")
public Result<VehicleData> getVehicleData(@PathVariable("vin") String vin){
return Result.success(LocalContainer.getVehicleInstance(vin).getVehicleData());
}
/**
*
* @param vin vin
* @return
*/
@PostMapping("/client/init/{vin}")
public Result<String> vehicleClientInit(@PathVariable("vin") String vin){
this.vehicleInstanceService.vehicleClientInit(vin);
return Result.success();
}
/**
*
* @param vin vin
* @return
*/
@PostMapping("/client/close/{vin}")
public Result<String> vehicleClientClose(@PathVariable("vin") String vin){
this.vehicleInstanceService.vehicleClientClose(vin);
return Result.success();
}
/**
*
* @param checkPositionReq
* @return
*/
@PostMapping("/position/check")
public Result<String> checkPosition(@RequestBody CheckPositionReq checkPositionReq){
this.vehicleInstanceService.checkPosition(checkPositionReq);
return Result.success();
}
/**
*
* @return
*/
@PostMapping("/msg")
public Result<String> msg(@RequestBody MsgReq msgReq){
this.vehicleInstanceService.msg(msgReq);
return Result.success();
}
/**
*
* @return
*/
@PostMapping("/gear")
public Result<String> gear(@RequestBody GearReq gearReq){
this.vehicleInstanceService.gear(gearReq);
return Result.success();
}
/**
*
* @param statusKey
* @param vin
* @param statusValue
* @return
*/
@PutMapping("/status/{vin}/{statusKey}/{statusValue}")
public Result<String> editStatus(@PathVariable("statusKey") String statusKey,
@PathVariable("vin") String vin,
@PathVariable("statusValue") Integer statusValue){
this.vehicleInstanceService.editStatus(vin, statusKey, statusValue);
return Result.success();
}
}

View File

@ -0,0 +1,32 @@
package com.muyu.controller;
import com.muyu.common.Result;
import com.muyu.domain.PositionRouteInfo;
import com.muyu.service.PositionRouteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author DongZl
* @description:
* @Date 2023-11-27 10:50
*/
@RestController
@RequestMapping("/vehicle/position")
public class VehiclePositionController {
@Autowired
private PositionRouteService positionRouteService;
@GetMapping("/list")
public Result<List<String>> listAll(){
List<PositionRouteInfo> positionRouteInfos = positionRouteService.list();
List<String> list = positionRouteInfos.stream().map(PositionRouteInfo::getName)
.toList();
return Result.success(list);
}
}

View File

@ -0,0 +1,80 @@
package com.muyu.controller;
import com.muyu.common.Result;
import com.muyu.domain.resp.UnifiedTaskResp;
import com.muyu.service.VehicleUnifiedService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author DongZeLiang
* @version 1.0
* @description
* @date 2023/12/6
*/
@Log4j2
@RestController
@RequestMapping("/vehicle/unified")
public class VehicleUnifiedController {
@Autowired
private VehicleUnifiedService vehicleUnifiedService;
/**
* 线
*/
@PostMapping("/online")
public Result<String> unifiedOnline(){
this.vehicleUnifiedService.unifiedOnline();
return Result.success(null,"已成功发布一键上线任务");
}
/**
* 线
*/
@PostMapping("/offline")
public Result<String> unifiedOffline(){
this.vehicleUnifiedService.unifiedOffline();
return Result.success(null,"已成功发布一键离线任务");
}
/**
*
*/
@PostMapping("/send")
public Result<String> unifiedSend(){
this.vehicleUnifiedService.unifiedSend();
return Result.success(null,"已成功发布一键上报任务");
}
/**
*
*/
@PostMapping("/position")
public Result<String> unifiedPosition(){
this.vehicleUnifiedService.unifiedPosition();
return Result.success(null,"已成功发布一键上报任务");
}
/**
*
*/
@PostMapping("/stop")
public Result<String> unifiedStop(){
this.vehicleUnifiedService.unifiedStop();
return Result.success(null,"已成功发布取消上报任务");
}
/**
*
* @return
*/
@GetMapping("/status")
public Result<UnifiedTaskResp> unifiedStatus(){
return Result.success(this.vehicleUnifiedService.unifiedStatus());
}
}

View File

@ -0,0 +1,40 @@
package com.muyu.controller;
import com.muyu.common.Result;
import com.muyu.domain.model.MqttServerModel;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author DongZl
* @description: 线
* @Date 2023-11-30 02:59
*/
@RestController
@RequestMapping("/verify")
public class VerifyController {
@Value("${mqtt.server.host}")
private String broker;
@Value("${mqtt.server.topic}")
private String topic;
/**
* 线
* @return test
*/
@PostMapping("/vehicleConnection")
public Result<MqttServerModel> vehicleConnection(){
return Result.success(
MqttServerModel.builder()
.broker(broker)
.topic(topic)
.build()
);
}
}

View File

@ -0,0 +1,48 @@
package com.muyu.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* @author DongZl
* @description:
* @Date 2023-11-20 09:28
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("route_info")
public class PositionRouteInfo {
/**
*
*/
@TableId("id")
private Long id;
/**
*
*/
@TableField(value = "name")
private String name;
/**
*
*/
@TableField(value = "data")
private String routeData;
/**
*
*/
@TableField(value = "create_time")
private Date createTime;
}

View File

@ -0,0 +1,17 @@
package com.muyu.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* @ClassName ServerNode
* @Description
* @Author YunFei.Du
* @Date 2024/5/27 11:36
*/
@Data
@AllArgsConstructor
public class ServerNode {
private String ip;
private Integer port;
}

View File

@ -0,0 +1,92 @@
package com.muyu.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.muyu.utils.VehicleUtils;
import com.muyu.vehicle.VehicleInstance;
import com.muyu.vehicle.model.VehicleData;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.Date;
/**
* @author DongZeLiang
* @version 1.0
* @description
* @date 2023/11/9
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("vehicle")
public class Vehicle {
/**
* VIN
*/
@TableId(value = "vin")
private String vin;
/**
*
*/
@TableField("remaining_battery")
private BigDecimal remainingBattery;
/**
*
*/
@TableField("battery_level")
private BigDecimal batteryLevel;
/**
*
*/
@TableField("total_mileage")
private BigDecimal totalMileage;
/**
*
*/
@TableField("create_time")
private Date createTime;
/**
*
* @return
*/
public static Vehicle gen() {
return Vehicle.create(VehicleUtils.genVin());
}
/**
*
* @return
*/
public static Vehicle create(String vin) {
BigDecimal battery = VehicleUtils.genBattery();
return Vehicle.builder()
.vin(vin)
.createTime(new Date())
.batteryLevel(battery)
.remainingBattery(battery)
.totalMileage(BigDecimal.ZERO)
.build();
}
public static Vehicle instanceBuild (VehicleInstance vehicleInstance) {
VehicleData vehicle = vehicleInstance.getVehicleData();
return Vehicle.builder()
.vin(vehicleInstance.getVin())
.remainingBattery(vehicle.getRemainingBattery())
.totalMileage(vehicle.getMileage())
.build();
}
}

View File

@ -0,0 +1,28 @@
package com.muyu.domain.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author DongZl
* @description: Mqtt
* @Date 2024-3-26 09:53
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MqttServerModel {
/**
* MQTT
*/
private String broker;
/**
* MQTT
*/
private String topic;
}

View File

@ -0,0 +1,35 @@
package com.muyu.domain.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author DongZl
* @description:
* @Date 2023-11-20 09:36
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PositionModel {
/**
*
*/
private String longitude;
/**
*
*/
private String latitude;
public static PositionModel strBuild (String positionStr) {
String[] split = positionStr.split(",");
return PositionModel.builder()
.longitude(split[0])
.latitude(split[1])
.build();
}
}

View File

@ -0,0 +1,121 @@
package com.muyu.domain.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author DongZeLiang
* @version 1.0
* @description
* @date 2023/12/4
*/
@Data
@Log4j2
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TaskModel {
/**
* false
*/
private final AtomicBoolean unifiedStatus = new AtomicBoolean(Boolean.FALSE);
private CountDownLatch countDownLatch ;
/**
*
* @return
*/
public boolean isExecution(){
return !unifiedStatus.get();
}
/**
*
*/
private String taskName;
/**
*
*/
private Integer taskExecutionSum = 0;
/**
*
*/
private long taskStartTime;
/**
* 线
* @param taskName
* @param taskExecutionSum
*/
public void submit(String taskName,Integer taskExecutionSum){
if (!this.isExecution()){
throw new RuntimeException("["+this.taskName+"]的任务正在进行中,请等待任务执行完成再次发布一键任务");
}
unifiedStatus.set(Boolean.TRUE);
this.taskName = taskName;
this.countDownLatch = new CountDownLatch(taskExecutionSum);
this.taskExecutionSum = taskExecutionSum;
this.taskSuccessSum = new AtomicInteger();
this.taskErrorSum = new AtomicInteger();
this.taskStartTime = System.currentTimeMillis();
log.info("[{}]任务执行开始", this.taskName);
}
/**
*
*/
public void down(){
log.info("[{}]任务执行结束,耗时:[{}]MS", this.taskName, System.currentTimeMillis() - taskStartTime);
this.taskName = null;
this.taskExecutionSum = 0;
this.taskSuccessSum.set(0);
this.taskErrorSum.set(0);
unifiedStatus.set(Boolean.FALSE);
}
/**
*
*/
private AtomicInteger taskSuccessSum = new AtomicInteger();
/**
*
*/
public void incrementSuccess(){
this.taskSuccessSum.incrementAndGet();
}
/**
*
*/
public int getSuccessSum(){
return this.taskSuccessSum.incrementAndGet();
}
/**
*
*/
private AtomicInteger taskErrorSum = new AtomicInteger();
/**
*
*/
public void incrementError(){
this.taskErrorSum.incrementAndGet();
}
/**
*
*/
public int getErrorSum(){
return this.taskErrorSum.incrementAndGet();
}
}

View File

@ -0,0 +1,28 @@
package com.muyu.domain.req;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author DongZl
* @description:
* @Date 2023-11-27 11:04
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CheckPositionReq {
/**
* VIN
*/
private String vin;
/**
*
*/
private String positionCode;
}

View File

@ -0,0 +1,28 @@
package com.muyu.domain.req;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author DongZl
* @description:
* @Date 2023-11-27 02:37
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class GearReq {
/**
* VIN
*/
private String vin;
/**
*
*/
private String gear;
}

View File

@ -0,0 +1,28 @@
package com.muyu.domain.req;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/** vehicleSimulation
* @author DongZl
* @description: msg
* @Date 2023-11-27 02:15
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MsgReq {
/**
* VIN
*/
private String vin;
/**
*
*/
private String msgCode;
}

View File

@ -0,0 +1,23 @@
package com.muyu.domain.req;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author DongZl
* @description:
* @Date 2023-12-2 08:58
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class VehicleCreateAddReq {
/**
* VIN
*/
private String vinStr;
}

View File

@ -0,0 +1,42 @@
package com.muyu.domain.req;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author DongZl
* @description:
* @Date 2023-11-25 10:03
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class VehicleInstanceListReq {
/**
*
*/
private Long page;
/**
*
*/
private Long pageSize;
/**
* VIN
*/
private String vin;
/**
* 线
*/
private boolean online;
}

View File

@ -0,0 +1,50 @@
package com.muyu.domain.resp;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author DongZeLiang
* @version 1.0
* @description
* @date 2023/12/5
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UnifiedTaskResp {
/**
* false
*/
private boolean unifiedStatus;
/**
*
*/
private String taskName;
/**
*
*/
private Integer taskExecutionSum;
/**
*
*/
private long taskStartTime;
/**
*
*/
private Integer taskSuccessSum;
/**
*
*/
private Integer taskErrorSum;
}

View File

@ -0,0 +1,69 @@
package com.muyu.domain.resp;
import com.muyu.vehicle.VehicleInstance;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* @author DongZl
* @description:
* @Date 2023-11-25 10:04
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class VehicleInstanceResp {
/**
* VIN
*/
private String vin;
/**
* 线
*/
private boolean isOnline;
/**
* 线
*/
private String positionCode;
/**
* 线
*/
private Integer positionLength = 0;
/**
*
*/
private String msgCode;
/**
*
*/
private String gear = "P";
/**
*
*/
private BigDecimal mileage;
public static VehicleInstanceResp instanceBuild (VehicleInstance vehicleInstance) {
return VehicleInstanceResp.builder()
.vin(vehicleInstance.getVin())
.isOnline(vehicleInstance.isOnline())
.positionCode(vehicleInstance.getPositionCode())
.positionLength(vehicleInstance.getPositionQueue().size())
.gear(vehicleInstance.getVehicleData().getGear())
.msgCode(vehicleInstance.getMsgCode())
.mileage(vehicleInstance.getVehicleData().getMileage())
.build();
}
}

View File

@ -0,0 +1,12 @@
package com.muyu.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.muyu.domain.PositionRouteInfo;
/**
* @author DongZl
* @description: mapper
* @Date 2023-11-20 09:32
*/
public interface PositionRouteMapper extends BaseMapper<PositionRouteInfo> {
}

View File

@ -0,0 +1,19 @@
package com.muyu.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.muyu.domain.PositionRouteInfo;
import com.muyu.domain.ServerNode;
import java.util.List;
/**
* @author DongZl
* @description: mapper
* @Date 2023-11-20 09:32
*/
public interface ServerNodeMapper {
List< ServerNode > getAllAvailableServerNodes();
}

View File

@ -0,0 +1,16 @@
package com.muyu.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.muyu.domain.Vehicle;
/**
* <p>
* Mapper
* </p>
*
* @author DongZeLiang
* @since 2022-07-05
*/
public interface VehicleMapper extends BaseMapper<Vehicle> {
}

View File

@ -0,0 +1,30 @@
package com.muyu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.muyu.domain.PositionRouteInfo;
import com.muyu.domain.model.PositionModel;
import java.util.List;
/**
* @author DongZl
* @description:
* @Date 2023-11-20 09:33
*/
public interface PositionRouteService extends IService<PositionRouteInfo> {
/**
* ID
* @param routeId ID
* @return ID
*/
public List<PositionModel> getPositionModelByRouteId(Long routeId);
/**
*
* @param positionCode
* @return
*/
List<PositionModel> getPositionModelByRouteName (String positionCode);
}

View File

@ -0,0 +1,10 @@
package com.muyu.service;
/**
* @ClassName VehicleAssignService
* @Description
* @Author YunFei.Du
* @Date 2024/5/27 11:38
*/
public class VehicleAssignService {
}

View File

@ -0,0 +1,74 @@
package com.muyu.service;
import com.muyu.common.PageList;
import com.muyu.domain.Vehicle;
import com.muyu.domain.req.CheckPositionReq;
import com.muyu.domain.req.GearReq;
import com.muyu.domain.req.MsgReq;
import com.muyu.domain.req.VehicleInstanceListReq;
import com.muyu.domain.resp.UnifiedTaskResp;
import com.muyu.domain.resp.VehicleInstanceResp;
/**
* @author DongZeLiang
* @version 1.0
* @description
* @date 2023/11/22
*/
public interface VehicleInstanceService {
/**
*
* @param vehicle
*/
public void init(Vehicle vehicle);
/**
*
*
* @param vehicleInstanceListReq
*
* @return
*/
PageList<VehicleInstanceResp> queryList (VehicleInstanceListReq vehicleInstanceListReq);
/**
*
* @param vin vin
*/
void vehicleClientInit (String vin);
/**
*
* @param vin vin
*/
void vehicleClientClose (String vin);
/**
*
* @param checkPositionReq
*/
void checkPosition (CheckPositionReq checkPositionReq);
/**
*
* @param msgReq
*/
void msg (MsgReq msgReq);
/**
*
* @param gearReq
*/
void gear (GearReq gearReq);
/**
*
* @param vin vin
* @param statusKey
* @param statusValue
*/
void editStatus (String vin, String statusKey, Integer statusValue);
}

View File

@ -0,0 +1,41 @@
package com.muyu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.muyu.domain.ServerNode;
import com.muyu.domain.Vehicle;
/**
* <p>
*
* </p>
*
* @author DongZeLiang
* @since 2022-07-05
*/
public interface VehicleService extends IService<Vehicle> {
/**
*
* @param sum
*/
void generate(Integer sum);
/**
* IVN
* @param vinStr VIN
*/
void create (String vinStr);
/**
*
*/
void syncDb();
/**
* VIN
* @param vin vin
*/
void delete(String vin);
ServerNode assignServerNode(String vehicleId);
}

View File

@ -0,0 +1,45 @@
package com.muyu.service;
import com.muyu.domain.resp.UnifiedTaskResp;
/**
* @author DongZeLiang
* @version 1.0
* @description
* @date 2023/12/6
*/
public interface VehicleUnifiedService {
/**
* 线
*/
public void unifiedOnline();
/**
* 线
*/
public void unifiedOffline();
/**
*
*/
public void unifiedSend();
/**
*
*/
void unifiedPosition ();
/**
*
*/
public void unifiedStop();
/**
*
* @return
*/
UnifiedTaskResp unifiedStatus();
}

View File

@ -0,0 +1,54 @@
package com.muyu.service.impl;
import com.alibaba.fastjson2.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.muyu.domain.PositionRouteInfo;
import com.muyu.domain.model.PositionModel;
import com.muyu.mapper.PositionRouteMapper;
import com.muyu.service.PositionRouteService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author DongZl
* @description:
* @Date 2023-11-20 09:34
*/
@Service
public class PositionRouteServiceImpl extends ServiceImpl<PositionRouteMapper, PositionRouteInfo> implements PositionRouteService {
/**
* ID
*
* @param routeId ID
*
* @return ID
*/
@Override
public List<PositionModel> getPositionModelByRouteId (Long routeId) {
PositionRouteInfo positionRouteInfo = this.getById(routeId);
return JSONArray.parseArray(positionRouteInfo.getRouteData(), String.class)
.stream()
.map(PositionModel::strBuild)
.toList();
}
/**
*
*
* @param positionCode
*
* @return
*/
@Override
public List<PositionModel> getPositionModelByRouteName (String positionCode) {
LambdaQueryWrapper<PositionRouteInfo> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(PositionRouteInfo::getName, positionCode);
PositionRouteInfo positionRouteInfo = getOne(queryWrapper);
return JSONArray.parseArray(positionRouteInfo.getRouteData(), String.class)
.stream()
.map(PositionModel::strBuild)
.toList();
}
}

View File

@ -0,0 +1,158 @@
package com.muyu.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.muyu.domain.ServerNode;
import com.muyu.domain.Vehicle;
import com.muyu.mapper.VehicleMapper;
import com.muyu.service.VehicleInstanceService;
import com.muyu.service.VehicleService;
import com.muyu.vehicle.VehicleInstance;
import com.muyu.vehicle.core.LocalContainer;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
/**
* <p>
*
* </p>
*
* @author DongZeLiang
* @since 2022-07-05
*/
@Log4j2
@Service
public class VechileServiceImpl extends ServiceImpl<VehicleMapper, Vehicle> implements VehicleService {
@Autowired
private VehicleInstanceService vehicleInstanceService;
/**
*
*
* @param sum
*/
@Override
@Transactional
public void generate (Integer sum) {
List<Vehicle> vehicleList = Stream.generate(Vehicle::gen).limit(sum).toList();
this.saveBatch(vehicleList);
vehicleList.forEach(vehicleInstanceService::init);
}
/**
* IVN
*
* @param vinStr VIN
*/
@Override
@Transactional
public void create (String vinStr) {
String[] vinList = vinStr.split("\n");
StringBuilder errorMsg = new StringBuilder();
for (String vin : vinList) {
if (vin.length() != 17) {
errorMsg.append("vin[").append(vin).append("]").append("不为17位\n");
} else {
LambdaQueryWrapper<Vehicle> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Vehicle::getVin, vin);
long count = this.count(queryWrapper);
if (count == 1) {
errorMsg.append("vin[").append(vin).append("]").append("已经存在\n");
}
}
}
if (!errorMsg.isEmpty()) {
throw new RuntimeException(errorMsg.toString());
}
List<Vehicle> vehicleList = Arrays.stream(vinList).map(Vehicle::create).toList();
this.saveBatch(vehicleList);
vehicleList.forEach(vehicleInstanceService::init);
}
/**
*
*/
@Override
public void syncDb () {
try {
// vehicleInstanceService.isTaskStatus();
log.info("同步数据库开始");
long startTime = System.currentTimeMillis();
Collection<VehicleInstance> vehicleInstanceList = LocalContainer.getOnlineVehicleInstance();
// 成功数量
AtomicInteger syncSuccessSum = new AtomicInteger();
List<Vehicle> vehicleList = vehicleInstanceList.stream()
.filter(VehicleInstance::isOnline)
.map(Vehicle::instanceBuild)
.toList();
vehicleList.forEach(vehicle -> {
LambdaUpdateWrapper<Vehicle> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.set(Vehicle::getRemainingBattery, vehicle.getRemainingBattery());
updateWrapper.set(Vehicle::getTotalMileage, vehicle.getTotalMileage());
updateWrapper.eq(Vehicle::getVin, vehicle.getVin());
try {
this.update(updateWrapper);
syncSuccessSum.incrementAndGet();
log.debug("车辆:[{}] - 数据同步成功 - 电池容量:[{}毫安] 总公里数量:[{}KM]", vehicle.getVin(), vehicle.getRemainingBattery(), vehicle.getTotalMileage());
}catch (Exception exception){
log.error("车辆:[{}] - 数据同步失败 - 电池容量:[{}毫安] 总公里数量:[{}KM]", vehicle.getVin(), vehicle.getRemainingBattery(), vehicle.getTotalMileage());
}
});
log.info("同步数据库结束 - 耗时:[{}MS],同步量:[{}辆],成功:[{}辆],失败:[{}辆]",
System.currentTimeMillis() - startTime, vehicleList.size(),syncSuccessSum.get(), vehicleList.size() - syncSuccessSum.get());
}catch (Exception exception){
log.error("数据同步异常:{}", exception.getMessage(), exception);
}
}
/**
* VIN
*
* @param vin vin
*/
@Override
public void delete(String vin) {
VehicleInstance vehicleInstance = LocalContainer.getVehicleInstance(vin);
// 先判断车辆是否在上报数据,上报则停止
if (vehicleInstance.isSend()){
vehicleInstance.stopSend();
}
// 判断车辆是否在线,若在线则让车辆下线
if (vehicleInstance.isOnline()){
vehicleInstance.closeClient();
}
// 进行缓存删除
LocalContainer.removeByVin(vin);
// 删除数据库
this.removeById(vin);
}
@Override
public ServerNode assignServerNode(String vehicleId) {
// 这里为了简化,我们随机选择一个节点
List< ServerNode > serverNodes = Arrays.asList (
new ServerNode ( "192.168.1.1", 8080 ),
new ServerNode ( "192.168.1.2", 8081 )
);
if (serverNodes.isEmpty()) {
throw new RuntimeException("No available server nodes.");
}
// 使用简单的轮询算法分配节点,实际中可能需要更复杂的负载均衡策略
int index = (int) (Math.random() * serverNodes.size());
return serverNodes.get(index);
}
}

View File

@ -0,0 +1,206 @@
package com.muyu.service.impl;
import com.muyu.common.PageList;
import com.muyu.common.Result;
import com.muyu.domain.Vehicle;
import com.muyu.domain.model.MqttServerModel;
import com.muyu.domain.model.PositionModel;
import com.muyu.domain.req.CheckPositionReq;
import com.muyu.domain.req.GearReq;
import com.muyu.domain.req.MsgReq;
import com.muyu.domain.req.VehicleInstanceListReq;
import com.muyu.domain.resp.VehicleInstanceResp;
import com.muyu.service.PositionRouteService;
import com.muyu.service.VehicleInstanceService;
import com.muyu.utils.MD5Util;
import com.muyu.utils.ReflectUtils;
import com.muyu.vehicle.VehicleInstance;
import com.muyu.vehicle.api.ClientAdmin;
import com.muyu.vehicle.api.req.VehicleConnectionReq;
import com.muyu.vehicle.core.LocalContainer;
import com.muyu.vehicle.model.VehicleData;
import com.muyu.vehicle.model.properties.MqttProperties;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;
import java.util.stream.Stream;
/**
* @author DongZeLiang
* @version 1.0
* @description
* @date 2023/11/22
*/
@Log4j2
@Service
public class VehicleInstanceServiceImpl implements VehicleInstanceService {
@Autowired
private PositionRouteService positionRouteService;
@Autowired
private ClientAdmin clientAdmin;
/**
*
*
* @param vehicle
*/
@Override
public void init(Vehicle vehicle) {
VehicleInstance vehicleInstance = new VehicleInstance();
vehicleInstance.setVehicle(vehicle);
vehicleInstance.setVehicleData(VehicleData.vehicleBuild(vehicle));
LocalContainer.setVehicleInstance(vehicleInstance);
log.debug("构建车辆对象: [{}]", vehicle.getVin());
}
/**
*
*
* @param vehicleInstanceListReq
*
* @return
*/
@Override
public PageList<VehicleInstanceResp> queryList (VehicleInstanceListReq vehicleInstanceListReq) {
Stream<VehicleInstance> stream = LocalContainer.vehicleDataMap.values()
.stream();
if (StringUtils.isNotBlank(vehicleInstanceListReq.getVin())){
stream = stream.filter(vehicleInstance ->
vehicleInstance.getVin().contains(vehicleInstanceListReq.getVin()));
}
if (vehicleInstanceListReq.isOnline()){
stream = stream.sorted(Comparator.comparingInt(o -> (o.isOnline() ? 0 : 1)));
}
return PageList.<VehicleInstanceResp>builder()
.total(LocalContainer.total())
.rows(
stream
.map(VehicleInstanceResp::instanceBuild)
.skip((vehicleInstanceListReq.getPage() - 1) * vehicleInstanceListReq.getPageSize())
.limit(vehicleInstanceListReq.getPageSize())
.toList()
)
.build();
}
/**
*
*
* @param vin vin
*/
@Override
public void vehicleClientInit (String vin) {
log.info("vin[{}],开始上线", vin);
VehicleInstance vehicleInstance = LocalContainer.getVehicleInstance(vin);
if (vehicleInstance == null){
throw new RuntimeException("没有【"+vin+"】车辆");
}
String timestamp = String.valueOf(System.currentTimeMillis());
VehicleConnectionReq connectionReq = VehicleConnectionReq.builder()
.vin(vin)
.timestamp(timestamp)
.userName(MD5Util.encrypted(vin+timestamp))
.nonce(MD5Util.encrypted(UUID.randomUUID().toString().replace("-", "")))
.build();
Result<MqttServerModel> result = clientAdmin.vehicleConnection(connectionReq);
if (result.getCode() != 200){
log.error("车辆:[{}],申请上线异常:[{}]", vin, result.getMsg());
throw new RuntimeException("远程服务器没有【"+vin+"】车辆");
}
MqttServerModel mqttServerModel = result.getData();
MqttProperties mqttProperties = MqttProperties.builder()
.broker(mqttServerModel.getBroker())
.topic(mqttServerModel.getTopic())
.clientId(vin)
.username(connectionReq.getUserName())
.password(vin + connectionReq.getTimestamp() + connectionReq.getNonce())
.build();
vehicleInstance.setMqttProperties(mqttProperties);
vehicleInstance.initClient();
log.info("vin[{}],上线成功", vin);
}
/**
*
*
* @param vin vin
*/
@Override
public void vehicleClientClose (String vin) {
VehicleInstance vehicleInstance = LocalContainer.getVehicleInstance(vin);
vehicleInstance.closeClient();
}
/**
*
*
* @param checkPositionReq
*/
@Override
public void checkPosition (CheckPositionReq checkPositionReq) {
VehicleInstance vehicleInstance = LocalContainer.getVehicleInstance(checkPositionReq.getVin());
List<PositionModel> positionModelList =
this.positionRouteService.getPositionModelByRouteName(checkPositionReq.getPositionCode());
vehicleInstance.settingPosition(positionModelList);
vehicleInstance.setPositionCode(checkPositionReq.getPositionCode());
}
/**
*
*
* @param msgReq
*/
@Override
public void msg (MsgReq msgReq) {
VehicleInstance vehicleInstance = LocalContainer.getVehicleInstance(msgReq.getVin());
switch (msgReq.getMsgCode()){
case "上报" -> {
if(vehicleInstance.getVehicleThread() == null){
vehicleInstance.initVehicleThread();
}
vehicleInstance.startSend();
}
case "暂停" -> vehicleInstance.pauseSend();
case "停止" -> vehicleInstance.stopSend();
default -> throw new RuntimeException("车辆消息事件错误");
}
}
/**
*
*
* @param gearReq
*/
@Override
public void gear (GearReq gearReq) {
VehicleInstance vehicleInstance = LocalContainer.getVehicleInstance(gearReq.getVin());
vehicleInstance.setGear(gearReq.getGear());
}
/**
*
*
* @param vin vin
* @param statusKey
* @param statusValue
*/
@Override
public void editStatus (String vin, String statusKey, Integer statusValue) {
VehicleInstance vehicleInstance = LocalContainer.getVehicleInstance(vin);
VehicleData vehicleData = vehicleInstance.getVehicleData();
ReflectUtils.invokeSetter(vehicleData, statusKey, statusValue);
}
// private final AtomicBoolean unifiedStatus = new AtomicBoolean(Boolean.TRUE);
}

View File

@ -0,0 +1,280 @@
package com.muyu.service.impl;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.muyu.common.pool.FixedThreadPool;
import com.muyu.domain.PositionRouteInfo;
import com.muyu.domain.model.PositionModel;
import com.muyu.domain.model.TaskModel;
import com.muyu.domain.resp.UnifiedTaskResp;
import com.muyu.service.PositionRouteService;
import com.muyu.service.VehicleInstanceService;
import com.muyu.service.VehicleUnifiedService;
import com.muyu.vehicle.VehicleInstance;
import com.muyu.vehicle.core.LocalContainer;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* @author DongZeLiang
* @version 1.0
* @description
* @date 2023/12/6
*/
@Log4j2
@Service
public class VehicleUnifiedServiceImpl implements VehicleUnifiedService {
@Autowired
private VehicleInstanceService vehicleInstanceService;
@Autowired
private PositionRouteService positionRouteService;
/**
*
*/
private final TaskModel taskModel = new TaskModel();
/**
* 线
*/
@Override
public void unifiedOnline () {
// 获取离线车辆VIN
List<String> vinList = LocalContainer.getOfflineVehicleInstance()
.stream()
.map(VehicleInstance::getVin)
.toList();
taskModel.submit("一键上线", vinList.size());
new Thread(() -> {
int vinSize = 0, executionSize = 15;
do {
int startIndex = vinSize++ * executionSize;
// 进行分页开启车辆
List<String> executionVinList = vinList.stream()
.skip(startIndex)
.limit(executionSize)
.toList();
CountDownLatch countDownLatch = new CountDownLatch(executionVinList.size());
Map<String, Thread> startVehicleThread = new ConcurrentHashMap<>();
executionVinList.forEach(vin -> {
Thread thread = new Thread(() -> {
try {
vehicleInstanceService.vehicleClientInit(vin);
startVehicleThread.remove(vin);
}catch (Exception interruptedException){
log.error(interruptedException);
}
});
startVehicleThread.put(vin, thread);
FixedThreadPool.submit(thread);
});
try {
boolean await = countDownLatch.await(5, TimeUnit.SECONDS);
log.info(
"开始:[{}] 结束:[{}],未上线成功:[{}], vin[{}]",
startIndex, startIndex+executionVinList.size(),
startVehicleThread.size(),
JSONObject.toJSONString(executionVinList));
if (!await){
startVehicleThread.values().forEach(Thread::interrupt);
}
} catch (InterruptedException ignored) {}
if (executionVinList.size() < executionSize){
break;
}
}while (true);
taskModel.down();
}).start();
}
/**
* 线
*/
@Override
public void unifiedOffline () {
List<VehicleInstance> onlineVehicleInstanceList = LocalContainer.getOnlineVehicleInstance();
new Thread(() -> {
try {
// 筛选出在线车辆使用并行流操作先停止车辆上报动作再进行车辆离线操作
onlineVehicleInstanceList
.stream()
.parallel()
.forEach(vehicleInstance -> {
try {
vehicleInstance.stopSend();
vehicleInstance.closeClient();
taskModel.incrementSuccess();
}catch (Exception exception){
log.error("车辆离线异常:{}", exception.getMessage());
taskModel.incrementError();
}
});
} catch (Exception exception) {
log.error("车辆一键离线报错:{}", exception.getMessage(), exception);
}
taskModel.down();
});
// taskModel.submit("一键离线", onlineVehicleInstanceList.size(), taskThread);
}
/**
*
*/
@Override
public void unifiedSend () {
List<VehicleInstance> vehicleInstanceList = LocalContainer.getOnlineVehicleInstance();
if (vehicleInstanceList.isEmpty()){
throw new RuntimeException("还没有车辆连接到服务器,请先让车辆上线");
}
// 获取到所有路径
List<PositionRouteInfo> positionRouteInfoList = positionRouteService.list();
// 路径长度
int positionSize = positionRouteInfoList.size();
// 随机数
Random random = new Random();
Thread taskThread = new Thread(() -> {
try {
vehicleInstanceList
.stream()
.parallel()
.forEach(vehicleInstance -> {
try {
// 随机一个路径结果
int positionIndex = random.nextInt(0, positionSize);
PositionRouteInfo positionRouteInfo = positionRouteInfoList.get(positionIndex);
String positionCode = positionRouteInfo.getName();
List<PositionModel> positionModelList = JSONArray.parseArray(positionRouteInfo.getRouteData(), String.class)
.stream()
.map(PositionModel::strBuild)
.toList();
// 设置车辆路径
vehicleInstance.settingPosition(positionModelList);
vehicleInstance.setPositionCode(positionCode);
// 设置车辆档位
vehicleInstance.setGear("D");
// 开启线程进行上报
if (vehicleInstance.getVehicleThread() == null) {
vehicleInstance.initVehicleThread();
}
vehicleInstance.startSend();
taskModel.incrementSuccess();
}catch (Exception exception){
log.info("车辆设置一键上报失败:{}", exception.getMessage());
taskModel.incrementError();
}
});
} catch (Exception exception) {
log.error("车辆一键上报报错:{}", exception.getMessage(), exception);
}
taskModel.down();
});
// taskModel.submit("一键上报", vehicleInstanceList.size(),taskThread);
}
/**
*
*/
@Override
public void unifiedPosition () {
List<VehicleInstance> vehicleInstanceList = LocalContainer.getOnlineVehicleInstance();
Thread taskThread = new Thread(() -> {
try {
// 获取到所有路径
List<PositionRouteInfo> positionRouteInfoList = positionRouteService.list();
// 路径长度
int positionSize = positionRouteInfoList.size();
// 随机数
Random random = new Random();
vehicleInstanceList
.stream()
.parallel()
.forEach(vehicleInstance -> {
try {
// 随机一个路径结果
int positionIndex = random.nextInt(0, positionSize);
PositionRouteInfo positionRouteInfo = positionRouteInfoList.get(positionIndex);
String positionCode = positionRouteInfo.getName();
List<PositionModel> positionModelList = JSONArray.parseArray(positionRouteInfo.getRouteData(), String.class)
.stream()
.map(PositionModel::strBuild)
.toList();
// 设置车辆路径
vehicleInstance.settingPosition(positionModelList);
vehicleInstance.setPositionCode(positionCode);
taskModel.incrementSuccess();
} catch (Exception exception) {
log.error("车辆设置路线异常:[{}]", exception.getMessage());
taskModel.incrementError();
}
});
} catch (Exception exception) {
log.error("车辆一键重置路径报错:{}", exception.getMessage(), exception);
}
taskModel.down();
});
// taskModel.submit("一键重置路径",vehicleInstanceList.size(), taskThread);
}
/**
*
*/
@Override
public void unifiedStop () {
List<VehicleInstance> onlineVehicleInstanceList = LocalContainer.getOnlineVehicleInstance();
Thread taskThread = new Thread(() -> {
try {
LocalContainer.getOnlineVehicleInstance()
.stream()
.parallel()
.forEach(vehicleInstance -> {
try {
vehicleInstance.stopSend();
taskModel.incrementSuccess();
}catch (Exception exception){
log.info("车辆一键取消上报发生错误:{}", exception.getMessage());
taskModel.incrementError();
}
});
taskModel.down();
} catch (Exception exception) {
log.error("车辆一键取消上报报错:{}", exception.getMessage(), exception);
}
});
// taskModel.submit("一键取消上报", onlineVehicleInstanceList.size(), taskThread);
}
/**
*
*
* @return
*/
@Override
public UnifiedTaskResp unifiedStatus() {
boolean unifiedStatus = this.taskModel.getUnifiedStatus().get();
return UnifiedTaskResp.builder()
.unifiedStatus(unifiedStatus)
.taskErrorSum(this.taskModel.getErrorSum())
.taskExecutionSum(this.taskModel.getTaskExecutionSum())
.taskSuccessSum(this.taskModel.getSuccessSum())
.taskName(this.taskModel.getTaskName())
.taskStartTime(System.currentTimeMillis() - this.taskModel.getTaskStartTime())
.build();
}
}

View File

@ -0,0 +1,44 @@
package com.muyu.utils;
/**
*
*/
public class CalculateCheckDigit {
/**
*
* @param sHex
* @return
*/
public static String makeCheck(String sHex){
return makeCheckSum(sHex.replace(" ", ""));
}
/**
*
* */
private static String makeCheckSum(String data) {
int dSum = 0;
int length = data.length();
int index = 0;
// 遍历十六进制,并计算总和
while (index < length) {
// 截取2位字符
String s = data.substring(index, index + 2);
// 十六进制转成十进制 , 并计算十进制的总和
dSum += Integer.parseInt(s, 16);
index = index + 2;
}
// 用256取余十六进制最大是FFFF的十进制是255
int mod = dSum % 256;
// 余数转成十六进制
String checkSumHex = Integer.toHexString(mod);
length = checkSumHex.length();
if (length < 2) {
// 校验位不足两位的在前面补0
checkSumHex = "0" + checkSumHex;
}
return checkSumHex;
}
}

View File

@ -0,0 +1,65 @@
package com.muyu.utils;
import java.nio.charset.StandardCharsets;
public class ConversionUtil {
/**
* 16
* @param s
* @return
*/
public static String strToSixteen(String s) {
StringBuilder sb = new StringBuilder();
int length = s.length();
for (int i = 0; i < length; i++) {
int ch = s.charAt(i);
String s4 = Integer.toHexString(ch);
sb.append(s4 + " ");
}
return sb.toString();
}
public static void main (String[] args) {
// String str = "<?xml version=\"1.0\"?>\n" +
// "<monitorRoot type=\"param\"><synchronizeSyptom event=\"0\" initial=\"true\"><Action_ECG><Rhythm>Sinus</Rhythm><HR>80</HR><EMD>No Change</EMD><Conduct>0</Conduct></Action_ECG><Action_Osat value=\"94\" isRelativePercent=\"false\"/><Action_BP isRelativePercent=\"false\"><Shrink value=\"120\"/><Stretch value=\"80\"/></Action_BP><Action_Resp breathType=\"Normal\" value=\"14\" isRelativePercent=\"false\"/><Action_etCO2 value=\"34\" isRelativePercent=\"false\"/><Action_Temperature value=\"35.2\"/><Action_CVP value=\"6.0\"/><Action_PAPDia value=\"10\"/><Action_PAPSys value=\"25\"/><Action_WP value=\"9\"/></synchronizeSyptom></monitorRoot>";
// String strToSixteen = strToSixteen(str);
// System.out.println(str);
// System.out.println(str.length());
// System.out.println(strToSixteen);
// System.out.println(strToSixteen.replace(" ", "").length());
String hexStr = "3C3F786D6C2076657273696F6E3D22312E30223F3E0D0A3C6D6F6E69746F72526F6F7420747970653D22706172616D223E3C73796E6368726F6E697A65537970746F6D206576656E743D22302220696E697469616C3D2274727565223E3C416374696F6E5F4543473E3C52687974686D3E53696E75733C2F52687974686D3E3C48523E38303C2F48523E3C454D443E4E6F204368616E67653C2F454D443E3C436F6E647563743E303C2F436F6E647563743E3C2F416374696F6E5F4543473E3C416374696F6E5F4F7361742076616C75653D2239342220697352656C617469766550657263656E743D2266616C7365222F3E3C416374696F6E5F425020697352656C617469766550657263656E743D2266616C7365223E3C536872696E6B2076616C75653D22313230222F3E3C537472657463682076616C75653D223830222F3E3C2F416374696F6E5F42503E3C416374696F6E5F5265737020627265617468547970653D224E6F726D616C222076616C75653D2231342220697352656C617469766550657263656E743D2266616C7365222F3E3C416374696F6E5F6574434F322076616C75653D2233342220697352656C617469766550657263656E743D2266616C7365222F3E3C416374696F6E5F54656D70657261747572652076616C75653D2233352E32222F3E3C416374696F6E5F4356502076616C75653D22362E30222F3E3C416374696F6E5F5041504469612076616C75653D223130222F3E3C416374696F6E5F5041505379732076616C75653D223235222F3E3C416374696F6E5F57502076616C75653D2239222F3E3C2F73796E6368726F6E697A65537970746F6D3E3C2F6D6F6E69746F72526F6F743E0D0A";
String hexStringToString = hexStringToString(hexStr);
System.out.println(hexStr);
System.out.println(hexStr.length());
System.out.println(hexStringToString);
System.out.println(hexStringToString.length());
}
/**
* 16string
* @param s
* @return
*/
public static String hexStringToString(String s) {
if (s == null || s.equals("")) {
return null;
}
s = s.replace(" ", "");
byte[] baKeyword = new byte[s.length() / 2];
for (int i = 0; i < baKeyword.length; i++) {
try {
baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));
} catch (Exception e) {
e.printStackTrace();
}
}
try {
s = new String(baKeyword, StandardCharsets.UTF_8);
} catch (Exception e1) {
e1.printStackTrace();
}
return s;
}
}

View File

@ -0,0 +1,893 @@
package com.muyu.utils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.text.NumberFormat;
import java.util.Set;
/**
*
*
* @author ruoyi
*/
public class Convert {
/**
* <br>
* null<br>
*
*
* @param value
* @param defaultValue
*
* @return
*/
public static String toStr (Object value, String defaultValue) {
if (null == value) {
return defaultValue;
}
if (value instanceof String) {
return (String) value;
}
return value.toString();
}
/**
* <br>
* <code>null</code><code>null</code><br>
*
*
* @param value
*
* @return
*/
public static String toStr (Object value) {
return toStr(value, null);
}
/**
* <br>
* null<br>
*
*
* @param value
* @param defaultValue
*
* @return
*/
public static Character toChar (Object value, Character defaultValue) {
if (null == value) {
return defaultValue;
}
if (value instanceof Character) {
return (Character) value;
}
final String valueStr = toStr(value, null);
return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0);
}
/**
* <br>
* <code>null</code><code>null</code><br>
*
*
* @param value
*
* @return
*/
public static Character toChar (Object value) {
return toChar(value, null);
}
/**
* byte<br>
* <code>null</code><br>
*
*
* @param value
* @param defaultValue
*
* @return
*/
public static Byte toByte (Object value, Byte defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Byte) {
return (Byte) value;
}
if (value instanceof Number) {
return ((Number) value).byteValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Byte.parseByte(valueStr);
} catch (Exception e) {
return defaultValue;
}
}
/**
* byte<br>
* <code>null</code><code>null</code><br>
*
*
* @param value
*
* @return
*/
public static Byte toByte (Object value) {
return toByte(value, null);
}
/**
* Short<br>
* <code>null</code><br>
*
*
* @param value
* @param defaultValue
*
* @return
*/
public static Short toShort (Object value, Short defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Short) {
return (Short) value;
}
if (value instanceof Number) {
return ((Number) value).shortValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Short.parseShort(valueStr.trim());
} catch (Exception e) {
return defaultValue;
}
}
/**
* Short<br>
* <code>null</code><code>null</code><br>
*
*
* @param value
*
* @return
*/
public static Short toShort (Object value) {
return toShort(value, null);
}
/**
* Number<br>
* <br>
*
*
* @param value
* @param defaultValue
*
* @return
*/
public static Number toNumber (Object value, Number defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Number) {
return (Number) value;
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return NumberFormat.getInstance().parse(valueStr);
} catch (Exception e) {
return defaultValue;
}
}
/**
* Number<br>
* <code>null</code><br>
*
*
* @param value
*
* @return
*/
public static Number toNumber (Object value) {
return toNumber(value, null);
}
/**
* int<br>
* <br>
*
*
* @param value
* @param defaultValue
*
* @return
*/
public static Integer toInt (Object value, Integer defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Integer) {
return (Integer) value;
}
if (value instanceof Number) {
return ((Number) value).intValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Integer.parseInt(valueStr.trim());
} catch (Exception e) {
return defaultValue;
}
}
/**
* int<br>
* <code>null</code><code>null</code><br>
*
*
* @param value
*
* @return
*/
public static Integer toInt (Object value) {
return toInt(value, null);
}
/**
* Integer<br>
*
* @param str
*
* @return
*/
public static Integer[] toIntArray (String str) {
return toIntArray(",", str);
}
/**
* Long<br>
*
* @param str
*
* @return
*/
public static Long[] toLongArray (String str) {
return toLongArray(",", str);
}
/**
* Integer<br>
*
* @param split
* @param split
*
* @return
*/
public static Integer[] toIntArray (String split, String str) {
if (StringUtils.isEmpty(str)) {
return new Integer[]{};
}
String[] arr = str.split(split);
final Integer[] ints = new Integer[arr.length];
for (int i = 0 ; i < arr.length ; i++) {
final Integer v = toInt(arr[i], 0);
ints[i] = v;
}
return ints;
}
/**
* Long<br>
*
* @param split
* @param str
*
* @return
*/
public static Long[] toLongArray (String split, String str) {
if (StringUtils.isEmpty(str)) {
return new Long[]{};
}
String[] arr = str.split(split);
final Long[] longs = new Long[arr.length];
for (int i = 0 ; i < arr.length ; i++) {
final Long v = toLong(arr[i], null);
longs[i] = v;
}
return longs;
}
/**
* String<br>
*
* @param str
*
* @return
*/
public static String[] toStrArray (String str) {
return toStrArray(",", str);
}
/**
* String<br>
*
* @param split
* @param split
*
* @return
*/
public static String[] toStrArray (String split, String str) {
return str.split(split);
}
/**
* long<br>
* <br>
*
*
* @param value
* @param defaultValue
*
* @return
*/
public static Long toLong (Object value, Long defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Long) {
return (Long) value;
}
if (value instanceof Number) {
return ((Number) value).longValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
// 支持科学计数法
return new BigDecimal(valueStr.trim()).longValue();
} catch (Exception e) {
return defaultValue;
}
}
/**
* long<br>
* <code>null</code><code>null</code><br>
*
*
* @param value
*
* @return
*/
public static Long toLong (Object value) {
return toLong(value, null);
}
/**
* double<br>
* <br>
*
*
* @param value
* @param defaultValue
*
* @return
*/
public static Double toDouble (Object value, Double defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Double) {
return (Double) value;
}
if (value instanceof Number) {
return ((Number) value).doubleValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
// 支持科学计数法
return new BigDecimal(valueStr.trim()).doubleValue();
} catch (Exception e) {
return defaultValue;
}
}
/**
* double<br>
* <code>null</code><br>
*
*
* @param value
*
* @return
*/
public static Double toDouble (Object value) {
return toDouble(value, null);
}
/**
* Float<br>
* <br>
*
*
* @param value
* @param defaultValue
*
* @return
*/
public static Float toFloat (Object value, Float defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Float) {
return (Float) value;
}
if (value instanceof Number) {
return ((Number) value).floatValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Float.parseFloat(valueStr.trim());
} catch (Exception e) {
return defaultValue;
}
}
/**
* Float<br>
* <code>null</code><br>
*
*
* @param value
*
* @return
*/
public static Float toFloat (Object value) {
return toFloat(value, null);
}
/**
* boolean<br>
* Stringtruefalseyesokno1,0 <br>
*
*
* @param value
* @param defaultValue
*
* @return
*/
public static Boolean toBool (Object value, Boolean defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Boolean) {
return (Boolean) value;
}
String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
valueStr = valueStr.trim().toLowerCase();
switch (valueStr) {
case "true":
case "yes":
case "ok":
case "1":
return true;
case "false":
case "no":
case "0":
return false;
default:
return defaultValue;
}
}
/**
* boolean<br>
* <code>null</code><br>
*
*
* @param value
*
* @return
*/
public static Boolean toBool (Object value) {
return toBool(value, null);
}
/**
* Enum<br>
* <br>
*
* @param clazz EnumClass
* @param value
* @param defaultValue
*
* @return Enum
*/
public static <E extends Enum<E>> E toEnum (Class<E> clazz, Object value, E defaultValue) {
if (value == null) {
return defaultValue;
}
if (clazz.isAssignableFrom(value.getClass())) {
@SuppressWarnings("unchecked")
E myE = (E) value;
return myE;
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Enum.valueOf(clazz, valueStr);
} catch (Exception e) {
return defaultValue;
}
}
/**
* Enum<br>
* <code>null</code><br>
*
* @param clazz EnumClass
* @param value
*
* @return Enum
*/
public static <E extends Enum<E>> E toEnum (Class<E> clazz, Object value) {
return toEnum(clazz, value, null);
}
/**
* BigInteger<br>
* <br>
*
*
* @param value
* @param defaultValue
*
* @return
*/
public static BigInteger toBigInteger (Object value, BigInteger defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof BigInteger) {
return (BigInteger) value;
}
if (value instanceof Long) {
return BigInteger.valueOf((Long) value);
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return new BigInteger(valueStr);
} catch (Exception e) {
return defaultValue;
}
}
/**
* BigInteger<br>
* <code>null</code><br>
*
*
* @param value
*
* @return
*/
public static BigInteger toBigInteger (Object value) {
return toBigInteger(value, null);
}
/**
* BigDecimal<br>
* <br>
*
*
* @param value
* @param defaultValue
*
* @return
*/
public static BigDecimal toBigDecimal (Object value, BigDecimal defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof BigDecimal) {
return (BigDecimal) value;
}
if (value instanceof Long) {
return new BigDecimal((Long) value);
}
if (value instanceof Double) {
return BigDecimal.valueOf((Double) value);
}
if (value instanceof Integer) {
return new BigDecimal((Integer) value);
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return new BigDecimal(valueStr);
} catch (Exception e) {
return defaultValue;
}
}
/**
* BigDecimal<br>
* <br>
*
*
* @param value
*
* @return
*/
public static BigDecimal toBigDecimal (Object value) {
return toBigDecimal(value, null);
}
/**
* <br>
* 1ByteByteBuffer 2Arrays.toString
*
* @param obj
*
* @return
*/
public static String utf8Str (Object obj) {
return str(obj, "utf-8");
}
/**
* <br>
* 1ByteByteBuffer 2Arrays.toString
*
* @param obj
* @param charsetName
*
* @return
*/
public static String str (Object obj, String charsetName) {
return str(obj, Charset.forName(charsetName));
}
/**
* <br>
* 1ByteByteBuffer 2Arrays.toString
*
* @param obj
* @param charset
*
* @return
*/
public static String str (Object obj, Charset charset) {
if (null == obj) {
return null;
}
if (obj instanceof String) {
return (String) obj;
} else if (obj instanceof byte[]) {
return str((byte[]) obj, charset);
} else if (obj instanceof Byte[]) {
byte[] bytes = ArrayUtils.toPrimitive((Byte[]) obj);
return str(bytes, charset);
} else if (obj instanceof ByteBuffer) {
return str((ByteBuffer) obj, charset);
}
return obj.toString();
}
/**
* byte
*
* @param bytes byte
* @param charset
*
* @return
*/
public static String str (byte[] bytes, String charset) {
return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset));
}
/**
*
*
* @param data
* @param charset
*
* @return
*/
public static String str (byte[] data, Charset charset) {
if (data == null) {
return null;
}
if (null == charset) {
return new String(data);
}
return new String(data, charset);
}
/**
* byteBuffer
*
* @param data
* @param charset 使
*
* @return
*/
public static String str (ByteBuffer data, String charset) {
if (data == null) {
return null;
}
return str(data, Charset.forName(charset));
}
/**
* byteBuffer
*
* @param data
* @param charset 使
*
* @return
*/
public static String str (ByteBuffer data, Charset charset) {
if (null == charset) {
charset = Charset.defaultCharset();
}
return charset.decode(data).toString();
}
// ----------------------------------------------------------------------- 全角半角转换
/**
*
*
* @param input String.
*
* @return .
*/
public static String toSBC (String input) {
return toSBC(input, null);
}
/**
*
*
* @param input String
* @param notConvertSet
*
* @return .
*/
public static String toSBC (String input, Set<Character> notConvertSet) {
char[] c = input.toCharArray();
for (int i = 0 ; i < c.length ; i++) {
if (null != notConvertSet && notConvertSet.contains(c[i])) {
// 跳过不替换的字符
continue;
}
if (c[i] == ' ') {
c[i] = '\u3000';
} else if (c[i] < '\177') {
c[i] = (char) (c[i] + 65248);
}
}
return new String(c);
}
/**
*
*
* @param input String.
*
* @return
*/
public static String toDBC (String input) {
return toDBC(input, null);
}
/**
*
*
* @param text
* @param notConvertSet
*
* @return
*/
public static String toDBC (String text, Set<Character> notConvertSet) {
char[] c = text.toCharArray();
for (int i = 0 ; i < c.length ; i++) {
if (null != notConvertSet && notConvertSet.contains(c[i])) {
// 跳过不替换的字符
continue;
}
if (c[i] == '\u3000') {
c[i] = ' ';
} else if (c[i] > '\uFF00' && c[i] < '\uFF5F') {
c[i] = (char) (c[i] - 65248);
}
}
String returnString = new String(c);
return returnString;
}
/**
*
*
* @param n
*
* @return
*/
public static String digitUppercase (double n) {
String[] fraction = {"角", "分"};
String[] digit = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
String[][] unit = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}};
String head = n < 0 ? "负" : "";
n = Math.abs(n);
String s = "";
for (int i = 0 ; i < fraction.length ; i++) {
s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
}
if (s.length() < 1) {
s = "整";
}
int integerPart = (int) Math.floor(n);
for (int i = 0 ; i < unit[0].length && integerPart > 0 ; i++) {
String p = "";
for (int j = 0 ; j < unit[1].length && n > 0 ; j++) {
p = digit[integerPart % 10] + unit[1][j] + p;
integerPart = integerPart / 10;
}
s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
}
return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
}
}

View File

@ -0,0 +1,71 @@
package com.muyu.utils;
import lombok.extern.log4j.Log4j2;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
@Log4j2
public class MD5Util {
private static final Integer SALT_LENGTH = 12;
/**
* byte16
* @param b
* @return
*/
public static String byteToHexString(byte[] b) {
StringBuilder hexString = new StringBuilder();
for (byte value : b) {
String hex = Integer.toHexString(value & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
hexString.append(hex.toUpperCase());
}
return hexString.toString();
}
/**
*
* @param str
* @return
*/
public static String encrypted (String str) {
try {
// 声明加密后的口令数组变量
byte[] pwd = null;
// 随机数生成器
SecureRandom random = new SecureRandom();
// 声明盐数组变量
byte[] salt = new byte[SALT_LENGTH];
// 将随机数放入盐变量中
random.nextBytes(salt);
// 声明消息摘要对象
MessageDigest md = null;
// 创建消息摘要
md = MessageDigest.getInstance("MD5");
// 将盐数据传入消息摘要对象
md.update(salt);
// 将口令的数据传给消息摘要对象
md.update(str.getBytes(StandardCharsets.UTF_8));
// 获得消息摘要的字节数组
byte[] digest = md.digest();
// 因为要在口令的字节数组中存放盐,所以加上盐的字节长度
pwd = new byte[digest.length + SALT_LENGTH];
// 将盐的字节拷贝到生成的加密口令字节数组的前12个字节以便在验证口令时取出盐
System.arraycopy(salt, 0, pwd, 0, SALT_LENGTH);
// 将消息摘要拷贝到加密口令字节数组从第13个字节开始的字节
System.arraycopy(digest, 0, pwd, SALT_LENGTH, digest.length);
// 将字节数组格式加密后的口令转化为16进制字符串格式的口令
return byteToHexString(pwd);
}catch (Exception exception){
log.info("md5加密失败[{}]", str, exception);
return str;
}
}
}

View File

@ -0,0 +1,314 @@
package com.muyu.utils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.*;
/**
* . getter/setter, 访, , Class, AOP.
*
* @author ruoyi
*/
@SuppressWarnings("rawtypes")
public class ReflectUtils {
private static final String SETTER_PREFIX = "set";
private static final String GETTER_PREFIX = "get";
private static final String CGLIB_CLASS_SEPARATOR = "$$";
private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
/**
* Getter.
* ..
*/
@SuppressWarnings("unchecked")
public static <E> E invokeGetter (Object obj, String propertyName) {
Object object = obj;
for (String name : StringUtils.split(propertyName, ".")) {
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
object = invokeMethod(object, getterMethodName, new Class[]{}, new Object[]{});
}
return (E) object;
}
/**
* Setter,
* ..
*/
public static <E> void invokeSetter (Object obj, String propertyName, E value) {
Object object = obj;
String[] names = StringUtils.split(propertyName, ".");
for (int i = 0 ; i < names.length ; i++) {
if (i < names.length - 1) {
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
object = invokeMethod(object, getterMethodName, new Class[]{}, new Object[]{});
} else {
String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, setterMethodName, new Object[]{value});
}
}
}
/**
* , private/protected, getter.
*/
@SuppressWarnings("unchecked")
public static <E> E getFieldValue (final Object obj, final String fieldName) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
return null;
}
E result = null;
try {
result = (E) field.get(obj);
} catch (IllegalAccessException e) {
logger.error("不可能抛出的异常{}", e.getMessage());
}
return result;
}
/**
* , private/protected, setter.
*/
public static <E> void setFieldValue (final Object obj, final String fieldName, final E value) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
// throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
return;
}
try {
field.set(obj, value);
} catch (IllegalAccessException e) {
logger.error("不可能抛出的异常: {}", e.getMessage());
}
}
/**
* , private/protected.
* 使getAccessibleMethod()Method.
* +
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethod (final Object obj, final String methodName, final Class<?>[] parameterTypes,
final Object[] args) {
if (obj == null || methodName == null) {
return null;
}
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
if (method == null) {
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
return null;
}
try {
return (E) method.invoke(obj, args);
} catch (Exception e) {
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
throw convertReflectionExceptionToUnchecked(msg, e);
}
}
/**
* , private/protected
* 使getAccessibleMethodByName()Method.
*
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethodByName (final Object obj, final String methodName, final Object[] args) {
Method method = getAccessibleMethodByName(obj, methodName, args.length);
if (method == null) {
// 如果为空不报错,直接返回空。
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
return null;
}
try {
// 类型转换(将参数数据类型转换为目标方法参数类型)
Class<?>[] cs = method.getParameterTypes();
for (int i = 0 ; i < cs.length ; i++) {
if (args[i] != null && !args[i].getClass().equals(cs[i])) {
if (cs[i] == String.class) {
args[i] = Convert.toStr(args[i]);
if (StringUtils.endsWith((String) args[i], ".0")) {
args[i] = StringUtils.substringBefore((String) args[i], ".0");
}
} else if (cs[i] == Integer.class) {
args[i] = Convert.toInt(args[i]);
} else if (cs[i] == Long.class) {
args[i] = Convert.toLong(args[i]);
} else if (cs[i] == Double.class) {
args[i] = Convert.toDouble(args[i]);
} else if (cs[i] == Float.class) {
args[i] = Convert.toFloat(args[i]);
} else if (cs[i] == boolean.class || cs[i] == Boolean.class) {
args[i] = Convert.toBool(args[i]);
}
}
}
return (E) method.invoke(obj, args);
} catch (Exception e) {
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
throw convertReflectionExceptionToUnchecked(msg, e);
}
}
/**
* , DeclaredField, 访.
* Object, null.
*/
public static Field getAccessibleField (final Object obj, final String fieldName) {
// 为空不报错。直接返回 null
if (obj == null) {
return null;
}
Validate.notBlank(fieldName, "fieldName can't be blank");
for (Class<?> superClass = obj.getClass() ; superClass != Object.class ; superClass = superClass.getSuperclass()) {
try {
Field field = superClass.getDeclaredField(fieldName);
makeAccessible(field);
return field;
} catch (NoSuchFieldException e) {
continue;
}
}
return null;
}
/**
* , DeclaredMethod,访.
* Object, null.
* +
* . 使Method,Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethod (final Object obj, final String methodName,
final Class<?>... parameterTypes) {
// 为空不报错。直接返回 null
if (obj == null) {
return null;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass() ; searchType != Object.class ; searchType = searchType.getSuperclass()) {
try {
Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
makeAccessible(method);
return method;
} catch (NoSuchMethodException e) {
continue;
}
}
return null;
}
/**
* , DeclaredMethod,访.
* Object, null.
*
* . 使Method,Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethodByName (final Object obj, final String methodName, int argsNum) {
// 为空不报错。直接返回 null
if (obj == null) {
return null;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass() ; searchType != Object.class ; searchType = searchType.getSuperclass()) {
Method[] methods = searchType.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum) {
makeAccessible(method);
return method;
}
}
}
return null;
}
/**
* private/protectedpublicJDKSecurityManager
*/
public static void makeAccessible (Method method) {
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
&& !method.isAccessible()) {
method.setAccessible(true);
}
}
/**
* private/protectedpublicJDKSecurityManager
*/
public static void makeAccessible (Field field) {
if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
|| Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) {
field.setAccessible(true);
}
}
/**
* , Class,
* , Object.class.
*/
@SuppressWarnings("unchecked")
public static <T> Class<T> getClassGenricType (final Class clazz) {
return getClassGenricType(clazz, 0);
}
/**
* , Class.
* , Object.class.
*/
public static Class getClassGenricType (final Class clazz, final int index) {
Type genType = clazz.getGenericSuperclass();
if (!(genType instanceof ParameterizedType)) {
logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType");
return Object.class;
}
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if (index >= params.length || index < 0) {
logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
+ params.length);
return Object.class;
}
if (!(params[index] instanceof Class)) {
logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
return Object.class;
}
return (Class) params[index];
}
public static Class<?> getUserClass (Object instance) {
if (instance == null) {
throw new RuntimeException("Instance must not be null");
}
Class clazz = instance.getClass();
if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
Class<?> superClass = clazz.getSuperclass();
if (superClass != null && !Object.class.equals(superClass)) {
return superClass;
}
}
return clazz;
}
/**
* checked exceptionunchecked exception.
*/
public static RuntimeException convertReflectionExceptionToUnchecked (String msg, Exception e) {
if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
|| e instanceof NoSuchMethodException) {
return new IllegalArgumentException(msg, e);
} else if (e instanceof InvocationTargetException) {
return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());
}
return new RuntimeException(msg, e);
}
}

View File

@ -0,0 +1,93 @@
package com.muyu.utils;
import com.muyu.common.SystemConstant;
import com.muyu.domain.model.PositionModel;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Random;
public class VehicleUtils {
/**
* VIN
* @return
*/
public static String genVin() {
String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
StringBuilder sb = new StringBuilder(17);
for (int i = 0; i < 17; i++) {
int index = (int) (random.nextFloat() * characters.length());
sb.append(characters.charAt(index));
}
return sb.toString();
}
private static Random random = new Random();
/**
*
* @return
*/
public static BigDecimal genBattery(){
return BigDecimal.valueOf(random.nextInt(60, 80) * 1000L);
}
/**
*
* @param startPositionModel
* @param endPositionModel
* @return
*/
public static BigDecimal distance(PositionModel startPositionModel, PositionModel endPositionModel){
double lon1 = Double.parseDouble(startPositionModel.getLongitude());
double lat1 = Double.parseDouble(startPositionModel.getLatitude());
double lon2 = Double.parseDouble(endPositionModel.getLongitude());
double lat2 = Double.parseDouble(endPositionModel.getLatitude());
double lon1Rad = Math.toRadians(lon1);
double lat1Rad = Math.toRadians(lat1);
double lon2Rad = Math.toRadians(lon2);
double lat2Rad = Math.toRadians(lat2);
double earthRadius = 6371; // 地球半径(以公里为单位)
double latDiff = lat2Rad - lat1Rad;
double lonDiff = lon2Rad - lon1Rad;
double a = Math.sin(latDiff / 2) * Math.sin(latDiff / 2) +
Math.cos(lat1Rad) * Math.cos(lat2Rad) *
Math.sin(lonDiff / 2) * Math.sin(lonDiff / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double distance = earthRadius * c;
return BigDecimal.valueOf(distance).setScale(2, RoundingMode.HALF_UP);
}
/**
*
* @return
*/
public static BigDecimal batteryFloat(){
Random rand = new Random();
// 生成0.00-0.31之间的随机数
double num = rand.nextDouble() * 0.31;
// 加上0.90得到0.90-1.21之间的随机数
num += 0.90;
// 保留两位小数
num = (double) Math.round(num * 100) / 100;
return BigDecimal.valueOf(num);
}
/**
*
* @param start
* @param end
* @return
*/
public static String genValue(int start, int end){
Random rand = new Random();
return String.valueOf(rand.nextInt(start, end));
}
}

View File

@ -0,0 +1,308 @@
package com.muyu.vehicle;
import com.alibaba.fastjson2.JSONObject;
import com.muyu.common.SystemConstant;
import com.muyu.common.pool.ScheduledThreadPool;
import com.muyu.domain.Vehicle;
import com.muyu.domain.model.PositionModel;
import com.muyu.utils.CalculateCheckDigit;
import com.muyu.utils.ConversionUtil;
import com.muyu.utils.VehicleUtils;
import com.muyu.vehicle.model.VehicleData;
import com.muyu.vehicle.model.properties.MqttProperties;
import com.muyu.vehicle.thread.VehicleThread;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledFuture;
import static com.muyu.common.SystemConstant.*;
/**
* @author DongZeLiang
* @version 1.0
* @description
* @date 2023/11/16
*/
@Data
@Log4j2
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class VehicleInstance {
/**
* 线
*/
private String positionCode;
/**
*
*/
private LinkedBlockingQueue<PositionModel> positionQueue = new LinkedBlockingQueue<>();
/**
*
*/
private Vehicle vehicle;
/**
*
*/
private VehicleData vehicleData;
/**
*
*/
private PositionModel lastPosition;
/**
* 线
*/
private VehicleThread vehicleThread;
/**
*
*/
private String msgCode;
/**
* 线
*/
private ScheduledFuture<?> scheduledFuture;
/**
*
*/
private MqttClient client = null;
/**
* Mqtt
*/
private MqttProperties mqttProperties;
/***
* VIN
* @return VIN
*/
public String getVin() {
return this.vehicle.getVin();
}
/**
*
* @param msg
*/
public void sendMsg(String msg) {
//得到16进制报文
String sHex = ConversionUtil.strToSixteen(msg);
//计算校验和
String makeCheck = CalculateCheckDigit.makeCheck(sHex);
msg = MSG_START + sHex + makeCheck + " " + MSG_END;
// 创建消息并设置 QoS
MqttMessage message = new MqttMessage(msg.getBytes());
message.setQos(this.mqttProperties.getQos());
// 发布消息
try {
client.publish(this.mqttProperties.getTopic(), message);
} catch (MqttException e) {
throw new RuntimeException(e);
}
}
/**
*
*/
public void initClient () {
try {
client = new MqttClient(mqttProperties.getBroker(), mqttProperties.getClientId(), new MemoryPersistence());
// 连接参数
MqttConnectOptions options = new MqttConnectOptions();
// 设置用户名和密码
if (Objects.nonNull(mqttProperties.getUsername()) && Objects.nonNull(mqttProperties.getPassword())) {
options.setUserName(mqttProperties.getUsername());
options.setPassword(mqttProperties.getPassword().toCharArray());
}
options.setConnectionTimeout(1);
options.setKeepAliveInterval(20);
// 连接
client.connect(options);
log.debug("车辆:[{}] 客户端初始化成功连接配置:{}", getVin(),
JSONObject.toJSONString(this.mqttProperties));
} catch (MqttException e) {
log.error("车辆:[{}] 客户端初始化异常", getVin(), e);
}
}
/**
* 线
* @return 线true线false
*/
public boolean isOnline () {
if (this.client == null){
return false;
}
return this.client.isConnected();
}
/**
* 线
* @return truefalse
*/
public boolean isSend(){
return this.vehicleThread != null;
}
/**
*
*/
public void closeClient(){
if (this.client != null){
try {
// 断开连接
this.client.disconnect();
// 关闭连接
this.client.close();
log.debug("车辆:[{}] 客户端下线成功", getVin());
} catch (MqttException e) {
log.error("车辆:[{}] 客户端关闭异常:[{}]",getVin(), e.getMessage(), e);
}
}
}
/**
* 线
* @param positionModelList 线
*/
public void settingPosition(List<PositionModel> positionModelList){
positionQueue.clear();
positionModelList.forEach(positionQueue::offer);
log.info("车辆:{} 设置路径成功", this.getVin());
}
/**
* 线
*/
public void initVehicleThread() {
if (this.positionCode == null){
throw new RuntimeException("车辆["+getVin()+"]为选中路径");
}
VehicleThread vehicleThread = new VehicleThread();
vehicleThread.setVehicleInstance(this);
this.setVehicleThread(vehicleThread);
ScheduledFuture<?> scheduledFuture = ScheduledThreadPool.submit(vehicleThread);
this.setScheduledFuture(scheduledFuture);
log.info("初始化车辆上报模拟线程开始:[{}]", this.getVin());
}
/**
* 线
*/
public void startSend() {
this.msgCode = "上报";
if (this.vehicleThread != null){
this.vehicleThread.resume();
}
log.info("车辆[{}],开始上报", this.getVin());
}
/**
* 线
*/
public void pauseSend() {
this.msgCode = "暂停";
if (this.vehicleThread != null) {
this.vehicleThread.pause();
}
log.info("车辆[{}],暂停上报", this.getVin());
}
/**
*
*/
public void stopSend() {
this.msgCode = "停止";
if (this.vehicleThread != null){
this.vehicleThread.stop();
}
log.info("车辆[{}],停止上报", this.getVin());
}
/**
*
*/
public void cancelExecution() {
scheduledFuture.cancel(true);
this.vehicleThread = null;
this.scheduledFuture = null;
}
/**
*
*/
public String imitateData() {
String gear = this.vehicleData.getGear();
if (!"D".equals(gear)){
log.info("车辆不是动车档位,不进行模拟数据");
return null;
}
// 获取上一次定位点
PositionModel lastPositionModel = this.lastPosition == null ? positionQueue.poll() : this.lastPosition;
// 获取当前定位点
PositionModel currentPositionModel = positionQueue.poll();
if (currentPositionModel == null) {
return "表示当前定位点已经跑完,需要其他操作";
}
// 两点之间的距离
BigDecimal distance = VehicleUtils.distance(lastPositionModel, currentPositionModel);
// 车辆总里程 相加
vehicleData.setMileage(vehicleData.getMileage().add(distance));
// 定位点填写
vehicleData.setLongitude(currentPositionModel.getLongitude());
vehicleData.setLatitude(currentPositionModel.getLatitude());
// 当前电量减少
// 电池浮动
BigDecimal batteryFloat = VehicleUtils.batteryFloat();
// 百公里占比
BigDecimal hundredKMScale = distance.divide(SystemConstant.hundredKilometers).setScale(3, RoundingMode.HALF_UP);
// 使用电量
BigDecimal powerUsage = powerConsumption.multiply(hundredKMScale)
.multiply(batteryFloat)
.setScale(2, RoundingMode.HALF_UP);
// 剩余电量
vehicleData.setRemainingBattery(vehicleData.getRemainingBattery().subtract(powerUsage));
// 百公里消耗量
vehicleData.setFuelConsumptionRate(
powerConsumption.multiply(batteryFloat).divide(new BigDecimal(1000)).setScale(2, RoundingMode.HALF_UP).toString()
);
// 计算总速度
vehicleData.setSpeed(
distance.divide(new BigDecimal(2))
.multiply(new BigDecimal("3600"))
.setScale(2, RoundingMode.HALF_UP).toString()
);
vehicleData.imitateBase();
vehicleData.imitateMotor();
vehicleData.imitateBatteryPack();
return null;
}
/**
*
* @param gear
*/
public void setGear (String gear) {
this.vehicleData.setGear(gear);
}
}

View File

@ -0,0 +1,22 @@
package com.muyu.vehicle.api;
import com.dtflys.forest.annotation.BaseRequest;
import com.dtflys.forest.annotation.JSONBody;
import com.dtflys.forest.annotation.Post;
import com.muyu.common.Result;
import com.muyu.domain.model.MqttServerModel;
import com.muyu.vehicle.api.req.VehicleConnectionReq;
/**
* @author DongZl
* @description:
* @Date 2023-11-28 10:20
*/
@BaseRequest(
baseURL = "${adminHost}"
)
public interface ClientAdmin {
@Post("${adminTopicUri}")
public Result<MqttServerModel> vehicleConnection(@JSONBody VehicleConnectionReq vehicleConnectionReq);
}

View File

@ -0,0 +1,51 @@
package com.muyu.vehicle.api.req;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author DongZl
* @description:
* @Date 2023-11-28 10:32
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class VehicleConnectionReq {
/**
* {
* "vehicleVin": "VIN1234567894",
* "timestamp": "11111",
* "username": "你好",
* "nonce": "33"
* }
*/
/**
* vin
*/
@JSONField(name = "vehicleVin")
private String vin;
/**
*
*/
private String timestamp;
/**
*
*/
@JSONField(name = "username")
private String userName;
/**
*
*/
private String nonce;
}

View File

@ -0,0 +1,81 @@
package com.muyu.vehicle.core;
import com.muyu.vehicle.VehicleInstance;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author DongZl
* @description:
* @Date 2023-11-16 02:30
*/
public class LocalContainer {
/**
*
*/
public static final Map<String, VehicleInstance> vehicleDataMap = new HashMap<>();
/**
*
* @param vehicleInstance
*/
public static void setVehicleInstance(List<VehicleInstance> vehicleInstance){
vehicleInstance.forEach(LocalContainer::setVehicleInstance);
}
public static void setVehicleInstance(VehicleInstance vehicleInstance){
String vin = vehicleInstance.getVehicle().getVin();
if (!vehicleDataMap.containsKey(vin)) {
vehicleDataMap.put(vin, vehicleInstance);
}
}
/**
*
* @param vin vin
* @return
*/
public static VehicleInstance getVehicleInstance(String vin){
return vehicleDataMap.get(vin);
}
/**
* 线
* @return
*/
public static long total () {
return vehicleDataMap.size();
}
public static Collection<VehicleInstance> getVehicleInstanceAll () {
return vehicleDataMap.values();
}
/**
* 线
* @return 线
*/
public static List<VehicleInstance> getOnlineVehicleInstance(){
return vehicleDataMap.values().stream().filter(VehicleInstance::isOnline).toList();
}
/**
* 线
* @return 线
*/
public static List<VehicleInstance> getOfflineVehicleInstance(){
return vehicleDataMap.values().stream().filter(vehicleInstance -> !vehicleInstance.isOnline()).toList();
}
/**
* VIN
* @param vin VIN
*/
public static void removeByVin(String vin) {
vehicleDataMap.remove(vin);
}
}

View File

@ -0,0 +1,79 @@
package com.muyu.vehicle.core;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.muyu.common.pool.FixedThreadPool;
import com.muyu.common.pool.ScheduledThreadPool;
import com.muyu.domain.Vehicle;
import com.muyu.service.VehicleInstanceService;
import com.muyu.service.VehicleService;
import com.muyu.vehicle.VehicleInstance;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PreDestroy;
import java.util.List;
/**
* @author DongZeLiang
* @version 1.0
* @description
* @date 2023/11/9
*/
@Log4j2
@Configuration
@AllArgsConstructor
public class VehicleConfiguration implements ApplicationRunner {
private final VehicleService vehicleService;
private final VehicleInstanceService vehicleInstanceService;
/**
*
*/
public void vehiclePageInit (){
long startTime = System.currentTimeMillis();
int page = 0, pageSize = 10;
log.info("初始开始,批量从数据库当中加载数据到内存当中,每次[{}]条", pageSize);
while (true){
Page<Vehicle> vehiclePage = vehicleService.page(new Page<>(page++, pageSize));
List<Vehicle> vehicleList = vehiclePage.getRecords();
vehicleList.forEach(vehicleInstanceService::init);
log.debug("第[{}]页,[{}]条", page, vehicleList.size());
if (vehicleList.size() < pageSize){
break;
}
}
log.info("数据加载完成,耗时:{} MS", System.currentTimeMillis() - startTime);
}
@Override
public void run (ApplicationArguments args) {
this.vehiclePageInit();
// 提交给线程池 一分钟 执行一次
// ThreadPool.submit(new Thread(vehicleService::syncDb), 30);
}
/**
*
*/
@PreDestroy
public void destroy(){
log.info("数据库同步");
vehicleService.syncDb();
log.info("下线所有车辆");
List<VehicleInstance> onlineVehicleInstanceList = LocalContainer.getOnlineVehicleInstance();
onlineVehicleInstanceList.forEach(VehicleInstance::closeClient);
log.info("关闭线程池");
ScheduledThreadPool.shutdown();
FixedThreadPool.shutDown();
}
}

View File

@ -0,0 +1,521 @@
package com.muyu.vehicle.model;
import com.muyu.domain.Vehicle;
import com.muyu.utils.VehicleUtils;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import static com.muyu.utils.VehicleUtils.genValue;
/**
* @author
* @Classname VehicleData
* @Description
* @Date 2021/8/5
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class VehicleData {
/**
* VIN
*/
private String vin;
/**
* 线
*/
private String drivingRoute;
/**
*
*/
private String longitude;
/**
*
*/
private String latitude;
/**
*
*/
private String speed;
/**
*
*/
private BigDecimal mileage;
/**
*
*/
private String voltage;
/**
*
*/
private String current;
/**
*
*/
private String resistance;
/**
*
*/
private String gear = "P";
/**
*
*/
private String accelerationPedal;
/**
*
*/
private String brakePedal;
/**
*
*/
private String fuelConsumptionRate;
/**
*
*/
private String motorControllerTemperature;
/**
*
*/
private String motorSpeed;
/**
*
*/
private String motorTorque;
/**
*
*/
private String motorTemperature;
/**
*
*/
private String motorVoltage;
/**
*
*/
private String motorCurrent;
/**
* SOC
*/
private BigDecimal remainingBattery;
/**
*
*/
private BigDecimal batteryLevel;
/**
*
*/
private String maximumFeedbackPower;
/**
*
*/
private String maximumDischargePower;
/**
* BMS
*/
private String selfCheckCounter;
/**
*
*/
private String totalBatteryCurrent;
/**
* V3
*/
private String totalBatteryVoltage;
/**
*
*/
private String singleBatteryMaxVoltage;
/**
*
*/
private String singleBatteryMinVoltage;
/**
*
*/
private String singleBatteryMaxTemperature;
/**
*
*/
private String singleBatteryMinTemperature;
/**
*
*/
private String availableBatteryCapacity;
/**
*
*/
private int vehicleStatus = 1;
/**
*
*/
private int chargingStatus = 1;
/**
*
*/
private int operatingStatus = 1;
/**
* SOC
*/
private int socStatus = 1;
/**
*
*/
private int chargingEnergyStorageStatus = 1;
/**
*
*/
private int driveMotorStatus = 1;
/**
*
*/
private int positionStatus = 1;
/**
* EAS()
*/
private int easStatus = 1;
/**
* PTC()
*/
private int ptcStatus = 1;
/**
* EPS()
*/
private int epsStatus = 1;
/**
* ABS()
*/
private int absStatus = 1;
/**
* MCU(/)
*/
private int mcuStatus = 1;
/**
*
*/
private int heatingStatus = 1;
/**
*
*/
private int batteryStatus = 1;
/**
*
*/
private int batteryInsulationStatus = 1;
/**
* DCDC()
*/
private int dcdcStatus = 1;
/**
* CHG()
*/
private int chgStatus = 1;
/**
*
*/
private String vehicleStatusMsg;
/**
*
*/
private String smartHardwareMsg;
/**
*
*/
private String batteryMsg;
public String getMsg(){
//第一位VIN
return vin +
// 当前时间戳
System.currentTimeMillis() +
//第二位经度 longitude latitude
getValue(longitude, 11) +
//第三位维度 longitude latitude
getValue(latitude, 10) +
//车速
getValue(speed, 6) +
//总里程
getValue(mileage == null ? "" : mileage.toString(), 11) +
// 总电压
getValue(voltage, 6) +
//总电流
getValue(current, 5) +
//绝缘电阻 79 - 87
getValue(resistance, 9) +
//档位
(gear == null ? "D" : gear) +
// 加速踏板行程值
getValue(accelerationPedal, 2) +
// 制动踏板行程值
getValue(brakePedal, 2) +
// 燃料消耗率
getValue(fuelConsumptionRate, 5) +
//电机控制器温度
getValue(motorControllerTemperature, 6) +
//电机转速
getValue(motorSpeed, 5) +
//点击转矩
getValue(motorTorque, 4) +
//电机温度
getValue(motorTemperature, 6) +
//电机电压
getValue(motorVoltage, 5) +
//电机电流
getValue(motorCurrent, 8) +
//动力电池剩余电量SOC
getValue(remainingBattery == null ? "" : remainingBattery.toString(), 6) +
//当前状态允许的最大反馈功率
getValue(maximumFeedbackPower, 6) +
//当前状态允许最大放电功率
getValue(maximumDischargePower, 6) +
//BMS自检计数器
getValue(selfCheckCounter, 2) +
//动力电池充放电电流
getValue(totalBatteryCurrent, 5) +
//动力电池负载端总电压V3
getValue(totalBatteryVoltage, 6) +
//单次最大电压
getValue(singleBatteryMaxVoltage, 4) +
//单体电池最低电压
getValue(singleBatteryMinVoltage, 4) +
//单体电池最高温度
getValue(singleBatteryMaxTemperature, 6) +
//单体电池最低温度
getValue(singleBatteryMinTemperature, 6) +
//动力电池可用容量
getValue(availableBatteryCapacity, 6) +
//车辆状态
vehicleStatus +
//充电状态
chargingStatus +
//运行状态
operatingStatus +
//SOC
socStatus +
//可充电储能装置工作状态
chargingEnergyStorageStatus +
//驱动电机状态
driveMotorStatus +
//定位是否有效
positionStatus +
//EAS
easStatus +
//PTC
ptcStatus +
//EPS
epsStatus +
//ABS
absStatus +
//MCU
mcuStatus +
//动力电池加热状态
heatingStatus +
//动力电池当前状态
batteryStatus +
//动力电池保温状态
batteryInsulationStatus +
//DCDC
dcdcStatus +
//CHG
chgStatus;
}
public String getValue(String val , int valLength){
if(val == null){
val = "";
}
int length = val.length();
if (length > valLength){
return val.substring( 0 , valLength);
}
val = val + "0".repeat(valLength - length);
return val;
}
/**
* VIN
* @param vehicle
* @return
*/
public static VehicleData vehicleBuild (Vehicle vehicle) {
return VehicleData.builder()
.vin(vehicle.getVin())
.gear("P")
.remainingBattery(vehicle.getRemainingBattery())
.batteryLevel(vehicle.getBatteryLevel())
.mileage(vehicle.getTotalMileage())
.vehicleStatus(1)
.chargingStatus(1)
.operatingStatus(1)
.socStatus(1)
.chargingEnergyStorageStatus(1)
.driveMotorStatus(1)
.positionStatus(1)
.easStatus(1)
.ptcStatus(1)
.epsStatus(1)
.absStatus(1)
.mcuStatus(1)
.heatingStatus(1)
.batteryStatus(1)
.batteryInsulationStatus(1)
.dcdcStatus(1)
.chgStatus(1)
.build();
}
/**
*
*/
public void imitateBase(){
// 总电压
this.voltage = genValue(110, 750);
// 总电流
this.current = genValue(3, 50);
// 绝缘电阻
this.resistance = genValue(0,30000);
// 加速踏板行程值
this.accelerationPedal = genValue(0, 10);
// 制动踏板行程值
this.brakePedal = genValue(0, 10);
}
/**
*
*/
public void imitateMotor(){
// 电机控制器温度
this.motorControllerTemperature = genValue(0, 100);
// 电机转速
this.motorSpeed = genValue(0, 99999);
// 电机转矩
this.motorTorque = genValue(0, 1000);
// 电机温度
this.motorTemperature = genValue(0, 150);
// 电机电压
this.motorVoltage = genValue(110, 300);
// 电机电流
this.motorCurrent = genValue(0, 15000);
}
/**
*
*/
public void imitateBatteryPack(){
// 当前状态允许的最大反馈功率
this.maximumFeedbackPower = genValue(0, 100);
// 当前状态允许最大放电功率
this.maximumDischargePower = genValue(0, 100);
// BMS自检计数器
this.selfCheckCounter = genValue(0, 15);
// 动力电池充放电电流
this.totalBatteryCurrent = genValue(0, 15);
// 动力电池负载端总电压V3
this.totalBatteryVoltage = genValue(220, 750);
// 单体电池最高电压
this.singleBatteryMaxVoltage = genValue(3, 5);
// 单体电池最低电压
this.singleBatteryMinVoltage = genValue(3, 5);
// 单体电池最高温度
this.singleBatteryMaxTemperature = genValue(0, 100);
// 单体电池最低温度
this.singleBatteryMinTemperature = genValue(0, 100);
// 动力电池可用容量
this.availableBatteryCapacity = genValue(0,100 );
}
/**
vehicleStatus;
chargingStatus;
operatingStatus;
SOC
socStatus;
chargingEnergyStorageStatus;
driveMotorStatus;
positionStatus;
*/
/**
EAS()
easStatus;
PTC()
ptcStatus;
EPS()
epsStatus;
ABS()
absStatus;
MCU(/)
mcuStatus;
*/
/**
heatingStatus;
batteryStatus;
batteryInsulationStatus;
DCDC()
dcdcStatus;
CHG()
chgStatus;
*/
}

View File

@ -0,0 +1,47 @@
package com.muyu.vehicle.model.properties;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @author DongZeLiang
* @version 1.0
* @description Mqtt
* @date 2023/11/8
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MqttProperties {
/**
*
*/
private String broker;
/**
*
*/
private String topic;
/**
*
*/
private String username;
/**
*
*/
private String password;
/**
* ID
*/
private String clientId;
private int qos = 0;
}

View File

@ -0,0 +1,76 @@
package com.muyu.vehicle.thread;
import com.alibaba.fastjson2.JSONObject;
import com.muyu.vehicle.VehicleInstance;
import lombok.extern.log4j.Log4j2;
@Log4j2
public class VehicleThread implements Runnable {
/**
* 线
*/
private volatile boolean isStop = false;
/**
*
*/
private volatile boolean isPaused;
/**
*
*/
private VehicleInstance vehicleInstance;
@Override
public void run() {
try {
if (!isStop){
if (!isPaused){
log.info("{} - 上报数据", this.vehicleInstance.getVin());
String imitateResult = this.vehicleInstance.imitateData();
if (imitateResult == null){
this.vehicleInstance.sendMsg(
this.vehicleInstance.getVehicleData().getMsg()
);
}else {
log.warn("车辆[{}]数据模拟:{}", this.vehicleInstance.getVin(), imitateResult);
}
}else {
log.info("暂停模拟和上报:[{}]", this.vehicleInstance.getVin());
}
}else {
log.info("终止模拟和上报:[{}]", this.vehicleInstance.getVin());
vehicleInstance.cancelExecution();
}
}catch (Throwable throwable){
log.error("车辆模拟输出错误:{}", this.vehicleInstance.getVin(), throwable);
}
}
/**
* 线
*/
public void pause() {
isPaused = true;
}
/**
* 线
*/
public void resume() {
isPaused = false;
}
/**
*
*/
public void stop(){
this.isStop = true;
}
public void setVehicleInstance(VehicleInstance vehicleInstance) {
this.vehicleInstance = vehicleInstance;
}
}

View File

@ -0,0 +1,93 @@
server:
port: 82
spring:
mvc:
static-path-pattern: /static/**
datasource:
username: muyu
password: 123456
# 如果需要数据本地化,则改成 file 方式
# jdbc:h2:mem:testDB;DB_CLOSE_DELAY=-1
url: jdbc:h2:file:~/vehicle/db;AUTO_SERVER=TRUE;DB_CLOSE_DELAY=-1
driver-class-name: org.h2.Driver
h2:
# 开启这个配置就可以通过 web 页面访问了例如http://localhost:8080/springboot-h2/h2-console
console:
enabled: true
settings:
# 开启h2 console 跟踪 方便调试 默认 false
trace: true
# 允许console 远程访问 默认false
web-allow-others: true
# h2 访问路径上下文
path: /h2-console
sql:
init:
schema-locations: classpath:schema.sql
data-locations: classpath:data.sql
mode: always
continue-on-error: true
# mybatis-plus 配置
mybatis-plus:
mapper-locations: classpath*:/com.muyu.mapper/**/*.xml
#实体扫描多个package用逗号或者分号分隔
typeAliasesPackage: com.dmo.entity
global-config:
#数据库相关配置
db-config:
#主键类型 AUTO:"数据库ID自增", INPUT:"用户输入ID", ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
id-type: AUTO
#字段策略 IGNORED:"忽略判断",NOT_NULL:"非 NULL 判断"),NOT_EMPTY:"非空判断"
field-strategy: NOT_NULL
#驼峰下划线转换
column-underline: true
logic-delete-value: -1
logic-not-delete-value: 0
#原生配置
configuration:
# 打印sql
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
cache-enabled: false
call-setters-on-nulls: true
jdbc-type-for-null: 'null'
# 日志输出配置
logging:
level:
com.muyu: DEBUG
com.muyu.service: DEBUG
com.muyu.mapper: DEBUG
com.muyu.vehicle: DEBUG
root: INFO
org:
springframework:
security: WARN
web: ERROR
file:
path: ./logs
name: './logs/vehicle.log'
pattern:
file: '%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n'
console: '%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n'
# http调用框架
forest:
max-connections: 1000 # 连接池最大连接数
connect-timeout: 3000 # 连接超时时间,单位为毫秒
read-timeout: 3000 # 数据读取超时时间,单位为毫秒
variables:
adminHost: ${mqtt.admin.host}
adminTopicUri: ${mqtt.admin.topic-uri}
log-enabled: false
# 服务器配置
mqtt:
server:
host: tcp://47.92.65.101:1883
topic: test1
admin:
host: http://127.0.0.1:${server.port}
topic-uri: /verify/vehicleConnection

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,14 @@
create table if not exists vehicle (
`vin` char (17) primary key not null,
`remaining_battery` DOUBLE not null,
`total_mileage` DOUBLE not null,
`battery_level` DOUBLE not null,
`create_time` datetime not null
) ;
create table if not exists route_info (
`id` int primary key not null ,
`name` char (3) not null,
`data` CLOB not null,
`create_time` datetime not null
) ;

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
.wscn-http404-container[data-v-c095f994]{-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);position:absolute;top:40%;left:50%}.wscn-http404[data-v-c095f994]{position:relative;width:1200px;padding:0 50px;overflow:hidden}.wscn-http404 .pic-404[data-v-c095f994]{position:relative;float:left;width:600px;overflow:hidden}.wscn-http404 .pic-404__parent[data-v-c095f994]{width:100%}.wscn-http404 .pic-404__child[data-v-c095f994]{position:absolute}.wscn-http404 .pic-404__child.left[data-v-c095f994]{width:80px;top:17px;left:220px;opacity:0;-webkit-animation-name:cloudLeft-data-v-c095f994;animation-name:cloudLeft-data-v-c095f994;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1s;animation-delay:1s}.wscn-http404 .pic-404__child.mid[data-v-c095f994]{width:46px;top:10px;left:420px;opacity:0;-webkit-animation-name:cloudMid-data-v-c095f994;animation-name:cloudMid-data-v-c095f994;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1.2s;animation-delay:1.2s}.wscn-http404 .pic-404__child.right[data-v-c095f994]{width:62px;top:100px;left:500px;opacity:0;-webkit-animation-name:cloudRight-data-v-c095f994;animation-name:cloudRight-data-v-c095f994;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1s;animation-delay:1s}@-webkit-keyframes cloudLeft-data-v-c095f994{0%{top:17px;left:220px;opacity:0}20%{top:33px;left:188px;opacity:1}80%{top:81px;left:92px;opacity:1}to{top:97px;left:60px;opacity:0}}@keyframes cloudLeft-data-v-c095f994{0%{top:17px;left:220px;opacity:0}20%{top:33px;left:188px;opacity:1}80%{top:81px;left:92px;opacity:1}to{top:97px;left:60px;opacity:0}}@-webkit-keyframes cloudMid-data-v-c095f994{0%{top:10px;left:420px;opacity:0}20%{top:40px;left:360px;opacity:1}70%{top:130px;left:180px;opacity:1}to{top:160px;left:120px;opacity:0}}@keyframes cloudMid-data-v-c095f994{0%{top:10px;left:420px;opacity:0}20%{top:40px;left:360px;opacity:1}70%{top:130px;left:180px;opacity:1}to{top:160px;left:120px;opacity:0}}@-webkit-keyframes cloudRight-data-v-c095f994{0%{top:100px;left:500px;opacity:0}20%{top:120px;left:460px;opacity:1}80%{top:180px;left:340px;opacity:1}to{top:200px;left:300px;opacity:0}}@keyframes cloudRight-data-v-c095f994{0%{top:100px;left:500px;opacity:0}20%{top:120px;left:460px;opacity:1}80%{top:180px;left:340px;opacity:1}to{top:200px;left:300px;opacity:0}}.wscn-http404 .bullshit[data-v-c095f994]{position:relative;float:left;width:300px;padding:30px 0;overflow:hidden}.wscn-http404 .bullshit__oops[data-v-c095f994]{font-size:32px;line-height:40px;color:#1482f0;margin-bottom:20px;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__headline[data-v-c095f994],.wscn-http404 .bullshit__oops[data-v-c095f994]{font-weight:700;opacity:0;-webkit-animation-name:slideUp-data-v-c095f994;animation-name:slideUp-data-v-c095f994;-webkit-animation-duration:.5s;animation-duration:.5s}.wscn-http404 .bullshit__headline[data-v-c095f994]{font-size:20px;line-height:24px;color:#222;margin-bottom:10px;-webkit-animation-delay:.1s;animation-delay:.1s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__info[data-v-c095f994]{font-size:13px;line-height:21px;color:grey;margin-bottom:30px;-webkit-animation-delay:.2s;animation-delay:.2s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__info[data-v-c095f994],.wscn-http404 .bullshit__return-home[data-v-c095f994]{opacity:0;-webkit-animation-name:slideUp-data-v-c095f994;animation-name:slideUp-data-v-c095f994;-webkit-animation-duration:.5s;animation-duration:.5s}.wscn-http404 .bullshit__return-home[data-v-c095f994]{display:block;float:left;width:110px;height:36px;background:#1482f0;border-radius:100px;text-align:center;color:#fff;font-size:14px;line-height:36px;cursor:pointer;-webkit-animation-delay:.3s;animation-delay:.3s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}@-webkit-keyframes slideUp-data-v-c095f994{0%{-webkit-transform:translateY(60px);transform:translateY(60px);opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@keyframes slideUp-data-v-c095f994{0%{-webkit-transform:translateY(60px);transform:translateY(60px);opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}

View File

@ -0,0 +1 @@
@supports(-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#fff;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;box-shadow:inset 0 0 0 1000px #283443!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container[data-v-5d9ae9a2]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-5d9ae9a2]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-5d9ae9a2]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-5d9ae9a2]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-5d9ae9a2]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-5d9ae9a2]{position:relative}.login-container .title-container .title[data-v-5d9ae9a2]{font-size:26px;color:#eee;margin:0 auto 40px auto;text-align:center;font-weight:700}.login-container .show-pwd[data-v-5d9ae9a2]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}

View File

@ -0,0 +1 @@
.dashboard-container[data-v-3e145b52]{margin:30px}.dashboard-text[data-v-3e145b52]{font-size:30px;line-height:46px}

View File

@ -0,0 +1 @@
.app-container[data-v-3ebe39a8]{padding:10px 5px 0 10px;background-color:#f4f4f5}.el-row[data-v-3ebe39a8]{&:last-child{margin-bottom:0}}.bg-purple[data-v-3ebe39a8]{background:#f4f4f5}.grid-content[data-v-3ebe39a8]{border-radius:4px;overflow-x:hidden;overflow-y:auto}.grid-content[data-v-3ebe39a8]::-webkit-scrollbar{width:4px}.grid-content[data-v-3ebe39a8]::-webkit-scrollbar-thumb{border-radius:10px;background:rgba(0,0,0,.2)}.grid-content[data-v-3ebe39a8]::-webkit-scrollbar-track{border-radius:0;background:rgba(0,0,0,.1)}.vehicleDiv[data-v-3ebe39a8]{height:50px;margin:0 0 10px 0}.contentMain[data-v-3ebe39a8]{margin-top:10px}.vehicleDataTab[data-v-3ebe39a8]{width:100%;overflow-y:auto;overflow-x:hidden}.vehicleDataTab[data-v-3ebe39a8]::-webkit-scrollbar{width:4px}.vehicleDataTab[data-v-3ebe39a8]::-webkit-scrollbar-thumb{border-radius:10px;background:rgba(0,0,0,.2)}.vehicleDataTab[data-v-3ebe39a8]::-webkit-scrollbar-track{border-radius:0;background:rgba(0,0,0,.1)}.el-form-item__label[data-v-3ebe39a8]{padding:0}.el-form-item[data-v-3ebe39a8]{margin-bottom:5px}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:inherit;font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}[hidden],template{display:none}#nprogress{pointer-events:none}#nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;-webkit-box-shadow:0 0 10px #29d,0 0 5px #29d;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;-webkit-transform:rotate(3deg) translateY(-4px);transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;-webkit-box-sizing:border-box;box-sizing:border-box;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;-webkit-animation:nprogress-spinner .4s linear infinite;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@-webkit-keyframes nprogress-spinner{0%{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(1turn)}}@keyframes nprogress-spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -0,0 +1 @@
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=/favicon.ico><title>车辆</title><link href=/static/css/app.949a0224.css rel=preload as=style><link href=/static/css/chunk-elementUI.c1c3b808.css rel=preload as=style><link href=/static/css/chunk-libs.3dfb7769.css rel=preload as=style><link href=/static/js/app.967d9126.js rel=preload as=script><link href=/static/js/chunk-elementUI.2491fb2f.js rel=preload as=script><link href=/static/js/chunk-libs.2ec7c235.js rel=preload as=script><link href=/static/css/chunk-elementUI.c1c3b808.css rel=stylesheet><link href=/static/css/chunk-libs.3dfb7769.css rel=stylesheet><link href=/static/css/app.949a0224.css rel=stylesheet></head><body><noscript><strong>We're sorry but 车辆 doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script>(function(e){function t(t){for(var n,o,c=t[0],i=t[1],l=t[2],f=0,d=[];f<c.length;f++)o=c[f],Object.prototype.hasOwnProperty.call(a,o)&&a[o]&&d.push(a[o][0]),a[o]=0;for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(e[n]=i[n]);s&&s(t);while(d.length)d.shift()();return u.push.apply(u,l||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,o=1;o<r.length;o++){var c=r[o];0!==a[c]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={runtime:0},a={runtime:0},u=[];function c(e){return i.p+"static/js/"+({}[e]||e)+"."+{"chunk-019c66da":"ded8571e","chunk-cefe5306":"756dde8f","chunk-22cea610":"a50359dd","chunk-510f32e7":"18a692c7","chunk-630a64ed":"8295bd3f"}[e]+".js"}function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.e=function(e){var t=[],r={"chunk-cefe5306":1,"chunk-22cea610":1,"chunk-510f32e7":1,"chunk-630a64ed":1};o[e]?t.push(o[e]):0!==o[e]&&r[e]&&t.push(o[e]=new Promise((function(t,r){for(var n="static/css/"+({}[e]||e)+"."+{"chunk-019c66da":"31d6cfe0","chunk-cefe5306":"0a41cd80","chunk-22cea610":"3c7f5ad9","chunk-510f32e7":"1510e3c5","chunk-630a64ed":"9a9361c6"}[e]+".css",a=i.p+n,u=document.getElementsByTagName("link"),c=0;c<u.length;c++){var l=u[c],f=l.getAttribute("data-href")||l.getAttribute("href");if("stylesheet"===l.rel&&(f===n||f===a))return t()}var d=document.getElementsByTagName("style");for(c=0;c<d.length;c++){l=d[c],f=l.getAttribute("data-href");if(f===n||f===a)return t()}var s=document.createElement("link");s.rel="stylesheet",s.type="text/css",s.onload=t,s.onerror=function(t){var n=t&&t.target&&t.target.src||a,u=new Error("Loading CSS chunk "+e+" failed.\n("+n+")");u.code="CSS_CHUNK_LOAD_FAILED",u.request=n,delete o[e],s.parentNode.removeChild(s),r(u)},s.href=a;var h=document.getElementsByTagName("head")[0];h.appendChild(s)})).then((function(){o[e]=0})));var n=a[e];if(0!==n)if(n)t.push(n[2]);else{var u=new Promise((function(t,r){n=a[e]=[t,r]}));t.push(n[2]=u);var l,f=document.createElement("script");f.charset="utf-8",f.timeout=120,i.nc&&f.setAttribute("nonce",i.nc),f.src=c(e);var d=new Error;l=function(t){f.onerror=f.onload=null,clearTimeout(s);var r=a[e];if(0!==r){if(r){var n=t&&("load"===t.type?"missing":t.type),o=t&&t.target&&t.target.src;d.message="Loading chunk "+e+" failed.\n("+n+": "+o+")",d.name="ChunkLoadError",d.type=n,d.request=o,r[1](d)}a[e]=void 0}};var s=setTimeout((function(){l({type:"timeout",target:f})}),12e4);f.onerror=f.onload=l,document.head.appendChild(f)}return Promise.all(t)},i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/",i.oe=function(e){throw console.error(e),e};var l=window["webpackJsonp"]=window["webpackJsonp"]||[],f=l.push.bind(l);l.push=t,l=l.slice();for(var d=0;d<l.length;d++)t(l[d]);var s=f;r()})([]);</script><script src=/static/js/chunk-elementUI.2491fb2f.js></script><script src=/static/js/chunk-libs.2ec7c235.js></script><script src=/static/js/app.967d9126.js></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-22cea610"],{"26fc":function(t,s,a){t.exports=a.p+"static/img/404_cloud.0f4bc32b.png"},"8cdb":function(t,s,a){"use strict";a.r(s);var e=function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("div",{staticClass:"wscn-http404-container"},[a("div",{staticClass:"wscn-http404"},[t._m(0),a("div",{staticClass:"bullshit"},[a("div",{staticClass:"bullshit__oops"},[t._v("OOPS!")]),t._m(1),a("div",{staticClass:"bullshit__headline"},[t._v(t._s(t.message))]),a("div",{staticClass:"bullshit__info"},[t._v("Please check that the URL you entered is correct, or click the button below to return to the homepage.")]),a("a",{staticClass:"bullshit__return-home",attrs:{href:""}},[t._v("Back to home")])])])])},c=[function(){var t=this,s=t.$createElement,e=t._self._c||s;return e("div",{staticClass:"pic-404"},[e("img",{staticClass:"pic-404__parent",attrs:{src:a("a36b"),alt:"404"}}),e("img",{staticClass:"pic-404__child left",attrs:{src:a("26fc"),alt:"404"}}),e("img",{staticClass:"pic-404__child mid",attrs:{src:a("26fc"),alt:"404"}}),e("img",{staticClass:"pic-404__child right",attrs:{src:a("26fc"),alt:"404"}})])},function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("div",{staticClass:"bullshit__info"},[t._v("All rights reserved "),a("a",{staticStyle:{color:"#20a0ff"},attrs:{href:"https://wallstreetcn.com",target:"_blank"}},[t._v("wallstreetcn")])])}],i={name:"Page404",computed:{message:function(){return"The webmaster said that you can not enter this page..."}}},l=i,n=(a("dd53"),a("2877")),r=Object(n["a"])(l,e,c,!1,null,"c095f994",null);s["default"]=r.exports},a36b:function(t,s,a){t.exports=a.p+"static/img/404.a57b6f31.png"},b0a8:function(t,s,a){},dd53:function(t,s,a){"use strict";a("b0a8")}}]);

View File

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-510f32e7"],{3985:function(e,t,n){},"92f2":function(e,t,n){},"9ed6":function(e,t,n){"use strict";n.r(t);var r=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"login-container"},[n("el-form",{ref:"loginForm",staticClass:"login-form",attrs:{model:e.loginForm,rules:e.loginRules,"auto-complete":"on","label-position":"left"}},[n("div",{staticClass:"title-container"},[n("h3",{staticClass:"title"},[e._v("车辆模拟")])]),n("el-form-item",{attrs:{prop:"username"}},[n("span",{staticClass:"svg-container"},[n("svg-icon",{attrs:{"icon-class":"user"}})],1),n("el-input",{ref:"username",attrs:{placeholder:"Username",name:"username",type:"text",tabindex:"1","auto-complete":"on",readonly:""},model:{value:e.loginForm.username,callback:function(t){e.$set(e.loginForm,"username",t)},expression:"loginForm.username"}})],1),n("el-form-item",{attrs:{prop:"password"}},[n("span",{staticClass:"svg-container"},[n("svg-icon",{attrs:{"icon-class":"password"}})],1),n("el-input",{ref:"password",attrs:{type:"text",placeholder:"Password",name:"password",tabindex:"2","auto-complete":"on"},nativeOn:{keyup:function(t){return!t.type.indexOf("key")&&e._k(t.keyCode,"enter",13,t.key,"Enter")?null:e.handleLogin(t)}},model:{value:e.loginForm.password,callback:function(t){e.$set(e.loginForm,"password",t)},expression:"loginForm.password"}})],1),n("el-button",{staticStyle:{width:"100%","margin-bottom":"30px"},attrs:{loading:e.loading,type:"primary"},nativeOn:{click:function(t){return t.preventDefault(),e.handleLogin(t)}}},[e._v("进入")])],1)],1)},o=[],s={name:"Login",data:function(){return{loginForm:{username:"你永远是最棒的",password:"加油,一切都是值得的"},loginRules:{username:[{required:!0,trigger:"blur"}],password:[{required:!0,trigger:"blur"}]},loading:!1,passwordType:"password",redirect:void 0}},watch:{$route:{handler:function(e){this.redirect=e.query&&e.query.redirect},immediate:!0}},methods:{handleLogin:function(){var e=this;this.$refs.loginForm.validate((function(t){if(!t)return console.log("error submit!!"),!1;e.loading=!0,e.$store.dispatch("user/login",e.loginForm).then((function(){e.$router.push({path:e.redirect||"/"}),e.loading=!1})).catch((function(){e.loading=!1})),e.$router.push({path:e.redirect||"/"})}))}}},a=s,i=(n("d1bd"),n("f8c5"),n("2877")),l=Object(i["a"])(a,r,o,!1,null,"5d9ae9a2",null);t["default"]=l.exports},d1bd:function(e,t,n){"use strict";n("92f2")},f8c5:function(e,t,n){"use strict";n("3985")}}]);

View File

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-630a64ed"],{"30fb":function(t,a,e){"use strict";e("7148")},7148:function(t,a,e){},9406:function(t,a,e){"use strict";e.r(a);var n=function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("div",{staticClass:"dashboard-container"},[e("div",{staticClass:"dashboard-text"},[t._v("name: "+t._s(t.name))])])},s=[],c=e("5530"),i=e("2f62"),o={name:"Dashboard",computed:Object(c["a"])({},Object(i["b"])(["name"]))},r=o,u=(e("30fb"),e("2877")),b=Object(u["a"])(r,n,s,!1,null,"3e145b52",null);a["default"]=b.exports}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

20
pom.xml 100644
View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.fei</groupId>
<artifactId>open-api</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>VehicleSimulation</module>
</modules>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View File

@ -0,0 +1,7 @@
package com.fei;
public class Main {
public static void main(String[] args) {
System.out.println ( "Hello world!" );
}
}