GithubHelp home page GithubHelp logo

twelvet-projects / netty-websocket-spring-boot-starter Goto Github PK

View Code? Open in Web Editor NEW
9.0 1.0 3.0 114 KB

(Based on Netty's WebSocket)基于Netty作为底层实现的Spring Boot Starter轻量级、高性能WebSocket框架,支持多端口,多路径,SSL,jdk >= 1.8 (兼容Spring Boot 3)

Home Page: https://twelvet.cn

License: Apache License 2.0

Java 100.00%
java netty spring-boot websocket

netty-websocket-spring-boot-starter's Introduction

中文 | English

netty-websocket-spring-boot-starter

It is a code refactoring and feature enhancement for the original netty-websocket-spring-boot-starter.

Thank you very much for the author's sharing of netty-websocket-spring-boot-starter.

AUR GitHub stars GitHub forks star fork

Introduction

Developing a WebSocket server using Netty in Spring Boot, with the simplicity and high performance of spring-websocket annotations.

Requirements

  • jdk >= 1.8 (compatible with jdk 17、21)

Quick Start

  • Add dependencies:
<dependency>
    <groupId>cn.twelvet</groupId>
    <artifactId>netty-websocket-spring-boot-starter</artifactId>
    <version>${version}</version>
</dependency>
  • Add the @WebSocketEndpoint annotation to the endpoint class, and add the @BeforeHandshake@OnOpen@OnClose@OnError@OnMessage@OnBinary and @OnEvent annotations to the respective methods. Here's an example:
  • Use @PathVariable to retrieve path parameters and @RequestParam to retrieve query parameters, both of which have the same effect as the corresponding Spring annotations (Note: Use the annotations provided by this framework, not Spring's annotations).
import cn.twelvet.websocket.netty.annotation.*;
import cn.twelvet.websocket.netty.domain.NettySession;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.timeout.IdleStateEvent;
import org.springframework.util.MultiValueMap;

import java.util.Map;

@WebSocketEndpoint(path = "/ws")
public class MyWebSocket {

    @BeforeHandshake
    public void handshake(NettySession nettySession, HttpHeaders headers, @RequestParam String req, @RequestParam MultiValueMap reqMap, @PathVariable String arg, @PathVariable Map pathMap) {
        nettySession.setSubprotocols("stomp");
        if (!"ok".equals(req)) {
            System.out.println("Authentication failed!");
            // nettySession.close();
        }
    }

    @OnOpen
    public void onOpen(NettySession nettySession, HttpHeaders headers, @RequestParam String req, @RequestParam MultiValueMap reqMap, @PathVariable String arg, @PathVariable Map pathMap) {
        System.out.println("new connection");
        System.out.println(req);
    }

    @OnClose
    public void onClose(NettySession nettySession) {
        System.out.println("one connection closed");
    }

    @OnError
    public void onError(NettySession nettySession, Throwable throwable) {
        throwable.printStackTrace();
    }

    @OnMessage
    public void onMessage(NettySession nettySession, String message) {
        System.out.println(message);
        nettySession.sendText("Hello Netty!");
    }

    @OnBinary
    public void onBinary(NettySession nettySession, byte[] bytes) {
        for (byte b : bytes) {
            System.out.println(b);
        }
        nettySession.sendBinary(bytes);
    }

    @OnEvent
    public void onEvent(NettySession nettySession, Object evt) {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
            switch (idleStateEvent.state()) {
                case READER_IDLE:
                    System.out.println("read idle");
                    break;
                case WRITER_IDLE:
                    System.out.println("write idle");
                    break;
                case ALL_IDLE:
                    System.out.println("all idle");
                    break;
                default:
                    break;
            }
        }
    }

}
  • Open the WebSocket client and connect to ws://127.0.0.1:80/ws/xxx

Multi Endpoint

  • base on Quick-Start,use annotation @WebSocketEndpoint in classes which hope to become a endpoint.
  • you can get all socket addresses in WebSocketEndpointExporter.getAddressWebsocketServerMap().
  • when there are different addresses(different host or different port) in WebSocket,they will use different ServerBootstrap instance.
  • when the addresses are the same,but path is different,they will use the same ServerBootstrap instance.
  • when multiple port of endpoint is 0 ,they will use the same random port
  • when multiple port of endpoint is the same as the path,host can't be set as "0.0.0.0",because it means it binds all of the addresses

Configure using application.properties.

All parameters can be obtained from the configuration in application.yml using ${...} placeholders. Here's an example::

  • First, use ${...} placeholders in the attributes of the @WebSocketEndpoint annotation.
@WebSocketEndpoint(host = "${ws.host}", port = "${ws.port}")
public class MyWebSocket {
    ...
}
  • Next, you can configure it in the application.yml file.
ws:
  host: 0.0.0.0
  port: 80

netty-websocket-spring-boot-starter's People

Contributors

twelvet-s avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

netty-websocket-spring-boot-starter's Issues

多个入参如何使用

`@BeforeHandshake
public void handshake(NettySession nettySession, HttpHeaders headers, @RequestParam String req, @RequestParam MultiValueMap reqMap, @PathVariable String arg, @PathVariable Map pathMap) {
nettySession.setSubprotocols("stomp");
if (!"ok".equals(req)) {
System.out.println("Authentication failed!");
// nettySession.close();
}
System.out.println(arg);
// onlineSessionMap.put()
}

@OnOpen
public void onOpen(NettySession nettySession, HttpHeaders headers, @RequestParam String req, @RequestParam MultiValueMap reqMap, @PathVariable String arg, @PathVariable Map pathMap) {
    System.out.println("new connection");
    System.out.println(req);
}`

这两个方法中@RequestParam String req 和 @PathVariable String arg 在什么情况下能收到值,我测试无论单个参数 还是多个参数都没有值

ws://127.0.0.1:9099/ws?aaa=bbbb&bbb=ccc @RequestParam MultiValueMap reqMap 接收不到

ws://127.0.0.1:9099/ws?aaa=bbbb&bbb=ccc @RequestParam MultiValueMap reqMap 接收不到
package com.dahuang.dragon.netty;

import com.dahuang.dragon.RedisUtil;
import com.dahuang.dragon.annotation.*;
import com.dahuang.dragon.domain.NettySession;
import io.netty.channel.ChannelId;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.timeout.IdleStateEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

@WebSocketEndpoint(path = "/ws",port = "9099")
@component
public class MyWebSocket {
@Autowired
private RedisUtil redisUtil;
private static final AtomicInteger OnlineCount = new AtomicInteger(0);
/**
* 链接的NettySession,需要进行心跳检测 在分布式下,记录NettySession在哪个机器上
* 在需要发送的时候通过机器IP,或者其他唯一特征进行发送即可完成分布式
*/
private final static Map<ChannelId, NettySession> sessionMap = new HashMap<>();
@BeforeHandshake
public void handshake(NettySession nettySession, HttpHeaders headers, @RequestParam String req, @RequestParam MultiValueMap reqMap, @PathVariable String arg, @PathVariable Map pathMap) {
nettySession.setSubprotocols("stomp");
if (!"ok".equals(req)) {
System.out.println("Authentication failed!");
// nettySession.close();
}
}

@OnOpen
public void onOpen(NettySession nettySession, HttpHeaders headers,  @RequestParam String req,@RequestParam MultiValueMap reqMap, @PathVariable String arg, @PathVariable Map pathMap) {
    System.out.println("new connection");
    ChannelId channelId = nettySession.id();
    //这里最好先校验下是否登录
    sessionMap.put(nettySession.id(), nettySession);
    //扫码连接开始同步商品信息
    redisUtil.hset(String.valueOf(reqMap.get("ableCodeId")),"1000","用户信息");
    for (Map.Entry<ChannelId, NettySession> channelIdNettySessionEntry : sessionMap.entrySet()) {
        ChannelId channelIdTemp = channelIdNettySessionEntry.getKey();
        NettySession session = channelIdNettySessionEntry.getValue();
        if (!channelIdTemp.equals(channelId)) {
            session.sendText("找到你了");
        } else {
            session.sendText("成功连接服务");
        }
    }

}

@OnClose
public void onClose(NettySession nettySession) {
    int cnt = OnlineCount.decrementAndGet();
    System.out.println("有连接关闭,当前连接数为:" + cnt);
    //这里要把Session从缓存中移除
    System.out.println("one connection closed");
}

@OnError
public void onError(NettySession nettySession, Throwable throwable) {
    throwable.printStackTrace();
}

@OnMessage
public void onMessage(NettySession nettySession, String message) {
    System.out.println(message);
    nettySession.sendText("Hello Netty!");
}

@OnBinary
public void onBinary(NettySession nettySession, byte[] bytes) {
    for (byte b : bytes) {
        System.out.println(b);
    }
    nettySession.sendBinary(bytes);
}

@OnEvent
public void onEvent(NettySession nettySession, Object evt) {
    if (evt instanceof IdleStateEvent) {
        IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
        switch (idleStateEvent.state()) {
            case READER_IDLE:
                System.out.println("read idle");
                break;
            case WRITER_IDLE:
                System.out.println("write idle");
                break;
            case ALL_IDLE:
                System.out.println("all idle");
                break;
            default:
                break;
        }
    }
}

}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.