SpringBoot整合WebSocket(获取客户端真实ip)
遇到”后台推送“之类的需求,自然是躲不开websocket了。这一次遇到的需求有点特殊,客户端的ip是固定,需要根据客户端的ip来分辨具体是哪个客户端。
不过,为了方便以后使用,我也列一下另一种获取连接用户身份的方式——url参数。
有一点要格外注意,如果你的项目加了拦截器,或者用了security之类的安全框架,需要对websocket的路径放行,否则会一直报连接失败。
目录
依赖
配置文件
主类
方案一:URL鉴权
方案二:ip鉴权
1、定义一个拦截器
2、定义 WebSocketConfigurator
3、定义主体类
4、拦截器扫描
依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>2.4.5</version></dependency>
配置文件
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}
主类
主类管理websocket的连接,下面给出两种方案:
方案一:URL鉴权
下面的userNo在实际项目中可以换成token,在onOpen中做鉴权操作。
@Slf4j
@Component
@ServerEndpoint(value = "/websocket/{userNo}")
public class WebSocketServer {private static int onlineCount = 0;private static ConcurrentHashMap<String, WebSocketServer> serverMap = new ConcurrentHashMap<>();private Session session;private String userNo;@OnOpenpublic void onOpen(Session session, @PathParam("userNo") String userNo) {this.session = session;this.userNo = userNo;if(serverMap.containsKey(userNo)) {serverMap.remove(userNo);serverMap.put(userNo, this);}else {serverMap.put(userNo, this);addOnlineCount();log.info(userNo + ",已上线!");}}/*** 服务器接收客户端发来的消息* @param message 消息* @param session 会话session*/@OnMessagepublic void onMessage(String message, Session session) {log.info("服务器收到了用户" + userNo + "发来的消息:" + message);}/*** 服务器主动发送消息* @param message 消息*/public void sendMessage(String message){try {this.session.getBasicRemote().sendText(message);} catch (IOException e) {log.error(e.getMessage());}}/*** 获取在线人数* @return 在线人数*/public static int getOnlineCount() {return onlineCount;}@OnClosepublic void onClose() {if(serverMap.containsKey(userNo)) {serverMap.remove(userNo);subOnlineCount();log.info(userNo + ",已下线!");}}@OnErrorpublic void onError(Session session, Throwable throwable) {log.error("用户" + userNo + "发生了错误,具体如下:" + throwable.getMessage());}private static synchronized void subOnlineCount() {onlineCount--;}public static synchronized void addOnlineCount() {onlineCount++;}public static WebSocketServer get(String userNo) {return serverMap.get(userNo);}public static ConcurrentHashMap<String, WebSocketServer> getMap() {return serverMap;}public static boolean isOnline(String userNo) {return serverMap.containsKey(userNo);}
}
方案二:ip鉴权
适用于内网环境,且主机数固定、ip固定的场合。
WebSocket只是一种协议,实现这种协议的方式有很多种。
我们用的这个starter是无法直接获取客户端ip的,网上也有人很多人用的是netty-websocket-xx 包,这包提供了api用于获取客户端的ip。
换包太麻烦了,即使是在不换包的前提下,我们也可以解决这个问题。
1、定义一个拦截器
此拦截器用于获取ip,并放入session中
@javax.servlet.annotation.WebFilter(filterName = "sessionFilter",urlPatterns = "/*")
@Order(1)
public class WebFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest req= (HttpServletRequest) servletRequest;req.getSession().setAttribute("ip",req.getRemoteHost());filterChain.doFilter(servletRequest,servletResponse);}
}
2、定义 WebSocketConfigurator
用于将客户端的ip传递给websocket中的session,相当于是一个中介
public class WebSocketConfigurator extends ServerEndpointConfig.Configurator {public static final String IP_ADDR = "IP.ADDR";@Overridepublic void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {Map<String, Object> attributes = sec.getUserProperties();HttpSession session = (HttpSession) request.getHttpSession();if (session != null) {attributes.put(IP_ADDR, session.getAttribute("ip"));Enumeration<String> names = session.getAttributeNames();while (names.hasMoreElements()) {String name = names.nextElement();attributes.put(name, session.getAttribute(name));}}}
}
3、定义主体类
主体类用于管理websocket连接,并配置configurator
@Slf4j
@Component
@ServerEndpoint(value = "/websocket",configurator = WebSocketConfigurator.class)
public class WebSocketServer {private static int onlineCount = 0;private static ConcurrentHashMap<String, WebSocketServer> serverMap = new ConcurrentHashMap<>();private Session session;private String ipAddr;@OnOpenpublic void onOpen(Session session) {this.session = session;Map<String, Object> userProperties = session.getUserProperties();this.ipAddr = (String) userProperties.get(WebSocketConfigurator.IP_ADDR);if(serverMap.containsKey(this.ipAddr)) {serverMap.remove(this.ipAddr);serverMap.put(this.ipAddr, this);}else {serverMap.put(this.ipAddr, this);addOnlineCount();log.info(this.ipAddr + ",已上线!");}}/*** 服务器接收客户端发来的消息* @param message 消息* @param session 会话session*/@OnMessagepublic void onMessage(String message, Session session) {log.info("服务器收到了用户" + ipAddr + "发来的消息:" + message);//方便前端测试sendMessage("服务器收到了用户" + ipAddr + "发来的消息:" + message);}/*** 给ip地址为ipAddr的客户端发送消息* @param ipAddr ip地址* @param message 消息*/public static void sendMessage(String ipAddr, String message) {if(serverMap.containsKey(ipAddr)) {WebSocketServer webSocketServer = serverMap.get(ipAddr);webSocketServer.sendMessage(message);}else {log.error("发送失败,客户端未连接: " + ipAddr);}}/*** 服务器主动发送消息* @param message 消息*/public void sendMessage(String message){try {this.session.getBasicRemote().sendText(message);} catch (IOException e) {log.error(e.getMessage());}}/*** 获取在线人数* @return 在线人数*/public static int getOnlineCount() {return onlineCount;}@OnClosepublic void onClose() {if(serverMap.containsKey(ipAddr)) {serverMap.remove(ipAddr);subOnlineCount();log.info(ipAddr + ",已下线!");}}@OnErrorpublic void onError(Session session, Throwable throwable) {log.error("用户" + ipAddr + "发生了错误,具体如下:" + throwable.getMessage());}private static synchronized void subOnlineCount() {onlineCount--;}public static synchronized void addOnlineCount() {onlineCount++;}public static WebSocketServer get(String ipAddr) {return serverMap.get(ipAddr);}public static ConcurrentHashMap<String, WebSocketServer> getMap() {return serverMap;}public static boolean isOnline(String ipAddr) {return serverMap.containsKey(ipAddr);}}
4、拦截器扫描
如果只有上面的代码,会出现tomcat session获取不到的情况,因为拦截器没有生效。
在SpringBoot启动类上加一个注解@ServletComponentScan:
@EnableScheduling
@SpringBootApplication
@ServletComponentScan("拦截器所在的包名")
public class WmsServerApplication {public static void main(String[] args) {SpringApplication.run(WmsServerApplication.class, args);}}
SpringBoot整合WebSocket(获取客户端真实ip)相关推荐
- 获取客户端真实IP地址
Java-Web获取客户端真实IP: 发生的场景:服务器端接收客户端请求的时候,一般需要进行签名验证,客户端IP限定等情况,在进行客户端IP限定的时候,需要首先获取该真实的IP. 一般分为两种情况: ...
- Java正确获取客户端真实IP方法整理
转载自 干货:Java正确获取客户端真实IP方法整理 在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的.但是在通过了Apach ...
- vue获取url中ip_Kubernetes 集群中这样获取客户端真实 IP
Kubernetes 依靠 kube-proxy 组件实现 Service 的通信与负载均衡.在这个过程中,由于使用了 SNAT 对源地址进行了转换,导致 Pod 中的服务拿不到真实的客户端 IP 地 ...
- 获取客户端真实 IP
Tomcat + Nginx 反向代理获取客户端真实IP.域名.协议.端口 Nginx 反向代理后,Servlet 应用通过 request.getRemoteAddr() 取到的 IP 是 Ngin ...
- 获取客户端真实ip的方法
为什么需要获取客户端真实ip ip地址是按地域分布的,服务器获取到客户端ip后可以做流量统计和分析,服务器也可以针对客户端ip做一些定制化的功能,比如限流和黑白名单. 网络环境十分复杂,客户端发出的一 ...
- 获取客户端真实IP方法
2019独角兽企业重金招聘Python工程师标准>>> 我们经常会记录审计日志,那么如何获取客户端真实IP呢?让我们了解一下HTTP协议头吧. 在讨论获取客户端IP 地址前,我们首先 ...
- 如何获取客户端真实 IP?从 Gin 的一个 Bug 说起
1. 背景 请求 IP 作为用户的身份标识属性之一,是一种非常重要的基础数据.在很多场景下,我们会基于客户端请求 IP 去做网络安全攻击防范或访问风险控制.通常我们可以通过 HTTP 协议 Reque ...
- PHP获取客户端真实IP地址的方法
php获取客户端IP地址有四种方法,这五种方法分别为 1 2 3 4 REMOTE_ADDR HTTP_CLIENT_IP HTTP_X_FORWARDED_FOR HTTP_VIA REMOTE_A ...
- asp.net如何获取客户端真实IP地址
目前网上流行的所谓"取真实IP地址"的方法,都有bug,没有考虑到多层透明代理的情况. 多数代码类似: string IpAddress = (HttpContext.Curren ...
最新文章
- Windump网络命令的简单用法
- JSON字符串key缺少双引号的解决方法
- php html5 css样式,怎么在html页面写css样式表
- 【机器学习基础】数学推导+纯Python实现机器学习算法15:GBDT
- python sort()、sorted()
- tensorflow之安装tensorboard
- Jmeter4.0---- HTTP请求默认值(14)
- 【深度学习笔记】个人阅读的Deep Learning方向的paper整理
- 哔哩哔哩用户需求分析报告
- Python 人脸表情识别
- Logstash详解之——input模块
- 区分微信开发平台和公众平台(小程序)
- 林炳文Evankaka原创作品之mybatis的增删改查简单操作
- 数据结构与算法分析java语言描述 严蔚敏翻译_重读数据结构——严蔚敏C语言版...
- Java 之未支付订单30分钟后自动取消
- 两大Mac内存清理方法,嫌麻烦的就直接使用第二种
- vue-cli Webpack之Loader原理及自定义Loader
- 2022-2027年中国房产网络服务行业市场全景评估及发展战略规划报告
- 立体像对空间前方交会(利用外方位元素交会出地面点三维坐标)
- CentOS 7 中Tomcat7注册成服务
热门文章
- 艾永亮:快时尚市场格局,超级产品战略成优衣库持续增长的杀手锏
- 深度学习射频干扰检测网络:Deep residual detection of Radio Frequency Interferencefor FAST
- 什么是Windows服务
- 《C++捷径教程》读书笔记--Chapter 10--结构与联合
- 系统交互流程-订单支付-支付流程-JAVA实战演示
- 自考本科和全日制本科有什么区别?
- 基因数据处理47之ART基因序列数据生成器(仿真)
- 旅游类小程序的优势将带来怎样的旅游体验
- 如何让SPRO配置页面中显示对应的事务代码
- 怎么把tif文件转成jpg?试试这几招吧!值得收藏