一、长连接
1. 前端代码
<template>
<div>
<button @click="initSocket">建立websocket连接</button>
<el-input v-model="types">
</el-input>
<button @click="sendmessage()">点击发送消息了</button>
</div>
</template>
<script>
export default {
data() {
return {
webSocket: null,
url: '110.128.131.1:9003/ws',
types: '给后台参数'
}
},
methods: {
initSocket() {
let url = `ws://${this.url}/${参数}`
this.webSocket = new WebSocket(url)
this.webSocket.onopen = this.webSocketOnOpen
this.webSocket.onclose = this.webSocketOnClose
this.webSocket.onerror = this.webSocketOnError
this.webSocket.onmessage = this.webSocketOnMessage
},
sendmessage() {
this.webSocket.send(this.types);
},
webSocketOnOpen() {
console.log('websocket连接成功');
},
webSocketOnMessage(res) {
console.log(res.data);
},
webSocketOnClose() {
this.webSocket.close()
console.log('websocket连接已关闭');
},
webSocketOnError(res) {
console.log('websocket连接失败');
console.log(res);
}
},
created() {
this.initSocket()
},
destroyed() {
this.webSocket.close()
},
}
</script>
2. 后端代码
1. 配置类
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.7.0</version>
</dependency>
package com.hua.dentistryschedule.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
@EnableWebMvc
@EnableWebSocket
public class WebSocketconfig {
@Bean
public ServerEndpointExporter serverEndpointExporter () {
return new ServerEndpointExporter();
}
}
2. service类
无参
package com.hua.dentistryschedule.config;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
@Log4j2
@Component
@ServerEndpoint(value = "/ws")
public class WebSocketServer {
private Session session;
private static final AtomicInteger OnlineCount = new AtomicInteger(0);
private static CopyOnWriteArraySet<Session> SessionSet = new CopyOnWriteArraySet<Session>();
private static int num = 0;
private Timer timer = new Timer();
@OnOpen
public void onOpen(Session session) {
SessionSet.add(session);
this.session = session;
int cnt = OnlineCount.incrementAndGet();
log.info("有连接加入,当前连接数为:{}", cnt);
SendMessage(this.session, num+"");
heartBeat(session);
}
@OnClose
public void onClose() {
SessionSet.remove(this.session);
int cnt = OnlineCount.decrementAndGet();
log.info("有连接关闭,当前连接数为:{}", cnt);
}
@OnMessage
public void onMessage(String message, Session session) {
log.info("收到客户端消息:"+message);
if("ping".equalsIgnoreCase(message)){
SendMessage(session, "pong" );
timer.cancel();
heartBeat(session);
return;
}
if("+1".equalsIgnoreCase(message)){
this.num ++;
}
if("-1".equalsIgnoreCase(message)){
this.num --;
}
BroadCastInfo(""+num );
}
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误:{},Session ID: {}", error.getMessage(), session.getId());
error.printStackTrace();
}
private void heartBeat(Session session) {
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
try {
session.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}, 40000);
}
public static void SendMessage(Session session, String message) {
try {
if (session.isOpen()) {
session.getBasicRemote().sendText(message);
}
} catch (IOException e) {
log.error("发送消息出错:{}", e.getMessage());
e.printStackTrace();
}
}
public static void BroadCastInfo(String message) {
for (Session session : SessionSet) {
SendMessage(session, message);
}
}
public static void SendMessage(String message, String sessionId) {
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 java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
@ServerEndpoint("/api/pushMessage/{userId}")
public class WebSocketServer {
private static int onlineCount = 0;
private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
private Session session;
private String userId = "";
@OnOpen
public void onOpen(Session session,@PathParam("userId") String userId) {
this.session = session;
this.userId=userId;
if(webSocketMap.containsKey(userId)){
webSocketMap.remove(userId);
webSocketMap.put(userId,this);
}else{
webSocketMap.put(userId,this);
addOnlineCount();
}
log.info("用户连接:"+userId+",当前在线人数为:" + getOnlineCount());
sendMessage("连接成功");
}
@OnClose
public void onClose() {
if(webSocketMap.containsKey(userId)){
webSocketMap.remove(userId);
subOnlineCount();
}
log.info("用户退出:"+userId+",当前在线人数为:" + getOnlineCount());
}
@OnMessage
public void onMessage(String message, Session session) {
log.info("用户消息:"+userId+",报文:"+message);
if(StringUtils.isNotBlank(message)){
try {
JSONObject jsonObject = JSON.parseObject(message);
jsonObject.put("fromUserId",this.userId);
String toUserId=jsonObject.getString("toUserId");
if(StringUtils.isNotBlank(toUserId)&&webSocketMap.containsKey(toUserId)){
webSocketMap.get(toUserId).sendMessage(message);
}else{
log.error("请求的userId:"+toUserId+"不在该服务器上");
}
}catch (Exception e){
e.printStackTrace();
}
}
}
@OnError
public void onError(Session session, Throwable error) {
log.error("用户错误:"+this.userId+",原因:"+error.getMessage());
error.printStackTrace();
}
public void sendMessage(String message) {
try {
this.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void sendInfo(String message, String userId) {
log.info("发送消息到:"+userId+",报文:"+message);
if(StringUtils.isNotBlank(userId) && webSocketMap.containsKey(userId)){
webSocketMap.get(userId).sendMessage(message);
}else{
log.error("用户"+userId+",不在线!");
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketServer.onlineCount--;
}
}
二、定时任务
1. 依赖
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</dependency>
2. 配置类
package com.hua.dentistryschedule.schedule;
import com.hua.dentistryschedule.Service.scheduleSercive;
import org.quartz.JobDetail;
import org.quartz.Trigger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
@Configuration
public class schedulemethod {
@Bean(name = "changeTimeoutConditionDetail")
public MethodInvokingJobDetailFactoryBean changeTimeoutConditionDetail(scheduleSercive scheduleSercive) {
MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();
jobDetail.setConcurrent(false);
jobDetail.setTargetObject(scheduleSercive);
jobDetail.setTargetMethod("changeTimeoutCondition");
return jobDetail;
}
@Bean(name = "messageToRemindDetail")
public MethodInvokingJobDetailFactoryBean messageToRemindDetail(scheduleSercive scheduleSercive) {
MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();
jobDetail.setConcurrent(false);
jobDetail.setTargetObject(scheduleSercive);
jobDetail.setTargetMethod("messageToRemind");
return jobDetail;
}
@Bean(name = "changeTimeoutConditionTrigger")
public CronTriggerFactoryBean changeTimeoutConditionTrigger(JobDetail changeTimeoutConditionDetail) {
CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();
trigger.setJobDetail(changeTimeoutConditionDetail);
trigger.setCronExpression("0/5 * * * * ?");
return trigger;
}
@Bean(name = "messageToRemindTrigger")
public CronTriggerFactoryBean messageToRemindTrigger(JobDetail messageToRemindDetail) {
CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();
trigger.setJobDetail(messageToRemindDetail);
trigger.setCronExpression("0/5 * * * * ?");
return trigger;
}
@Bean(name = "scheduler")
public SchedulerFactoryBean schedulerFactory(Trigger changeTimeoutConditionTrigger, Trigger messageToRemindTrigger) {
SchedulerFactoryBean bean = new SchedulerFactoryBean();
bean.setOverwriteExistingJobs(true);
bean.setStartupDelay(1);
bean.setTriggers(changeTimeoutConditionTrigger,messageToRemindTrigger);
return bean;
}
}