- 苏标是江苏省交通厅2018年发布的道路运输车辆主动安全智能防控系统的平台技术规范,是继部标1078流媒体后这两年最火热的规范,今年深圳展会几乎所有参展商都以主动安全报警作为亮点。
- 苏标的主动安全实现是通过终端视频算法分析,主动判断出司机驾驶行为是否违反驾驶行为规范,并触发报警,如前向碰撞报警、车道偏离报警、车距过近报警、疲劳驾驶报警、分神驾驶报警、接打电话报警、抽烟报警、驾驶员异常报警、胎压异常报警等。在发生报警的时候,可以上传违章证据到服务器平台,如视频,图片和记录仪数据等。
- 苏标的报警是通过扩展部标JT808协议0x0200位置上报的附加数据上报的,平台判断附件数量大于0,则下发苏标0x9208附件上传指令让终端把证据文件发到附件服务器。
-
附件上传的协议使用了2种:(1) 0x1210报警附件信息消息、0x1211文件信息上传、0x1212文件上传完成消息采用部标JT808协议。(2) 文件数据上传采用苏标自定义的格式。
- 因为部标上传的文件有3处:808多媒体文件、1078录像上传FTP、苏标附件,我们将这3块整合在一起,程序起名为file-server,既能处理FTP录像文件又能处理苏标附件,还提供了http文件访问接口给前端。JT808协议解析可以直接复用JT808网关程序的,已经兼容了JT808-2019国标协议。
public class Jt808Message extends BaseMessage {
/**
* 消息ID
*/
private int msgId;
/**
* 终端手机号
*/
private String phoneNumber;
/**
* 终端手机号数组
*/
private byte[] phoneNumberArr;
/**
* 协议版本号
*/
private int protocolVersion;
/**
* 消息流水号
*/
private int msgFlowId;
/**
* 是否分包
*/
private boolean multiPacket;
/**
* 版本标识
*/
private int versionFlag;
/**
* 加密方式,0:不加密,1:RSA加密
*/
private int encryptType;
/**
* 消息总包数
*/
private int packetTotalCount;
/**
* 包序号
*/
private int packetOrder;
}
- 我们在底层做了一个消息服务处理的provider,每条指令的处理服务在程序启动时自动注册到provider。当每条消息解析成vo传递到netty的handler时,会根据消息ID从provider找到对应的处理服务。市面上开源的或者卖的源码,基本上都用if/else去判断消息ID处理,造成处理类非常庞大,而且很难维护。
@Slf4j
@Sharable
public class Jt808BusinessHandler extends SimpleChannelInboundHandler<Jt808Message> {
private MessageServiceProvider messageServiceProvider;
public static final Jt808BusinessHandler INSTANCE = new Jt808BusinessHandler();
private Jt808BusinessHandler() {
messageServiceProvider = SpringBeanService.getBean(MessageServiceProvider.class);
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, Jt808Message msg) throws Exception {
//获取对应的消息处理器
int messageId = msg.getMsgId();
BaseMessageService messageService = messageServiceProvider.getMessageService(messageId);
ByteBuf msgBodyBuf = Unpooled.wrappedBuffer(msg.getMsgBodyArr());
try {
Object result = messageService.process(ctx, msg, msgBodyBuf);
log.info("收到{}({}),终端手机号:{},消息流水号:{},内容:{}", messageService.getDesc(), CommonUtil.formatMessageId(messageId), msg.getPhoneNumber(), msg.getMsgFlowId(), result);
} catch (Exception e) {
Jt808PacketUtil.reply8001(ctx, msg, Jt808ReplyResultEnum.MSG_ERROR);
printExceptionLog(msg, messageService, e);
} finally {
ReferenceCountUtil.release(msgBodyBuf);
}
}
}
-
文件路径入库的时候,我们把路径用base64编码保存,前端查询时根据base64的路径请求,后台把base64路径解码后直接获取到多媒体文件数据返回前端,这样就省去了查询数据库的步骤。
@Api(tags = {"文件管理"})
@RestController
@RequestMapping({"/api/v1/files/"})
public class FileController {
@Autowired
private ResourceLoader resourceLoader;
@ApiOperation("显示文件")
@GetMapping("/display")
public ResponseEntity<Resource> show(@ApiParam("路径") @RequestParam String path) {
try {
byte[] pathArr = Base64.getDecoder().decode(path);
String filePath = new String(pathArr, "UTF8");
log.info("显示文件,路径:{}", filePath);
return ResponseEntity.ok(resourceLoader.getResource("file:" + filePath));
} catch (Exception e) {
return ResponseEntity.notFound().build();
}
}
-
由于file-server做了跨域处理,所以前端直接调用接口没有问题,也可以使用nginx做反向代理,前端页面和接口都用同一个端口,前后端分离一般都用这种方案实现。