欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

WebSocket搭建教程

程序员文章站 2022-06-22 14:54:19
如何搭建一个websocket呢? 第一步,编写一个简单的jsp文件,它主要有websocket连接和4个websocket响应事件。 <%@ page langua...

如何搭建一个websocket呢?

第一步,编写一个简单的jsp文件,它主要有websocket连接和4个websocket响应事件。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%-- <jsp:include
    page="/js/jspfunc/supplierBackGroundMan/supplierBackGroundMan.jsp" /> --%>
<%
  String path = request.getContextPath();
  String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path;
%>
<!DOCTYPE html>  
<html>  
<head>  
<title>Testing websockets</title>  
<script type="text/javascript" src="<%=path %>/js/jquery-1.11.3.js"></script>  
<script type="text/javascript" src="<%=path %>/js/zzcjs/jquery.serializejson.min.js"></script>  
<script type="text/javascript">  
    var webSocket = new WebSocket('ws://192.168.3.130:8080/supplier/websocket/chat');  

    webSocket.onerror = function(event) {  
        alert(event.data);  
    };  

    webSocket.onclose = function(event) {  
        document.getElementById('messages').innerHTML = 'onclose';  
    };  

    webSocket.onopen = function(event) {  
        document.getElementById('messages').innerHTML = 'open';  
    };  

    webSocket.onmessage = function(event) {  
        document.getElementById('messages').innerHTML += '<br/>' + event.data;  
    };  

    function start() {
     webSocket.send(JSON.stringify({type:1,message:'huang1',userid:'1',farmid:'1'}));  
      return false;  
    }  
  </script>  
</head>  
<body>  
  <p>  
    <input type="submit" value="Start" onclick="start()" />  
  </p>  
  <p id="messages"></p>  

</body>  
</html>  

第二步,配置struts.xml配置文件

<!--不拦截ws请求 -->
    <constant name="struts.action.excludePattern" value="/websocket/chat"></constant>

第三步,编写后台代码

//onOpen 我们创建一个连接到服务器的连接时将会调用此方法。
//onClose 我们关闭一个连接到服务器的连接时将会调用此方法。
//onError 当客户端-服务器通信发生错误时将会调用此方法。
//onMessage事件提供了一个data属性,它可以包含消息的Body部分。消息的Body部分必须是一个字符串,可以进行序列化/反序列化操作,以便传递更多的数据。
package com.nmfz.app.websocket;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.ServletActionContext;
import org.directwebremoting.json.JsonUtil;
import org.directwebremoting.json.parse.JsonParseException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.alibaba.fastjson.JSON;
import com.nmfz.app.action.SharedFarmUsers;
import com.nmfz.app.manager.SharedFarmUsersManager;
import com.nmfz.app.manager.impl.SharedFarmUsersManagerImpl;

import net.sf.json.JSONObject;

/**
 * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端。注解的值将被用于监听用户连接的终端访问URL地址。
 *  configurator:通过GetHttpSessionConfigurator可以在onOpen方法中取得HttpSession,然后通过HttpSession的ServletContext容器可以取得spring的service,实现在websocket中变相注入spring bean。
 * @author zho
 */
@ServerEndpoint(value = "/websocket/chat",configurator=GetHttpSessionConfigurator.class)
public class MyWebSocket{ 

    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。  
    private final static AtomicInteger onlineCount = new AtomicInteger(0);  
    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识  
//  private static CopyOnWriteArraySet webSocketSet = new CopyOnWriteArraySet(); 
    private static List clients = new ArrayList<>();
    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;  
    private HttpSession httpSession;
//  ngs static int userid ; 

    @OnOpen  
    public void onOpen(Session session, EndpointConfig config) throws IOException, InterruptedException  {  
        this.session = session;  
        this.httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());  
        clients.add(this);  //当前客户端加入集合
        MyWebSocket.onlineCount.incrementAndGet();//在线数加1
        sendMessage("打开");//向此用户发送一条最新的偷菜记录
    }  

    @OnClose  
    public void onClose() throws IOException, InterruptedException   {
        clients.remove(this);  //从set中删除
        MyWebSocket.onlineCount.decrementAndGet();//在线数减1
        System.out.println("close");

    }  

    @OnMessage  
    public void onMessage(String message, EndpointConfig config) throws IOException, InterruptedException   {   
        sendMessage(message);           
    }   

    @OnError  
    public void onError(Throwable t) throws Throwable {  
        t.printStackTrace();
        System.out.println("error");

    }
    /**
      * 发送消息给客户端
      * @param message
      * @throws IOException
      */
    public void sendMessage(String message) throws IOException{
        //自己和自己对话
         try {
//          this.session.getBasicRemote().sendText(message);//同步
            this.session.getAsyncRemote().sendText(message);//异步
        } catch (Exception e) {
            e.printStackTrace();
        }
//      MyWebSocket.broadcast(message);
     }
    /** 
     * 给某个用户发送消息 
     * 
     * @param userName 
     * @param message 
     */  
/*    public void sendMessageToUser(String userName, TextMessage message) {  
        for (MyWebSocket client : clients) {  
            if (client.getAttributes().get("websocket_username").equals(userName)) {  
                try {  
                    if (client.isOpen()) {  
                        client.sendMessage(message);  
                    }  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
                break;  
            }  
        }  
    }  */
    /*广播:遍历客户端集,发送消息,注意发送要用的session,用session.getBasicRemote().sendText(msg)发送消息*/  
    public static void broadcast(String msg) {  
         for (MyWebSocket client : clients) {//遍历所有  
               try {//如果这个client已经在线  
                   synchronized (client) {  
                       client.session.getBasicRemote().sendText(msg);//发送消息  
                  }  
               } catch (IOException e) {//如果这个client不在线  
//                   log.debug("Chat Error: 向用户"+client.getUser().getUsername()+"发送消息失败", e);  
                   clients.remove(client);  
                   try {  
                       client.session.close();  
                   } catch (IOException e1) {  
                       // Ignore  
                   }  
//                   String message = String.format("-- %s %s", client.user.getUsername(), "已经下线.");  
//                   broadcast(message);
               }  
           }  
     }
    /**
     * @触发事件
     * @param msg
     * @param pa1
     */
    public void triggerEvent(String msg) {
          try {
           onMessage(msg,null);
          } catch (Exception e) {
           e.printStackTrace();
          } 
         }

    /**
     * 获取当前在线人数
     * @return
     */
    public static int currentOnline() {
        return onlineCount.get();
    }

第四步,编写一个继承Configurator的子类GetHttpSessionConfigurator,通过GetHttpSessionConfigurator可以在onOpen方法中取得HttpSession,然后通过HttpSession的ServletContext容器可以取得spring的service,实现在websocket中变相注入spring bean。

package com.nmfz.app.websocket;

import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
import javax.websocket.server.ServerEndpointConfig.Configurator;

public class GetHttpSessionConfigurator extends Configurator{
    @Override  
    public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {  
        HttpSession httpSession = (HttpSession) request.getHttpSession();  
        if(httpSession != null){  
            config.getUserProperties().put(HttpSession.class.getName(), httpSession);  
        }  
    }  
}