银行对接的保险类项目,需要使用socket协议来做接口的对接,于是就想到了netty
- 构建netty服务端
/**
* netty服务端
* 1.创建一个serverBootstrap的实例引导和绑定服务器
* 2.创建并分配一个NioEventLoopGroup实例以进行事件的处理,比如接受连接以及读写数据
* 3.指定服务器绑定的本地的InetSocketAddress
* 4.使用一个EchoServerHandler的实例初始化每一个新的Channel
* 5.调用ServerBootstrap.bind()方法以绑定服务器
*
* @auther quanming
* @Date 2019/9/26 9:16
*/
@Slf4j
@Component
public class EchoServer {
/**
* NioEventLoop并不是一个纯粹的I/O线程,它除了负责I/O的读写之外
* 创建了两个NioEventLoopGroup,
* 它们实际是两个独立的Reactor线程池。
* 一个用于接收客户端的TCP连接,
* 另一个用于处理I/O相关的读写操作,或者执行系统Task、定时任务Task等。
*/
private final EventLoopGroup bossGroup = new NioEventLoopGroup();
private final EventLoopGroup workerGroup = new NioEventLoopGroup();
private Channel channel;
@Autowired
private ServerChannelInitializer serverChannelInitializer;
public ChannelFuture start(String host,int port)throws Exception{
ChannelFuture channelFuture = null;
try {
// 服务端启动引导工具类
ServerBootstrap b = new ServerBootstrap();
// 组装NioEventLoopGroup
b.group(bossGroup,workerGroup)
// 设置channel类型为NIO类型
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(host,port))
// 配置入站、出站事件handler
.childHandler(serverChannelInitializer)
// 设置连接配置参数
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
// 绑定端口 接收进来的链接
channelFuture = b.bind().sync();
channel = channelFuture.channel();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
if (channelFuture != null && channelFuture.isSuccess()) {
log.info("Netty server listening " + host + " on port " + port + " and ready for connections...");
} else {
log.error("Netty server start up Error!");
}
}
return channelFuture;
}
}
- 构建编码器,解码器
- 编码器
/**
* 消息编码器 返回的消息进行编码
*
* @auther quanming
* @Date 2019/9/29 17:09
*/
public class MyMessageEncoder extends MessageToByteEncoder<NettyMessageVO> {
/** 报文标识 **/
private static final int MSG_SIGN = 4;
/** 交易代码 **/
private static final int TRANS_CODE = 4;
/** 交易流水号 **/
private static final int TRANS_NO = 21;
/** 报文体 **/
private static final int XML_CONTEXT = 8;
@Override
protected void encode(ChannelHandlerContext ctx, NettyMessageVO msg, ByteBuf out) throws Exception {
int packageLen = MSG_SIGN + TRANS_CODE + TRANS_NO + XML_CONTEXT + msg.getXmlContext().getBytes().length;
ByteBuffer bf = ByteBuffer.allocate(packageLen);
// 报文标示
bf.put(msg.getMsgSign().getBytes(CharsetUtil.UTF_8));
// 交易代码
BeanPropertiesConfig beanPropertiesConfig = SpringBeanUtils.getBean("beanPropertiesConfig");
bf.put(beanPropertiesConfig.getTransCodeMap().get(msg.getTransCode()).getBytes(CharsetUtil.UTF_8));
// 交易流水号
bf.put(msg.getTransNo().getBytes(CharsetUtil.UTF_8));
// 报文体长度 8个字节 不够则采取左补0机制
bf.put(String.format("%08d",msg.getXmlContext().getBytes().length).getBytes(CharsetUtil.UTF_8));
// 报文体
bf.put(msg.getXmlContext().getBytes(CharsetUtil.UTF_8));
bf.flip();
byte[] bytes = new byte[bf.limit()];
bf.get(bytes);
out.writeBytes(bytes);
}
}
- 解码器-1
/**
*
* 消息解码器, 请求的消息进行解码
*
* maxFrameLength:最大帧长度。也就是可以接收的数据的最大长度。如果超过,此次数据会被丢弃。
* lengthFieldOffset:长度域偏移。就是说数据开始的几个字节可能不是表示数据长度,需要后移几个字节才是长度域。
* lengthFieldLength:长度域字节数。用几个字节来表示数据长度。
* lengthAdjustment:数据长度修正。因为长度域指定的长度可以是header+body的整个长度,也可以只是body的长度。如果表示header+body的整个长度,那么我们需要修正数据长度。
* initialBytesToStrip:跳过的字节数。如果你需要接收header+body的所有数据,此值就是0,如果你只想接收body数据,那么需要跳过header所占用的字节数。
*
* 发送数据包长度 = 长度域的值 + lengthFieldOffset + lengthFieldLength + lengthAdjustment
*
* @auther quanming
* @Date 2019/9/26 12:25
*/
@Slf4j
public class MyMessageDecoder extends LengthFieldBasedFrameDecoder {
public MyMessageDecoder() {
super(ByteOrder.BIG_ENDIAN, 1024*1024*10, 29, 8, 0, 0, true);
}
@Override
protected NettyMessageVO decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
ByteBuf frame = (ByteBuf) super.decode(ctx, in);
if (frame == null){
log.info("客户端请求数据为空");
return null;
}
// 报文标示
byte[] bytes = new byte[4];
frame.readBytes(bytes);
String msgSign = new String(bytes);
log.info("报文标示msgSign:{} ",msgSign);
// 交易代码
bytes = new byte[4];
frame.readBytes(bytes);
String transCode = new String(bytes);
log.info("交易代码transCode:{} ",transCode);
// 交易流水号
bytes = new byte[21];
frame.readBytes(bytes);
String transNo = new String(bytes);
log.info("交易流水号transNo:{} ",transNo);
// 报文体长度
bytes = new byte[8];
frame.readBytes(bytes);
String xmlLength = new String(bytes);
log.info("报文体长度:{}",xmlLength);
// 报文体
byte[] data = new byte[frame.readableBytes()];
frame.readBytes(data);
String requestXml = new String(data);
log.info("报文体xml:{}",requestXml);
NettyMessageVO nettyMessageVO = new NettyMessageVO();
nettyMessageVO.setMsgSign(msgSign);
nettyMessageVO.setTransCode(transCode);
nettyMessageVO.setTransNo(transNo);
nettyMessageVO.setXmlLength(Integer.parseInt(xmlLength));
nettyMessageVO.setXmlContext(requestXml);
return nettyMessageVO;
}
@Override
protected ByteBuf extractFrame(ChannelHandlerContext ctx, ByteBuf buffer, int index, int length) {
return super.extractFrame(ctx, buffer, index, length);
}
- 解码器-2
/**
* @auther quanming
* @Date 2019/10/16 12:06
*/
@Slf4j
public class StringDecoder extends ReplayingDecoder<MyDecoderState> {
private int length = 0;
private NettyMessageVO nettyMessageVO = new NettyMessageVO();
public StringDecoder() {
// Set the initial state.
super(MyDecoderState.READ_LENGTH);
}
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
MyDecoderState readSign = state();
log.info("readSign = {}",readSign);
switch (readSign) {
case READ_LENGTH:
nettyMessageVO = new NettyMessageVO();
byte[] bytes = new byte[4];
byteBuf.readBytes(bytes);
String msgSign = new String(bytes,CharsetUtil.UTF_8);
log.info("报文标示msgSign:{}",msgSign);
// 交易代码
bytes = new byte[4];
byteBuf.readBytes(bytes);
String transCode = new String(bytes,CharsetUtil.UTF_8);
log.info("交易代码transCode:{}",transCode);
// 交易流水号
bytes = new byte[21];
byteBuf.readBytes(bytes);
String transNo = new String(bytes,CharsetUtil.UTF_8);
log.info("交易流水号transNo:{} ",transNo);
// 报文体长度
bytes = new byte[8];
byteBuf.readBytes(bytes);
String xmlLength = new String(bytes,CharsetUtil.UTF_8);
log.info("报文体长度:{}",xmlLength);
length = Integer.valueOf(xmlLength);
checkpoint(MyDecoderState.READ_CONTENT);
nettyMessageVO.setMsgSign(msgSign);
nettyMessageVO.setTransCode(transCode);
nettyMessageVO.setTransNo(transNo);
nettyMessageVO.setXmlLength(Integer.parseInt(xmlLength));
break;
case READ_CONTENT:
bytes = new byte[length];
byteBuf.readBytes(bytes);
String requestXml = new String(bytes,CharsetUtil.UTF_8);
log.info("报文体:{}",requestXml);
checkpoint(MyDecoderState.READ_LENGTH);
nettyMessageVO.setXmlContext(requestXml);
list.add(nettyMessageVO);
break;
default:
throw new Error("Shouldn't reach here.");
}
}
}
- 注入通道处理器
/**
* 通道处理器
*
* @auther quanming
* @Date 2019/9/26 16:24
*/
@Component
@Slf4j
@ChannelHandler.Sharable
public class ServerHandler extends ChannelInboundHandlerAdapter {
@Autowired
private StrategyFactory strategyFactory;
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
NettyMessageVO nettyMessageVO = (NettyMessageVO) msg;
NettyStrategy strategy = strategyFactory.createStrategy(nettyMessageVO.getTransCode());
String responseXml = strategy.transToCgb(nettyMessageVO.getXmlContext());
nettyMessageVO.setXmlContext(responseXml);
ctx.writeAndFlush(nettyMessageVO);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
log.error("netty读取信息异常:{}",cause);
}
}
-
设置出站和入站的编码器和解码器
-
/** * 设置出站和入站的编码器和解码器 * * @auther quanming * @Date 2019/9/26 9:43 */ @Component public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> { @Autowired private ServerHandler serverHandler; @Override protected void initChannel(SocketChannel channel) throws Exception { channel.pipeline().addLast(new MyMessageEncoder()); channel.pipeline().addLast(new StringDecoder()); channel.pipeline().addLast(serverHandler); } }
本文介绍如何使用Netty框架构建银行保险类项目的接口,包括服务端搭建、编码器和解码器的实现,以及通道处理器的配置,旨在解决银行与保险系统间的数据通信问题。

1021

被折叠的 条评论
为什么被折叠?



