赞
踩
1、本代码需要一定java基础
Netty原理
我们都知道 Netty 是一个高性能、异步事件驱动的 NIO 框架,基于 JAVA NIO 提供的 API 实现
2、代码文件目录
直接上代码
1、往BBWConfig.properties写入服务信息
- package com.com.test.bbw;
-
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.springframework.boot.context.properties.ConfigurationProperties;
- import org.springframework.context.annotation.PropertySource;
- import org.springframework.stereotype.Component;
-
- import java.io.*;
- import java.util.Properties;
-
- @Component
- @ConfigurationProperties
- @PropertySource("classpath:BBWConfig.properties")
- public class BBWConfig {
-
- private static final Log logger = LogFactory.getLog(BBWConfig.class);
-
-
- private String config_path = "src/main/resources/"; //本地路径
- private String config_filename = "BBWConfig.properties";
- private static Properties properties;
-
- private static String bbwServerIp; //BBW服务器地址
- private static String bbwServerPort; //BBW服务器端口
- private static String paySendPort; //支付发出端口
- private static String payRcvServerIp; //支付接收地址
- private static String payTcpRcvPort; //tcp支付接收端口
- private static String payHttpRcvPort; //http支付接收端口
- private static String warningNum; //AGENt重连次数警告consumer
- private static String encoding; //报文编码格式
- private static String reStartTime; //AGNET异常重连间隔(单位:毫秒)
-
-
- // Netty服务连接状态:连接中
- public static final int CONNECT_STATE_CONNECTING = 0;
- // Netty服务连接状态:连接成功
- public static final int CONNECT_STATE_SUCC = 1;
- // Netty服务连接状态:连接失败
- public static final int CONNECT_STATE_FAIL = -1;
-
- public BBWConfig() {
- String home =System.getProperty("user.dir");
- // set config file path
- if (null != home && !"".equals(home.trim())){
- if (!home.endsWith("/")){
- home = home + "/";
- }
- config_filename = home + config_path + config_filename;
- }
- else{
- config_filename = config_path + config_filename;
- }
- // check config file
- creatConfigFile();
- this.properties = getConfigFile();
- init();
- }
-
- private Properties getConfigFile() {
- properties = new Properties();
- try {
- FileReader fileReader = new FileReader(config_filename);
- properties.load(fileReader);
- fileReader.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return properties;
- }
-
- public static Properties getProperties() {
- return properties;
- }
-
- public static void setProperties(Properties properties) {
- BBWConfig.properties = properties;
- }
-
- public static String getBbwServerIp() {
- return bbwServerIp;
- }
-
- public static void setBbwServerIp(String bbwServerIp) {
- BBWConfig.bbwServerIp = bbwServerIp;
- }
-
- public static String getBbwServerPort() {
- return bbwServerPort;
- }
-
- public static void setBbwServerPort(String bbwServerPort) {
- BBWConfig.bbwServerPort = bbwServerPort;
- }
-
- public static String getPaySendPort() {
- return paySendPort;
- }
-
- public static void setPaySendPort(String paySendPort) {
- BBWConfig.paySendPort = paySendPort;
- }
-
- public static String getPayRcvServerIp() {
- return payRcvServerIp;
- }
-
- public static void setPayRcvServerIp(String payRcvServerIp) {
- BBWConfig.payRcvServerIp = payRcvServerIp;
- }
-
- public static String getPayTcpRcvPort() {
- return payTcpRcvPort;
- }
-
- public static void setPayTcpRcvPort(String payTcpRcvPort) {
- BBWConfig.payTcpRcvPort = payTcpRcvPort;
- }
-
- public static String getPayHttpRcvPort() {
- return payHttpRcvPort;
- }
-
- public static void setPayHttpRcvPort(String payHttpRcvPort) {
- BBWConfig.payHttpRcvPort = payHttpRcvPort;
- }
-
- public static String getWarningNum() {
- return warningNum;
- }
-
- public static void setWarningNum(String warningNum) {
- BBWConfig.warningNum = warningNum;
- }
-
- public static String getEncoding() {
- return encoding;
- }
-
- public static void setEncoding(String encoding) {
- BBWConfig.encoding = encoding;
- }
-
- public static String getReStartTime() {
- return reStartTime;
- }
-
- public static void setReStartTime(String reStartTime) {
- BBWConfig.reStartTime = reStartTime;
- }
-
- /**
- *
- * @说明 创建默认的配置文件
- */
- private File creatConfigFile() {
- File file = new File(config_filename);
-
- if (logger.isInfoEnabled()) {
- logger.info("BBWConfig config_filename = " + config_filename);
- }
-
- if (!file.exists()) {
- if (logger.isInfoEnabled()) {
- logger.info("BBWConfig start creatConfigFile ..............");
- }
- try {
- file.createNewFile();
- OutputStreamWriter osw = new OutputStreamWriter(
- new FileOutputStream(file));
- osw.write("#BBW服务器地址" + "\n");
- osw.write("bbwServerIp=127.0.0.1" + "\n");
- osw.write("#BBW服务器端口" + "\n");
- osw.write("bbwServerPort=4444" + "\n");
- osw.write("#支付接出端口Tcp" + "\n");
- osw.write("paySendPort=50039" + "\n");
- osw.write("#支付接入平台地址" + "\n");
- osw.write("payRcvServerIp=127.0.0.1" + "\n");
- osw.write("#支付平台接入端口tcp" + "\n");
- osw.write("payTcpRcvPort=50040" + "\n");
- osw.write("#支付平台接入http端口" + "\n");
- osw.write("payHttpRcvPort=9004" + "\n");
- osw.write("#AGENt重连次数警告consumer" + "\n");
- osw.write("warningNum=10" + "\n");
- osw.write("#报文编码格式" + "\n");
- osw.write("encoding=UTF8" + "\n");
- osw.write("#AGNET异常重连间隔(单位:毫秒)" + "\n");
- osw.write("reStartTime=10000" + "\n");
- osw.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- return file;
- }
- private void init(){
- BBWConfig.bbwServerIp=BBWConfig.properties.getProperty("bbwServerIp");
- BBWConfig.bbwServerPort=BBWConfig.properties.getProperty("bbwServerPort");
- BBWConfig.paySendPort=BBWConfig.properties.getProperty("paySendPort");
- BBWConfig.payRcvServerIp=BBWConfig.properties.getProperty("payRcvServerIp");
- BBWConfig.payTcpRcvPort=BBWConfig.properties.getProperty("payTcpRcvPort");
- BBWConfig.payHttpRcvPort=BBWConfig.properties.getProperty("payHttpRcvPort");
- BBWConfig.encoding=BBWConfig.properties.getProperty("encoding");
- BBWConfig.warningNum=BBWConfig.properties.getProperty("warningNum");
- }
- public static void main(String[] args) {
- BBWConfig nc = new BBWConfig();
- if (logger.isDebugEnabled()) {
- logger.debug("BBWConfig toString \n" + nc.getConfigFile().toString());
- }
- }
-
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
2、读取数据工具类
- package com.com.test.bbw;
-
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
-
- import java.io.BufferedInputStream;
- import java.io.BufferedOutputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
-
- public class ConverUtils {
-
- private static final Logger log = LoggerFactory.getLogger(ConverUtils.class);
-
- private static final Integer msgLeng = 5;
-
- /**
- * 循环去写数据
- *
- * @param bos
- * @param buff
- * @param bufferCapacity
- * @throws IOException
- */
- public static void cycleWriteMessage(BufferedOutputStream bos, byte[] buff, int bufferCapacity) throws IOException {
- int len = buff.length;
-
- int count = 0;
- int tmpLen = len;
- while (true) {
- if (tmpLen <= bufferCapacity) {
- bos.write(buff, count, tmpLen);
- bos.flush();
- count += tmpLen;
- tmpLen = 0;
- } else {
- bos.write(buff, count, bufferCapacity);
- bos.flush();
- count += bufferCapacity;
- tmpLen -= bufferCapacity;
- }
- if (tmpLen == 0)
- break;
- }
- }
-
- /**
- * 循环去读数据
- *
- * @param bis
- * @param baos
- * @param bufferCapacity
- * @param len
- * @param socketReaderCircleTimes
- * @throws IOException
- */
- public static String cycleReadMessage(BufferedInputStream bis, StringBuffer msgInfo, int bufferCapacity, int len,
- int socketReaderCircleTimes) throws IOException {
- int index = 0;
- // 读取的明文长度
- int numberRead = 0;
- // 读取的字节长度
- int numberReadByte = 0;
- // 明文的长度变量
- int tmpLen = len;
- byte[] buff = null;
- // 定义可变字符串用于存储取到的明文数据
- StringBuffer msgTemp = new StringBuffer();
- for (int i = 0; i < socketReaderCircleTimes; i++) {
- buff = new byte[tmpLen];
- numberReadByte = bis.read(buff, 0, tmpLen);
- if (numberReadByte <= 0) {
- break;
- }
- // 拿到的字节数据转为16进制数据
- String asciiBytesToMsg = byteArr2HexStr(buff);
- String msg = convertHexToString(asciiBytesToMsg);
- msgTemp.append(msg);
- // 判断长度
- numberRead = asciiBytesToMsg.length();
- // 如果明文长度小于剩余报文头长度
- if (numberRead < tmpLen) {
- index += numberRead;
- tmpLen -= numberRead;
- } else {
- if (numberRead != tmpLen)
- break;
- index += numberRead;
- tmpLen -= numberRead;
- }
-
- if (tmpLen <= 0)
- break;
- }
- // 判断长度
- if (msgTemp.length() == len) {
- msgInfo.append(msgTemp);
- return msgInfo.toString();
- }
- return null;
- }
-
-
-
- /**
- * 将两个字节数组合并
- *
- * @param data1
- * @param data2
- * @return
- */
- public static byte[] addBytes(byte[] headData, byte[] bodyData) {
- byte[] data3 = null;
- if(null != bodyData && 0 < bodyData.length){
- data3 = new byte[headData.length + bodyData.length];
- System.arraycopy(headData, 0, data3, 0, headData.length);
- System.arraycopy(bodyData, 0, data3, headData.length, bodyData.length);
- }else {
- data3 = "00000".getBytes();
- }
- return data3;
- }
-
- /**
- * 循环去读报文的长度
- *
- * @param bis
- * @param baos
- * @param bufferCapacity
- * @param len
- * @param socketReaderCircleTimes
- * @throws IOException
- */
- public static void cycleReadMessageHeadLeng(BufferedInputStream bis, ByteArrayOutputStream baos, int bufferCapacity,
- int len, int socketReaderCircleTimes) throws IOException {
-
- int numberRead = 0;
- int tmpLen = len;
- int index = 0;
- byte[] buff = null;
- for (int i = 0; i < socketReaderCircleTimes; i++) {
- if (tmpLen < bufferCapacity) {
- buff = new byte[tmpLen];
- int available = bis.available();
- if(available >0){
- numberRead = bis.read(buff, 0, tmpLen);
- }else{
- continue;
- }
- } else {
- buff = new byte[bufferCapacity];
- numberRead = bis.read(buff, 0, bufferCapacity);
- }
-
- if (numberRead < 0) {
- return;
- }
- if (numberRead < tmpLen) {
- index += numberRead;
- tmpLen -= numberRead;
-
- byte[] tmpByte = new byte[numberRead];
- System.arraycopy(buff, 0, tmpByte, 0, numberRead);
- baos.write(tmpByte);
- } else {
- if (numberRead != tmpLen)
- break;
- index += numberRead;
- tmpLen -= numberRead;
- baos.write(buff);
- }
-
- if (tmpLen <= 0)
- break;
- }
- }
-
- /**
- * 将报文的2位ASCII码字符码转为10进制
- *
- * @param bytes
- * @return
- */
- public static int decodeMsgLength(byte[] bytes) {
- if (bytes != null && bytes.length == 2) {
-
- return bytes2Short(bytes, 0);
- } else {
- log.error("bytes of length cannot decode to int value.");
- }
- return 0;
- }
-
- public static short bytes2Short(byte[] b, int offset) {
- short n = (short) (((b[offset] < 0 ? b[offset] + 256 : b[offset]) << 8)
- + (b[offset + 1] < 0 ? b[offset + 1] + 256 : b[offset + 1]));
- return n;
- }
-
- public static byte[] encode(int lengthValue, int length) {
- if (lengthValue > 0 && length > 0) {
- byte[] bytes;
- try {
- String hexStr = Integer.toHexString(lengthValue);
- if (hexStr.length() % 2 != 0) {
- hexStr = "0" + hexStr;
- }
- bytes = hexstr2ByteArr(hexStr);
- byte[] ret = new byte[length];
- for (int i = 0; i < length; i++) {
- ret[i] = 0x00;
- }
- System.arraycopy(bytes, 0, ret, length - bytes.length, bytes.length);
- return ret;
- } catch (Exception e) {
- log.error("报文长度转化出错");
- }
- } else {
- if(lengthValue == 0){
- return "00000".getBytes();
- }
- log.error("无效的报文长度:"+lengthValue);
- }
- return new byte[0];
- }
-
- public static byte[] hexstr2ByteArr(String strIn) {
- byte[] arrB = strIn.getBytes();
- int iLen = arrB.length;
- byte[] arrOut = new byte[iLen / 2];
-
- for (int i = 0; i < iLen; i += 2) {
- String strTmp = new String(arrB, i, 2);
- arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
- }
-
- return arrOut;
- }
-
- /**
- * hex字符串转byte数组
- *
- * @param inHex
- * 待转换的Hex字符串
- * @return 转换后的byte数组结果
- */
- public static byte[] hexToByteArray(String inHex) {
- if (inHex != null && !inHex.isEmpty()) {
- int hexlen = inHex.trim().length();
- byte[] result;
- if (hexlen % 2 == 1) {
- // 奇数
-
- } else {
- // 偶数
- result = new byte[(hexlen / 2)];
- int j = 0;
- for (int i = 0; i < hexlen; i += 2) {
- result[j] = hexToByte(inHex.substring(i, i + 2));
- j++;
- }
- return result;
- }
- }
- return new byte[0];
-
- }
-
- /**
- * Hex字符串转byte
- *
- * @param inHex
- * 待转换的Hex字符串
- * @return 转换后的byte
- */
- public static byte hexToByte(String inHex) {
- return (byte) Integer.parseInt(inHex, 16);
- }
-
- /**
- * ASCII码转换为16进制
- *
- * @param str
- * @return
- */
- public static String convertStringToHex(String str) {
-
- char[] chars = str.toCharArray();
-
- StringBuffer hex = new StringBuffer();
- for (int i = 0; i < chars.length; i++) {
- hex.append(Integer.toHexString((int) chars[i]));
- }
-
- return hex.toString();
- }
-
- /**
- * 将字节数组转为16进制数据
- *
- * @param arrB
- * @return
- * @throws IOException
- */
- public static String byteArr2HexStr(byte[] arrB) throws IOException {
- int iLen = arrB.length;
- StringBuffer sb = new StringBuffer(iLen * 2);
-
- for (int i = 0; i < iLen; ++i) {
- int intTmp;
- for (intTmp = arrB[i]; intTmp < 0; intTmp += 256) {
- }
-
- if (intTmp < 16) {
- sb.append("0");
- }
-
- sb.append(Integer.toString(intTmp, 16));
- }
-
- return sb.toString();
- }
-
- /**
- *
- * 16进制数据转为明文
- * @param arrB
- * @return
- * @throws IOException
- */
- public static String convertHexToString(String hex) {
-
- StringBuilder sb = new StringBuilder();
- StringBuilder temp = new StringBuilder();
- for (int i = 0; i < hex.length() - 1; i += 2) {
- String output = hex.substring(i, (i + 2));
- int decimal = Integer.parseInt(output, 16);
- sb.append((char) decimal);
- temp.append(decimal);
- }
-
- return sb.toString();
- }
- /**
- * 左补齐
- *
- * @param 原字符串
- * @param 左补字符
- * @param 补齐长度
- * @return 如果原字符串超长,返回原字符串
- */
- public static String lpad(String str, char ch, int len) {
- if (str.length() >= len) {
- return str;
- }
-
- char[] origChs = str.toCharArray();
- char[] chs = new char[len];
- int pos = len - origChs.length;
-
- for (int i = 0; i < len; i++) {
- if (i < pos) {
- chs[i] = ch;
- } else {
- chs[i] = origChs[i - pos];
- }
- }
- return new String(chs);
- }
-
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
3、解码
- package com.com.test.bbw;
-
- import io.netty.buffer.ByteBuf;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.handler.codec.MessageToMessageDecoder;
-
- import java.util.List;
-
- public class MsgPckDecode extends MessageToMessageDecoder<ByteBuf> {
- //明文长度
- private static final Integer msgLeng = 5;
- @Override
- protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
-
- final byte[] headMessage;
- final byte[] contentMessage;
- headMessage = new byte[2];
- // 定义可变字符串用于存储取到的明文数据
- StringBuffer msgTemp = new StringBuffer();
- //获取报文长度
- msg.getBytes(msg.readerIndex(), headMessage, 0, 2);
- // 将两位报文ASII码数据转为10进制长度
- int msgLength = ConverUtils.decodeMsgLength(headMessage);
- String msgLengthStr = msgLength+"";
- msgLengthStr = ConverUtils.lpad(msgLengthStr, '0', msgLeng);
- msgTemp.append(msgLengthStr);
- //根据报文长度读取内容
- contentMessage = new byte[msgLength];
- msg.getBytes(2, contentMessage, 0, msgLength);
- // 拿到的字节数据转为16进制数据
- String asciiBytesToMsg = ConverUtils.byteArr2HexStr(contentMessage);
- String message = ConverUtils.convertHexToString(asciiBytesToMsg);
- msgTemp.append(message);
- out.add(msgTemp.toString());
-
- }
-
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- package com.com.test.bbw;
-
- import io.netty.buffer.ByteBuf;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.handler.codec.MessageToByteEncoder;
- import org.msgpack.MessagePack;
-
- public class MsgPckEncode extends MessageToByteEncoder<Object> {
-
- private static final Integer msgLeng = 5;
- @Override
- protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf buf) throws Exception {
- MessagePack pack = new MessagePack();
- String dataStr = (String) msg;
- // 第一步:获取报文长度
- int msgLength = Integer.parseInt(dataStr.substring(0, msgLeng));
- String msgInfo = dataStr.substring(msgLeng);
- //将报文 长度转为16进制 ,内容转为ASCII码
- String convertStringToHex = ConverUtils.convertStringToHex(msgInfo);
- byte[] message = ConverUtils.addBytes(ConverUtils.encode(msgLength, 2), ConverUtils.hexToByteArray(convertStringToHex));
- buf.writeBytes(message);
-
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
4、前置与服务B之间长链接,支持断线重连机制
- package com.com.test.bbw;
-
- import io.netty.bootstrap.Bootstrap;
- import io.netty.channel.*;
- import io.netty.channel.nio.NioEventLoopGroup;
- import io.netty.channel.socket.SocketChannel;
- import io.netty.channel.socket.nio.NioSocketChannel;
- import io.netty.handler.timeout.IdleStateHandler;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
-
- import java.util.concurrent.TimeUnit;
-
- public class TCPBBWAdaptor {
- private static final Logger log = LoggerFactory.getLogger(TCPBBWAdaptor.class);
- private String bbwServerIp;
- private int bbwServerPort;/* 端口 */
- private String encoding;/* 编码方式 */
- private int timeout=10000;/* 超时时间:秒 */
- private EventLoopGroup group;
- private Bootstrap client;
- private Channel channel;
-
- public static Logger getLog() {
- return log;
- }
-
- private ChannelFuture future;
-
- public TCPBBWAdaptor() {
- init();
- group = new NioEventLoopGroup();
- client = new Bootstrap();
- client.group(group);
- client.channel(NioSocketChannel.class);
- client.option(ChannelOption.SO_KEEPALIVE, true);
- client.handler(new ChannelInitializer<SocketChannel>() {
-
- @Override
- protected void initChannel(SocketChannel ch) throws Exception {
- // 按照\r\n进行解码
- //ch.pipeline().addLast(new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, Delimiters.lineDelimiter()[0]));
- ch.pipeline().addLast(new IdleStateHandler(0, 0, 5))
- .addLast(new MsgPckDecode())
- .addLast(new MsgPckEncode())
- .addLast(new TcpBBWClientHandler(TCPBBWAdaptor.this));
- }
-
- });
- }
-
- public Object send(Object msg) {
- try {
- if (channel != null && channel.isActive()) {
- doSend(msg);
- } else {
- restConnOrConn();
- send(msg);
- }
- } catch (Exception e) {
- log.info("连接异常!");
- group.shutdownGracefully();
- }
-
- return msg;
- }
-
- private void doSend(Object msg) {
- group.execute(new Runnable() {
- @Override
- public void run() {
- channel.writeAndFlush(msg);
- }
- });
- }
-
- public void restConnOrConn() throws InterruptedException {
- future = client.connect(bbwServerIp, bbwServerPort).sync();
- future.addListener(new ChannelFutureListener() {
- @Override
- public void operationComplete(ChannelFuture future) throws Exception {
- if (future.isSuccess()) {
- channel = future.channel();
- } else {
- future.channel().eventLoop().schedule(new Runnable() {
-
- @Override
- public void run() {
- try {
- restConnOrConn();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- }
- }, 2, TimeUnit.SECONDS);
- }
- }
- });
-
- }
- public void init(){
- this.bbwServerIp=BBWConfig.getBbwServerIp();
- this.bbwServerPort= Integer.parseInt(BBWConfig.getBbwServerPort());
- this.encoding=BBWConfig.getEncoding();
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- package com.com.test.bbw;
-
- import com.com.test.client.TCPPayAdaptor;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.channel.ChannelInboundHandlerAdapter;
- import io.netty.handler.timeout.IdleStateEvent;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.util.StringUtils;
-
- public class TcpBBWClientHandler extends ChannelInboundHandlerAdapter {
- private static final Logger log = LoggerFactory.getLogger(TcpBBWClientHandler.class);
- // 明文报文长度
- private static final Integer msgLeng = 5;
- private TCPBBWAdaptor clinet;
- public TcpBBWClientHandler(TCPBBWAdaptor clinet) {
- this.clinet = clinet;
- }
- /**
- * 客户端与服务端创建连接的时候调用
- */
- @Override
- public void channelActive(ChannelHandlerContext ctx) throws Exception {
- ctx.fireChannelActive();
- }
-
- /**
- * 客户端与服务端断开连接时调用
- */
- @Override
- public void channelInactive(ChannelHandlerContext ctx) throws Exception {
- clinet.restConnOrConn();
- }
-
- /**
- * 服务端接收客户端发送过来的数据结束之后调用
- */
- @Override
- public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
- ctx.flush();
- }
-
- /**
- * 工程出现异常的时候调用
- */
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- cause.printStackTrace();
- ctx.close();
- //重新连接
- clinet.restConnOrConn();
- }
- /**
- * 心跳处理方法
- */
- @Override
- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
- // 如果属于心跳处理
- if (evt instanceof IdleStateEvent) {
- IdleStateEvent event = (IdleStateEvent) evt;
- switch (event.state()) {
- case READER_IDLE:
- break;
- case WRITER_IDLE:
- break;
- case ALL_IDLE:
- //发送心跳
- sendMsg(ctx);
- break;
- }
- }
- super.userEventTriggered(ctx, evt);
- }
- private void sendMsg(ChannelHandlerContext ctx) {
- ctx.channel().writeAndFlush("");
- }
- @Override
- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
- ctx.channel().eventLoop().execute(new Runnable() {
- @Override
- public void run() {
- final String msgL=(String)msg;
- if (!StringUtils.isEmpty(msgL)) {
- log.debug("接收到报文为:" +msg);
- TCPPayAdaptor payAdaptor=new TCPPayAdaptor();
- payAdaptor.send(msg);
- }
- }
- });
- }
-
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
5、前置与服务A之间短连接,异步调用
- package com.com.test.client;
-
- import com.com.test.bbw.BBWConfig;
- import io.netty.bootstrap.Bootstrap;
- import io.netty.buffer.ByteBuf;
- import io.netty.buffer.Unpooled;
- import io.netty.channel.*;
- import io.netty.channel.nio.NioEventLoopGroup;
- import io.netty.channel.socket.SocketChannel;
- import io.netty.channel.socket.nio.NioSocketChannel;
- import io.netty.handler.codec.string.StringDecoder;
- import io.netty.handler.codec.string.StringEncoder;
- import io.netty.handler.timeout.IdleStateHandler;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.util.StringUtils;
-
- import java.io.UnsupportedEncodingException;
-
- public class TCPPayAdaptor {
- private static final Logger log = LoggerFactory.getLogger(TCPPayAdaptor.class);
- private String payRcvServerIp;
- private int payTcpRcvPort;/* 端口 */
- private String encoding;/* 编码方式 */
- private int timeout=20000;/* 超时时间:秒 */
- private EventLoopGroup group;
- private Bootstrap client;
- private Channel channel;
-
- public static Logger getLog() {
- return log;
- }
-
- private ChannelFuture future;
-
- public TCPPayAdaptor() {
- init();
- group = new NioEventLoopGroup();
- client = new Bootstrap();
- client.group(group);
- client.channel(NioSocketChannel.class);
- client.option(ChannelOption.SO_KEEPALIVE, true);
- client.handler(new ChannelInitializer<SocketChannel>() {
-
- @Override
- protected void initChannel(SocketChannel ch) throws Exception {
- // 按照\r\n进行解码
- //ch.pipeline().addLast(new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, Delimiters.lineDelimiter()[0]));
- ch.pipeline().addLast(new IdleStateHandler(0, 0, 5))
- .addLast(new StringDecoder())
- .addLast(new StringEncoder())
- .addLast(new TcpPayClientHandler());
- }
-
- });
- try {
- future = client.connect(payRcvServerIp, payTcpRcvPort).sync();
- if(future!=null&&future.isSuccess()){
- channel=future.channel();
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- public Object send(Object msg) {
- try {
- if (channel != null && channel.isActive()) {
- doSend(msg);
- }
- } catch (Exception e) {
- log.info("连接异常!");
- group.shutdownGracefully();
- }
-
- return msg;
- }
-
- private void doSend(Object msg) {
- try {
- final String msgL=(String)msg;
- byte[] bytes = msgL.getBytes(encoding);
- ByteBuf buf = Unpooled.wrappedBuffer(bytes);
- byte[] req = new byte[buf.readableBytes()];
- buf.readBytes(req);
- String smsg = new String(req, encoding);
- if (!StringUtils.isEmpty(smsg)) {
- log.debug("接收到报文为:" + smsg);
- channel.writeAndFlush(smsg);
- }
- ByteBuf buffer = Unpooled.buffer();
- buffer.writeBytes(req);
- } catch (UnsupportedEncodingException e) {
- log.info("bbw返回发送异常");
- }
- }
-
- public void init(){
- this.payTcpRcvPort= Integer.parseInt(BBWConfig.getPayTcpRcvPort());
- this.payRcvServerIp= BBWConfig.getPayRcvServerIp();
- this.encoding= BBWConfig.getEncoding();
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- package com.com.test.client;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.channel.ChannelInboundHandlerAdapter;
- import io.netty.handler.timeout.IdleStateEvent;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
-
- import java.lang.reflect.Method;
-
- public class TcpPayClientHandler extends ChannelInboundHandlerAdapter {
- private static final Logger log = LoggerFactory.getLogger(TcpPayClientHandler.class);
- // 明文报文长度
- private static final Integer msgLeng = 5;
- /**
- * 客户端与服务端创建连接的时候调用
- */
- @Override
- public void channelActive(ChannelHandlerContext ctx) throws Exception {
- ctx.fireChannelActive();
- }
-
- /**
- * 客户端与服务端断开连接时调用
- */
- @Override
- public void channelInactive(ChannelHandlerContext ctx) throws Exception {
- ctx.channel().writeAndFlush("");
- }
-
- /**
- * 服务端接收客户端发送过来的数据结束之后调用
- */
- @Override
- public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
- ctx.flush();
- }
-
- /**
- * 工程出现异常的时候调用
- */
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- cause.printStackTrace();
- ctx.close();
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
6、 服务B监听器,用来监听B系统发送给前置消息,用来转发到服务A
- package com.com.test.listener;
-
- import com.com.test.server.Server;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.springframework.boot.ApplicationArguments;
- import org.springframework.boot.ApplicationRunner;
- import org.springframework.stereotype.Component;
-
-
-
- @Component
- public class BBWListener implements ApplicationRunner{
- private static final Log logger = LogFactory.getLog(BBWListener.class);
-
- @Override
- public void run(ApplicationArguments args) throws Exception {
-
- if (logger.isInfoEnabled()) {
- logger.info("Starting booting core banking services platform...");
- }
- // Start
- try {
- Server server = new Server();
- server.start();
- } catch (Exception e) {
- e.printStackTrace();
- logger.error(e);
- }
- if (logger.isInfoEnabled()) {
- logger.info("Started booted bbw banking services platform...");
- }
- }
-
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
7、接收到系统B消息服务端
- package com.com.test.server;
-
- import com.com.test.bbw.BBWConfig;
- import io.netty.bootstrap.ServerBootstrap;
- import io.netty.channel.ChannelFuture;
- import io.netty.channel.ChannelInitializer;
- import io.netty.channel.ChannelOption;
- import io.netty.channel.ChannelPipeline;
- import io.netty.channel.EventLoopGroup;
- import io.netty.channel.nio.NioEventLoopGroup;
- import io.netty.channel.socket.ServerSocketChannel;
- import io.netty.channel.socket.SocketChannel;
- import io.netty.channel.socket.nio.NioServerSocketChannel;
- import io.netty.handler.codec.string.StringDecoder;
- import io.netty.handler.codec.string.StringEncoder;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
-
-
- public class Server {
- private static final Log logger = LogFactory.getLog(Server.class);
- private int paySendPort;
- private String encoding;/* 编码方式 */
- private int timeout = 10000;/* 超时时间:秒 */
- private int conNum = 1;/* 保持连接数 */
- private ServerSocketChannel serverSocketChannel;
-
- private void bind() {
- //服务端要建立两个group,一个负责接收客户端的连接,一个负责处理数据传输
- //连接处理group
- EventLoopGroup boss = new NioEventLoopGroup();
- //事件处理group
- EventLoopGroup worker = new NioEventLoopGroup();
- ServerBootstrap bootstrap = new ServerBootstrap();
- // 绑定处理group
- bootstrap.group(boss, worker).channel(NioServerSocketChannel.class)
- //保持连接数
- // .option(ChannelOption.SO_BACKLOG, conNum)
- //有数据立即发送
- .option(ChannelOption.TCP_NODELAY, true)
- //保持连接
- .childOption(ChannelOption.SO_KEEPALIVE, false)
- //处理新连接
- .childHandler(new ChannelInitializer<SocketChannel>() {
- @Override
- protected void initChannel(SocketChannel sc) throws Exception {
- // 增加任务处理
- ChannelPipeline p = sc.pipeline();
- p.addLast(
- //使用了netty自带的编码器和解码器
- new StringDecoder(),
- new StringEncoder(),
- //心跳检测,读超时,写超时,读写超时
- //new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS),
- //自定义的处理器
- new ServerHandler());
- }
- });
-
- //绑定端口,同步等待成功
- ChannelFuture future;
- try {
- future = bootstrap.bind(paySendPort).sync();
- if (future.isSuccess()) {
- serverSocketChannel = (ServerSocketChannel) future.channel();
- logger.info("服务端启动成功,端口:" + paySendPort);
- } else {
- logger.info("服务端启动失败!");
- }
- //等待服务监听端口关闭,就是由于这里会将线程阻塞,导致无法发送信息,所以我这里开了线程
- future.channel().closeFuture().sync();
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- //优雅地退出,释放线程池资源
- boss.shutdownGracefully();
- worker.shutdownGracefully();
- }
- }
-
- public void init() {
- this.paySendPort = Integer.parseInt(BBWConfig.getPaySendPort());
- this.encoding = BBWConfig.getEncoding();
- }
-
- public void start() {
- init();
- bind();
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
7、接收到系统B消息客户端,调用
TCPPayAdaptor转发到系统A
- package com.com.test.server;
-
- import com.com.test.bbw.TCPBBWAdaptor;
- import io.netty.buffer.ByteBuf;
- import io.netty.buffer.Unpooled;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.channel.ChannelInboundHandlerAdapter;
- import io.netty.util.CharsetUtil;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.springframework.util.StringUtils;
-
- import java.io.UnsupportedEncodingException;
-
- public class ServerHandler extends ChannelInboundHandlerAdapter {
- private static final Log logger = LogFactory.getLog(ServerHandler.class);
- /**
- * 客户端与服务端创建连接的时候调用
- */
- @Override
- public void channelActive(ChannelHandlerContext ctx) throws Exception {
- ctx.fireChannelActive();
- }
-
- /**
- * 一旦建立连接第一个被执行
- */
- @Override
- public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
- }
-
- /**
- * 客户端与服务端断开连接时调用
- */
- @Override
- public void channelInactive(ChannelHandlerContext ctx) throws Exception {
- ctx.close();
- }
- /**
- * 服务端接收客户端发送过来的数据结束之后调用
- */
- @Override
- public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
- ctx.flush();
- }
-
- /**
- * 工程出现异常的时候调用
- */
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- cause.printStackTrace();
- ctx.close();
- }
-
- /**
- * 服务端处理客户端websocket请求的核心方法,这里接收了客户端发来的信息
- */
- @Override
- public void channelRead(ChannelHandlerContext channelHandlerContext, Object info) throws Exception {
- logger.info("接收到了:" + info);
- try {
- final String msgL=(String)info;
- byte[] bytes = msgL.getBytes(CharsetUtil.UTF_8);
- ByteBuf buf = Unpooled.wrappedBuffer(bytes);
- byte[] req = new byte[buf.readableBytes()];
- buf.readBytes(req);
- String smsg = new String(req, CharsetUtil.UTF_8);
- if (!StringUtils.isEmpty(smsg)) {
- logger.debug("接收到报文为:" + smsg);
- new TCPBBWAdaptor().send(info);
- }
- ByteBuf buffer = Unpooled.buffer();
- buffer.writeBytes(req);
- } catch (Exception e) {
- logger.info("bbw返回发送异常");
- }
- }
-
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
8、启动类
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
- import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
- import org.springframework.context.annotation.ComponentScan;
-
- @ComponentScan(basePackages = {"com"})
- @SuppressWarnings("all")
- @SpringBootApplication(exclude= {DataSourceAutoConfiguration.class, MongoAutoConfiguration.class})
- public class TestApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(TestApplication.class, args);
- }
-
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
日志 logging.config=classpath:logback-boot.xml
BBWConfig.properties
#BBW服务器地址 bbwServerIp=127.0.0.1 #BBW服务器端口 bbwServerPort=4444 #支付接出端口Tcp paySendPort=50039 #支付接入平台地址 payRcvServerIp=127.0.0.1 #支付平台接入端口tcp payTcpRcvPort=50040 #支付平台接入http端口 payHttpRcvPort=9004 #AGENt重连次数警告consumer warningNum=10 #报文编码格式 encoding=UTF8 #AGNET异常重连间隔(单位:毫秒) reStartTime=10000 test=003090800C220000080000000040000000000000003535122313335102421203535301
logback-boot.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
- <!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
- <!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
- <!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
- <configuration scan="true" scanPeriod="10 seconds">
-
- <!--<include resource="org/springframework/boot/logging/logback/base.xml" />-->
-
- <contextName>logback</contextName>
- <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
- <property name="log.path" value="D:/nmyslog/nmys" />
-
- <!-- 彩色日志 -->
- <!-- 彩色日志依赖的渲染类 -->
- <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
- <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
- <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
- <!-- 彩色日志格式 -->
- <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
-
-
- <!--输出到控制台-->
- <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
- <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
- <level>info</level>
- </filter>
- <encoder>
- <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
- <!-- 设置字符集 -->
- <charset>UTF-8</charset>
- </encoder>
- </appender>
-
-
- <!--输出到文件-->
-
- <!-- 时间滚动输出 level为 DEBUG 日志 -->
- <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <!-- 正在记录的日志文件的路径及文件名 -->
- <file>${log.path}/log_debug.log</file>
- <!--日志文件输出格式-->
- <encoder>
- <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
- <charset>UTF-8</charset> <!-- 设置字符集 -->
- </encoder>
- <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <!-- 日志归档 -->
- <fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
- <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
- <maxFileSize>100MB</maxFileSize>
- </timeBasedFileNamingAndTriggeringPolicy>
- <!--日志文件保留天数-->
- <maxHistory>15</maxHistory>
- </rollingPolicy>
- <!-- 此日志文件只记录debug级别的 -->
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <level>debug</level>
- <onMatch>ACCEPT</onMatch>
- <onMismatch>DENY</onMismatch>
- </filter>
- </appender>
-
- <!-- 时间滚动输出 level为 INFO 日志 -->
- <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <!-- 正在记录的日志文件的路径及文件名 -->
- <file>${log.path}/log_info.log</file>
- <!--日志文件输出格式-->
- <encoder>
- <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
- <charset>UTF-8</charset>
- </encoder>
- <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <!-- 每天日志归档路径以及格式 -->
- <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
- <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
- <maxFileSize>100MB</maxFileSize>
- </timeBasedFileNamingAndTriggeringPolicy>
- <!--日志文件保留天数-->
- <maxHistory>15</maxHistory>
- </rollingPolicy>
- <!-- 此日志文件只记录info级别的 -->
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <level>info</level>
- <onMatch>ACCEPT</onMatch>
- <onMismatch>DENY</onMismatch>
- </filter>
- </appender>
-
- <!-- 时间滚动输出 level为 WARN 日志 -->
- <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <!-- 正在记录的日志文件的路径及文件名 -->
- <file>${log.path}/log_warn.log</file>
- <!--日志文件输出格式-->
- <encoder>
- <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
- <charset>UTF-8</charset> <!-- 此处设置字符集 -->
- </encoder>
- <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
- <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
- <maxFileSize>100MB</maxFileSize>
- </timeBasedFileNamingAndTriggeringPolicy>
- <!--日志文件保留天数-->
- <maxHistory>15</maxHistory>
- </rollingPolicy>
- <!-- 此日志文件只记录warn级别的 -->
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <level>warn</level>
- <onMatch>ACCEPT</onMatch>
- <onMismatch>DENY</onMismatch>
- </filter>
- </appender>
-
-
- <!-- 时间滚动输出 level为 ERROR 日志 -->
- <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <!-- 正在记录的日志文件的路径及文件名 -->
- <file>${log.path}/log_error.log</file>
- <!--日志文件输出格式-->
- <encoder>
- <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
- <charset>UTF-8</charset> <!-- 此处设置字符集 -->
- </encoder>
- <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
- <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
- <maxFileSize>100MB</maxFileSize>
- </timeBasedFileNamingAndTriggeringPolicy>
- <!--日志文件保留天数-->
- <maxHistory>15</maxHistory>
- </rollingPolicy>
- <!-- 此日志文件只记录ERROR级别的 -->
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <level>ERROR</level>
- <onMatch>ACCEPT</onMatch>
- <onMismatch>DENY</onMismatch>
- </filter>
- </appender>
-
- <!--
- <logger>用来设置某一个包或者具体的某一个类的日志打印级别、
- 以及指定<appender>。<logger>仅有一个name属性,
- 一个可选的level和一个可选的addtivity属性。
- name:用来指定受此logger约束的某一个包或者具体的某一个类。
- level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
- 还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
- 如果未设置此属性,那么当前logger将会继承上级的级别。
- addtivity:是否向上级logger传递打印信息。默认是true。
- -->
- <!--<logger name="org.springframework.web" level="info"/>-->
- <!--<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>-->
- <!--
- 使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
- 第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
- 第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
- -->
-
-
- <!--
- root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
- level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
- 不能设置为INHERITED或者同义词NULL。默认是DEBUG
- 可以包含零个或多个元素,标识这个appender将会添加到这个logger。
- -->
-
- <!--开发环境:打印控制台-->
- <springProfile name="dev">
- <logger name="com.com.test.bbw" level="debug"/>
- </springProfile>
-
- <root level="info">
- <appender-ref ref="CONSOLE" />
- <appender-ref ref="DEBUG_FILE" />
- <appender-ref ref="INFO_FILE" />
- <appender-ref ref="WARN_FILE" />
- <appender-ref ref="ERROR_FILE" />
- </root>
-
- <!--生产环境:输出到文件-->
- <!--<springProfile name="pro">-->
- <!--<root level="info">-->
- <!--<appender-ref ref="CONSOLE" />-->
- <!--<appender-ref ref="DEBUG_FILE" />-->
- <!--<appender-ref ref="INFO_FILE" />-->
- <!--<appender-ref ref="ERROR_FILE" />-->
- <!--<appender-ref ref="WARN_FILE" />-->
- <!--</root>-->
- <!--</springProfile>-->
-
- </configuration>
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
pom.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.4.1</version>
- <relativePath/> <!-- lookup parent from repository -->
- </parent>
- <groupId>com.test</groupId>
- <artifactId>test</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <name>test</name>
- <description>Demo project for Spring Boot</description>
-
- <properties>
- <java.version>1.8</java.version>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-mongodb</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-jdbc</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.kafka</groupId>
- <artifactId>spring-kafka</artifactId>
- </dependency>
- <dependency>
- <groupId>io.netty</groupId>
- <artifactId>netty-all</artifactId>
- </dependency>
- <dependency>
- <groupId>org.msgpack</groupId>
- <artifactId>msgpack</artifactId>
- <version>0.6.12</version>
- </dependency>
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-classic</artifactId>
- <version>1.2.3</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.logging.log4j</groupId>
- <artifactId>log4j-to-slf4j</artifactId>
- <version>2.10.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>jul-to-slf4j</artifactId>
- <version>1.7.25</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework.kafka</groupId>
- <artifactId>spring-kafka-test</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
-
- </project>
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。