UDP协议进行远程开门

介绍:

  1. 本次Java后端和硬件进行交互,采用的是UDP协议,JSON传输,POST请求,springboot,mysql(用的是alibaba.fastjson的包)
  2. 主要流程是: 由于当前设备含有心跳包,所以先去配置好接收心跳的接口,配置好之后再让云端调用JAVA后台的接口获取存入云端数据库的数据,使用网络请求工具类HttpClientUtil.doPost() 填入本地另一套程序的路径和将拿到的数据封装成JSON进行请求, 另一套程序需要写一个方法,配置好路径,之后需要创建UDP客户端Socket,接收需要向设备传输的数据,配置好设备硬件的IP地址和端口号,默认写死门禁硬件的端口号,防止空指针,设备发生心跳后,更新端口数组,并将解析后的UTF-8(心跳)信息传送给云端接收。

No nonsense

云端代码(只含逻辑层)

参考如下:

  public R<Map<String,Integer>> unlockDoors(JSONObject jsonObject)  {
        if(null == jsonObject.getString("deviceId")){
            return R.fail("门禁设备表ID不能为空");
        }
        if(null == jsonObject.getString("xqId")){
            return R.fail("小区ID不能为空");
        }
        if(null == jsonObject.getString("ubicellJyh")){
            return R.fail("系统家园号不能为空");
        }
        //门禁设备表
        AcDevlist dev = acDevlistDao.selectById(jsonObject.getString("deviceId"));
        if(null == dev){
            return R.fail("系统未找到对应用户");
        }
        TUserbase base = tUserbaseDao.getUserByJyh(Long.parseLong(jsonObject.getString("xqId")),jsonObject.getString("ubicellJyh"));
        if(null == base){
            return R.fail("系统未找到对应用户");
        }
        XqInfo info = xqInfoDao.selectById(Long.parseLong(jsonObject.getString("xqId")));
        if(null == info){
            return R.fail("系统没找到小区信息");
        }
        AcHouse house =acHouseDao.selectById(dev.getHouseId());
        if(null == house){
            return R.fail("系统没找到设备对应的房间");
        }
// 发送的数据 
        JSONObject json = new JSONObject();
        json.put("communityId", info.getCommunityCode());
        json.put("deviceCode", dev.getDevSn());
        json.put("cmd","unlock");
        json.put("phone",base.getPhone());
        json.put("roomNumber",house.getHouseNum());
        json.put("unitId","0011");
        json.put("id",info.getId());
        String strJson = json.toString();
        System.err.println("strJson---------------:"+strJson);
        AcDoorOperLog acDoorOperLog = new AcDoorOperLog();
        acDoorOperLog.setXqId(Long.valueOf(jsonObject.getString("xqId")));//小区ID
        acDoorOperLog.setDoorId(dev.getId());//设备ID
        acDoorOperLog.setOperResult(0);//开门状态,0失败,1成功
        acDoorOperLog.setDevName(dev.getName());//设备名称
        acDoorOperLog.setUsername(base.getUbicellJyh());//系统家园号
        acDoorOperLog.setNickname(base.getNickname());//用户昵称
        acDoorOperLog.setPhone(base.getPhone());//用户手机号
        SimpleDateFormat   sdf =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            acDoorOperLog.setGmtCreate( sdf.parse(sdf.format(new Date())));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        //新增一条开门日志
        acDoorOperLogDao.insert(acDoorOperLog);
        insertId = acDoorOperLog.getId();
        try { HttpClientUtil.doPost("本地另一套程序的路径接口地址",strJson);
            //休眠3秒
            Thread.sleep(3000);
            if (udpControl.getReceiveControlParameters() != null){
                Map<String, Integer> map = new HashMap<>();
                if (udpControl.getReceiveControlParameters().equals("0")){
                    //修改开门日志->改为开门状态(1)
                    AcDoorOperLog acDoorOperLog2 = new AcDoorOperLog();
                    acDoorOperLog2.setId(insertId);
                    acDoorOperLog2.setOperResult(1);
                    acDoorOperLogDao.updateById(acDoorOperLog2);
                    map.put("开门成功",0);
                    return R.success(map);
                }
                if (udpControl.getReceiveControlParameters().equals("1") ||   udpControl.getReceiveControlParameters().equals("2")){
                    map.put("开门失败",1);
                    return R.success(map);
                }
            }else{
                System.err.println("检查对象参数");
                return R.fail("返回的参数为null");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.success(new HashMap<>());
    }

另一套程序的逻辑层

参考如下:

    private  void  AccessControlUDP(@RequestBody JSONObject jsonObject) {
        try {
            // 创建UDP客户端Socket
            DatagramSocket socket = new DatagramSocket();
            // 发送数据
            JSONObject data = new JSONObject();
            data.put("communityId",jsonObject.getString("communityId"));
            data.put("deviceCode", jsonObject.getString("deviceCode"));
            data.put("cmd", jsonObject.getString("cmd"));
            data.put("phone", jsonObject.getString("phone"));
            data.put("roomNumber", jsonObject.getString("roomNumber"));
            data.put("unitId", jsonObject.getString("unitId"));
            data.put("id", jsonObject.getString("id"));
            String message = data.toString();
            System.err.println("message:"+message);
            // 设备硬件的IP地址和端口号
            InetAddress address = InetAddress.getByName("设备IP");
              Map<String,Integer> udpPortMap = RLFUDPServer.udpPortMap.getMaps();
            if (udpPortMap == null || udpPortMap.isEmpty()) {
               int ports = "随便写死个端口";// 门禁硬件的端口号为空默认写死(*) 防止空指针
                byte[] sendData = message.getBytes();
                DatagramPacket packet = new DatagramPacket(sendData, sendData.length, address, ports);
                socket.send(packet);
                socket.close(); //关闭Socket
            }else {//发生心跳后,更新端口数组
                if (jsonObject.getString("deviceCode").equals(udpPortMap.keySet().iterator().next())){
                    String key = udpPortMap.keySet().iterator().next();
                    Integer value = udpPortMap.get(key);
                    byte[] sendData = message.getBytes();
                    DatagramPacket packet = new DatagramPacket(sendData, sendData.length, address, value);
                    socket.send(packet);
                    socket.close(); //关闭Socket
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

程序获取心跳

@WebListener
//@Component
public class RLFUDPServer implements ServletContextListener  {
    //记录日志
    public static Logger logger = Logger.getLogger(RLFUDPServer.class.getName());
    //最大udp数据大小
    public static final int MAX_UDP_DATA_SIZE = ();
    //监听端口
    public static final int UDP_PORT = ();
    //包
    public static DatagramPacket packet = ();
    //套接字
    public static DatagramSocket socket = ();

    public  static UdpPortMap udpPortMap;

    static {
        udpPortMap = new UdpPortMap();
    }

    //这是一个事件类,用于通知web应用程序servlet上下文的更改。( ServletContextEvent )
    //在contextInitialized()方法中,通过ServletContext对象注册一个Servlet,用于接收心跳请求。
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        try {
            logger.info("-------> 启动线程,监听UDP数据,端口为:"+UDP_PORT);
            // 启动一个线程,监听UDP数据报
            new Thread(new UDPProcess(UDP_PORT)).start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static class UDPProcess implements Runnable {
        public UDPProcess(final int port) throws SocketException {
            //创建服务器端DatagramSocket,指定端口
            socket = new DatagramSocket(port);
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            logger.info("-------> 创建数据报文,用于接收客户端发送的数据");
            //创建数据报文,用于接收客户端发送的数据
            while (true) {
                byte[] buffer = new byte[MAX_UDP_DATA_SIZE];
                packet = new DatagramPacket(buffer, buffer.length);
                try {
                    logger.info("-------> 门禁心跳将在50秒后发送");
                    logger.info("-------> 等稍后....");
                    logger.info("-------> 此方法在接收到数据之前,将会一直阻塞");
                    logger.info("-------> 等待中接收....");
                    socket.receive(packet);
                    new Thread(new Process(packet)).start();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static class Process   implements Runnable {
        public Process(DatagramPacket packet) throws UnsupportedEncodingException {
            // TODO Auto-generated constructor stub
            //返回数据缓冲区。接收到的数据或要发送的数据从缓冲区中的偏移量开始,并运行长度为long。
            // 接收到的UDP信息,然后解码
            byte[] buffer = packet.getData();
            String srt2 = new String(buffer, "UTF-8").trim();
            logger.info("-------> 解析后的UTF-8(心跳)信息为:" + srt2);
            //使用第三方的Gson库, 将UTF-8编码的字符串, 转换为(google.gson.JsonObject)对象进行传递
            Gson gson = new Gson();
            JsonObject jsonObjects = gson.fromJson(srt2, JsonObject.class);
HttpClientUtil.doPost("解析后的UTF-8(心跳)信息向云端传送(云端接收心跳信息的接口路径)",jsonObjects);
            int port = packet.getPort();
            String code = jsonObjects.get("deviceCode").getAsString();
            Map<String,Integer> map = new HashMap<>();
            map.put(code,port);
            udpPortMap.setMaps(map);
        }
      }
    }
    @Override //在contextDestroyed()方法中,取消注册的Servlet。
    public void contextDestroyed(ServletContextEvent sce) {   logger.info("========UDPListener摧毁========="); }
}

云端接收心跳逻辑层

 public void  HeartbeatProcessingService(JSONObject jsonObject) {
        if (jsonObject.getString("cmd").equals("unlockack")){
            udpControl = new UDPControl();
            udpControl.setReceiveControlParameters(jsonObject.getString("type"));
        } else if (jsonObject.getString("cmd").equals("heart")){
            try{
                //设备编码, 小区ID 不能回空
                if (jsonObject.getString("deviceCode") != null && jsonObject.getString("communityId") != null){
                    System.err.println("进入心跳判断");
                    //进入心跳判断
                    List<AcDevlist> list = acDevlistDao.equipmentList(jsonObject.getString("deviceCode"),Long.valueOf(jsonObject.getString("communityId")));
                    SimpleDateFormat   sdf =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    if (list.isEmpty()){
                        log.info("当前设备没有录入");
                    }else{
                        for (AcDevlist acDevlist : list){
                            int sums = acDevlistHeartDao.acAevListIdNum(acDevlist.getId());
                            if (sums >= 1){
                                log.info("在心跳表中已存在");
acDevlistHeartDao.acdevlistByXqCode(acDevlist.getId(),sdf.parse(sdf.format(new Date())));
                            }else{
                                log.info("在心跳表中不存在");
                                AcDevlistHeart acDevlistHeart = new AcDevlistHeart();
                                acDevlistHeart.setAcDevlistId(acDevlist.getId());
                                acDevlistHeart.setHeartbeatTime(sdf.parse(sdf.format(new Date())));
                                acDevlistHeartDao.insert(acDevlistHeart);
                            }
                        }
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

emmm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值