JAVA Netty开发苏标主动安全附件服务器

  • 苏标是江苏省交通厅2018年发布的道路运输车辆主动安全智能防控系统的平台技术规范,是继部标1078流媒体后这两年最火热的规范,今年深圳展会几乎所有参展商都以主动安全报警作为亮点。
  • 苏标的主动安全实现是通过终端视频算法分析,主动判断出司机驾驶行为是否违反驾驶行为规范,并触发报警,如前向碰撞报警、车道偏离报警、车距过近报警、疲劳驾驶报警、分神驾驶报警、接打电话报警、抽烟报警、驾驶员异常报警、胎压异常报警等。在发生报警的时候,可以上传违章证据到服务器平台,如视频,图片和记录仪数据等。
  • 苏标的报警是通过扩展部标JT808协议0x0200位置上报的附加数据上报的,平台判断附件数量大于0,则下发苏标0x9208附件上传指令让终端把证据文件发到附件服务器。
  • 附件上传的协议使用了2种:(1) 0x1210报警附件信息消息、0x1211文件信息上传、0x1212文件上传完成消息采用部标JT808协议。(2) 文件数据上传采用苏标自定义的格式。
    image.png
  • 因为部标上传的文件有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);
        }
    }
}

image.png

  • 文件路径入库的时候,我们把路径用base64编码保存,前端查询时根据base64的路径请求,后台把base64路径解码后直接获取到多媒体文件数据返回前端,这样就省去了查询数据库的步骤。
    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做了跨域处理,所以前端直接调用接口没有问题,也可以使用nginx做反向代理,前端页面和接口都用同一个端口,前后端分离一般都用这种方案实现。
    image.png
    image.png

官方网站:http://www.gps-pro.cn
开源地址:https://github.com/gnss-pro
微信:17158638841 或扫描下图
image.png

猜你喜欢

转载自blog.csdn.net/gps_pro/article/details/91893919