使用纯Java实现一个WebSSH项目的示例代码

2020-03-13 18:02:03王冬梅

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

可以看到页面已经出现了类似与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;
 }
}