最近在项目中有一个场景,在内网的应用需要接受外网应用的指令。有两种解决方案:
1.内网应用轮询外网应用,http请求指令
2.内网应用与外网应用之间建立websocket长连接
记录一下websocket server/client的java实现
一、websocket server
@Configuration
public class WebSocketConfig extends Configurator
{
/**
* 日志
*/
private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketConfig.class);
/**
* 首先要注入ServerEndpointExporter,这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint。
* 要注意,如果使用独立的servlet容器,而不是直接使用springboot的内置容器,就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理。
*
* @return ServerEndpointExporter
*/
@Bean
public ServerEndpointExporter serverEndpointExporter()
{
return new ServerEndpointExporter();
}
@Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request,
HandshakeResponse response)
{
/* 如果没有监听器,那么这里获取到的HttpSession是null */
StandardSessionFacade ssf = (StandardSessionFacade)request.getHttpSession();
if (ssf != null)
{
HttpSession httpSession = (HttpSession)request.getHttpSession();
// 关键操作
sec.getUserProperties().put("sessionId", httpSession.getId());
LOGGER.debug("获取到的SessionID:" + httpSession.getId());
}
}
}
@Component
@ServerEndpoint(value = "/ws/{userId}")
public class WebSocketServer
{
/**
* 日志
*/
private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServer.class);
// 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
// concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
// 保存允许建立连接的id
private static List<String> idList = Lists.newArrayList();
private String id = "";
// 与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
/**
* <关闭连接>
*
* @param userId userId
* @throws
*/
public void closeConn(String userId)
{
// 关闭连接
try
{
WebSocketServer socket = webSocketMap.get(userId);
if (null != socket)
{
if (socket.session.isOpen())
{
socket.session.close();
}
}
}
catch (IOException e)
{
LOGGER.error("error, cause: ", e);
}
webSocketMap.remove(userId);
idList.remove(userId);
}
/**
* <连接/注册时去重>
*
* @param userId userId
* @throws
*/
public void conn(String userId)
{
// 去重
if (!idList.contains(userId))
{
idList.add(userId);
}
}
/**
* <获取注册在websocket进行连接的id>
*
* @return 结果
* @throws
*/
public static List<String> getIdList()
{
return idList;
}
/**
* <初始化方法>
*
* @throws
*/
@PostConstruct
public void init()
{
try
{
/**
* TODO 这里的设计是在项目启动时从DB或者缓存中获取注册了允许建立连接的id
*/
// TODO 初始化时将刚注入的对象进行静态保存
}
catch (Exception e)
{
// TODO 项目启动错误信息
LOGGER.error("error, cause: ", e);
}
}