springboot项目中使用netty+websocket 实现消息推送(带校验用户是否登陆功能)

该博客介绍了如何在SpringBoot项目中结合Netty和WebSocket实现消息推送功能,并添加了用户登录验证的机制。首先,通过Maven引入相关依赖,然后创建Netty服务器启动类。在WebSocket处理器中,对连接地址进行处理,去除携带的登录参数以避免通道自动断开。当WebSocket握手成功后,检查用户是否已登录,未登录则关闭连接。同时,定义了WebSocket权限校验实体类和全局ChannelGroup,用于存储Channel以便广播消息。
摘要由CSDN通过智能技术生成

maven 引入包:

<!--    websocket    -->
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.36.Final</version>
</dependency>

 netty 启动server类:

package com.minivision.user.manage.websocket;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.stream.ChunkedWriteHandler;

/**
 * webSocket启动server <br>
 * 
 * @author yangxiaodong<br>
 * @version 1.0<br>
 * @taskId <br>
 * @CreateDate 2019年7月22日 <br>
 */

@Component
public class NettyServer {
    /**
     * 调测日志
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketHandler.class);

    /**
     * websocket协议名 <br>
     */
    private static final String WEBSOCKET_PROTOCOL = "WebSocket";

    /**
     * 端口号 <br>
     */
    @Value("${websocket.netty.port:58080}")
    private int port;

    /**
     * wesocket路径 <br>
     */
    @Value("${websocket.netty.path:/websocket}")
    private String websocketPath;

    /**
     * websokcet处理器 <br>
     */
    @Autowired
    private WebSocketHandler webSocketHandler;

    /**
     * permissionWebSocketHandler <br>
     */
    @Autowired
    private PermissionWebSocketHandler permissionWebSocketHandler;

    /**
     * bossGroup <br>
     */
    private EventLoopGroup bossGroup;

    /**
     * parentGroup <br>
     */
    private EventLoopGroup group;

    /**
     * 启动: <br>
     * 
     * @author yangxiaodong<br>
     * @throws InterruptedException
     * @taskId <br>
     * @throws InterruptedException <br>
     */
    @PostConstruct
    public void start() throws InterruptedException {
        bossGroup = new NioEventLoopGroup();
        group = new NioEventLoopGroup();
        ServerBootstrap sb = new ServerBootstrap();
        sb.option(ChannelOption.SO_BACKLOG, 1024);// 配置TCP参数,握手字符串长度设置
        sb.group(group, bossGroup) // group辅助客户端的tcp连接请求 bossGroup负责与客户端之前的读写操作
                .channel(NioServerSocketChannel.class) // 配置客户端的channel类型
                .localAddress(this.port)// 绑定监听端口
                .childHandler(new ChannelInitializer<SocketChannel>() { // 绑定客户端连接时候触发操作
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        // websocket协议本身是基于http协议的,所以这边也要使用http解编码器
                        ch.pipeline().addLast(new HttpServerCodec());
                        ch.pipeline().addLast(new ObjectEncoder());
                        // 以块的方式来写的处理器
                        ch.pipeline().addLast(new ChunkedWriteHandler());
                        ch.pipeline().addLast(new HttpObjectAggregator(8192));
                        ch.pipeline().addLast(permissionWebSocketHandler);
                        ch.pipeline().addLast(new WebSocketServerProtocolHandler(websocketPath, WEBSOCKET_PROTOCOL, true, 65536 * 10));
                        ch.pipeline().addLast(webSocketHandler);
                    }
                });
        // 服务器异步创建绑定
        sb.bind().sync();
        LOGGER.info("websocket server start");
    }

    /**
     * 释放线程池资源: <br>
     * 
     * @author yangxiaodong<br>
     * @taskId <br>
     * @throws InterruptedException <br>
     */
    @PreDestroy
    private void destory() throws InterruptedException {
        if (null != bossGroup) {
            bossGroup.shutdownGracefully().sync();
        }
        if (null != group) {
            group.shutdownGracefully().sync();
        }
    }
}

 用户登陆验证码处理器:

通过ws后面携带的参数,进行用户登陆校验,

思路:获取到ws参数后,处理连接地址,把携带的参数去掉,否则,channel会自动断开的

package com.minivision.user.manage.websocket;

import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.minivision.user.manage.util.UrlUtil;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;

/**
 * websocket 用户登陆验证码处理器 <br>
 * 
 * @author yangxiaodong<br>
 * @version 1.0<br>
 * @taskId <br>
 * @CreateDate 2019年8月1日 <br>
 */
@Component
@Sharable
public class PermissionWebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    /**
     * 调测日志
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(PermissionWebSocketHandler.class);

    /**
     * wesocket路径 <br>
     */
    @Value("${websocket.netty.path:/websocket}")
    private String websocketPath;

    /**
     * 重新方法,获取url中参数,进行权限验证: <br>
     * 
     * @author yangxiaodong<br>
     * @taskId <br>
     * @param ctx 上下文
     * @param msg 参数
     * @throws Exception 异常<br>
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanc
  • 13
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值