WebSocket是JavaEE7新支持的:

Javax.websocket.server包含注解,类,接口用于创建和配置服务端点

Javax.websocket包则包含服务端点和客户断电公用的注解,类,接口,异常

创建一个编程式的端点,需要继承Endpoint类,重写它的方法。

创建一个注解式的端点,将自己的写的类以及类中的一些方法用前面提到的包中的注解装饰(@EndPoint,@OnOpen等等)。

@Component
@ServerEndpoint(value = "/websocket/{ip}")
public class MyWebSocket {
	private static final Logger log = LoggerFactory.getLogger(MyWebSocket.class);
	// 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
	private static int onlineCount = 0;
	// concurrent包的线程安全Map,用来存放每个客户端对应的MyWebSocket对象。
	private static ConcurrentHashMap<String, MyWebSocket> webSocketMap = new ConcurrentHashMap<String, MyWebSocket>();
	// 与某个客户端的连接会话,需要通过它来给客户端发送数据
	private Session session;
	private String ip; // 客户端ip
	public static final String ACTION_PRINT_ORDER = "printOrder";
	public static final String ACTION_SHOW_PRINT_EXPORT = "showPrintExport";
	 * 连接建立成功调用的方法
	@OnOpen
	public void onOpen(Session session, @PathParam("ip") String ip) {
		this.session = session;
		this.ip = ip;
		webSocketMap.put(ip, this);
		addOnlineCount(); // 在线数加1
//		System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
		log.info("有新连接加入,ip:{}!当前在线人数为:{}", ip, getOnlineCount());
		ExportService es = BeanUtils.getBean(ExportService.class);
		List<String> list = es.listExportCodesByPrintIp(ip);
		ResponseData<String> rd = new ResponseData<String>();
		rd.setAction(MyWebSocket.ACTION_SHOW_PRINT_EXPORT);
		rd.setList(list);
		sendObject(rd);
	 * 连接关闭调用的方法
	@OnClose
	public void onClose(@PathParam("ip") String ip) {
		webSocketMap.remove(ip); // 从set中删除
		// Map<String, String> map = session.getPathParameters();
		// webSocketMap.remove(map.get("ip"));
		subOnlineCount(); // 在线数减1
		// System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
		log.info("websocket关闭,IP:{},当前在线人数为:{}", ip, getOnlineCount());
	 * 收到客户端消息后调用的方法
	 * @param message
	 *            客户端发送过来的消息
	@OnMessage
	public void onMessage(String message, Session session) {
//		System.out.println("来自客户端的消息:" + message);
		log.debug("websocket来自客户端的消息:{}", message);
		OrderService os = BeanUtils.getBean(OrderService.class);
		OrderVo ov = os.getOrderDetailByOrderNo(message);
//		System.out.println(ov);
		ResponseData<OrderVo> rd = new ResponseData<OrderVo>();
		ArrayList<OrderVo> list = new ArrayList<OrderVo>();
		list.add(ov);
		rd.setAction(MyWebSocket.ACTION_PRINT_ORDER);
		rd.setList(list);
		sendObject(rd);
//		log.info("推送打印信息完成,单号:{}", ov.getOrderNo());
	 * 发生错误时调用
	@OnError
	public void onError(Session session, Throwable error) {
//		System.out.println("发生错误");
		log.error("webSocket发生错误!IP:{}", ip);
		error.printStackTrace();
	 * 像当前客户端发送消息
	 * @param message
	 *            字符串消息
	 * @throws IOException
	public void sendMessage(String message) {
		try {
			this.session.getBasicRemote().sendText(message);
			// this.session.getAsyncRemote().sendText(message);
		} catch (IOException e) {
			e.printStackTrace();
			log.error("发送数据错误,ip:{},msg:{}", ip, message);
	 * 向当前客户端发送对象
	 * @param obj
	 *            所发送对象
	 * @throws IOException
	public void sendObject(Object obj) {
		ObjectMapper mapper = new ObjectMapper();
		mapper.setSerializationInclusion(Include.NON_NULL);
		String s = null;
		try {
			s = mapper.writeValueAsString(obj);
		} catch (JsonProcessingException e) {
			e.printStackTrace();
			log.error("转json错误!{}", obj);
		this.sendMessage(s);
	 * 群发自定义消息
	public static void sendInfo(String message) {
		for (Entry<String, MyWebSocket> entry : webSocketMap.entrySet()) {
			MyWebSocket value = entry.getValue();
			value.sendMessage(message);
	public static synchronized int getOnlineCount() {
		return onlineCount;
	public static synchronized void addOnlineCount() {
		MyWebSocket.onlineCount++;
	public static synchronized void subOnlineCount() {
		MyWebSocket.onlineCount--;
	public static ConcurrentHashMap<String, MyWebSocket> getWebSocketMap() {
		return webSocketMap;

当创建好一个(服务)端点之后,将它以一个指定的URI发布到应用当中,这样远程客户端就能连接上它了。

Websocket(服务)端点以URI表述,有如下的访问方式:

ws://host:port/path?query

wss://host:port/path?query

注解详解:

@ServerEndPoint:

    RequiredElements :

        Value: URI映射

    OptionalElemens:

        subprotocols:

        decoders:解码器

        encoders:编码器

        configurator

建立连接相关:

Annotation

Event

Example

OnOpen

Connection opened

@OnOpen

Public void open(Sessionsession,

EndpointConfig conf) { }

OnMessage

Message received

@OnMessage

public void message(Sessionsession,

String msg) { }

OnError

Connection error

@OnError

public void error(Sessionsession,

Throwable error) { }

OnClose

Connection closed

@OnClose

public void close(Sessionsession,

CloseReason reason) { }

Session代表着服务端点与远程客户端点的一次会话。

容器会为每一个连接创建一个EndPoint的实例,需要利用实例变量来保存一些状态信息。

Session.getUserProperties提供了一个可编辑的map来保存properties,

例如,下面的端点在收到文本消息时,将前一次收到的消息回复给其他的端点

@ServerEndpoint("/delayedecho")
public class DelayedEchoEndpoint
  @OnOpen
  public void open(Sessionsession)
    session.getUserProperties().put("previousMsg", "");
  @OnMessage
  public void message(Session session, Stringmsg)
    String prev= (String) session.getUserProperties().get("previousMsg");
    session.getUserProperties().put("previousMsg",msg);
    try {
      session.getBasicRemote().sendText(prev);
        } catch (IOException e){ ... }

发送、接收消息:

Websocketendpoint能够发送和接收文本、二进制消息,另外,也可以发送ping帧和接收pong 帧

发送消息:

Obtain the Session object from theconnection.

从连接中获得Session对象

Session对象是endPoint中那些被注解标注的方法中可得到的参数

当你的message作为另外的消息的响应

在@OnMessage标注的方法中,有session对象接收message

如果你必须主动发送message,需要在标注了@OnOpen的方法中将session对象作为实例变量保存

这样,你可以再其他方法中得到该session对象

1.Use the Session object to obtain aRemote Endpoint object.

通过Session对象获得Remoteendpoint对象

2.Use the RemoteEndpoint object to sendmessages to the peer.

利用RemoteEndpoint对象来发送message

@ServerEndpoint("/echoall")
public class EchoAllEndpoint
    @OnMessage
    public void onMessage(Session session, Stringmsg)
       try {
         for (Session sess :session.getOpenSessions())
             if (sess.isOpen())
             sess.getBasicRemote().sendText(msg);
      } catch (IOExceptione) { ... }

OnMessage注解指定方法来处理接收的messages

在一个端点类中,至多可以为三个方法标注@OnMessage注解

消息类型分别为:text、binary、pong。

我们查看一下ServerEndpoint类源码:

@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
public @interface ServerEndpoint {
    public String value();
    public String[] subprotocols() default {};
    public Class<? extends Decoder>[] decoders() default {};
    public Class<? extends Encoder>[] encoders() default {};
    public Class<? extends ServerEndpointConfig.Configurator> configurator() default ServerEndpointConfig.Configurator.class;

Encoders and Decoders(编码器和解码器):

WebSocket Api 提供了encoders 和 decoders用于 Websocket Messages 与传统java 类型之间的转换

An encoder takes a Java object and produces a representation that can be transmitted as a WebSocket message;

编码器输入java对象,生成一种表现形式,能够被转换成Websocket message

for example, encoders typically produce JSON, XML, or binary representations.

例如:编码器通常生成json、XML、二进制三种表现形式

A decoder performs the reverse function; it reads a WebSocket message and creates a Java object.

解码器执行相反的方法,它读入Websocket消息,然后输出java对象

编码器编码:

looks for an encoder that matches your type and uses it to convert the object to a WebSocket message.

利用RemoteEndpoint.Basic 或者RemoteEndpoint.Async的sendObject(Object data)方法将对象作为消息发送,容器寻找一个符合此对象的编码器,

利用此编码器将此对象转换成Websocket message

代码示例:可以指定为自己的一个消息对象

package com.zlxls.information;
import com.alibaba.fastjson.JSON;
import com.common.model.SocketMsg;
import javax.websocket.EncodeException;
import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;
 * 配置WebSocket解码器,用于发送请求的时候可以发送Object对象,实则是json数据
 * sendObject()
 * @ClassNmae:ServerEncoder   
 * @author zlx-雄雄
 * @date    2017-11-3 15:47:13
public class ServerEncoder implements Encoder.Text<SocketMsg> {  
    @Override  
    public void destroy() {  
        // TODO Auto-generated method stub  
    @Override  
    public void init(EndpointConfig arg0) {  
        // TODO Auto-generated method stub  
    @Override  
    public String encode(SocketMsg socketMsg) throws EncodeException {  
        try {  
            return JSON.toJSONString(socketMsg);  
        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
            return "";  

Then, add the encodersparameter to the ServerEndpointannotation as follows:

@ServerEndpoint(value = "/myendpoint",encoders = { ServerEncoder.class })

解码器解码:

Decoder.Binary<T>for binary messages

These interfaces specify the willDecode and decode methods.

the container calls the method annotated with @OnMessage that takes your custom Java type as a parameter if this method exists.

package com.zlxls.information;
import com.common.model.SocketMsg;
import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
 * 解码器执,它读入Websocket消息,然后输出java对象
 * @ClassNmae:ServerDecoder   
 * @author zlx-雄雄
 * @date    2017-11-11 9:12:09
public class ServerDecoder implements Decoder.Text<SocketMsg>{
    @Override
    public void init(EndpointConfig ec){}
    @Override
    public void destroy(){}
    @Override
    public SocketMsg decode(String string) throws DecodeException{
        // Read message...
        return new SocketMsg();
    @Override
    public boolean willDecode(String string){
        // Determine if the message can be converted into either a
        // MessageA object or a MessageB object...
        return false;

Then, add the decoderparameter to the ServerEndpointannotation as follows:

@ServerEndpoint(value = "/myendpoint",encoders = { ServerEncoder.class},decoders = {ServerDecoder.class })

处理错误:

To designate a method that handles errors in an annotated WebSocket endpoint, decorate it with @OnError:

* 发生错误是调用方法 * @param t * @throws Throwable @OnError public void onError(Throwable t) throws Throwable { System.out.println("错误: " + t.toString());

为一个注解式的端点指定一个处理error的方法,为此方法加上@OnError注解:

This method is invoked when there are connection problems, runtime errors from message handlers, or conversion errors when decoding messages.

当出现连接错误,运行时错误或者解码时转换错误,该方法才会被调用

指定端点配置类:

The Java API for WebSocket enables you to configure how the container creates server endpoint instances.

Websocket的api允许配置容器合适创建server endpoint 实例

You can provide custom endpoint configuration logic to:

Access the details of the initial HTTP request for a WebSocket connection

Perform custom checks on the OriginHTTP header

Modify the WebSocket handshake response

Choose a WebSocket subprotocol from those requested by the client

Control the instantiation and initialization of endpoint instances

To provide custom endpoint configuration logic, you extend the ServerEndpointConfig.Configurator class and override some of its methods.

继承ServerEndpointConfig.Configurator 类并重写一些方法,来完成custom endpoint configuration 的逻辑代码

In the endpoint class, you specify the configurator class using the configurator parameter of the ServerEndpoint annotation.

package com.zlxls.information;
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;
 * 由于websocket的协议与Http协议是不同的,
 * 所以造成了无法直接拿到session。
 * 但是问题总是要解决的,不然这个websocket协议所用的场景也就没了
 * 重写modifyHandshake,HandshakeRequest request可以获取httpSession
 * @ClassNmae:GetHttpSessionConfigurator   
 * @author zlx-雄雄
 * @date    2017-11-3 15:47:13
public class GetHttpSessionConfigurator extends Configurator{
    @Override
    public void modifyHandshake(ServerEndpointConfig sec,HandshakeRequest request, HandshakeResponse response) {
        HttpSession httpSession=(HttpSession) request.getHttpSession();
        sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
@OnOpen
public void open(Session s, EndpointConfig conf){
    HandshakeRequest req = (HandshakeRequest) conf.getUserProperties().get("sessionKey");
@ServerEndpoint(value = "/myendpoint",configurator=GetHttpSessionConfigurator.class)

不过要特别说一句:

HandshakeRequest req = (HandshakeRequest) conf.getUserProperties().get("sessionKey");  目前获取到的是空值。会报错:java.lang.NullPointerException,这个错误信息,大家最熟悉不过了。

原因是:请求头里面并没有把相关的信息带上

这里就需要实现一个监听,作用很明显:将所有request请求都携带上httpSession,这样就可以正常访问了

说明:注解非常简单可以直接使用注解@WebListener[https://blog.csdn.net/zhizhuodewo6/article/details/82019409],也可以再web.xml配置监听

    package com.zlxls.information;
    import javax.servlet.ServletRequestEvent;
    import javax.servlet.ServletRequestListener;
    import javax.servlet.annotation.WebListener;
    import javax.servlet.http.HttpServletRequest;
     * http://www.cnblogs.com/zhuxiaojie/p/6238826.html
     * 配置监听器,将所有request请求都携带上httpSession
     * 用于webSocket取Session
     * @ClassNmae:RequestListener   
     * @author zlx-雄雄
     * @date    2017-11-4 11:27:33
    @WebListener
    public class RequestListener implements ServletRequestListener {
        @Override
        public void requestInitialized(ServletRequestEvent sre)  {
            //将所有request请求都携带上httpSession
            ((HttpServletRequest) sre.getServletRequest()).getSession();
        public RequestListener() {}
        @Override
        public void requestDestroyed(ServletRequestEvent arg0)  {}
                    WebSocket是JavaEE7新支持的:Javax.websocket.server包含注解,类,接口用于创建和配置服务端点Javax.websocket包则包含服务端点和客户断电公用的注解,类,接口,异常创建一个编程式的端点,需要继承Endpoint类,重写它的方法。创建一个注解式的端点,将自己的写的类以及类中的一些方法用前面提到的包中的注解装饰(@EndPoint,@OnOpen等等)。@Component@ServerEndpoint(val...
				
首先我们查看一下ServerEndpoint类源码:@Retention(value = RetentionPolicy.RUNTIME) @Target(value = {ElementType.TYPE}) public @interface ServerEndpoint { public String value(); public String[] subproto...
都会报空指针错误的原因 本质原因:spring管理的都是单例(singleton)和 websocket (多对象)相冲突。​因为WebSocket 是一个多例,因为你需要多个对象来保存链接,所以就和单例无缘了,然而我们交给Spring管理的是单例的东西,那么我们可以从这里知道,WebSocket的对象是不能交给Spring管理的,此时我们有两种解决方案; 方案1: 在上下文获取你需要的对象 package cn.jiabao.util; import org.springframework.bea
1. 第一种方式 WebSocketClient 注入方式 2. 第二种方式 @ClientEndpoint 注解方式 3. 第三种方式 extends WebSocketClient 的方式 4. 第四种方式 @ClientEndpoint 简单版 - websocket server 创建方式 @ServerEndpoint 注解方式
随着Web技术的发展,实时通信已成为许多应用的重要需求。WebSocket为Web应用程序提供了一种在单个TCP连接上进行全双工通信的方式。Spring Boot框架为开发者提供了集成WebSocket的便利性。本文将详细介绍如何在Spring Boot项目中设置和使用WebSocketWebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。 WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。
findMajority 函数用于寻找数组中的众数,利用了 Boyer-Moore Majority Vote 算法。 算法的核心思想是遍历数组,通过计数器来记录当前的众数和出现次数。 如果当前元素与众数相同,则计数器加一;否则计数器减一。当计数器变为0时,更新众数为当前元素。 最终得到的众数即为数组中出现次数最多的元素。 主函数中定义了一个示例数组,并调用 findMajority 函数找到众数,然后输出结果。
Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。
Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。
@ServerEndpoint是一个Java注解,用于声明一个类作为WebSocket端点。当被使用时,ServerEndpointExporter类会扫描带有@ServerEndpoint注解的类,并将其注册为一个WebSocket端点。通过注解的属性,可以设置WebSocket端点的配置项,比如指定端点的路径、子协议、解码器和编码器等。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [WebSocket](https://blog.csdn.net/weixin_38446891/article/details/115066409)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [websocket @ServerEndpoint(value = “/websocket/{ip}“)详解](https://blog.csdn.net/z69183787/article/details/110957622)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]