所需依赖:
<!-- websocketsdk-->
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.apache.tomcat.embed</groupId>-->
<!-- <artifactId>tomcat-embed-websocket</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<!--声明spring boot内嵌tomcat的作用范围 在运行时不起作用-->
<!-- <scope>provided</scope>-->
</dependency>
WebSocket配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
/**
* 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
【注】这里在本地启动的时候可以正常进行,但是将项目打包部署到Linux服务器的时候可能会出现报错,原因可能为线程不同步,提前创建了WebSocket对象但是对应的配置JavaBean还未生成;也有可能是Pom.xml的tomcat配置没有排除,spring内置了tomcat服务器,但是云端就会出现问题(仅提供bug修改参考意见)
WebSocketMap工具类
此工具类实现将在线的用户添加到哈希map中进行存储,采用ConcurrentHashMap来确保线程安全性
import com.minprogram.renthouse.controller.MyWebSocketServer;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* @Author zd
* @Date 2021/9/6 15:00
* @Version 1.0
*/
public class WebSocketMapUtil {
public static ConcurrentMap<String, MyWebSocketServer> webSocketMap = new ConcurrentHashMap<String, MyWebSocketServer>();
public static void put(String key, MyWebSocketServer myWebSocketServer){
webSocketMap.put(key, myWebSocketServer);
}
public static MyWebSocketServer get(String key){
return webSocketMap.get(key);
}
public static void remove(String key){
webSocketMap.remove(key);
}
public static Collection<MyWebSocketServer> getValues(){
return webSocketMap.values();
}
//判断用户是否存在于Map中
public static boolean isContain(String key){
return webSocketMap.containsKey(key);
}
}
WebSocket具体实现类
【注】一定要使用反射的方式来获取service或者mapper层的方法,否则会报错
/**
* @Author zd
* @Date 2021/9/2 16:53
* @Version 1.0
*/
@Component
@ServerEndpoint(value = "/WebSocket/{openId}") // 这里存放的是小程序前端输入的用户识别码,即openid
@Slf4j
public class MyWebSocketServer {
@Autowired
private UserMapper userMapper = MyApplicationContextAware.getApplicationContext().getBean(UserMapper.class);
// 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
private Session session;
private String openId;
/**
* 连接建立后触发的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("openId") String openId) {
this.session = session;
this.openId=openId;
log.info("onOpen-SessionId:{}",session.getId());
WebSocketMapUtil.put(openId, this);
addOnlineCount();
log.info("有新连接加入,openId:【{}】!当前在线人数为:{}", openId, getOnlineCount());
}
/**
* 连接关闭后触发的方法
*/
@OnClose
public void onClose() {/*从map中删除*/
WebSocketMapUtil.remove(this.openId);
subOnlineCount();//在线人数减少
log.info("====== onClose:【{}】,目前在线人数:{} ======",this.openId,getOnlineCount());
}
/**
* 接收到客户端消息时触发的方法
*/
@OnMessage
public void onMessage(String requestBody) throws Exception {/*获取服务端到客户端的通道*/
实现发送逻辑
}
/**
* 发生错误时触发的方法
*/
@OnError
public void onError(Session session, Throwable error) throws Exception {
log.info("{}连接发生错误{}",session.getId(),error.getMessage());
error.printStackTrace();
}
// 发送给某人消息的方法
public void SendMsgToSB(String uopenid,String nid) throws Exception {
//1.判断用户openid是否存在于websocket之中
// 存在:数据标记为已读(2)存入数据库然后直接推送 不存在:数据标记为未读(1)存入数据库,不推送
// String msg= SensitivewordFilter.filterText(requestData.getString("msg"));
notedto ndto = new notedto();
ndto.setNid(Integer.parseInt(nid));
Note n = adminMapper.getNoteDetail(ndto);
if(WebSocketMapUtil.isContain(uopenid)){
addToDataBases(n.getNId(),"unRead",uopenid);
List<Object> nlist = new ArrayList<>();
nlist.add(n);
sendMessage(44001,1,nlist,"noteNoRead",null);
}else{
addToDataBases(n.getNId(),"unOnline",uopenid);
}
}
// 获取未读消息列表
public void getNoReadMsg(String myOpenid) throws Exception {//房东上线自动查询
log.info("getNoReadMsg-myOpenid:【{}】",myOpenid);
MyWebSocketServer myWebSocket = WebSocketMapUtil.get(this.openId);
JSONObject receiverUserJson=new JSONObject();
receiverUserJson.put("UOpenId",this.openId);
notetouserdto ntudto = new notetouserdto();
ntudto.setUopenid(this.openId);
ntudto.setNtustatus(1);
List<NoteToUser> ntulist = noteToUserMapper.getNoteToUserList(ntudto);
List<Object> nlist = new ArrayList<>();
Integer sum = 0;
if(!ntulist.isEmpty()){
for(NoteToUser ntu:ntulist){
notedto ndto = new notedto();
ndto.setNid(ntu.getNId());
Note n = adminMapper.getNoteDetail(ndto);
nlist.add(n);
log.info("向用户推送内容:{}",n.toString());
sum++;
}
myWebSocket.sendMessage(44001,sum,nlist,"noteNoRead",new JSONObject());
}
}
// 实现发送操作
public void sendMessage(int code,int sum,List<Object> content,String type,JSONObject count) throws Exception {
JSONObject result = new JSONObject();
result.put("code",code);//插入发送内容
log.info("发送:{}",result.toString());
this.session.getAsyncRemote().sendText(result.toString().replace("=",":"));
}
// 获取当前在线用户人数
public static synchronized int getOnlineCount() {
return onlineCount;
}
// 新增上线用户人数
public static synchronized void addOnlineCount() {
MyWebSocketServer.onlineCount++;
}
// 减去一个上线用户人数
public static synchronized void subOnlineCount() {
MyWebSocketServer.onlineCount--;
}
}