最终测试,页面就是下面这个样子:

可以看到页面已经出现了类似与shell的样式,那就根据这个继续深入,实现一个webssh。
后端实现
由于xterm只要只是实现了前端的样式,并不能真正地实现与服务器交互,与服务器交互主要还是靠我们Java后端来进行控制的,所以我们从后端开始,使用jsch+websocket实现这部分内容。
WebSocket配置
由于消息实时推送到前端需要用到WebSocket,不了解WebSocket的同学可以先去自行了解一下,这里就不过多介绍了,我们直接开始进行WebSocket的配置。
/**
* @Description: websocket配置
* @Author: NoCortY
* @Date: 2020/3/8
*/
@Configuration
@EnableWebSocket
public class WebSSHWebSocketConfig implements WebSocketConfigurer{
@Autowired
WebSSHWebSocketHandler webSSHWebSocketHandler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
//socket通道
//指定处理器和路径,并设置跨域
webSocketHandlerRegistry.addHandler(webSSHWebSocketHandler, "/webssh")
.addInterceptors(new WebSocketInterceptor())
.setAllowedOrigins("*");
}
}
处理器(Handler)和拦截器(Interceptor)的实现
刚才我们完成了WebSocket的配置,并指定了一个处理器和拦截器。所以接下来就是处理器和拦截器的实现。
拦截器:
public class WebSocketInterceptor implements HandshakeInterceptor {
/**
* @Description: Handler处理前调用
* @Param: [serverHttpRequest, serverHttpResponse, webSocketHandler, map]
* @return: boolean
* @Author: NoCortY
* @Date: 2020/3/1
*/
@Override
public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {
if (serverHttpRequest instanceof ServletServerHttpRequest) {
ServletServerHttpRequest request = (ServletServerHttpRequest) serverHttpRequest;
//生成一个UUID,这里由于是独立的项目,没有用户模块,所以可以用随机的UUID
//但是如果要集成到自己的项目中,需要将其改为自己识别用户的标识
String uuid = UUID.randomUUID().toString().replace("-","");
//将uuid放到websocketsession中
map.put(ConstantPool.USER_UUID_KEY, uuid);
return true;
} else {
return false;
}
}
@Override
public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {
}
}
处理器:
/**
* @Description: WebSSH的WebSocket处理器
* @Author: NoCortY
* @Date: 2020/3/8
*/
@Component
public class WebSSHWebSocketHandler implements WebSocketHandler{
@Autowired
private WebSSHService webSSHService;
private Logger logger = LoggerFactory.getLogger(WebSSHWebSocketHandler.class);
/**
* @Description: 用户连接上WebSocket的回调
* @Param: [webSocketSession]
* @return: void
* @Author: Object
* @Date: 2020/3/8
*/
@Override
public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
logger.info("用户:{},连接WebSSH", webSocketSession.getAttributes().get(ConstantPool.USER_UUID_KEY));
//调用初始化连接
webSSHService.initConnection(webSocketSession);
}
/**
* @Description: 收到消息的回调
* @Param: [webSocketSession, webSocketMessage]
* @return: void
* @Author: NoCortY
* @Date: 2020/3/8
*/
@Override
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: Object
* @Date: 2020/3/8
*/
@Override
public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
logger.error("数据传输错误");
}
/**
* @Description: 连接关闭的回调
* @Param: [webSocketSession, closeStatus]
* @return: void
* @Author: NoCortY
* @Date: 2020/3/8
*/
@Override
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);
}
@Override
public boolean supportsPartialMessages() {
return false;
}
}










