参考文章:https://blog.csdn.net/zt15732625878/article/details/80560088
小菜鸟一枚,可能有很多问题,但功能已经简单实现
angular整合websocket
1、引入依赖
//依赖库
npm install ws --save
//类型定义文件
npm install @types/ws -save
2、ts文件
import { Component, OnInit } from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
@Component({
selector: 'app-batch-task',
templateUrl: './batch-task.component.html',
styleUrls: ['./batch-task.component.css']
})
export class BatchTaskComponent implements OnInit {
ws: WebSocket;//定义websocket
constructor(private http: HttpClient) { }
ngOnInit(): void {
//打开页面时连接websocket
this.openSocket()
}
//启动webSocket方法
openSocket() {
//判断浏览器支不支持
if(typeof(WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
}else{
console.log("您的浏览器支持WebSocket");
// 访问的后端地址 对应WebSocketServer.java的@ServerEndpoint("/imserver/{token}")
//我这里使用的参数的token 大家可以自行设置
var socketUrl="http://localhost:4433/imserver/"+$('#token')[0].innerHTML;
//将http和https替换成ws 因为使用的是websocket协议
socketUrl=socketUrl.replace("https","ws").replace("http","ws");
console.log(socketUrl);
//如果存在则关闭,然后重启
if(this.ws!=null){
this.ws.close();
this.ws=null;
}
//实例化websocket
this.ws = new WebSocket(socketUrl);
//打开事件:这个主要是用来打开之后输出信息,同时也可以用send()发送信息给服务端
this.ws.onopen = function() {
console.log("websocket已打开");
this.send("hi服务器,我开启了");
};
//获得消息事件:这里主要是处理后端sendText方法传过来的数据的处理,传回来的结果为msg
this.ws.onmessage = function(msg) {
console.log(msg.data);
};
//关闭事件
this.ws.onclose = function() {
console.log("websocket已关闭");
};
//发生了错误事件
this.ws.onerror = function() {
console.log("websocket发生了错误");
}
}
}
//发送消息方法为: this.send("信息")
}
如此一来,angular就处理好了,之后就整合后端
springboot整合websocket
1、导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
<scope>compile</scope>
</dependency>
2、配置文件:主要是用来支持websocket
package com.fusdom.webSocket;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* 开启WebSocket支持
* @author zhengkai
*/
//@Configuration注解
@Configuration
public class WebSocketConfig {
//@Bean注解
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
3、!!! 对接口不能进行拦截
大家的拦截器有很多不同的用法,我们是在application.properties进行处理的,大家可以找个自己处理拦截的地方,不然访问接口时会给拦截
然后拦截的问题要怎么处理?? 这个我是在成功访问之后在WebSocketServer.java种的onOpen方法处理
4、WebSocketServer.java
这个方法类似于我们的controller 层,主要用于与前端之间的交互
package com.fusdom.webSocket;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fusdom.config.JWTConfig;
import com.fusdom.entity.TempInfo;
import com.fusdom.utils.DruidUtils;
import com.rabbitmq.client.Channel;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.apache.commons.lang.StringUtils;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* WebSocketServer:相当于ws协议的controller
*/
//这个地址类似我们requestMapping,前端可以通过这个地址进行访问
@ServerEndpoint("/imserver/{token}")
@Component
public class WebSocketServer {
//日志
static Log log= LogFactory.get(WebSocketServer.class);
/**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/
private static int onlineCount = 0;
/**concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。*/
//新建一个ConcurrentHashMap webSocketMap 用于接收当前userId的WebSocket,方便IM之间对userId进行推送消息。
private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
/**与某个客户端的连接会话,需要通过它来给客户端发送数据*/
private Session session;
// /**接收userId*/
private String userId="";
//这个temp主要是用来处理mq发送数据的一些问题,后面我会贴上代码,可以看一下
public static Session temp;
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("token") String token) {
//这里是我的token处理,可以看着处理
//去掉token前缀
String afterToken = token.replace(JWTConfig.tokenPrefix, "");
//解析JWT
Claims claims = Jwts.parser()
//设置解析秘钥
.setSigningKey(JWTConfig.secret)
//解析token
.parseClaimsJws(afterToken)
.getBody();
//如果有token的话,执行下面的逻辑,这里也就是你们要处理的
if(claims!=null){
//获取到session和userId
this.session = session;
this.userId= claims.getId().toString();
this.temp=session;
//如果userId存在,则移除,再添加一个相同的userId和新的Session(防止session过期)
if(webSocketMap.containsKey(userId)){
webSocketMap.remove(userId);
webSocketMap.put(userId,this);
//加入set中
}else{
webSocketMap.put(userId,this);
//加入set中
addOnlineCount();
//在线数加1
}
log.info("用户连接:"+userId+",当前在线人数为:" + getOnlineCount());
try {
sendMessage(this.userId+"连接成功");
} catch (IOException e) {
log.error("用户:"+userId+",网络异常!!!!!!");
}
}else{
log.error("用户:"+userId+",没有权限!!!!!!");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
//如果存在userId则移除,然后人数-1
if(webSocketMap.containsKey(userId)){
webSocketMap.remove(userId);
//从set中删除
subOnlineCount();
}
log.info("用户退出:"+userId+",当前在线人数为:" + getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
*@OnMessage可以用来接到客户端的信息之后的处理,可以在自己的方法上添加@OnMessage
* @param message 客户端发送过来的消息*/
@OnMessage
public void onMessage(String message, Session session) {
}
/**
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("用户错误:"+this.userId+",原因:"+error.getMessage());
error.printStackTrace();
}
/**
* 实现服务器主动推送:主要是这个方法,拿到session之后发送想要的消息给前端
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketServer.onlineCount--;
}
public void setSession(Session session) {
this.session = session;
}
}
mq处理
这里的代码只供参考,没有太大的价值,只是想展示一下我怎么样调用WebSocketServer.java的sendMessage方法,这里也是为什么使用到temp的原因