初始化

master
ZhiShuo_Lou 2023-11-29 15:37:13 +08:00
parent 93a6f80e9f
commit e1ac6283d9
9 changed files with 569 additions and 0 deletions

View File

@ -44,6 +44,25 @@
<artifactId>god-common-swagger</artifactId>
</dependency>
<!-- Car base remote-->
<dependency>
<groupId>com.god</groupId>
<artifactId>car-base-remote</artifactId>
<version>3.6.3</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,100 @@
package com.god.business.common.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.god.base.common.domain.Fence;
import com.god.business.common.domain.request.ReqAddBreakDown;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
*
*
* @author LouZhiSHuo
* @Date 2023/11/29 14:40
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BreakDown {
/**
*
*/
private Integer id;
/**
* VIN
*/
@NotEmpty(message = "车辆VIN不能为空")
private String carVin;
/**
* Id
*/
@NotNull(message = "故障主建不能为空")
private Integer breakdownId;
/**
*
*/
private Integer status;
/**
*
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH-mm-ss")
@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss",timezone = "GMT+8")
private Date createTime;
/**
*
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH-mm-ss")
@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss",timezone = "GMT+8")
private Date endTime;
/**
*
*/
private String createBy;
/**
*
*/
private String updateBy;
/**
*
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH-mm-ss")
@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss",timezone = "GMT+8")
private Date updateTime;
public static BreakDown insertBreakDown(ReqAddBreakDown reqAddBreakDown){
return BreakDown.builder()
.carVin(reqAddBreakDown.getCarVin())
.breakdownId(reqAddBreakDown.getBreakdownId())
.status(reqAddBreakDown.getStatus())
.createTime(reqAddBreakDown.getCreateTime())
.endTime(reqAddBreakDown.getEndTime())
.createBy(reqAddBreakDown.getCreateBy())
.updateBy(reqAddBreakDown.getUpdateBy())
.updateTime(reqAddBreakDown.getUpdateTime())
.build();
}
}

View File

@ -0,0 +1,81 @@
package com.god.business.common.domain.request;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
*
*
* @author LouZhiSHuo
* @Date 2023/11/29 14:48
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ReqAddBreakDown {
/**
* VIN
*/
private String carVin;
/**
* Id
*/
private Integer breakdownId;
/**
*
*/
private Integer status;
/**
*
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH-mm-ss")
@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss",timezone = "GMT+8")
private Date createTime;
/**
*
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH-mm-ss")
@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss",timezone = "GMT+8")
private Date endTime;
/**
*
*/
private String createBy;
/**
*
*/
private String updateBy;
/**
*
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH-mm-ss")
@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss",timezone = "GMT+8")
private Date updateTime;
}

View File

@ -0,0 +1,16 @@
package com.god.base.server.consumer;
import com.god.common.redis.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
/**
*
*
* @author LouZhiSHuo
* @Date 2023/11/27 13:36
**/
public class KafkaSub {
}

View File

@ -0,0 +1,64 @@
package com.god.base.server.controller;
import com.god.base.remote.RemoteCarService;
import com.god.base.server.service.AlarmService;
import com.god.business.common.domain.BreakDown;
import com.god.business.common.domain.request.ReqAddBreakDown;
import com.god.common.core.domain.Result;
import com.god.common.log.annotation.Log;
import com.god.common.log.enums.BusinessType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
/**
*
*
* @author LouZhiSHuo
* @Date 2023/11/27 10:50
**/
@Controller
public class AlarmController {
@Autowired
private AlarmService alarmService;
/**
*
* @param carVinId
* @return
*/
@GetMapping("/startAlarm")
@Log(title = "围栏报警业务")
public Result<Boolean> rangeWarning(@RequestParam("carVinId") String carVinId) {
//围栏报警业务实现
alarmService.startAlarm(carVinId);
return Result.success();
}
/**
*
* @param reqAddBreakDown
* @return
*/
@PostMapping("/insertBreakDownLogs")
@Log(title = "添加车辆预警记录",businessType = BusinessType.INSERT)
public Result<String> insertBreakDownLogs(@RequestBody ReqAddBreakDown reqAddBreakDown) {
//添加车辆预警记录
alarmService.save(BreakDown.insertBreakDown(reqAddBreakDown));
return Result.success();
}
}

View File

@ -0,0 +1,14 @@
package com.god.base.server.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.god.business.common.domain.BreakDown;
/**
* mapper
*
* @author LouZhiSHuo
* @Date 2023/11/29 15:02
**/
public interface AlarmMapper extends BaseMapper<BreakDown> {
}

View File

@ -0,0 +1,17 @@
package com.god.base.server.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.god.business.common.domain.BreakDown;
/**
* @author LouZhiSHuo
* @Date 2023/11/27 20:40
**/
public interface AlarmService extends IService<BreakDown>{
/**
*
* @param carVinId
*/
void startAlarm(String carVinId);
}

View File

@ -0,0 +1,134 @@
package com.god.base.server.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.god.base.common.domain.Fence;
import com.god.base.remote.RemoteCarService;
import com.god.base.server.common.domain.Car;
import com.god.base.server.mapper.AlarmMapper;
import com.god.base.server.service.AlarmService;
import com.god.base.server.util.FenceAlgorithm;
import com.god.business.common.domain.BreakDown;
import com.god.common.core.domain.Result;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.awt.geom.Point2D;
import java.util.*;
/**
* @author LouZhiSHuo
* @Date 2023/11/27 20:40
**/
@Service
@Log4j2
public class AlarmServiceImpl extends ServiceImpl<AlarmMapper, BreakDown> implements AlarmService {
@Resource
private RemoteCarService remoteCarService;
@Resource
private FenceAlgorithm fenceAlgorithm;
/**
*
* @param carVinId
*/
@Override
public void startAlarm(String carVinId) {
//调用 根据车辆VIN查询车辆信息 carController/list
Result<Car> carResult = remoteCarService.list(carVinId);
//车辆信息
Car car = carResult.getData();
//根据车辆信息查询该车辆绑定的围栏Id
long fenceId = car.getFenceId();
//获取到围栏Id,根据围栏Id查询围栏 信息 FenceController/fenceById
//Redis中的围栏坐标信息格式: " 经度,维度; "
Result<Fence> fenceResult = remoteCarService.fenceById((int) fenceId);
//围栏信息
Fence fence = fenceResult.getData();
//获取该围栏行驶状态
Integer driveStatus = fence.getDriveStatus();// 1-驶入 2-驶出
//获取围栏坐标串
String fenceLocation = fence.getFenceLocation(); //116.357183,39.926512; 116.394348,39.909989; 116.34757,39.90617;
String[] split = fenceLocation.split(";");
List<Point2D.Double> polygon = new ArrayList<>();
for (int i = 0; i < split.length; i++) {
String[] splits = split[i].split(",");
Point2D.Double aDouble = new Point2D.Double();
for (int j = 0; j < splits.length; j++) {
if (j == 0){
aDouble.x = Double.parseDouble(splits[j]);
} else {
aDouble.y = Double.parseDouble(splits[j]);
}
}
polygon.add(aDouble);
}
//消费消息的消息
//算法计算
//假设当前经纬度
Point2D.Double car_one = new Point2D.Double(39.9125, 116.3917);
boolean ptInPoly = fenceAlgorithm.computeFence(car_one, polygon);
if (driveStatus == 1){
//驶入
//围栏区域外 -正常 进入后报警
if (ptInPoly) {
//报警
//存储消息到redis
} else {
log.info("当前车辆:{},正常行驶中~~~~~~",carVinId);
}
} else {
//驶出
//围栏区域内 -正常 驶出报警
if (!ptInPoly) {
//报警
} else {
log.info("当前车辆:{},正常行驶中~~~~~~",carVinId);
}
}
//判断围栏状态
//1-驶入
//判断坐标是否在范围 外围:不做操作 , 坐标进入围栏内: 发送消息给围栏内的用户(使用RabbitMq)
//2-驶出
//判断坐标是否在范围 外围:发送消息给围栏内的用户(使用RabbitMq) , 坐标在围栏内:不做操作
}
/**
*
* @param entity
* @return
*/
@Override
public boolean save(BreakDown entity) {
entity.setCreateTime(new Date());
boolean save = super.save(entity);
if (!save) {
throw new RuntimeException("故障记录添加失败");
}
return true;
}
}

View File

@ -0,0 +1,124 @@
package com.god.base.server.util;
import org.springframework.stereotype.Component;
import java.awt.geom.Point2D;
import java.util.List;
/**
*
*
* @author LouZhiSHuo
* @Date 2023/11/28 19:12
**/
@Component
public class FenceAlgorithm {
/**
*
* @param point
* @param pts
* @return
*/
public boolean computeFence(Point2D.Double point, List<Point2D.Double> pts){
//围栏顶点坐标数
int fenceSize = pts.size();
//如果点位在多边形的顶点或边上,也算在多边形内部,返回true
boolean boundDrVertex = true;
//射线与多边形相交次数
int intersectCount = 0;
///浮点型计时候的容差
double precision = 2e-10;
//相邻两点位置
Point2D.Double fenceOne,fenceTwo;
//确认当前点
Point2D.Double p = point;
//起点
fenceOne = pts.get(0);
for (int i =0;i<fenceSize;i++) {
//判断当前点是否在围栏范围边界
if (p.equals(fenceOne)) {
//返回 true
return boundDrVertex;
}
//终点
fenceTwo = pts.get(i % fenceSize);
//判断是否无交汇集
if (p.x < Math.min(fenceOne.x,fenceTwo.x) || p.x > Math.max(fenceOne.x,fenceTwo.x)) {
//无交点
fenceOne = fenceTwo;
//继续判断
continue;
}
if (p.x > Math.min(fenceOne.x,fenceTwo.x) && p.x < Math.max(fenceOne.x,fenceTwo.x)) {
//当前点在线段于X轴上的投影内
if (p.y <= Math.max(fenceOne.y,fenceTwo.y)) {
//当前点的y坐标小于线段对y轴投影的最大值
if (fenceOne.x == fenceTwo.x && p.y >= Math.min(fenceOne.y,fenceTwo.y)) {
//当前点垂直在x轴边上
return boundDrVertex;
}
if (fenceOne.y == fenceTwo.y) {
//平行于X轴
if (fenceOne.y == p.y) {
//位于当前围栏的边上
return boundDrVertex;
} else {
//反之相交次数+1
++intersectCount;
}
} else {
//非水平情况
double v = (p.x - fenceOne.x) * (fenceTwo.y - fenceOne.y) / (fenceTwo.x - fenceOne.x) + fenceOne.y;
//围栏某条边上
if (Math.abs(p.y - v) < precision) {
return boundDrVertex;
}
if (p.y < v) {
//相交次数+1
++intersectCount;
}
}
}
} else {
//当前带你不在线段投影到x轴的区间中
if (p.x == fenceTwo.x && p.y <= fenceTwo.y) {
//位于x坐标对应的平行于y轴上的线上的低于终点y的坐标
Point2D.Double temp = pts.get((i + 1) % fenceSize);
if (p.x >= Math.min(fenceOne.x , temp.x) && p.x <= Math.max(fenceOne.x,temp.x)) {
//若当前点的x坐标位于fenceOne 和 temp 组成的线段关于x轴的投影中
//则记为该点的射线只穿过端点一次
//那么相交+1
++intersectCount;
} else {
//若当前坐标的x不包含 fenceOne 和 temp 组成的线段关于x轴的投影中 , 则点射线通过的两条线段组成了一个弯折的部分,
//那么记为该点的射线穿过了端点两次
intersectCount += 2;
}
}
}
fenceOne = fenceTwo;
}
if (intersectCount % 2 == 0) {
//偶数在围栏外面
return false;
} else {
//奇数在围栏内
return true;
}
}
}