android 集成websocket,并发送通知

android端

第一步 添加依赖,我使用的是Java-WebSocket
implementation "org.java-websocket:Java-WebSocket:1.4.0"
第二步 定义JWebSocketClient,实现WebSocketClient接口,实现其中onOpen()onMessage()onClose()onError()方法。
package com.cngs.lcgh.service.ws;

import android.util.Log;

import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;

/**
 * WebSocket客户端
 *
 * @author 刘鹏
 * @date 2021-04-20
 */
public class JWebSocketClient extends WebSocketClient {
    public JWebSocketClient(URI serverUri) {
        super(serverUri, new Draft_6455());
    }

    @Override
    public void onOpen(ServerHandshake handshakedata) {
        Log.e("JWebSocketClient", "onOpen()");
    }

    @Override
    public void onMessage(String message) {
        Log.e("JWebSocketClient", "onMessage()");
    }

    @Override
    public void onClose(int code, String reason, boolean remote) {
        Log.e("JWebSocketClient", "onClose()");
    }

    @Override
    public void onError(Exception ex) {
        Log.e("JWebSocketClient", "onError()");
    }
}
第三步 定义一个自己的NotifyService,继承Service而来。实现一个方法,initSocketClient(String id) 初始化WebSocket连接。
    /**
     * 初始化websocket连接
     */
    private void initSocketClient(String id) {
        URI uri = URI.create(WebSocketConfig.ws);
        client = new JWebSocketClient(uri) {
            @Override
            public void onMessage(String message) {
                Log.e("JWebSocketClientService", "收到的消息:" + message);
                sendMessage(message);
            }

            @Override
            public void onOpen(ServerHandshake handshakedata) {
                super.onOpen(handshakedata);
                Log.e("JWebSocketClientService", "websocket连接成功");
                sendMsg(id);
            }
        };
        connect();
    }
第四步 发送通知notifycation
  /**
     * 发送通知消息
     */
    private void sendMessage(String content) {
        Intent intent;
        NotificationChannel notificationChannel = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            notificationChannel = new NotificationChannel("important", "Important", NotificationManager.IMPORTANCE_LOW);
            NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            assert notificationManager != null;
            notificationManager.createNotificationChannel(notificationChannel);
        }
        Notification notification = new NotificationCompat.Builder(this, "important")
                .setContentTitle("道路拥堵信息")
                .setAutoCancel(false)
                .setStyle(new NotificationCompat.BigTextStyle().bigText(content))
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.icon)
                .build();

        startForeground(16, notification);
    }
第五步 在对应的activity中启动当前NotifyService
  @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getPersimmions();
        userId= PreferencesUtils.getUserId(MainActivity.this);
        Intent myIntent = new Intent(this, NotifyService.class);
        myIntent.putExtra("userId",userId);
        startService(myIntent);
    }
第六步 在AndroidManifest.xml中注册NotifyService服务
        

代码

JWebSocketClient:

package com.cngs.lcgh.service.ws;

import android.util.Log;

import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;

/**
 * WebSocket客户端
 *
 * @author 刘鹏
 * @date 2021-04-20
 */
public class JWebSocketClient extends WebSocketClient {
    public JWebSocketClient(URI serverUri) {
        super(serverUri, new Draft_6455());
    }

    @Override
    public void onOpen(ServerHandshake handshakedata) {
        Log.e("JWebSocketClient", "onOpen()");
    }

    @Override
    public void onMessage(String message) {
        Log.e("JWebSocketClient", "onMessage()");
    }

    @Override
    public void onClose(int code, String reason, boolean remote) {
        Log.e("JWebSocketClient", "onClose()");
    }

    @Override
    public void onError(Exception ex) {
        Log.e("JWebSocketClient", "onError()");
    }
}

WebSocketConfig:

package com.cngs.lcgh.service.ws;

import android.content.Context;
import android.widget.Toast;

/**
 * WebSocket配置类
 *
 * @author 刘鹏
 * @date 2021-04-20
 */
