1.依赖导入
pom.xml
<!-- WebSocket 支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- 文件上传解析器 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
2.websocket后端配置
2.1WebSSHWebSocketConfig.java
public
class
WebSSHWebSocketConfig
implements
WebSocketConfigurer {
WebSSHWebSocketHandler
webSSHWebSocketHandler;
public
void
registerWebSocketHandlers(
WebSocketHandlerRegistry
webSocketHandlerRegistry) {
//socket通道
//指定处理器和路径
webSocketHandlerRegistry.
addHandler(
webSSHWebSocketHandler,
"/api/v1/webssh")
.
addInterceptors(
new
WebSocketInterceptor())
.
setAllowedOrigins(
"*");
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
3.处理器(Handler)和拦截器(Interceptor)的实现
3.1WebSSHWebSocketHandler.java
public
class
WebSSHWebSocketHandler
implements
WebSocketHandler {
private
WebSSHService
webSSHService;
private
Logger
logger
=
LoggerFactory.
getLogger(
WebSSHWebSocketHandler.
class);
private
static
boolean
bRunFlag;
private
static
List
<
AppInfo
>
appInfo;
public
void
afterConnectionEstablished(
WebSocketSession
webSocketSession)
throws
Exception {
logger.
info(
"用户:{},连接WebSSH",
webSocketSession.
getAttributes().
get(
ConstantPool.
USER_UUID_KEY));
//调用初始化连接
webSSHService.
initConnection(
webSocketSession);
}
public
void
close(){
bRunFlag
=
false;
}
/**
* @Description: 收到消息的回调
* @Param: [webSocketSession, webSocketMessage]
* @return: void
* @Author:
* @Date: 2020/8/10
*/
public
void
handleMessage(
WebSocketSession
webSocketSession,
WebSocketMessage
<?>
webSocketMessage)
throws
Exception {
if (
webSocketMessage
instanceof
TextMessage) {
logger.
info(
"用户:{},发送命令:{}",
webSocketSession.
getAttributes().
get(
ConstantPool.
USER_UUID_KEY),
webSocketMessage.
toString());
//调用service接收消息
webSSHService.
recvHandle(((
TextMessage)
webSocketMessage).
getPayload(),
webSocketSession);
}
else
if (
webSocketMessage
instanceof
BinaryMessage) {
}
else
if (
webSocketMessage
instanceof
PongMessage) {
}
else {
System.
out.
println(
"Unexpected WebSocket message type: "
+
webSocketMessage);
}
}
/**
* @Description: 出现错误的回调
* @Param: [webSocketSession, throwable]
* @return: void
* @Author:
* @Date: 2020/8/10
*/
public
void
handleTransportError(
WebSocketSession
webSocketSession,
Throwable
throwable)
throws
Exception {
logger.
error(
"数据传输错误:"
+
throwable.
getMessage());
}
/**
* @Description: 连接关闭的回调
* @Param: [webSocketSession, closeStatus]
* @return: void
* @Author:
* @Date: 2020/8/10
*/
public
void
afterConnectionClosed(
WebSocketSession
webSocketSession,
CloseStatus
closeStatus)
throws
Exception {
logger.
info(
"用户:{}断开webssh连接",
String.
valueOf(
webSocketSession.
getAttributes().
get(
ConstantPool.
USER_UUID_KEY)));
//调用service关闭连接
webSSHService.
close(
webSocketSession);
}
public
boolean
supportsPartialMessages() {
return
false;
}
}
- 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.
3.2WebSocketInterceptor.java
public
class
WebSocketInterceptor
implements
HandshakeInterceptor {
public
boolean
beforeHandshake(
ServerHttpRequest
serverHttpRequest,
ServerHttpResponse
serverHttpResponse,
WebSocketHandler
webSocketHandler,
Map
<
String,
Object
>
map)
throws
Exception {
if (
serverHttpRequest
instanceof
ServletServerHttpRequest) {
ServletServerHttpRequest
request
= (
ServletServerHttpRequest)
serverHttpRequest;
//生成一个UUID
String
uuid
=
UUID.
randomUUID().
toString().
replace(
"-",
"");
//将uuid放到websocketsession中
map.
put(
ConstantPool.
USER_UUID_KEY,
uuid);
return
true;
}
else {
return
false;
}
}
public
void
afterHandshake(
ServerHttpRequest
serverHttpRequest,
ServerHttpResponse
serverHttpResponse,
WebSocketHandler
webSocketHandler,
Exception
e) {
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
4.WebSSH的业务逻辑实现(核心)
4.1WebSSHService.java
public
interface
WebSSHService {
public
void
setAppMap(
Map
<
String,
Map
<
String,
Object
>>
map);
public
Map
<
String,
Map
<
String,
Object
>>
getAppMap();
public
void
handleMsg (
PushMessage
message);
public
void
setSwitch();
/**
* @Description: 初始化ssh连接
* @Param:
* @return:
* @Author:
* @Date:
*/
public
void
initConnection(
WebSocketSession
session);
/**
* @Description: 处理客户段发的数据
* @Param:
* @return:
* @Author:
* @Date:
*/
public
void
recvHandle(
String
buffer,
WebSocketSession
session);
/**
* @Description: 数据写回前端 for websocket
* @Param:
* @return:
* @Author:
* @Date:
*/
public
void
sendMessage(
WebSocketSession
session,
byte[]
buffer)
throws
IOException;
/**
* @Description: 关闭连接
* @Param:
* @return:
* @Author:
* @Date:
*/
public
void
close(
WebSocketSession
session);
}
- 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.
public
void
sendMessage(
WebSocketSession
session,
byte[]
buffer)
throws
IOException {
session.
sendMessage(
new
TextMessage(
buffer));
}
public
void
close(
WebSocketSession
session) {
String
userId
=
String.
valueOf(
session.
getAttributes().
get(
ConstantPool.
USER_UUID_KEY));
SSHConnectInfo
sshConnectInfo
= (
SSHConnectInfo)
sshMap.
get(
userId);
if (
sshConnectInfo
!=
null) {
//断开连接
if (
sshConnectInfo.
getChannel()
!=
null)
{
sshConnectInfo.
getChannel().
disconnect();
}
//map中移除
sshMap.
remove(
userId);
}
}
/**
* @Description: 将消息转发到终端
* @Param: [channel, data]
* @return: void
* @Author:
* @Date:
*/
private
void
transToSSH(
Channel
channel,
String
command)
throws
IOException {
if (
channel
!=
null) {
OutputStream
outputStream
=
channel.
getOutputStream();
outputStream.
write(
command.
getBytes());
outputStream.
flush();
}
}
public
void
recvHandle(
String
buffer,
WebSocketSession
session) {
ObjectMapper
objectMapper
=
new
ObjectMapper();
WebSSHData
webSSHData
=
null;
try {
webSSHData
=
objectMapper.
readValue(
buffer,
WebSSHData.
class);
if(
null
==
webSSHData
||
null
==
webSSHData.
getAppId()){
logger.
error(
"传入数据为空或没有传appId");
session.
sendMessage(
new
TextMessage(
"传入数据为空或没有传appId"));
return;
}
}
catch (
IOException
e) {
logger.
error(
"Json转换异常");
logger.
error(
"异常信息:{}",
e.
getMessage());
return;
}
String
appId
=
webSSHData.
getAppId();
if(
StringUtils.
isEmpty(
appId)){
close(
session);
}
//设置appId
bRunFlag
=
true;
while (
bRunFlag){
//前端关闭会话、应该退出
if(
null
==
session
||
!
session.
isOpen()){
break;
}
//收到消息不用sleep
try{
if(
bReceiveFlag){
if(
null
!=
appMap.
get(
appId)){
sendMsg(
session,
appId);
}
bReceiveFlag
=
false;
}
else{
if(
null
!=
appMap.
get(
appId)){
sendMsg(
session,
appId);
}
Thread.
sleep(
5000);
}
}
catch (
IOException
e){
e.
printStackTrace();
}
catch (
InterruptedException
e) {
e.
printStackTrace();
}
}
//TODO
}
- 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.