以前写接口都是前端调用一次后端,后端给前端返回一次数据,这次要写一个接口是后端主动向前端返回数据,就用到了WebSocket,也是初用!
个人理解:
WebSocket 是前端和后端的一个不会关闭的通道,后端发送一个数据,前端就会接收,然后前端自行判断此数据是否有用!
每个访问此WebSocket 的连接都有一个独立的sessionId ,WebSocket 可以群发,也可以指定给某一个ID发消息
下面上代码:
新建一个springboot 项目
maven包:
<!--websocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
第一步:写配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* 开启 websocket 支持
* @author :lsy
* @date :Created in 2019/12/6 11:23
* @modified By:
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
第二步: WebSocket 工具类
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@ServerEndpoint(value = "/ws/asset") //WebSocket 地址
@Component
public class WebSocketServer {
private static Logger log = LoggerFactory.getLogger(WebSocketServer.class);
private static final AtomicInteger OnlineCount = new AtomicInteger(0);
// concurrent包的线程安全Set,用来存放每个客户端对应的Session对象。
private static CopyOnWriteArraySet<Session> SessionSet = new CopyOnWriteArraySet<Session>();
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session) {
SessionSet.add(session);
int cnt = OnlineCount.incrementAndGet(); // 在线数加1
log.info("有连接加入,当前连接数为:{}", cnt);
SendMessage(session, "连接成功");
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(Session session) {
SessionSet.remove(session);
int cnt = OnlineCount.decrementAndGet();
log.info("有连接关闭,当前连接数为:{}", cnt);
}
/**
* 收到客户端消息后调用的方法
*
* @param message
* 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("来自客户端的消息:{}",message);
SendMessage(session, "收到消息,消息内容:"+message);
}
/**
* 出现错误
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误:{},Session ID: {}",error.getMessage(),session.getId());
error.printStackTrace();
}
/* *//**
* 发送消息,实践表明,每次浏览器刷新,session会发生变化。
* @param session
* @param message
*//*
public static void SendMessage(Session session, String message) {
try {
session.getBasicRemote().sendText(String.format("%s (From Server,Session ID=%s)",message,session.getId()));
} catch (IOException e) {
log.error("发送消息出错:{}", e.getMessage());
e.printStackTrace();
}
}*/
/**
* 发送消息,实践表明,每次浏览器刷新,session会发生变化。
* @param session
* @param message
*/
public static void SendMessage(Session session, String message) {
try {
session.getBasicRemote().sendText(String.format(message));
} catch (IOException e) {
log.error("发送消息出错:{}", e.getMessage());
e.printStackTrace();
}
}
/**
* 群发消息
* @param message
* @throws IOException
*/
public static void BroadCastInfo(String message) throws IOException {
for (Session session : SessionSet) {
if(session.isOpen()){
SendMessage(session, message);
}
}
}
/**
* 指定Session发送消息
* @param sessionId
* @param message
* @throws IOException
*/
public static void SendMessage(String sessionId,String message) throws IOException {
Session session = null;
for (Session s : SessionSet) {
if(s.getId().equals(sessionId)){
session = s;
break;
}
}
if(session!=null){
SendMessage(session, message);
}
else{
log.warn("没有找到你指定ID的会话:{}",sessionId);
}
}
}
第三步: 模拟一个调用方法
import com.kdmins.websocket.WebSocketServer;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
@Controller
public class WebSocketController {
//模拟推送数据接口
@ResponseBody
@RequestMapping("/socket")
public void pushToWeb(@RequestParam("message") String message) throws IOException {
//群发消息
WebSocketServer.BroadCastInfo(message);
}
}
下面开始测试:
进入WebSocket 测试网站: http://coolaf.com/tool/chattest 模拟连接
地址为:本地地址+工具类@ServerEndpoint注解地址 注意我的端口号是8085
java 后台也显示有一个连接加入,此连接为持续开启
最后模拟群发消息:
用postman 调用controller 来模拟控制
再来一次
这个controller 只是模拟,你可以在其他任何逻辑层里写群发
比如: 写一个定时任务,每天中午12点 给前端发一个消息:按时吃饭
好了,一个简单的websocket 完成