netty 入门 demo,基于 NettyController 注解 + json 的交互
1、添加数据包装器配置
这个配置是用来包装原始数据的,主要用来处理自定义协议或粘包拆包
package com.kfyty.netty.handler.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kfyty.netty.handler.HandlerDataWrapper;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class DataWrapper implements HandlerDataWrapper {
@Autowired
private ObjectMapper objectMapper;
@Override
@SneakyThrows
public Object wrap(Object source) {
return objectMapper.writeValueAsString(source) + NettyConfig.DELIMITER;
}
}
2、创建 netty 服务
package com.kfyty.netty.handler.server;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kfyty.netty.handler.codec.BaseHandlerModelDecoder;
import com.kfyty.netty.handler.config.NettyConfig;
import com.kfyty.netty.handler.handler.NettyDispatcherHandler;
import com.kfyty.netty.handler.handler.OnlineMonitorHandler;
import com.kfyty.netty.handler.handler.StringMessageHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;
import java.nio.charset.StandardCharsets;
import static com.kfyty.netty.handler.config.NettyConfig.DELIMITER;
import static com.kfyty.netty.handler.config.NettyConfig.PORT;
/**
* 描述:
*
* @author kfyty
* @date 2021/1/8 11:09
* @email kfyty725@hotmail.com
*/
@Slf4j
@Configuration
public class NettyServer implements CommandLineRunner, DisposableBean {
private final NioEventLoopGroup serverGroup;
private final NioEventLoopGroup clientGroup;
private final ServerBootstrap serverBootstrap;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private NettyDispatcherHandler nettyDispatcherHandler;
public NettyServer() {
this.serverGroup = new NioEventLoopGroup();
this.clientGroup = new NioEventLoopGroup();
this.serverBootstrap = new ServerBootstrap();
}
@Override
public void run(String... args) throws Exception {
serverBootstrap.group(serverGroup, clientGroup)
.channel(NioServerSocketChannel.class)
.childOption(ChannelOption.SO_SNDBUF, NettyConfig.DEFAULT_BUF)
.childOption(ChannelOption.SO_RCVBUF, NettyConfig.DEFAULT_BUF)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new DelimiterBasedFrameDecoder(NettyConfig.DEFAULT_BUF, Unpooled.copiedBuffer(DELIMITER.getBytes(StandardCharsets.UTF_8))));
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new StringEncoder());
ch.pipeline().addLast(new OnlineMonitorHandler());
ch.pipeline().addLast(new BaseHandlerModelDecoder(objectMapper));
ch.pipeline().addLast(nettyDispatcherHandler);
ch.pipeline().addLast(new StringMessageHandler());
log.info("IP:{} connected !", ch.remoteAddress());
}
})
.bind(PORT)
.sync();
}
@Override
public void destroy() throws Exception {
clientGroup.shutdownGracefully();
serverGroup.shutdownGracefully();
}
}
3、编写控制器
package com.kfyty.netty.handler.controller;
import com.kfyty.netty.handler.annotation.NettyController;
import com.kfyty.netty.handler.annotation.NettyMapping;
import com.kfyty.netty.handler.annotation.NettyParam;
import com.kfyty.netty.handler.model.UserModel;
import java.util.List;
@NettyController
@NettyMapping("netty")
public class HelloController {
@NettyMapping("test")
public String test(@NettyParam("name") String name) {
return "test: " + name;
}
@NettyMapping("hello")
public String hello(@NettyParam("names") List<String> names) {
return "hello: " + names;
}
@NettyMapping("user")
public String user(UserModel user, @NettyParam("userId") String userId) {
return "hello: " + userId + ":" + user.getUserName();
}
}
再加一个数据模型:
package com.kfyty.netty.handler.model;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class UserModel extends BaseHandlerModel {
private String userName;
}
最后启动服务端,客户端。
然后客户端发送:{“nettyPath”:"/netty/user",“userName”:“tom”,“userId”:123456}
那么客户端就可以随之收到回复啦:hello: 123456:tom