master
ljw 2025-11-08 13:37:21 +08:00
commit 25190d46bd
9 changed files with 199 additions and 11 deletions

View File

@ -151,6 +151,8 @@ public final class JT808 {
public static JT808Message parseMessage(ByteBuf buf) { public static JT808Message parseMessage(ByteBuf buf) {
JT808Message jt808Message = new JT808Message(); JT808Message jt808Message = new JT808Message();
byte[] h_b = ByteBufUtil.getBytes(buf);
try { try {
// 1. 消息ID (2字节) // 1. 消息ID (2字节)
jt808Message.setMessageId(buf.readUnsignedShort()); jt808Message.setMessageId(buf.readUnsignedShort());
@ -184,14 +186,22 @@ public final class JT808 {
jt808Message.setMessageBody(array); jt808Message.setMessageBody(array);
// 7. 校验码 (1字节) // 7. 校验码 (1字节)
jt808Message.setCheckCode(buf.readByte()); byte checkCode = buf.readByte();
jt808Message.setCheckCode(checkCode);
// 验证校验码
if (!verifyCheckCode(jt808Message, buf)) { if (jt808Message.getMessageId() == 0x704) {
log.error("校验码错误: {}", jt808Message); log.info("报文:{}", h_b);
return null;
} }
int code = 0;
for (int i = 0; i < h_b.length - 1; i++) {
code = code ^ h_b[i];
}
if (code != checkCode) {
log.error("校验码错误: {} {}", code, checkCode);
// return null;
}
return jt808Message; return jt808Message;
} }
} catch (Exception e) { } catch (Exception e) {

View File

@ -7,6 +7,9 @@ import lombok.Setter;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
/** /**
* JT808 * JT808
* JT808 * JT808
@ -31,6 +34,7 @@ public class JT808Message {
private byte[] messageBody; private byte[] messageBody;
// 校验码 (1字节) // 校验码 (1字节)
private byte checkCode; private byte checkCode;
public JT808Message() { public JT808Message() {
} }
@ -39,6 +43,17 @@ public class JT808Message {
return messageBodyProps & 0x3FF; return messageBodyProps & 0x3FF;
} }
public List<Integer> getBodyBytes() {
if (messageBody == null || messageBody.length == 0) {
return null;
}
ArrayList<Integer> integers = new ArrayList<>(messageBody.length);
for (byte b : messageBody) {
integers.add((int) b);
}
return integers;
}
// 从消息体属性中获取是否分包 // 从消息体属性中获取是否分包
public boolean isPackaged() { public boolean isPackaged() {
return (messageBodyProps & 0x4000) != 0; return (messageBodyProps & 0x4000) != 0;

View File

@ -31,6 +31,10 @@ public class JT808MessageCenter {
Map<MessageType, Consumer<TerminalMessageBody>> m = listeners.computeIfPresent(localizerType, (k, v) -> { Map<MessageType, Consumer<TerminalMessageBody>> m = listeners.computeIfPresent(localizerType, (k, v) -> {
MessageType messageType = MessageType.getMessageType(messageId); MessageType messageType = MessageType.getMessageType(messageId);
if (messageType == MessageType.TerminalLocationBatchReport) {
log.info("批量上报:{}", message);
}
if (messageType == null) { if (messageType == null) {
log.error("未找到消息类型,设备号:{},消息 Id0x{}", terminalId, Integer.toHexString(messageId)); log.error("未找到消息类型,设备号:{},消息 Id0x{}", terminalId, Integer.toHexString(messageId));
return v; return v;

View File

@ -134,6 +134,9 @@ public abstract class JT808MessageListener {
int speedThreshold = localizer.getSpeedThreshold(); int speedThreshold = localizer.getSpeedThreshold();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
int length = byteBuf.readUnsignedShort(); int length = byteBuf.readUnsignedShort();
/* if (length > 28) { // 有扩展信息
} */
LocationReportMessage locationReportMsg = new LocationReportMessage(byteBuf.slice(byteBuf.readerIndex(), length)); LocationReportMessage locationReportMsg = new LocationReportMessage(byteBuf.slice(byteBuf.readerIndex(), length));
byteBuf.skipBytes(length); byteBuf.skipBytes(length);
double speed = locationReportMsg.getSpeed(); double speed = locationReportMsg.getSpeed();
@ -144,6 +147,8 @@ public abstract class JT808MessageListener {
Mqtt.publish(terminalId + "/track_location", realtimeLocationResult); Mqtt.publish(terminalId + "/track_location", realtimeLocationResult);
Mqtt.publish(terminalId + "/track_location_real", realtimeLocationResult); Mqtt.publish(terminalId + "/track_location_real", realtimeLocationResult);
} }
} catch (Exception e) {
log.error("批量上报处理失败:{} {}", terminalId, message.getFlowId());
} finally { } finally {
byteBuf.release(); byteBuf.release();
} }

View File

@ -41,6 +41,10 @@ public class Hsoa {
param.setCityCode(defaultPlace.getCity()) param.setCityCode(defaultPlace.getCity())
.setCityName(defaultPlace.getCityName()) .setCityName(defaultPlace.getCityName())
; ;
if (StrUtil.isBlank(tnt) || StrUtil.isBlank(refTnt)) {
return new HsoaResult<>()
.setSuccess(false);
}
return API.pushVehicleTrajectory(param, new TokenParam().setTnt(tnt).setRefTnt(refTnt)); return API.pushVehicleTrajectory(param, new TokenParam().setTnt(tnt).setRefTnt(refTnt));
} finally { } finally {
rlock.unlock(); rlock.unlock();
@ -64,6 +68,7 @@ public class Hsoa {
} else { } else {
refTnt = ""; refTnt = "";
tnt = ""; tnt = "";
log.error("政务平台登录失败");
} }
} else if (now - lastLoginTime > hsoaProperties.getExpire() - 60) { } else if (now - lastLoginTime > hsoaProperties.getExpire() - 60) {
HsoaResult<LoginResult> loginResult = API.refreshToken(new RefreshTokenParam().setRefTnt(refTnt)); HsoaResult<LoginResult> loginResult = API.refreshToken(new RefreshTokenParam().setRefTnt(refTnt));
@ -75,6 +80,7 @@ public class Hsoa {
} else { } else {
refTnt = ""; refTnt = "";
tnt = ""; tnt = "";
log.error("政务平台登录失败");
} }
} }
} catch (Exception e) { } catch (Exception e) {

View File

@ -4,17 +4,17 @@ import com.njzscloud.common.core.utils.R;
import com.njzscloud.supervisory.hsoa.Hsoa; import com.njzscloud.supervisory.hsoa.Hsoa;
import com.njzscloud.supervisory.hsoa.pojo.param.PushVehicleTrajectoryParam; import com.njzscloud.supervisory.hsoa.pojo.param.PushVehicleTrajectoryParam;
import com.njzscloud.supervisory.hsoa.pojo.result.HsoaResult; import com.njzscloud.supervisory.hsoa.pojo.result.HsoaResult;
import com.njzscloud.supervisory.hsoa.service.HsoaService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@RequiredArgsConstructor @RequiredArgsConstructor
@RequestMapping("/hsoa") @RequestMapping("/hsoa")
public class HsoaController { public class HsoaController {
private final HsoaService hsoaService;
@PostMapping("/push") @PostMapping("/push")
public R<?> push(@RequestBody PushVehicleTrajectoryParam pushVehicleTrajectoryParam) { public R<?> push(@RequestBody PushVehicleTrajectoryParam pushVehicleTrajectoryParam) {
HsoaResult<?> objectHsoaResult = Hsoa.pushVehicleTrajectory(pushVehicleTrajectoryParam); HsoaResult<?> objectHsoaResult = Hsoa.pushVehicleTrajectory(pushVehicleTrajectoryParam);
@ -23,4 +23,9 @@ public class HsoaController {
} }
return R.failed(); return R.failed();
} }
@GetMapping("/push_order")
public R<?> pushOrder(@RequestParam Long orderId, @RequestParam Integer count) {
return R.success(hsoaService.pushOrder(orderId, count));
}
} }