public class WebSocketConfig {
    public static final String ws = "ws://11.11.12.139:9002/ws";//websocket测试地址
    }
}

NotifyService

package com.cngs.lcgh.service;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import com.cngs.lcgh.MainActivity;
import com.cngs.lcgh.R;
import com.cngs.lcgh.service.ws.JWebSocketClient;
import com.cngs.lcgh.service.ws.WebSocketConfig;

import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;

public class NotifyService extends Service {

    public JWebSocketClient client;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("MyService", "onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("MyService", "onStartCommand");
        super.onStartCommand(intent, flags, startId);

        String userId = intent.getStringExtra("userId");
        initSocketClient(userId);
        return START_STICKY;
    }

    /**
     * 发送通知消息
     */
    private void sendMessage(String content) {
        Intent intent;
        NotificationChannel notificationChannel = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            notificationChannel = new NotificationChannel("important", "Important", NotificationManager.IMPORTANCE_LOW);
            NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            assert notificationManager != null;
            notificationManager.createNotificationChannel(notificationChannel);
        }
        Notification notification = new NotificationCompat.Builder(this, "important")
                .setContentTitle("道路拥堵信息")
                .setAutoCancel(false)
                .setStyle(new NotificationCompat.BigTextStyle().bigText(content))
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.icon)
                .build();

        startForeground(16, notification);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("MyService", "onDestroy");
    }


    /**
     * 初始化websocket连接
     */
    private void initSocketClient(String id) {
        URI uri = URI.create(WebSocketConfig.ws);
        client = new JWebSocketClient(uri) {
            @Override
            public void onMessage(String message) {
                Log.e("JWebSocketClientService", "收到的消息:" + message);
                sendMessage(message);
            }

            @Override
            public void onOpen(ServerHandshake handshakedata) {
                super.onOpen(handshakedata);
                Log.e("JWebSocketClientService", "websocket连接成功");
                sendMsg(id);
            }
        };
        connect();
    }

    /**
     * 连接websocket
     */
    private void connect() {
        new Thread() {
            @Override
            public void run() {
                try {
                    //connectBlocking多出一个等待操作,会先连接再发送,否则未连接发送会报错
                    client.connectBlocking();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    /**
     * 发送消息
     *
     * @param msg
     */
    public void sendMsg(String msg) {
        if (null != client) {
            Log.e("JWebSocketClientService", "发送的消息:" + msg);
            client.send(msg);
        }
    }
}

java后端

使用javax.websocket-api来实现,基于tomcat,如果是spring-boot项目,可以用spring-websocket。因为我们原来项目不是springboot项目,所以只能用javax.websocket-api。使用百度地图api去获取道路实况信息。
百度地图实时路况API:http://lbsyun.baidu.com/index.php?title=webapi/traffic

第一步 添加依赖
        
            javax.websocket
            javax.websocket-api
            1.0
            provided
        
第二步 实现一个WebSocketServer,来实现一个websocket连接。用@ServerEndpoint("/ws")注解。
package com.hyty.cnlcgh.maps.websocket;

import com.hyty.cnlcgh.maps.service.IRoadCongestionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.ContextLoader;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * websocket
 *
 * @author 刘鹏
 * @date 2021/4/21 14:52
 */
@ServerEndpoint("/ws")
@Component
public class WebSocketServer {
    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;

    private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class);

    private static CopyOnWriteArraySet webSocketSet = new CopyOnWriteArraySet();

    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;

    private String uid;

    @Autowired
    public IRoadCongestionService roadCongestionService;

    /**
     * 连接建立成功调用的方法
     *
     * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        addOnlineCount();
        logger.info("有新连接加入!当前在线人数为" + getOnlineCount());
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        if (webSocketSet.contains(this)){
            webSocketSet.remove(this);
        }
        subOnlineCount();           //在线数减1
        logger.info("有一连接关闭!当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     * @param session 可选的参数
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        logger.info("================来自客户端的消息:" + message);
        roadCongestionService = ContextLoader.getCurrentWebApplicationContext().getBean(IRoadCongestionService.class);
        // 当当前id判断不是对应组织的人的时候就不推送消息
        String org = "38";
        if (null != message){
            if (roadCongestionService.judgeOrgById(message, org)) {
                this.uid = message;
                webSocketSet.add(this);
                logger.info("当前在线有效人数为" + webSocketSet.size());
            }
        }
    }

    /**
     * 发生错误时调用
     */
    @OnError
    public void onError(Session session, Throwable error) {
        logger.error("发生错误");
        error.printStackTrace();
    }

    /**
     * 发送消息
     *
     * @throws IOException
     */
    public void sendMessage(String context) throws IOException {
        logger.info("================推送的消息:" + context);
        this.session.getBasicRemote().sendText(context);
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

    public Session getSession() {
        return session;
    }

    public void setSession(Session session) {
        this.session = session;
    }

    public static CopyOnWriteArraySet getWebSocketSet() {
        return webSocketSet;
    }

    public String getUid() {
        return uid;
    }

    public void setUid(String uid) {
        this.uid = uid;
    }

    public static void setWebSocketSet(CopyOnWriteArraySet webSocketSet) {
        WebSocketServer.webSocketSet = webSocketSet;
    }

}

这个类中我在onMessage()方法中实现了自己的逻辑,android端建立连接的时候发送一个当前用户id过来,这边接收到这个id,判断当前id是否是我们待会儿准备推送消息的人,是的话将当前示例添加到set中,声明了一个私有变量uid,是为了后面推送消息的时候使用。

第三步 实现定时任务发送消息到对应id的用户
package com.hyty.cnlcgh.maps.websocket;

import com.hyty.cnlcgh.maps.service.IRoadCongestionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.context.ContextLoader;

import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * 定时推送消息
 *
 * @author 刘鹏
 * @date 2021/4/22 14:23
 */
@Component
public class MessageTask {

    @Autowired
    public IRoadCongestionService roadCongestionService;
    private static final Logger logger = LoggerFactory.getLogger(MessageTask.class);
    @Scheduled(cron = "0 0/3 * * * ?") // 每隔3分钟向android推送一次
    public void sendMessageTask(){
        logger.info("********* 定时任务:推送消息到android端 执行  **************");
        CopyOnWriteArraySet webSocketSet = WebSocketServer.getWebSocketSet();
        roadCongestionService = ContextLoader.getCurrentWebApplicationContext().getBean(IRoadCongestionService.class);
        for (WebSocketServer item:webSocketSet) {
            try {
                String content = null;
                // A大队
                if (roadCongestionService.judgeOrgById(item.getUid(), "54")){
                    content = buildMessageCongestion(1);
                }
                // B大队
                if (roadCongestionService.judgeOrgById(item.getUid(), "55")){
                    content = buildMessageCongestion(2);
                }
                // C大队
                if (roadCongestionService.judgeOrgById(item.getUid(), "56")){
                    content = buildMessageCongestion(3);
                }
                if (null != content){
                    item.sendMessage(content);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        logger.info("/n 定时任务:推送消息到android端 完成.......");
    }

    /**
     * 构建返回消息
     *
     * @param type 判断属于是哪个大队 1 A  2 B 3 C
     * @return String
     */
    public String buildMessageCongestion(int type) {
        roadCongestionService = ContextLoader.getCurrentWebApplicationContext().getBean(IRoadCongestionService.class);
        return roadCongestionService.getCongestion(type);
    }
}

CopyOnWriteArraySet webSocketSet = WebSocketServer.getWebSocketSet();从websocket中取出当时建立连接时候的server。通过遍历set判断给不同的人推送不同的消息。
item.sendMessage(content); 调用websocket的发送消息方法将消息推送到android端

代码

IRoadCongestionService

package com.hyty.cnlcgh.maps.service;


import com.hyty.cnlcgh.maps.entity.Congestion;

import java.util.List;

/**
 * 道路拥堵情况接口
 *
 * @author 刘鹏
 * @date 2021/3/24 11:38
 */
public interface IRoadCongestionService {
    /**
     * 获取拥堵信息路段,组成String类型,供websocket调用返回给前端
     *
     * @param type 判断属于是哪个大队 
     * @return String
     */
    String getCongestion(int type);

    /**
     * 判断是否是该组织的人
     *
     * @param uid   用户id
     * @param orgId 组织id
     * @return 是否
     */
    boolean judgeOrgById(String uid, String orgId);
}

RoadCongestionServiceImpl:

package com.hyty.cnlcgh.maps.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.hyty.cnlcgh.maps.dao.IRoadMapper;
import com.hyty.cnlcgh.maps.entity.Congestion;
import com.hyty.cnlcgh.maps.service.IRoadCongestionService;
import org.apache.http.client.fluent.Request;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 道路拥堵情况实现类
 *
 * @author 刘鹏
 * @date 2021/3/24 11:45
 */
@Service
public class RoadCongestionServiceImpl implements IRoadCongestionService {

    @Autowired
    public IRoadMapper roadMapper;

    private static final Logger logger = LoggerFactory.getLogger(RoadCongestionServiceImpl.class);
    /**
     * 定时任务从百度地图API获取对应道路拥堵情况并存放数据库
     */
    @Scheduled(cron = "0 0/10 * * * ?") // 每隔10分钟请求一次百度地图API
    public void congestionTask() {

        logger.info("----------------定时任务(访问百度API获取道路拥堵信息) 开始:----------------");
        String ak = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";//百度地图API控制台应用的AK
        String BaseUrl = "http://api.map.baidu.com/traffic/v1/road?";

        List list = roadMapper.selectAll();

        for (Congestion item : list) {
            String url = BaseUrl + "road_name=" + item.getRoadName() + "&city=" + item.getCityName() + "&ak=" + ak;
            try {
                String result = Request.Get(url)
                        .connectTimeout(1000).socketTimeout(1000)
                        .execute().returnContent().asString();
                JSONObject jsonResult = JSONObject.parseObject(result);

                Congestion congestion = new Congestion();
                congestion.setId(item.getId());
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分");
                congestion.setCurTime(sdf.format(new Date()));
                congestion.setCongestion(jsonResult.getString("description"));
                if (roadMapper.updateById(congestion) <= 0) {
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        logger.info("----------------定时任务(访问百度API获取道路拥堵信息) 结束----------------");
    }

    /**
     * 获取道路拥堵情况生成String
     *
     * @param type 判断属于哪个大队 
     * @return string
     */
    @Override
    public String getCongestion(int type) {
        StringBuilder sb = new StringBuilder();
        String filterName1 = "拥堵";
        String filterName2 = "缓慢";

        List idList = new ArrayList<>();
        switch (type) {
            case 1:
                idList.add(1);
                idList.add(3);
                break;
            case 2:
                idList.add(2);
                idList.add(4);
                idList.add(6);
                break;
            case 3:
                idList.add(5);
                break;
        }
        List congestionList = roadMapper.selectAllCongestion(filterName1, filterName2, idList);
        if (congestionList.size() > 0) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分");
            sb.append(sdf.format(new Date())).append(",");
            for (Congestion cong : congestionList) {
                String city = cong.getCityName().replaceAll("市", "段");
                String Domingo = cong.getCongestion();
                sb.append(Domingo);
            }
            return sb.toString();
        }
        return null;
    }

    /**
     * 判断是否是该组织的人
     *
     * @param userId 用户id
     * @param orgId  组织id
     * @return 是否
     */
    @Override
    public boolean judgeOrgById(String userId, String orgId) {
        return roadMapper.countNumChengNanById(userId, orgId) > 0;
    }
}

你可能感兴趣的:(android 集成websocket,并发送通知)