0
点赞
收藏
分享

微信扫一扫

springboot-服务端-android-客户端实现长连接

1.springboot websocket服务端

话不多说先上代码,首先是配置类


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

//webSocket配置类
@Configuration
@EnableWebSocket
public class WebsocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }

}

然后是websocket服务端 用username区分是哪个客户端,然后后续客户端连上之后可以通过这个给客户端发消息,我是用json的格式发送。

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.junit.platform.commons.util.StringUtils;
import org.springframework.stereotype.Component;

import javax.imageio.ImageIO;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.awt.*;
import java.awt.image.RenderedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.atomic.AtomicInteger;



@Component
@ServerEndpoint("/websocket/{username}") //暴露的ws应用的路径
@Slf4j
public class MyWebSocket {

    //存储每一个客户端会话信息的线程安全的集合
    public static final ConcurrentSkipListMap<String,Session> sessions = new ConcurrentSkipListMap<>();
    //使用线程安全的计数器,记录在线数
    private static final AtomicInteger onlineCount = new AtomicInteger(0);


    private SeekableByteChannel byteChannel;


    /**
     * 客户端与服务端连接成功
     * @param session
     * @param username
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("username") String username){
        /*
            do something for onOpen
            与当前客户端连接成功时
         */
        if(sessions.containsKey(username)){
            return;
        }
        //存储会话信息
        sessions.put(username,session);
        //计数+1
        int cnt = onlineCount.incrementAndGet();
        //打印日志
        log.info(username + "连接加入,当前连接数为:" + cnt);