View File

@ -0,0 +1,141 @@
package com.njzscloud.supervisory.hsoa.service;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.thread.ThreadUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.njzscloud.common.core.ex.Exceptions;
import com.njzscloud.supervisory.biz.pojo.entity.TruckLocationTrackEntity;
import com.njzscloud.supervisory.biz.service.TruckLocationTrackService;
import com.njzscloud.supervisory.hsoa.Hsoa;
import com.njzscloud.supervisory.hsoa.pojo.param.PushVehicleTrajectoryParam;
import com.njzscloud.supervisory.hsoa.pojo.result.HsoaResult;
import com.njzscloud.supervisory.order.pojo.result.OrderPagingResult;
import com.njzscloud.supervisory.order.service.OrderInfoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@Slf4j
@Service
@RequiredArgsConstructor
public class HsoaService {
private final OrderInfoService orderInfoService;
private final TruckLocationTrackService truckLocationTrackService;
private final AtomicBoolean run = new AtomicBoolean(false);
private final AtomicInteger succ = new AtomicInteger(0);
private final AtomicInteger fail = new AtomicInteger(0);
private final AtomicInteger total = new AtomicInteger(0);
private final AtomicLong order = new AtomicLong(0);
public synchronized Map<String, Object> pushOrder(Long orderId, Integer count) {
MapBuilder<String, Object> builder = MapUtil.<String, Object>builder();
if (run.get()) {
int i1 = total.get();
int i2 = succ.get();
int i3 = fail.get();
long v = order.get();
return builder
.put("订单", v)
.put("任务数量", i1)
.put("成功数量", i2)
.put("失败数量", i3)
.put("剩余数量", i1 - i2 - i3)
.build();
}
OrderPagingResult orderDetail = orderInfoService.detail(orderId);
Assert.notNull(orderDetail, () -> Exceptions.clierr("订单不存在"));
String licensePlate = orderDetail.getLicensePlate();
String transCompanyName = orderDetail.getTransCompanyName();
List<TruckLocationTrackEntity> list = truckLocationTrackService.list(Wrappers.<TruckLocationTrackEntity>lambdaQuery().eq(TruckLocationTrackEntity::getOrderId, orderId));
if (list.isEmpty()) {
return builder
.put("订单", orderId)
.put("任务数量", 0)
.build();
}
if (count == null || count == 0) {
count = list.size();
} else {
count = Math.min(count, list.size());
}
run.set(true);
order.set(orderId);
total.set(count);
succ.set(0);
fail.set(0);
int c = count;
Thread thread = new Thread(() -> {
for (int i = 0; i < c; i++) {
ThreadUtil.sleep(1000);
TruckLocationTrackEntity locationTrack = list.get(i);
boolean b = run.get();
if (!b) {
return;
}
try {
Double longitude = locationTrack.getLongitude();
Double latitude = locationTrack.getLatitude();
Double speed = locationTrack.getSpeed();
Integer direction = locationTrack.getDirection();
LocalDateTime locationTime = locationTrack.getLocationTime();
String time = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(locationTime);
HsoaResult<?> result = Hsoa.pushVehicleTrajectory(new PushVehicleTrajectoryParam()
.setCompanyName(transCompanyName)
.setTransportLicense(orderDetail.getCertificateSn())
.setPlateNumber(licensePlate)
.setVehicleType(orderDetail.getTruckCategory())
.setLongitude(longitude + "")
.setLatitude(latitude + "")
.setSpeed(speed)
.setDirection(direction + 0.0)
.setStateType("正常行驶")
.setAlarmType("无")
.setLoadStatus("2")
.setSealedStatus("1")
.setLiftStatus("0")
.setAccStatus(1)
.setGpsTime(time)
.setLocationMode("WGS84")
);
if (result == null || !result.isSuccess()) {
fail.incrementAndGet();
log.error("推送定位数据失败数据Id{}", locationTrack.getId());
} else {
succ.incrementAndGet();
}
} catch (Exception e) {
fail.incrementAndGet();
log.error("推送定位数据失败数据Id{}", locationTrack.getId(), e);
}
}
run.set(false);
});
thread.setDaemon(true);
thread.start();
int i1 = total.get();
int i2 = succ.get();
int i3 = fail.get();
return builder
.put("订单", orderId)
.put("任务数量", i1)
.put("成功数量", i2)
.put("失败数量", i3)
.put("剩余数量", i1 - i2 - i3)
.build();
}
}

