java 实现websocket的两种方式

简单说明

1.两种方式,一种使用tomcat的websocket实现,一种使用spring的websocket

2.tomcat的方式需要tomcat 7.x,JEE7的支持。

3.spring与websocket整合需要spring 4.x,并且使用了socketjs,对不支持websocket的浏览器可以模拟websocket使用

方式一:tomcat

使用这种方式无需别的任何配置,只需服务端一个处理类,

服务器端代码

package com.Socket;  import java.io.IOException;  
import java.util.Map;  
import java.util.concurrent.ConcurrentHashMap;  
import javax.websocket.*;  
import javax.websocket.server.PathParam;  
import javax.websocket.server.ServerEndpoint;  
import net.sf.json.JSONObject;  @ServerEndpoint("/websocket/{username}")  
public class WebSocket {  private static int onlineCount = 0;  private static Map<String, WebSocket> clients = new ConcurrentHashMap<String, WebSocket>();  private Session session;  private String username;  @OnOpen  public void onOpen(@PathParam("username") String username, Session session) throws IOException {  this.username = username;  this.session = session;  addOnlineCount();  clients.put(username, this);  System.out.println("已连接");  }  @OnClose  public void onClose() throws IOException {  clients.remove(username);  subOnlineCount();  }  @OnMessage  public void onMessage(String message) throws IOException {  JSONObject jsonTo = JSONObject.fromObject(message);  if (!jsonTo.get("To").equals("All")){  sendMessageTo("给一个人", jsonTo.get("To").toString());  }else{  sendMessageAll("给所有人");  }  }  @OnError  public void onError(Session session, Throwable error) {  error.printStackTrace();  }  public void sendMessageTo(String message, String To) throws IOException {  // session.getBasicRemote().sendText(message);  //session.getAsyncRemote().sendText(message);  for (WebSocket item : clients.values()) {  if (item.username.equals(To) )  item.session.getAsyncRemote().sendText(message);  }  }  public void sendMessageAll(String message) throws IOException {  for (WebSocket item : clients.values()) {  item.session.getAsyncRemote().sendText(message);  }  }  public static synchronized int getOnlineCount() {  return onlineCount;  }  public static synchronized void addOnlineCount() {  WebSocket.onlineCount++;  }  public static synchronized void subOnlineCount() {  WebSocket.onlineCount--;  }  public static synchronized Map<String, WebSocket> getClients() {  return clients;  }  
}  

客户端js

var websocket = null;  
var username = localStorage.getItem("name");  //判断当前浏览器是否支持WebSocket  
if ('WebSocket' in window) {  websocket = new WebSocket("ws://" + document.location.host + "/WebChat/websocket/" + username + "/"+ _img);  
} else {  alert('当前浏览器 Not support websocket')  
}  //连接发生错误的回调方法  
websocket.onerror = function() {  setMessageInnerHTML("WebSocket连接发生错误");  
};  //连接成功建立的回调方法  
websocket.onopen = function() {  setMessageInnerHTML("WebSocket连接成功");  
}  //接收到消息的回调方法  
websocket.onmessage = function(event) {  setMessageInnerHTML(event.data);  
}  //连接关闭的回调方法  
websocket.onclose = function() {  setMessageInnerHTML("WebSocket连接关闭");  
}  //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。  
window.onbeforeunload = function() {  closeWebSocket();  
}  //关闭WebSocket连接  
function closeWebSocket() {  websocket.close();  
}  

发送消息只需要使用websocket.send(“发送消息”),就可以触发服务端的onMessage()方法,当连接时,触发服务器端onOpen()方法,此时也可以调用发送消息的方法去发送消息。关闭websocket时,触发服务器端onclose()方法,此时也可以发送消息,但是不能发送给自己,因为自己的已经关闭了连接,但是可以发送给其他人。

方法二:spring整合

此方式基于spring mvc框架,相关配置可以看我的相关博客文章

WebSocketConfig.java

这个类是配置类,所以需要在spring mvc配置文件中加入对这个类的扫描,第一个addHandler是对正常连接的配置,第二个是如果浏览器不支持websocket,使用socketjs模拟websocket的连接。

package com.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.config.annotation.WebSocketConfigurer;  
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;  
import org.springframework.web.socket.handler.TextWebSocketHandler;  @Configuration  
@EnableWebSocket  
public class WebSocketConfig implements WebSocketConfigurer {  @Override  public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {  registry.addHandler(chatMessageHandler(),"/webSocketServer").addInterceptors(new ChatHandshakeInterceptor());  registry.addHandler(chatMessageHandler(), "/sockjs/webSocketServer").addInterceptors(new ChatHandshakeInterceptor()).withSockJS();  }  @Bean  public TextWebSocketHandler chatMessageHandler(){  return new ChatMessageHandler();  }  }  

ChatHandshakeInterceptor.java

这个类的作用就是在连接成功前和成功后增加一些额外的功能,Constants.java类是一个工具类,两个常量。

package com.websocket;  import java.util.Map;  
import org.apache.shiro.SecurityUtils;  
import org.springframework.http.server.ServerHttpRequest;  
import org.springframework.http.server.ServerHttpResponse;  
import org.springframework.web.socket.WebSocketHandler;  
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;  public class ChatHandshakeInterceptor extends HttpSessionHandshakeInterceptor {  @Override  public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,  Map<String, Object> attributes) throws Exception {  System.out.println("Before Handshake");  /* * if (request instanceof ServletServerHttpRequest) { * ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) * request; HttpSession session = * servletRequest.getServletRequest().getSession(false); if (session != * null) { //使用userName区分WebSocketHandler,以便定向发送消息 String userName = * (String) session.getAttribute(Constants.SESSION_USERNAME); if * (userName==null) { userName="default-system"; } * attributes.put(Constants.WEBSOCKET_USERNAME,userName); *  * } } */  //使用userName区分WebSocketHandler,以便定向发送消息(使用shiro获取session,或是使用上面的方式)  String userName = (String) SecurityUtils.getSubject().getSession().getAttribute(Constants.SESSION_USERNAME);  if (userName == null) {  userName = "default-system";  }  attributes.put(Constants.WEBSOCKET_USERNAME, userName);  return super.beforeHandshake(request, response, wsHandler, attributes);  }  @Override  public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,  Exception ex) {  System.out.println("After Handshake");  super.afterHandshake(request, response, wsHandler, ex);  }  }  

ChatMessageHandler.java

这个类是对消息的一些处理,比如是发给一个人,还是发给所有人,并且前端连接时触发的一些动作

package com.websocket;  import java.io.IOException;  
import java.util.ArrayList;  
import org.apache.log4j.Logger;  
import org.springframework.web.socket.CloseStatus;  
import org.springframework.web.socket.TextMessage;  
import org.springframework.web.socket.WebSocketSession;  
import org.springframework.web.socket.handler.TextWebSocketHandler;  public class ChatMessageHandler extends TextWebSocketHandler {  private static final ArrayList<WebSocketSession> users;// 这个会出现性能问题,最好用Map来存储,key用userid  private static Logger logger = Logger.getLogger(ChatMessageHandler.class);  static {  users = new ArrayList<WebSocketSession>();  }  /** * 连接成功时候,会触发UI上onopen方法 */  @Override  public void afterConnectionEstablished(WebSocketSession session) throws Exception {  System.out.println("connect to the websocket success......");  users.add(session);  // 这块会实现自己业务,比如,当用户登录后,会把离线消息推送给用户  // TextMessage returnMessage = new TextMessage("你将收到的离线");  // session.sendMessage(returnMessage);  }  /** * 在UI在用js调用websocket.send()时候,会调用该方法 */  @Override  protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {  sendMessageToUsers(message);  //super.handleTextMessage(session, message);  }  /** * 给某个用户发送消息 * * @param userName * @param message */  public void sendMessageToUser(String userName, TextMessage message) {  for (WebSocketSession user : users) {  if (user.getAttributes().get(Constants.WEBSOCKET_USERNAME).equals(userName)) {  try {  if (user.isOpen()) {  user.sendMessage(message);  }  } catch (IOException e) {  e.printStackTrace();  }  break;  }  }  }  /** * 给所有在线用户发送消息 * * @param message */  public void sendMessageToUsers(TextMessage message) {  for (WebSocketSession user : users) {  try {  if (user.isOpen()) {  user.sendMessage(message);  }  } catch (IOException e) {  e.printStackTrace();  }  }  }  @Override  public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {  if (session.isOpen()) {  session.close();  }  logger.debug("websocket connection closed......");  users.remove(session);  }  @Override  public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {  logger.debug("websocket connection closed......");  users.remove(session);  }  @Override  public boolean supportsPartialMessages() {  return false;  }  }  

spring-mvc.xml

正常的配置文件,同时需要增加对WebSocketConfig.java类的扫描,并且增加

xmlns:websocket="http://www.springframework.org/schema/websocket"  http://www.springframework.org/schema/websocket   <a target="_blank" href="http://www.springframework.org/schema/websocket/spring-websocket-4.1.xsd">http://www.springframework.org/schema/websocket/spring-websocket-4.1.xsd</a>  

客户端

<script type="text/javascript"  src="http://localhost:8080/Bank/js/sockjs-0.3.min.js"></script>  <script>  var websocket;  if ('WebSocket' in window) {  websocket = new WebSocket("ws://" + document.location.host + "/Bank/webSocketServer");  } else if ('MozWebSocket' in window) {  websocket = new MozWebSocket("ws://" + document.location.host + "/Bank/webSocketServer");  } else {  websocket = new SockJS("http://" + document.location.host + "/Bank/sockjs/webSocketServer");  }  websocket.onopen = function(evnt) {};  websocket.onmessage = function(evnt) {  $("#test").html("(<font color='red'>" + evnt.data + "</font>)")  };  websocket.onerror = function(evnt) {};  websocket.onclose = function(evnt) {}  $('#btn').on('click', function() {  if (websocket.readyState == websocket.OPEN) {  var msg = $('#id').val();  //调用后台handleTextMessage方法  websocket.send(msg);  } else {  alert("连接失败!");  }  });  </script>  

注意导入socketjs时要使用地址全称,并且连接使用的是http而不是websocket的ws

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/555508.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php 地址传递,PHP引用符传递存储地址

关于php的引用(就是在变量或者函数、对象等前面加上&符号)的作用&#xff0c;我们先看下面这个程序。代码如下:$a 100; //声明变量a$b &$a; //声明变量b,引用自变量aecho "$a ";echo "$b ";$a; //变量a自增1echo "$a ";echo "$b …

idea创建多模块Springboot项目、导入多模块、删除多模块

前言 在eclipse中有Workspace&#xff08;工作空间&#xff09;和 Project&#xff08;工程&#xff09;的概念在 IDEA中只有 Project&#xff08;工程&#xff09;和 Module&#xff08;模块&#xff09;的概念。这个地方刚开始用的时候会很容易理不清它们之间的关系。在eclip…

php 高效缓存类,简单高效的文件缓存php类

简单高效的文件缓存php类class FileCache{public $keyPrefix ;public $cachePath ;public $cacheFileSuffix .bin;public $directoryLevel 1;public $gcProbability 10;public $fileMode;public $dirMode 0775;function __construct(){$this->cachePath HT::$cacheRo…

Java四种访问权限

java基础(七) java四种访问权限 引言 Java中的访问权限理解起来不难&#xff0c;但完全掌握却不容易&#xff0c;特别是4种访问权限并不是任何时候都可以使用。下面整理一下&#xff0c;在什么情况下&#xff0c;有哪些访问权限可以允许选择。 一、访问权限简介 访问权限控…

php表单提取,php – 使用RegEx提取表单字段

使用正则表达式解析HTML可能不是最好的方法.您可以查看DOMDocument::loadHTML,这将允许您使用DOM方法处理HTML文档(例如,如果您知道这些,则使用XPath查询).您可能还想看一下Zend_Dom和Zend_Dom_Query,顺便说一句,如果您可以在应用程序中使用Zend Framework的某些部分,这是非常好…

phpexcel.php实际应用,PHP操作excel的一个例子(原创)-PHP教程,PHP应用

这是对于那些只喜欢简单处理一下excel朋友来说的//定义一个excel文件$workbook "c:/my documents/test.xls";$sheet "sheet1";//生成一个com对象$ex$ex new com("excel.sheet") or die ("连不上&#xff01;&#xff01;&#xff01;&qu…

集成 websocket 的四种方案

集成 websocket 的四种方案 1. 原生注解 pom.xml <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dependency>WebSocketConfig package cn.coder4j.study.exampl…

java异常不懂,看不懂的异常提示啊

当前位置:我的异常网 Java Web开发 看不懂的异常提示啊看不懂的异常提示啊www.myexceptions.net 网友分享于&#xff1a;2013-09-12 浏览&#xff1a;7次看不懂的错误提示啊&#xff01;&#xff01;&#xff01;&#xff01;写的一个JSP程序&#xff0c;运行时提示如下错误…

包含内部类的.java文件编译后生成几个.class文件

如果一个类有内部类&#xff0c;编译将生成几个字节码文件&#xff0c;规则是怎样呢&#xff1f; 写在前&#xff0c;自己动手丰衣足食&#xff0c;结论只有个人实验支持&#xff0c;没有官方数据支持&#xff0c;欢迎自行查阅文档然后来指正&#xff0c;轻喷&#xff0c;谢谢…

java服务端无法发送给客户端,无法从客户端向服务器发送消息

我正在开发一个应用程序&#xff0c;我需要从客户端向服务器发送消息&#xff0c;并在客户端上的文件发生更改时通知服务器 . 我在Qt中使用QTcpServer和QTcpSocket类 . 我正在写socket并从服务器端的socket读取但是我的读取失败了 .我可以知道如何将消息发布到服务器 . 我需要在…

java 泛型详解

对java的泛型特性的了解仅限于表面的浅浅一层&#xff0c;直到在学习设计模式时发现有不了解的用法&#xff0c;才想起详细的记录一下。 本文参考java 泛型详解、Java中的泛型方法、 java泛型详解 1. 概述 泛型在java中有很重要的地位&#xff0c;在面向对象编程及各种设计模式…

mysql 截取字符串部分值,Mysql字符串截取_获取指定字符串中的数据

搜索热词前言&#xff1a;本人遇到一个需求&#xff0c;需要在MysqL的字段中截取一段字符串中的特定字符&#xff0c;类似于正则表达式的截取&#xff0c;苦于没有合适的方法&#xff0c;百度之后终于找到一个合适的方法&#xff1a;substring_index(www.sqlstudy.com.cn,.,-2)…

Intellij IDEA远程debug教程实战和要点总结

远程调试&#xff0c;特别是当你在本地开发的时候&#xff0c;你需要调试服务器上的程序时&#xff0c;远程调试就显得非常有用。 JAVA支持调试功能&#xff0c;本身提供了一个简单的调试工具JDB&#xff0c;支持设置断点及线程级的调试同时&#xff0c;不同的JVM通过接口的协…

php嗅探木马,PHP安全-密码嗅探

密码嗅探尽管攻击者通过嗅探(察看)你的用户和应用间的网络通信并不专门用于访问控制&#xff0c;但要意识到数据暴露变得越来越重要&#xff0c;特别是对于验证信息。使用SSL可以有效地防止HTTP请求和回应不被暴露。对任何使用https方案的资源的请求可以防止密码嗅探。最好的方…

Idea进行远程Debug

Idea远程调试 当把一个本地项目部署到远程服务器后有可能出现意想不到错误&#xff0c;这个时候通过远程调试能够更清楚的找到bug所在位置。本篇主要讲解如何使用Idea开发工具 进行调试1.远程调试服务器上面的SpringBoot 项目2.远程调试服务器上运行在tomcat中的项目&#xff…

如何用php查不同,php-MySql调查不同查询

大家好,我确实在MySql查询中苦苦挣扎,我有一个名为“ info”的表,并且其中有一个名为“ rating”的列,评分在1-10之间.现在,我需要生成一个百分比值,该百分比值表示1-6、7-8和9-10中有多少评级,但我需要它们拼命显示,之后我需要第二个查询,该查询可以从中减去结果的百分比值1-6…

如何使用websocket实现前后端通信

如何使用websocket实现前后端通信 websocket通信是很好玩的&#xff0c;也很有用的的通信方式&#xff0c;使用方式如下&#xff1a; 第一步由于springboot很好地集成了websocket&#xff0c;所以先在在pom.xml文件中引入依赖 <dependency><groupId>org.springfr…

matlab表示DFT和DTFT,【 MATLAB 】离散傅里叶级数(DFS)与DFT、DTFT及 z变换之间的关系...

上篇博文我们简单的讨论了离散傅里叶级数DFS和离散傅里叶变换DFT之间的关系&#xff0c;简单地说&#xff0c;DFT就是DFS在一个周期内的表现。为了后面讨论方便&#xff0c;这里给出DFS的系数公式(分析公式)&#xff1a;(1) 其中&#xff1a;综合公式&#xff1a;(2) 为了对比&…

tail查看nohup.out文件内容

1.前台实时查看nohub.out文件内容&#xff1a; tail -f nohup.out 2.根据关键字查看 tail -f nohup.out |grep "关键字"3.输出文件最后100行 tail -n 100 nohup.out 4.输出文件最后100行&#xff0c;含关键字 tail -n 100 nohup.out |grep "关键字"

Linux nohup实现后台运行程序及查看(nohup与)

Linux nohup实现后台运行程序及查看&#xff08;nohup与&&#xff09; 更新时间&#xff1a;2019年09月11日 09:28:40 作者&#xff1a;猿的生活 这篇文章主要介绍了Linux nohup实现后台运行程序及查看&#xff08;nohup与&&#xff09;&#xff0c;文中通过示例代码…