SpringBoot——使用WebSocket功能

springboot自带websocket,通过几个简单的注解就可以实现websocket的功能;

启动类跟普通的springboot一样:

/**
 * 2023年3月2日下午4:16:57
 */
package testspringboot.test7websocket;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;

/**
 * @author XWF
 *
 */
@SpringBootApplication
@PropertySource(value = "test7.properties")
public class Test7Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		SpringApplication.run(Test7Main.class, args);
	}

}

还需要一个websocket的配置类:

/**
 * 2023年3月2日下午4:26:15
 */
package testspringboot.test7websocket;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * @author XWF
 *
 */
@Configuration
public class WebSocketConfig {

	@Bean
	public ServerEndpointExporter serverEndpointExporter() {
		return new ServerEndpointExporter();
	}
	
}

配置文件里只配置了一个端口:

主要的逻辑都放到@ServerEndpoint标签注释的类里,类似controller的功能;

可以使用4种注解处理业务:

  • @OnOpen:处理客户端的连接;
  • @OnClose:处理客户端断开;
  • @OnError:处理故障错误;
  • @OnMessage:处理具体消息,有三种消息类型:String类型,ByteBuffer类型,PongMessage类型,同一消息类型类里不能出现多次;

另外可以通过Session对象设置属性或者发送数据,session.getUserProperties()存取属性,session.getBasicRemote()或者session.getAsyncRemote()可以进行同步异步发送数据;

处理类:

/**
 * 2023年3月2日下午4:27:01
 */
package testspringboot.test7websocket;

import java.io.IOException;
import java.nio.ByteBuffer;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.PongMessage;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import org.springframework.stereotype.Component;

/**
 * @author XWF
 *
 */
@Component
@ServerEndpoint(value = "/websockettest/{name}")
public class WebSocketHandler {

	@OnOpen  
    public void onOpen(@PathParam("name") String name, Session session) throws IOException {  
        System.out.println("onOpen:" + name);
        session.getUserProperties().put("name", name);
    }
	
	@OnClose  
    public void onClose(@PathParam("name") String name, Session session) throws IOException {
		System.out.println("onClose:" + name);
		System.out.println(session.getUserProperties().get("name") + "关闭了");
    }
	
	@OnError  
    public void onError(Session session, Throwable error) {
		System.out.println("onERROR");
        error.printStackTrace();  
    }
	
	@OnMessage
	public void textMessage(Session session, String msg) {
		System.out.println("收到:" + msg);
		try {
			session.getBasicRemote().sendText("hello");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	@OnMessage
	public void binaryMessage(Session session, ByteBuffer msg) {
		System.out.println("Binary message: " + msg.toString());
	}
	@OnMessage
	public void pongMessage(Session session, PongMessage msg) {
		System.out.println("Pong message: " + msg.getApplicationData().toString());
	}
	
}

测试websocket用的Apipost:

连接测试:

SpringBoot——使用WebSocket功能_第1张图片

SpringBoot——使用WebSocket功能_第2张图片

发送数据测试:

SpringBoot——使用WebSocket功能_第3张图片

SpringBoot——使用WebSocket功能_第4张图片

断开连接:

SpringBoot——使用WebSocket功能_第5张图片

SpringBoot——使用WebSocket功能_第6张图片

另外,也可以设置自己的编解码处理自己的消息,实现javax.websocket.Encoder.Text或者javax.websocket.Encoder.Binary接口实现编码器,实现javax.websocket.Decoder.Text或者javax.websocket.Decoder.Binary接口实现解码器,解码器最多两个,一个解码Text一个Binary;

在@ServerEndpoint注解里配置上自己的encoders和decoders就可以实现自定义编解码了;

自定义消息MsgA:

/**
 * 2023年3月3日下午3:12:47
 */
package testspringboot.test7websocket;

/**
 * @author XWF
 *
 */
public class MsgA {
	
	public int id;

	public String name;

	@Override
	public String toString() {
		return "MsgA [id=" + id + ", name=" + name + "]";
	}

}

编码器:

/**
 * 2023年3月3日下午3:14:02
 */
package testspringboot.test7websocket;

import javax.websocket.EncodeException;
import javax.websocket.Encoder.Text;
import javax.websocket.EndpointConfig;

/**
 * @author XWF
 *
 */
public class MsgATextEncoder implements Text{

	@Override
	public void init(EndpointConfig endpointConfig) {
		System.out.println("msga encoder init");
	}

	@Override
	public void destroy() {
		System.out.println("msga encoder destroy");
	}

	// 进行编码操作,将对象编码成string
	@Override
	public String encode(MsgA object) throws EncodeException {
		return object.toString();
	}

}

解码器:

/**
 * 2023年3月3日下午3:16:52
 */
package testspringboot.test7websocket;

import javax.websocket.DecodeException;
import javax.websocket.Decoder.Text;
import javax.websocket.EndpointConfig;

/**
 * @author XWF
 *
 */
public class MsgATextDecoder implements Text {

	@Override
	public void init(EndpointConfig endpointConfig) {
		System.out.println("msga decoder init");
	}

	@Override
	public void destroy() {
		System.out.println("msga decoder destroy");
	}

	// 进行解码操作,将string解码成需要的对象
	@Override
	public MsgA decode(String s) throws DecodeException {
		MsgA msga = new MsgA();
		msga.id = Integer.parseInt(s.split(",")[0]);
		msga.name = s.split(",")[1];
		return msga;
	}

	// 验证消息是否可以解码,返回true可以解码,否则返回false
	@Override
	public boolean willDecode(String s) {
		// 接收格式:id,name
		if (s.split(",").length == 2) {
			try {
				Integer.parseInt(s.split(",")[0]);
			} catch (NumberFormatException e) {
				return false;
			}
			return true;
		} else {
			return false;
		}
	}

}

处理类:

/**
 * 2023年3月3日下午3:07:45
 */
package testspringboot.test7websocket;

import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import javax.websocket.EncodeException;
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.springframework.stereotype.Component;

/**
 * @author XWF
 *
 */
@Component
@ServerEndpoint(value = "/websocketmsgtest", encoders = {MsgATextEncoder.class}, decoders = {MsgATextDecoder.class})
public class WebSocketMsgHandler {

	@OnOpen
	public void onOpen() {
	}
	
	@OnClose
	public void onClose() {
	}
	
	@OnError
	public void onError(Throwable error) {
	}
	
	@OnMessage
	public void textMessageA(Session session, MsgA msga) {
		System.out.println("收到:" + msga);
		MsgA sendMsg = new MsgA();
		sendMsg.id = 9999;
		sendMsg.name = "HELLO WORLD";
		try {
			session.getBasicRemote().sendObject(sendMsg);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (EncodeException e) {
			e.printStackTrace();
		}
		
		sendMsg.id = 8888;
		sendMsg.name = "hello world";
		Future future = session.getAsyncRemote().sendObject(sendMsg);
		try {
			future.get(3, TimeUnit.SECONDS);
			System.out.println("发送完毕");
		} catch (InterruptedException | ExecutionException | TimeoutException e) {
			System.out.println("超时");
			e.printStackTrace();
		}
	}
	
	
}

测试:

不按照解码格式要求请求会异常并断开连接:

SpringBoot——使用WebSocket功能_第7张图片

正常测试:

SpringBoot——使用WebSocket功能_第8张图片

SpringBoot——使用WebSocket功能_第9张图片

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