        //改为json格式数据 方便客户端区别消息或者指令
        JSONObject msgJson = new JSONObject();
        msgJson.put("key","msg");
        msgJson.put("msg","连接成功");
        //给客户端发消息
        this.sendMessage(session, username,msgJson.toString());
    }


    /**
     * 客户端与服务端连接关闭
     * @param session
     * @param username
     */
    @OnClose
    public void onClose(Session session,@PathParam("username") String username){
        /*
            do something for onClose
            与当前客户端连接关闭时
         */
        //删除会话信息
        sessions.remove(username);
        //计数-1
        int cnt = onlineCount.decrementAndGet();
        //打印日志
        log.info(username + "连接关闭,当前连接数为:" + cnt);
    }

    /**
     * 客户端与服务端连接异常
     * @param error
     * @param session
     * @param username
     */
    @OnError
    public void onError(Throwable error,Session session,@PathParam("username") String username) {
        //打印日志
        log.error("发生错误:Username:" + error.getMessage() + username);
    }

    /**
     * 客户端向服务端发送消息
     * @param message
     * @param username
     * @throws IOException
     */
    @OnMessage
    public void onMsg(Session session,String message,@PathParam("username") String username) throws IOException {
        /*
            do something for onMessage
            收到来自当前客户端的消息时
         */
        //打印日志
        log.info("来自"+username+"的消息:" + message);
        //给客户端发消息
        this.sendMessage(session,username, "收到消息,消息内容:" + message);
    }

    @OnMessage
    public void onMsg(byte[] byteBuffer, Session session, @PathParam("username") String username) throws IOException {

        System.out.println("接收到消息");
        try {
            // 将字节数组转换为图片对象
            Image image = ImageIO.read(new ByteArrayInputStream(byteBuffer));

            // 在这里可以对接收到的图片进行处理或保存
            ImageIO.write((RenderedImage) image,"jpg",new File("123.jpg"));

            System.out.println("Received image: " + image);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 发送消息
     * @param session
     * @param message
     */
    public void sendMessage(Session session,String username,String message) {
        if(StringUtils.isBlank(username)){
            return;
        }
        if(session == null){
            session = sessions.get(username);
        }
        //发送消息
        session.getAsyncRemote().sendText( message);
    }

    /**
     * 群发消息
     * @param message
     * @param message
     */
    public void sendMessage(String message) {
        if(sessions.keySet().size() <= 0)
            return;
        sessions.keySet().stream().forEach(key -> {
            Session session = sessions.get(key);
            //判断连接是否开着
            if(session.isOpen()){
                //一个一个发
                this.sendMessage(session, key,message);
            }
        });
    }


    

}

然后是我手写的一个小的测试控制器类

import com.alibaba.fastjson.JSONObject;
import com.wsdn.websocketdemo.command.CommonStand;
import com.wsdn.websocketdemo.socket.MyWebSocket;
import org.junit.platform.commons.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Map;
import java.util.Scanner;

/**
 * websocket 控制器
 */
@RestController
@RequestMapping("/wsk")
public class WskController {

    @Autowired
    private MyWebSocket myWebSocket;

    @PostMapping("/sendMsg/{username}")
    public String sendMsgToClient(@RequestBody Map<String,String> msgMap,@PathVariable String username){
        try {
            System.out.println(msgMap.get("msg"));
            myWebSocket.sendMessage(null,username,msgMap.get("msg"));
        } catch (Exception e) {
            return "没有与" + username + "建立连接";
        }
        return "success";
    }

    /**
     * 发送命令
     * @param username
     * @return
     */
    @GetMapping("/command/{username}/{key}")
    public String sendCommand(@PathVariable("key") String key,@PathVariable("username") String username){
        try {
            if(StringUtils.isNotBlank(key) && StringUtils.isNotBlank(username)){
                if(CommonStand.getEnum(key) != null){
                    CommonStand anEnum = CommonStand.getEnum(key);
                    JSONObject json = new JSONObject();
                    json.put("key",key);
                    json.put("msg",anEnum.getMsg());
                    myWebSocket.sendMessage(null,username,json.toString());
                    return "success";
                }
            }else{
                return "没有与" + username + "建立连接";
            }
        } catch (Exception e) {
            return "没有与" + username + "建立连接";
        }
        return "success";
    }


}

2.Android客户端 websocket

import android.app.Service;
import android.content.Context;
import android.os.Build;
import android.os.Environment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dji.sdk.sample.R;
import com.dji.sdk.sample.internal.view.PresentableView;


import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;


import androidx.annotation.NonNull;
import de.tavendo.autobahn.WebSocketConnection;
import de.tavendo.autobahn.WebSocketException;
import de.tavendo.autobahn.WebSocketHandler;

public class WebsocketView  extends LinearLayout implements View.OnClickListener, PresentableView {

    public WebsocketView(Context webContext){
        super(webContext);
        initUI();
    }


    private WebSocketConnection mConnect = new WebSocketConnection();


    /**
     *
     按钮 变量
     */

    // 连接 断开连接 发送数据到服务器 的按钮变量
    private Button btnConnect, btnDisconnect, btnSend;

    // 显示接收服务器消息 按钮
    private TextView Receive,receive_message;

    // 输入需要发送的消息 输入框
    private EditText mEdit,socketEdit;

    private void initUI(){
        setClickable(true);
        setOrientation(VERTICAL);
        LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService(Service.LAYOUT_INFLATER_SERVICE);
        layoutInflater.inflate(R.layout.view_websocket, this, true);

        // 初始化所有按钮
        btnConnect = (Button) findViewById(R.id.connect);
        btnDisconnect = (Button) findViewById(R.id.disconnect);
        btnSend = (Button) findViewById(R.id.send);
        mEdit = (EditText) findViewById(R.id.edit);
        socketEdit = (EditText) findViewById(R.id.socketUrl);
        receive_message = (TextView) findViewById(R.id.receive_message);
        Receive = (Button) findViewById(R.id.Receive);

        /**
         * 创建客户端 & 服务器的连接
         */
        btnConnect.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mConnect.isConnected()){
                    Toast.makeText(getContext(), "ws already connect....", Toast.LENGTH_SHORT).show();
                    return;
                }

                Toast.makeText(getContext(), "ws connect....", Toast.LENGTH_SHORT).show();
                try {
                    mConnect.connect(socketEdit.getText().toString(), new WebSocketHandler() {
                        @Override
                        public void onOpen() {
                            Toast.makeText(getContext(), "Status:Connect to ", Toast.LENGTH_SHORT).show();
                        }

                        @Override
                        public void onTextMessage(String payload) {
                            receive_message.setText(payload != null ? payload : "");
                            if(payload.equals("test")){
                                receive_message.setText("进入测试模式");
                            }
                            //解析json数据
                            JSONObject msgJson = JSON.parseObject(payload);
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                                msgJson.keySet().stream().forEach(k -> Log.v("cyy json key/value",k+"/"+msgJson.get(k)));
                            }
                            receive_message.setText(msgJson.getString("msg"));
                        }

                        @Override
                        public void onClose(int code, String reason) {
                            Toast.makeText(getContext(), "Connection lost..", Toast.LENGTH_SHORT).show();
                        }

                    });
                } catch (WebSocketException e) {
                    e.printStackTrace();
                }

            }
        });



        /**
         * 断开客户端 & 服务器的连接
         */
        btnDisconnect.setOnClickListener(new View.OnClickListener() {
             public void onClick(View view) {
                    mConnect.disconnect();
                }
        });

        /**
         * 点击发送
         */
        btnSend.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                String content = mEdit.getText().toString();
                //内容为空不能发送
                if (content != null && content.length() != 0) {
                    sendFileMessage();
                }else
                    Toast.makeText(getContext(), "内容不能为空", Toast.LENGTH_SHORT).show();
            }
        });

    }

    //发送消息
    public void sendMessage(String content) {
        if (mConnect.isConnected()) {
            mConnect.sendTextMessage(content);
            Toast.makeText(getContext(), "发送成功", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(getContext(), "no connection!!", Toast.LENGTH_SHORT).show();
        }

    }

    public void sendBinaryMessage() {
        if (mConnect.isConnected()) {
            File imageFile = new File(Environment.getExternalStorageDirectory().
                    getPath() + "/Dji/com.dji.sdk.sample/photo/123.jpg");
            byte[] imageBytes = new byte[0];
            try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
                try (FileInputStream fis = new FileInputStream(imageFile)) {
                    byte[] buffer = new byte[1024];
                    int len;
                    while ((len = fis.read(buffer)) != -1) {
                        bos.write(buffer, 0, len);
                    }
                    imageBytes = bos.toByteArray();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            mConnect.sendBinaryMessage(imageBytes);
            Toast.makeText(getContext(), "发送成功", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(getContext(), "no connection!!", Toast.LENGTH_SHORT).show();
        }

    }

    @Override
    public void onClick(View view) {

    }


    @Override
    public int getDescription() {
        return R.string.component_listview_websocket_controller;
    }

    @NonNull
    @Override
    public String getHint() {
       return this.getClass().getSimpleName() + ".java";
    }

    /**
     * 发送文件
     * @param file
     * @throws IOException
     */
    public void sendFileMessage()  {
        //新建一个线程
        new Thread(() -> {
            File imageFile = new File(Environment.getExternalStorageDirectory().
                    getPath() + "/Dji/com.dji.sdk.sample/photo/123.jpg");
            byte[] imageBytes = new byte[0];
            try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
                try (FileInputStream fis = new FileInputStream(imageFile)) {
                    byte[] buffer = new byte[1024];
                    int len;
                    while ((len = fis.read(buffer)) != -1) {
                        bos.write(buffer, 0, len);
                    }
                    imageBytes = bos.toByteArray();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            Log.v("cyy okhttp","imageBytes length:"+imageBytes.length);
            mConnect.sendBinaryMessage(imageBytes);
           //mConnect.sendBinaryMessage(new byte[1]);
            Log.v("cyy okhttp","发送成功");
        }).start();
    }
}

本人小白,第一次写,欢迎大佬指正。

下面就是一个需要引入的jar包

springboot-服务端-android-客户端实现长连接_websocket

举报

相关推荐

0 条评论