SpringBoot整合Netty4並實現JSON字串的解析處理
阿新 • • 發佈:2019-01-11
一、maven配置
<!-- springboot版本 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath />
</parent>
<!-- 設定編碼及版本號 -->
<properties >
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!--預設關掉單元測試 -->
<skipTests>true</skipTests>
<fastjson.version>1.2.31</fastjson.version >
<netty.version>4.1.6.Final</netty.version>
</properties>
<!-- 依賴 -->
<dependencies>
<!-- web專案必要的依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId >
</dependency>
<!-- 熱啟動devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
<scope>true</scope>
</dependency>
<!-- alibaba fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- netty -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>${netty.version}</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<!-- 支援devtools -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- 沒有該配置,devtools不生效 -->
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
二、netty服務端編寫
NettyServer
/**
* netty服務端 . <br>
*
* @author hkb
*/
@Component
public class NettyServer {
/**
* 日誌
*/
private Logger log = LoggerFactory.getLogger(getClass());
/**
* 埠號
*/
@Value("${netty.port}")
private int port;
/**
* 啟動伺服器方法
*
* @param port
*/
public void run() {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup);
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024);
serverBootstrap.handler(new LoggingHandler(LogLevel.INFO));
serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true);
serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
serverBootstrap.childHandler(new NettyServerInitializer());
// 繫結埠,開始接收進來的連線
ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
log.info("netty服務啟動: [port:" + port + "]");
// 等待伺服器socket關閉
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
log.error("netty服務啟動異常-" + e.getMessage());
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
NettyServerInitializer
/**
* 服務端初始化 . <br>
*
* @author hkb
*/
public class NettyServerInitializer extends ChannelInitializer<SocketChannel> {
/**
* 初始化channel
*/
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new NettyServerHandler());
}
}
NettyServerHandler
/**
* 服務端處理器 . <br>
*
* @author hkb
*/
public class NettyServerHandler extends SimpleChannelInboundHandler<String> {
/**
* 日誌
*/
private Logger log = LoggerFactory.getLogger(getClass());
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
StringBuilder sb = null;
Map<String, Object> result = null;
try {
// 報文解析處理
sb = new StringBuilder();
result = JSON.parseObject(msg);
sb.append(result);
sb.append("解析成功");
sb.append("\n");
ctx.writeAndFlush(sb);
} catch (Exception e) {
String errorCode = "-1\n";
ctx.writeAndFlush(errorCode);
log.error("報文解析失敗: " + e.getMessage());
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
String clientIp = insocket.getAddress().getHostAddress();
log.info("收到客戶端[ip:" + clientIp + "]連線");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// 當出現異常就關閉連線
ctx.close();
}
}
三、配置netty隨tomcat啟動
/**
* netty服務監聽器 . <br>
*
* @author hkb
*/
@WebListener
public class NettyServerListener implements ServletContextListener {
/**
* 注入NettyServer
*/
@Autowired
private NettyServer nettyServer;
@Override
public void contextInitialized(ServletContextEvent sce) {
Thread thread = new Thread(new NettyServerThread());
// 啟動netty服務
thread.start();
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
/**
* netty服務啟動執行緒 . <br>
*
* @author hkb
*/
private class NettyServerThread implements Runnable {
@Override
public void run() {
nettyServer.run();
}
}
}
四、netty客戶端測試
NettyClient
/**
* netty客戶端 . <br>
*
* @author hkb
*/
public class NettyClient {
/**
* 主機
*/
private String host;
/**
* 埠號
*/
private int port;
/**
* 建構函式
*
* @param host
* @param port
*/
public NettyClient(String host, int port) {
this.host = host;
this.port = port;
}
/**
* 連線方法
*/
public void connect() {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group).channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.TCP_NODELAY, true);
// bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
bootstrap.handler(new NettyClientInitializer());
Channel channel = bootstrap.connect(host, port).sync().channel();
// 傳送json字串
String msg = "{\"name\":\"admin\",\"age\":27}\n";
channel.writeAndFlush(msg);
channel.closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}
/**
* 測試入口
*
* @param args
*/
public static void main(String[] args) {
String host = "127.0.0.1";
int port = 8088;
NettyClient nettyClient = new NettyClient(host, port);
nettyClient.connect();
}
}
NettyClientInitializer
/**
* 客戶端初始化 . <br>
*
* @author hkb
*/
public class NettyClientInitializer extends ChannelInitializer<SocketChannel> {
/**
* 初始化channel
*/
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new NettyClientHandler());
}
}
NettyClientHandler
/**
* 客戶端處理器 . <br>
*
* @author hkb
*/
public class NettyClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("收到服務端訊息: " + msg);
}
}