最近在做毕业设计,订单这一块需要服务器给客户端发送消息,关于WebSocket的使用看了网上很多资料,最后终于成功了,记录一下。可能业务逻辑挺烂的。。。各位带佬笑笑就好
用的主要是 BeanContext MySpringConfigurator WebSocketConfig ShopOrderReceive WebSocket 这五个类
config
@Configuration
@ConditionalOnWebApplication
public class WebSocketConfig {
//使用boot内置tomcat时需要注入此bean
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
@Bean
public MySpringConfigurator mySpringConfigurator() {
return new MySpringConfigurator();
}
}
/**
* 以websocketConfig.java注册的bean是由自己管理的,需要使用配置托管给spring管理
*/
public class MySpringConfigurator extends ServerEndpointConfig.Configurator implements ApplicationContextAware {
private static volatile BeanFactory context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
MySpringConfigurator.context = applicationContext;
}
@Override
public <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException {
return context.getBean(clazz);
}
}
websocket
@ServerEndpoint("/websocket/{pageCode}")
@Component
public class WebSocket {
private ShopOrderReceive shopOrderReceive = new ShopOrderReceive();
private Thread receive = new Thread(shopOrderReceive);
private static final String loggerName = WebSocket.class.getName();
/**
* concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
*/
public static Map<String, List<Session>> electricSocketMap = new ConcurrentHashMap<String, List<Session>>();
/**
* 连接建立成功调用的方法
*
* @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
@OnOpen
public void onOpen(@PathParam("pageCode") String pageCode, Session session) {
List<Session> sessions = electricSocketMap.get(pageCode);
if (null == sessions) {
List<Session> sessionList = new ArrayList();
sessionList.add(session);
electricSocketMap.put(pageCode, sessionList);
} else {
sessions.add(session);
electricSocketMap.put(pageCode, sessions);
}
shopOrderReceive.setShopId(pageCode);
receive.start();
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(@PathParam("pageCode") String pageCode, Session session) {
shopOrderReceive.stopMe();
if (electricSocketMap.containsKey(pageCode)) {
electricSocketMap.get(pageCode).remove(session);
}
}
/**
* 收到客户端消息后调用的方法
*/
@OnMessage
public void onMessage(Integer userId) {
try {
List<Session> sessions = electricSocketMap.get(userId.toString());
for (Session session : sessions) {
session.getBasicRemote().sendText("newOrder");
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 发生错误时调用
*/
@OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误");
;
}
}
查询用的线程
因为Thread类不归Spring管理,所以没法使用@Autowired注入
public class ShopOrderReceive implements Runnable{
private OrderMainMapper orderMainMapper;
boolean stopMe = true;
Integer shopId = 0;
int oldPay = 0;
int oldFin = 0;
public void stopMe() {
stopMe = false;
}
public void setShopId(String pageCode) {
this.shopId = Integer.parseInt(pageCode);
}
@Override
public void run() {
this.orderMainMapper = BeanContext.getApplicationContext().getBean(OrderMainMapper.class);
OrderMain query = new OrderMain();
query.setShopId(this.shopId);
query.setStatus(1);
orderMainMapper.selectAll();
oldPay = orderMainMapper.selectCount(query);
query.setStatus(2);
oldFin= orderMainMapper.selectCount(query);
while(stopMe) {
query.setStatus(1);
int num1 = orderMainMapper.selectCount(query);
query.setStatus(2);
int num2 = orderMainMapper.selectCount(query);
if(num1 == oldPay - 1 && num2 == oldFin + 1) {
WebSocket webSocket = new WebSocket();
webSocket.onMessage(1);
oldPay = num1;
oldFin = num2;
}
// 1s执行一次
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
手动实现
@Component
public class BeanContext implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
BeanContext.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException {
return (T)applicationContext.getBean(name);
}
public static <T> T getBean(Class<T> clz) throws BeansException {
return (T)applicationContext.getBean(clz);
}
前端调用(Vue)
methods: {
initWebSocket() {
//初始化weosocket
const wsuri = "ws://127.0.0.1:8800/websocket/1";
this.websock = new WebSocket(wsuri);
this.websock.onmessage = this.websocketonmessage;
this.websock.onopen = this.websocketonopen;
this.websock.onerror = this.websocketonerror;
this.websock.onclose = this.websocketclose;
},
websocketonopen() {
//连接建立之后执行send方法发送数据
// this.websocketsend(JSON.stringify(actions));
console.log("websocket build");
},
websocketonerror() {
//连接建立失败重连
this.initWebSocket();
},
websocketonmessage(e) {
//数据接收
this.$Message.info("您有新的订单,请注意查收");
console.log("您有新的订单,请注意查收");
},
websocketsend(Data) {
//数据发送
this.websock.send(Data);
},
websocketclose(e) {
//关闭
console.log("断开连接", e);
}
},
created() {
this.initWebSocket();
},
destroyed() {
this.websock.close(); //离开路由之后断开websocket连接
},