Java实现WebSocket

1.WebSocket

平时开发的时候,对于一些平常的需求是不会使用基于WebSocket开发的需求。但是在一些特定场景,比如:主动推送,模拟聊天等等,因为WebSocket建立等实际上是一个长链接。

2.基于Java实现WebSocket的开发

代码方面很简单。

1.config配置
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
2.Server 的实现

基于注解的实现,
核心注解:
ServerEndpoint:标示一个websocket,两个参数设置:
value指定请求地址。
configurator:配置请求拦截类。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.websocket.*;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * socket推送消息(服务端)
 */
@ServerEndpoint(value = "/socket/websocket/{idno}", configurator = SocketServerConfigurator.class)
//@ServerEndpoint(value = "/socket/websocket/{idno}")
@Component
public class WebSocketServer {

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

    private static int onlineCount = 0;
    private static CopyOnWriteArrayList<WebSocketServer> webSockets = new CopyOnWriteArrayList<>();
    private static ConcurrentMap<String, WebSocketServer> socketConcurrentHashMap = new ConcurrentHashMap<>();
    private Session session;
    private String idno;
    //连接建立成功调用的方法
    @OnOpen
    public void onOpen(@PathParam("idno")String idno, Session session){
        this.session = session;
        this.idno = idno;
        socketConcurrentHashMap.put(idno,this);
        webSockets.add(this);     //加入set中
        addOnlineCount();
        logger.info("有新连接加入!当前在线人数为" + getOnlineCount());
    }

    @OnClose
    public void onClose(){
        if (!idno.equals("")) {
            socketConcurrentHashMap.remove(idno);  //从set中删除
        }
        webSockets.remove(this);
        subOnlineCount();
        logger.info("有一连接关闭!当前在线人数为" + getOnlineCount());
    }

    @OnMessage
    public void onMessage(String message, Session session){
        logger.info("client message:"+message);
        if(StringUtils.isEmpty(idno)){  //群发消息
            sendAll(message);
        }else{  //单独推送
            if(message.equalsIgnoreCase("ping")){
                heartCheck(message);
            }else{
                sendToUser(message);
            }
        }
    }

    private void sendAll(String message){
        for (String userId:socketConcurrentHashMap.keySet()) {
            try {
                socketConcurrentHashMap.get(userId).sendMessage(message);
            } catch (IOException e) {
                logger.error("WebSocketServer|sendAll[error]:e={}",e.getMessage());
            }
        }
    }
    private void heartCheck(String message){
        if(socketConcurrentHashMap.get(idno)!=null){
            try {
                socketConcurrentHashMap.get(idno).sendMessage(message);
            } catch (IOException e) {
                logger.error("WebSocketServer|heartCheck[error]:e={}",e.getMessage());
            }
        }
    }
    private void sendToUser(String message){
        if(socketConcurrentHashMap.get(idno)!=null){
            for (String userId:socketConcurrentHashMap.keySet()) {
                if(userId.equals(this.idno)){
                    continue;
                }
                try {
                    socketConcurrentHashMap.get(userId).sendMessage(message);
                } catch (IOException e) {
                    logger.error("WebSocketServer|sendToUser[error]:e={}",e.getMessage());
                }
            }
        }
    }

    @OnError
    public void onError(Session session, Throwable e){
//        throwable.printStackTrace();
        logger.error("WebSocketServer|onError[error]:e={}",e.getMessage());
    }

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

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }
    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
        //this.session.getAsyncRemote().sendText(message);
    }
}

3.client的实现
import com.alipay.api.java_websocket.client.WebSocketClient;
import com.alipay.api.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.net.URISyntaxException;

/**
 * socket推送消息(客户端)
 */
public class SocketClient extends WebSocketClient {
    private final static Logger logger = LoggerFactory.getLogger(SocketClient.class);
    public SocketClient(URI serverUri) {
        super(serverUri);
    }
    /**
     *  demo
     * @param args
     * @throws URISyntaxException
     * @throws InterruptedException
     */
    public static void main(String[] args) throws URISyntaxException, InterruptedException {
        String url = "ws://127.0.0.1:8080/socket/websocket/1233435";
        SocketClient client = new SocketClient(new URI(url));
        client.connect();
        Thread.sleep(5000);
        System.out.println(client.isOpen());
        client.send("哈哈哈哈");
        client.close();
    }
    @Override
    public void onOpen(ServerHandshake serverHandshake) {
        logger.info("SocketClient:------打开socket--------");
    }
    @Override
    public void onMessage(String s) {
        logger.info("SocketClient:-----接受服务端消息-----"+s);
    }
    @Override
    public void onClose(int i, String s, boolean b) {
        logger.info("SocketClient:----关闭socket链接");
    }
    @Override
    public void onError(Exception e) {
        logger.error("SocketClient|onError[error]:e={}",e.getMessage());
    }
}
4.websocket鉴权配置类
package com.ythk.crm.socket;

import com.ythk.crm.config.Constant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * websocketserver 鉴权
 */
@Slf4j
@Component
public class SocketServerConfigurator extends ServerEndpointConfig.Configurator {
    private final Logger logger = LoggerFactory.getLogger(SocketServerConfigurator.class);

    /**
     * token鉴权认证
     *
     * @param originHeaderValue
     * @return
     */
    @Override
    public boolean checkOrigin(String originHeaderValue) {
//        业务判断代码,可以判断一些请求参数时候合法
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String whiteUser = Constant.SETTING_MAP.get("websocket_white_user");
        try {
            HttpServletRequest request = servletRequestAttributes.getRequest();
            String url = request.getServletPath();
            if (StringUtils.isBlank(url)) {
                return false;
            }
            String phone = url.substring(url.lastIndexOf("/") + 1);
            logger.info("SocketServerConfigurator|checkOrigin:phone=" + phone);
            if (phones.contains(phone)) {
                return super.checkOrigin(originHeaderValue);
            } else {
                return false;
            }
        } catch (Exception e) {
            logger.error("SocketServerConfigurator|checkOrigin[ERROR]:e={}", e);
            return false;
        }
    }

    /**
     * Modify the WebSocket handshake response
     * 修改websocket 返回值
     *
     * @param sec
     * @param request
     * @param response
     */
    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        super.modifyHandshake(sec, request, response);

    }
}

以上就很简单的实现类一个websocket服务的创建和client请求demo,以供参考。

  • 15
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 18
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值