使用 Electron 框架中 http 请求与 Java 后端 websocket 服务端通信
Published in:2023-05-09 |
Words: 1.2k | Reading time: 6min | reading:

使用 Electron 框架中 http 请求与 Java 后端 websocket 服务端通信

Electron 框架基本搭建

1
参见《Electron Egg 框架研究》一文

后端 Websocker 服务建立

基础环境配置

  • 1.pom.xml 文件引入 websocket 包
1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
  • 2.后端服务搭建
  • websocket 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import com.czq.shop.handler.WebSocketHandler;
import com.czq.shop.interceptor.WebSocketInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebSocket
public class WebsocketConfiguration implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// webSocket通道
// 指定处理器和路径
registry.addHandler(new WebSocketHandler(), "/websocket")
// 指定自定义拦截器
.addInterceptors(new WebSocketInterceptor())
// 允许跨域
.setAllowedOrigins("*");
// sockJs通道
registry.addHandler(new WebSocketHandler(), "/sock-js")
.addInterceptors(new WebSocketInterceptor())
.setAllowedOrigins("*")
// 开启sockJs支持
.withSockJS();
}
}

  • handle 文件编写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;

import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
*
*/
public class WebSocketHandler extends AbstractWebSocketHandler {
/**
* 存储sessionId和webSocketSession
* 需要注意的是,webSocketSession没有提供无参构造,不能进行序列化,也就不能通过redis存储
* 在分布式系统中,要想别的办法实现webSocketSession共享
*/
private static Map<String, WebSocketSession> sessionMap = new ConcurrentHashMap<>();
private static Map<String, String> userMap = new ConcurrentHashMap<>();

/**
* webSocket连接创建后调用
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) {
// 获取参数
//session.g6
// String user = String.valueOf(session.getUri().getPath().get("user"));
userMap.put("user", session.getId());
sessionMap.put(session.getId(), session);
}

/**
* 接收到消息会调用
*/
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
JSONObject jsonObject = JSONObject.parseObject(message.getPayload().toString());
String username = jsonObject.getString("username");
String password = jsonObject.getString("password");
sendMessage(username, "hello user");
sendMessage(username, "data content is json data"+password+message.getPayload().toString());
}

/**
* 连接出错会调用
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) {
sessionMap.remove(session.getId());
}

/**
* 连接关闭会调用
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
sessionMap.remove(session.getId());
}

@Override
public boolean supportsPartialMessages() {
return false;
}

/**
* 后端发送消息
*/
public void sendMessage(String user, String message) throws IOException {
String sessionId = userMap.get("user");
if (StringUtils.isEmpty(sessionId)) {
return;
}
WebSocketSession session = sessionMap.get(sessionId);
if (session == null) {
return;
}
session.sendMessage(new TextMessage(message));
}
}
  • interceptor 文件编写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.czq.shop.interceptor;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;

import java.util.Map;

/**
*
*/
public class WebSocketInterceptor implements HandshakeInterceptor {
/**
* handler处理前调用,attributes属性最终在WebSocketSession里,
* 可能通过webSocketSession.getAttributes().get(key值)获得
*/
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) {
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request;
// 获取请求路径携带的参数
// String url = serverHttpRequest.getURI().getPath();
String user = serverHttpRequest.getServletRequest().getParameter("user");
// serverHttpRequest.getBody().g/
attributes.put("user", user);
// response.getHeaders().ge
return true;
} else {
return false;
}
}

@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {

}
}
  • 在此之后启动后端

前端 wesocket client 请求发起

  • 第三方库安装
1
npm install ReconnectingWebSocket
  • 1.编写 HTML 界面,编写单击事件
1
2
3
<el-button type="primary" round @click="websocket()"
>{{ $t("buttons.api") }}
</el-button>
  • 2.编写单击事件方法调用服务端 websocket 服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
websocket() {
const websocket = new ReconnectingWebSocket(local_url);
websocket.addEventListener('open', () => {
websocket.send(JSON.stringify(this.person_msg).toString());
});
//连接发生错误的回调方法
websocket.onerror = function () {
console.log("error");
};

//连接成功建立的回调方法
websocket.onopen = function (event) {
console.log("open");
}
console.log("-----")
//接收到消息的回调方法
websocket.onmessage = function (event) {
console.log('收到消息')
this.data = event.data;
console.log(event.data);
// setTimeout(function () {
websocket.send('get data');
// },2000)
ipcRenderer.send('openit');
}
},

普通 http 请求的发起

1
2
3
4
5
6
7
8
9
import request from "@/utils/request";

export function getInfo(token) {
return request({
url: "/shop/monitor/getOrderCount",
method: "get",
params: { token },
});
}
  • request.js 配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import axios from "axios";
import { Message } from "element-ui";
console.log(process.env.userConfig);
// const process.env.userConfig.BASE_API = 'http://127.0.0.1:10086'
const serves = axios.create({
baseURL: process.env.userConfig.BASE_API,
timeout: 5000,
});

// 设置请求发送之前的拦截器
serves.interceptors.request.use(
(config) => {
// 设置发送之前数据需要做什么处理
config.baseURL = "http://0.0.0.0:10086";
return config;
},
(err) => Promise.reject(err)
);

// 设置请求接受拦截器
serves.interceptors.response.use(
(res) => {
// 设置接受数据之后,做什么处理
if (res.data.code === 50000) {
Message.error(res.data.data);
}
return res.data;
},
(err) => {
// 判断请求异常信息中是否含有超时timeout字符串
if (err.message.includes("timeout")) {
console.log("错误回调", err);
Message.error("网络超时");
}
if (err.message.includes("Network Error")) {
console.log("错误回调", err);
Message.error("服务端未启动,或网络连接错误");
}
return Promise.reject(err);
}
);

// 将serves抛出去
export default serves;
Prev:
轻量快速的 Python ASGI uvicorn 框架使用
Next:
使用 django-rest-framework 框架编写接口与页面