- 蘇標(biāo)是江蘇省交通廳2018年發(fā)布的道路運輸車輛主動安全智能防控系統(tǒng)的平臺技術(shù)規(guī)范,是繼部標(biāo)1078流媒體后這兩年最火熱的規(guī)范,今年深圳展會幾乎所有參展商都以主動安全報警作為亮點。
- 蘇標(biāo)的主動安全實現(xiàn)是通過終端視頻算法分析,主動判斷出司機(jī)駕駛行為是否違反駕駛行為規(guī)范,并觸發(fā)報警,如前向碰撞報警、車道偏離報警、車距過近報警、疲勞駕駛報警、分神駕駛報警、接打電話報警、抽煙報警、駕駛員異常報警、胎壓異常報警等。在發(fā)生報警的時候,可以上傳違章證據(jù)到服務(wù)器平臺,如視頻,圖片和記錄儀數(shù)據(jù)等。
- 蘇標(biāo)的報警是通過擴(kuò)展部標(biāo)JT808協(xié)議0x0200位置上報的附加數(shù)據(jù)上報的,平臺判斷附件數(shù)量大于0,則下發(fā)蘇標(biāo)0x9208附件上傳指令讓終端把證據(jù)文件發(fā)到附件服務(wù)器。
-
附件上傳的協(xié)議使用了2種:(1) 0x1210報警附件信息消息、0x1211文件信息上傳、0x1212文件上傳完成消息采用部標(biāo)JT808協(xié)議。(2) 文件數(shù)據(jù)上傳采用蘇標(biāo)自定義的格式。
image.png - 因為部標(biāo)上傳的文件有3處:808多媒體文件、1078錄像上傳FTP、蘇標(biāo)附件,我們將這3塊整合在一起,程序起名為file-server,既能處理FTP錄像文件又能處理蘇標(biāo)附件,還提供了http文件訪問接口給前端。JT808協(xié)議解析可以直接復(fù)用JT808網(wǎng)關(guān)程序的,已經(jīng)兼容了JT808-2019國標(biāo)協(xié)議。
public class Jt808Message extends BaseMessage {
/**
* 消息ID
*/
private int msgId;
/**
* 終端手機(jī)號
*/
private String phoneNumber;
/**
* 終端手機(jī)號數(shù)組
*/
private byte[] phoneNumberArr;
/**
* 協(xié)議版本號
*/
private int protocolVersion;
/**
* 消息流水號
*/
private int msgFlowId;
/**
* 是否分包
*/
private boolean multiPacket;
/**
* 版本標(biāo)識
*/
private int versionFlag;
/**
* 加密方式,0:不加密,1:RSA加密
*/
private int encryptType;
/**
* 消息總包數(shù)
*/
private int packetTotalCount;
/**
* 包序號
*/
private int packetOrder;
}
- 我們在底層做了一個消息服務(wù)處理的provider,每條指令的處理服務(wù)在程序啟動時自動注冊到provider。當(dāng)每條消息解析成vo傳遞到netty的handler時,會根據(jù)消息ID從provider找到對應(yīng)的處理服務(wù)。市面上開源的或者賣的源碼,基本上都用if/else去判斷消息ID處理,造成處理類非常龐大,而且很難維護(hù)。
@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 {
//獲取對應(yīng)的消息處理器
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("收到{}({}),終端手機(jī)號:{},消息流水號:{},內(nèi)容:{}", 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);
}
}
}

image.png
-
文件路徑入庫的時候,我們把路徑用base64編碼保存,前端查詢時根據(jù)base64的路徑請求,后臺把base64路徑解碼后直接獲取到多媒體文件數(shù)據(jù)返回前端,這樣就省去了查詢數(shù)據(jù)庫的步驟。
image.png
@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做了跨域處理,所以前端直接調(diào)用接口沒有問題,也可以使用nginx做反向代理,前端頁面和接口都用同一個端口,前后端分離一般都用這種方案實現(xiàn)。
image.png
image.png