View File

@ -29,6 +29,7 @@ spring:
- /biz_audit_config/copy - /biz_audit_config/copy
- /order_info/gps_test - /order_info/gps_test
- /wechatTemplateMessage/bind - /wechatTemplateMessage/bind
- /hsoa/push_order
app: app:
default-place: default-place:
province: 320000 province: 320000
@ -93,4 +94,4 @@ mqtt:
hsoa: hsoa:
base-url: http://60.173.195.121:9908 base-url: http://60.173.195.121:9908
username: chuz_trajectory username: chuz_trajectory
password: e9t2YsgM5ug/kpIZpMdY9e9uXq60jyEQ30zQX+BzphI= password: e9t2YsgM5ug%2FkpIZpMdY9e9uXq60jyEQ30zQX%2BBzphI%3D

View File

@ -27,6 +27,7 @@ spring:
- /district/areaList - /district/areaList
- /biz_audit_config/copy - /biz_audit_config/copy
- /wechatTemplateMessage/bind - /wechatTemplateMessage/bind
- /hsoa/push_order
app: app:
in-out-gap: 180 in-out-gap: 180
@ -83,4 +84,4 @@ localizer:
hsoa: hsoa:
base-url: http://117.68.7.91:8088 base-url: http://117.68.7.91:8088
username: chuz_trajectory username: chuz_trajectory
password: e9t2YsgM5ug/kpIZpMdY9e9uXq60jyEQ30zQX+BzphI= password: e9t2YsgM5ug%2FkpIZpMdY9e9uXq60jyEQ30zQX%2BBzphI%3D