点击▲关注 “爪哇笔记” 给公众号标星置顶
更多摄影技巧 第一时间直达
前言
个人支付上线有一段时间了,也产生了几百条订单,不少热心的同志一分、一毛的在支付,都是满满的热情啊!为了更好的服务大家,小编决定接入实时通知用户订单支付状态的小功能。
实现思路
市面上一般有两种实现思路:
轮询,就是前端定时向后端发送请求,查询订单是否支付
WebSocket实现,服务器收到回调信息后主动推送消息到前端
优缺点:
轮询,服务端浪费CPU、内存和带宽资源,客户端占用较多的内存资源与请求数,非实时,延迟取决于请求间隔。
WebSocket,实时,CPU和内存资源不以客户端数量衡量,而是以客户端事件数衡量。需要Socket程序实现和额外端口,客户端实现简单。
项目集成
配置文件pom.xml引入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
定义 WebSocketConfig:
/**
* WebSocket配置
*/
@Configuration
public classWebSocketConfig{
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
定义 WebSocketServer:
@ServerEndpoint("/webSocket/{userId}")
@Component
public classWebSocketServer{
private final static Logger logger = LoggerFactory.getLogger(WebSocketServer.class);
/**
* 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
*/
private static int onlineCount = 0;
/**
* concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
*/
private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
/**
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
private Session session;
/**
* 接收userId
*/
private String userId="";
/**
* 连接建立成功调用的方法*/
@OnOpen
publicvoidonOpen(Session session,@PathParam("userId") String userId) {
this.session = session;
webSocketSet.add(this); //加入set中
addOnlineCount(); //在线数加1
logger.info("有新窗口开始监听:"+userId+",当前在线人数为" + getOnlineCount());
this.userId=userId;
try {
sendMessage("服务器连接成功,支付成功会提示你额!");
} catch (IOException e) {
logger.error("webSocket IO异常");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
publicvoidonClose(){
webSocketSet.remove(this); //从set中删除
subOnlineCount(); //在线数减1
logger.info("有一连接关闭!当前在线人数为" + getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
* @param message 客户端发送过来的消息
*/
@OnMessage
publicvoidonMessage(String message, Session session){
logger.info("收到来自窗口"+userId+"的信息:"+message);
//群发消息
for (WebSocketServer item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* @param session
* @param error
*/
@OnError
publicvoidonError(Session session, Throwable error){
logger.error("发生错误");
error.printStackTrace();
}
/**
* 实现服务器主动推送
*/
publicvoidsendMessage(String message)throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 群发自定义消息
* */
publicstaticvoidsendInfo(String message,@PathParam("userId") String userId){
logger.info("推送消息到窗口"+userId+",推送内容:"+message);
for (WebSocketServer item : webSocketSet) {
try {
//这里可以设定只推送给这个userId的,为null则全部推送
if(userId==null) {
item.sendMessage(message);
}else if(item.userId.equals(userId)){
item.sendMessage(message);
}
} catch (IOException e) {
continue;
}
}
}
publicstaticsynchronizedintgetOnlineCount(){
return onlineCount;
}
publicstaticsynchronizedvoidaddOnlineCount(){
WebSocketServer.onlineCount++;
}
publicstaticsynchronizedvoidsubOnlineCount(){
WebSocketServer.onlineCount--;
}
}
前端实现:
var basePath = "ws://localhost:8080/";
socket = {
webSocket : "",
init : function(userId) {
if ('WebSocket' in window) {
webSocket = new WebSocket(basePath+'webSocket/'+userId);
}
else if ('MozWebSocket' in window) {
webSocket = new MozWebSocket(basePath+"webSocket/"+userId);
}
else {
webSocket = new SockJS(basePath+"sockjs/webSocket/"+userId);
}
webSocket.onerror = function(event) {
alert("webSockt连接发生错误,请刷新页面重试!")
};
webSocket.onopen = function(event) {
};
webSocket.onmessage = function(event) {
var message = event.data;
alert(message);
};
}
}
这里需要注意的是,如果部署到外网,架设了Nginx代理和HTTPS认证,Nginx配置文件需要添加以下参数:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
前端需要修改以下协议前缀,改为:
var basePath = "wss://wwww.xxxxx.com/";
有兴趣的小伙伴可以去测试一下,支付一分钱,满满的都是爱。
网址:https://pay.cloudbed.vip
账号:pay 密码:123456
开源一个 SpringBoot 2.x 实现的个人支付项目源码
SpringBoot 2.x + MyBatis 实现的精品小说项目
源码
1. 识别下方二维码
2. 后台回复「支付」即可获取
你点的每个在看,我都认真当成了喜欢