springboot整合websocket实现微信小程序聊天

WebSocket的定义:

WebSocket 是独立的、创建在 TCP 上的协议。

Websocket 通过HTTP/1.1 协议的101状态码进行握手。

为了创建Websocket连接,需要通过浏览器发出请求,之后服务器进行回应,这个过程通常称为“握手”

浏览器发出请求


GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== //浏览器随机生成的Base64 加密值
Sec-WebSocket-Protocol: chat, superchat     //用户定义的字符串, 用来区分相同url下, 不同服务所需要的协议
Sec-WebSocket-Version: 13                  //版本
Origin: http://example.com

服务器响应请求


HTTP/1.1 101 Switching Protocols
Upgrade: websocket  //已经成功切换websocket协议
Connection: Upgrade //已经成功切换websocket协议
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

  至此,HTTP已经完成它所有工作了,接下来就是完全按照Websocket协议进行了

引入依赖 



	org.springframework.boot
	spring-boot-starter-websocket

WebSocketController

import cn.gzccc.wx.expertUser.domain.WxExpertUser;
import cn.gzccc.wx.expertUser.service.IWxExpertUserService;
import cn.gzccc.wx.utils.SecurityUtils;
import cn.gzccc.wx.utils.SpringContextUtil;
import cn.hutool.crypto.CryptoException;
import cn.hutool.json.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component

/**
 * 微信小程序聊天的websocket
 * token --> 微信小程序用户openId Aes加密后的Hex密文
 */
@ServerEndpoint("/wx/api/websocket/{token}") //@ServerEndpoint主要是将目前的类定义成一个websocket服务器端,
                                             //注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
public class WebSocketController {

    /**
     *  与某个客户端的连接对话,需要通过它来给客户端发送消息
     */
    private Session session;

    /**
     * 标识当前连接客户端的用户标识
     */
    private String token;

    /**
     *  用于存所有的连接服务的客户端,这个对象存储是安全的
     */
    public static ConcurrentHashMap map = new ConcurrentHashMap<>();

    public ConcurrentHashMap content(){
        return map;
    }


    /**
     * 连接建立成功调用的方法
     *
     * @param session 与某个客户端的连接会话,需要通过它来给客户端发送数据
     * @param token   用户token
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "token") String token){
        // 判断当前token 是否属于User中所存在的真实用户
        this.session = session;
        this.token = token;
        if (isUser()){
            map.put(this.token,this);
            log.info("[WebSocket] 连接成功,当前连接人数为:={}", map.size());
            appointSending(token,"连接成功");
        }else{
            map.put(this.token,this);
            log.info("[WebSocket] 异常用户连接,token为:={}", this.token);
            appointSending(token,"异常用户,已记录该行为");
            map.remove(this.token);
        }

    }


    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(){
        // 设置该用户下线
        String openId = SecurityUtils.decryption(token); //解密
        IWxExpertUserService wxExpertUserService = SpringContextUtil.getContext().getBean(IWxExpertUserService.class);
        WxExpertUser wxExpertUser = wxExpertUserService.selectWxUserByOpenId(openId);
        if (wxExpertUser !=null){
            wxExpertUser.setOnline(0); //设置下线
            wxExpertUserService.updateWxExpertUser(wxExpertUser);
        }
        map.remove(this.token);
        log.info("[WebSocket] 退出成功,当前连接人数为:={}", map.size());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message){
        if (isUser()){
            try{
                ObjectMapper mapper =new ObjectMapper();
                Message mess = null;
                try{
                    mess = mapper.readValue(message, Message.class);
                }catch (Exception e){
                    // 用户付费时间已过期
                    map.put(this.token,this);
                    appointSending(token,"消息格式错误,无法为您转发信息");
                    map.remove(this.token);
                }
                // 设置发送者
                mess.setSendToken(this.token);
                String toToken = mess.getToToken(); // 获取接收者Token
                String messageContent = mess.getMessageContent(); // 获取消息内容
                String messageType = mess.getMessageType(); // 获取消息类型
                JSONObject jsonObject = new JSONObject();
                jsonObject.set("sendToken",mess.getSendToken());
                jsonObject.set("toToken",mess.getToToken());
                jsonObject.set("messageType",mess.getMessageType());
                jsonObject.set("messageContent",mess.getMessageContent());
                String json = jsonObject.toString();
                // websocket提供了发送信息的方法
                appointSending(toToken,json);
            }catch (Exception e){
                e.printStackTrace();
            }
        }else{
            map.put(this.token,this);
            appointSending(token,"您的账号不存在,系统无法为您传达此信息");
            map.remove(this.token);
        }
        log.info("[WebSocket] 收到消息:{}","发送者Token:" + this.token + "," + message);
    }

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

    /**
     * 指定发送
     *
     * @param token    用户token
     * @param message  要发送的信息
     */
    public void appointSending(String token,String message){

        // 判断token 是否在线
        if (!"连接成功".equals(message)) {
            WebSocketController webSocketController = map.get(token);
            if (webSocketController == null){
                // 不在线 公众号发送消息
                log.info("指定发送 message: "+message);
                //sendWxTemplate(message,token);
            }
        }
        try {
            if (map.get(token) != null) {
                // websocket提供了发送信息的方法, this.session.getBasicRemote()对象的方法.
                map.get(token).session.getBasicRemote().sendText(message);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 判断当前用户是否存在
     * @return
     */
    public boolean isUser(){
        try{
            String openId = SecurityUtils.decryption(token); //解密
            IWxExpertUserService wxExpertUserService = SpringContextUtil.getContext().getBean(IWxExpertUserService.class);
            WxExpertUser wxExpertUser = wxExpertUserService.selectWxUserByOpenId(openId);
            if (wxExpertUser == null){
                return false;
            }else{
                // 设置该用户上线
                wxExpertUser.setOnline(1);
                wxExpertUserService.updateWxExpertUser(wxExpertUser);
                return true;
            }
        }catch (CryptoException e){
            return false;
        }
    }
}

SecurityUtils

import cn.hutool.crypto.symmetric.AES;

public class SecurityUtils {

    // 加密
    public static String encryption(String data){
        AES aes = new AES("CBC", "PKCS7Padding",
                // 密钥,不可更改
                "GzcccPCall012345".getBytes(),
                // iv加盐
                "GzcccCallDYgjCE0".getBytes());
        // 加密为16进制表示
        String encryptHex = aes.encryptHex(data);
        return encryptHex;
    }

    // 解密
    public static String decryption(String data){
        AES aes = new AES("CBC", "PKCS7Padding",
                // 密钥,不可更改
                "GzcccPCall012345".getBytes(),
                // iv加盐
                "GzcccCallDYgjCE0".getBytes());
        // 加密为16进制表示
        String decryptStr = aes.decryptStr(data);
        return decryptStr;
    }


}

 微信线上小程序测试

打开小程序 

springboot整合websocket实现微信小程序聊天_第1张图片

退出小程序 

springboot整合websocket实现微信小程序聊天_第2张图片

你可能感兴趣的:(webSocket,websocket,spring,boot)