当前位置:   article > 正文

Netty实现A服务信息到B服务信息转发_netty实现tcp转发

netty实现tcp转发

1、本代码需要一定java基础

Netty原理

我们都知道 Netty 是一个高性能、异步事件驱动的 NIO 框架,基于 JAVA NIO 提供的 API 实现

2、代码文件目录

直接上代码

1、往BBWConfig.properties写入服务信息

  1. package com.com.test.bbw;
  2. import org.apache.commons.logging.Log;
  3. import org.apache.commons.logging.LogFactory;
  4. import org.springframework.boot.context.properties.ConfigurationProperties;
  5. import org.springframework.context.annotation.PropertySource;
  6. import org.springframework.stereotype.Component;
  7. import java.io.*;
  8. import java.util.Properties;
  9. @Component
  10. @ConfigurationProperties
  11. @PropertySource("classpath:BBWConfig.properties")
  12. public class BBWConfig {
  13. private static final Log logger = LogFactory.getLog(BBWConfig.class);
  14. private String config_path = "src/main/resources/"; //本地路径
  15. private String config_filename = "BBWConfig.properties";
  16. private static Properties properties;
  17. private static String bbwServerIp; //BBW服务器地址
  18. private static String bbwServerPort; //BBW服务器端口
  19. private static String paySendPort; //支付发出端口
  20. private static String payRcvServerIp; //支付接收地址
  21. private static String payTcpRcvPort; //tcp支付接收端口
  22. private static String payHttpRcvPort; //http支付接收端口
  23. private static String warningNum; //AGENt重连次数警告consumer
  24. private static String encoding; //报文编码格式
  25. private static String reStartTime; //AGNET异常重连间隔(单位:毫秒)
  26. // Netty服务连接状态:连接中
  27. public static final int CONNECT_STATE_CONNECTING = 0;
  28. // Netty服务连接状态:连接成功
  29. public static final int CONNECT_STATE_SUCC = 1;
  30. // Netty服务连接状态:连接失败
  31. public static final int CONNECT_STATE_FAIL = -1;
  32. public BBWConfig() {
  33. String home =System.getProperty("user.dir");
  34. // set config file path
  35. if (null != home && !"".equals(home.trim())){
  36. if (!home.endsWith("/")){
  37. home = home + "/";
  38. }
  39. config_filename = home + config_path + config_filename;
  40. }
  41. else{
  42. config_filename = config_path + config_filename;
  43. }
  44. // check config file
  45. creatConfigFile();
  46. this.properties = getConfigFile();
  47. init();
  48. }
  49. private Properties getConfigFile() {
  50. properties = new Properties();
  51. try {
  52. FileReader fileReader = new FileReader(config_filename);
  53. properties.load(fileReader);
  54. fileReader.close();
  55. } catch (IOException e) {
  56. e.printStackTrace();
  57. }
  58. return properties;
  59. }
  60. public static Properties getProperties() {
  61. return properties;
  62. }
  63. public static void setProperties(Properties properties) {
  64. BBWConfig.properties = properties;
  65. }
  66. public static String getBbwServerIp() {
  67. return bbwServerIp;
  68. }
  69. public static void setBbwServerIp(String bbwServerIp) {
  70. BBWConfig.bbwServerIp = bbwServerIp;
  71. }
  72. public static String getBbwServerPort() {
  73. return bbwServerPort;
  74. }
  75. public static void setBbwServerPort(String bbwServerPort) {
  76. BBWConfig.bbwServerPort = bbwServerPort;
  77. }
  78. public static String getPaySendPort() {
  79. return paySendPort;
  80. }
  81. public static void setPaySendPort(String paySendPort) {
  82. BBWConfig.paySendPort = paySendPort;
  83. }
  84. public static String getPayRcvServerIp() {
  85. return payRcvServerIp;
  86. }
  87. public static void setPayRcvServerIp(String payRcvServerIp) {
  88. BBWConfig.payRcvServerIp = payRcvServerIp;
  89. }
  90. public static String getPayTcpRcvPort() {
  91. return payTcpRcvPort;
  92. }
  93. public static void setPayTcpRcvPort(String payTcpRcvPort) {
  94. BBWConfig.payTcpRcvPort = payTcpRcvPort;
  95. }
  96. public static String getPayHttpRcvPort() {
  97. return payHttpRcvPort;
  98. }
  99. public static void setPayHttpRcvPort(String payHttpRcvPort) {
  100. BBWConfig.payHttpRcvPort = payHttpRcvPort;
  101. }
  102. public static String getWarningNum() {
  103. return warningNum;
  104. }
  105. public static void setWarningNum(String warningNum) {
  106. BBWConfig.warningNum = warningNum;
  107. }
  108. public static String getEncoding() {
  109. return encoding;
  110. }
  111. public static void setEncoding(String encoding) {
  112. BBWConfig.encoding = encoding;
  113. }
  114. public static String getReStartTime() {
  115. return reStartTime;
  116. }
  117. public static void setReStartTime(String reStartTime) {
  118. BBWConfig.reStartTime = reStartTime;
  119. }
  120. /**
  121. *
  122. * @说明 创建默认的配置文件
  123. */
  124. private File creatConfigFile() {
  125. File file = new File(config_filename);
  126. if (logger.isInfoEnabled()) {
  127. logger.info("BBWConfig config_filename = " + config_filename);
  128. }
  129. if (!file.exists()) {
  130. if (logger.isInfoEnabled()) {
  131. logger.info("BBWConfig start creatConfigFile ..............");
  132. }
  133. try {
  134. file.createNewFile();
  135. OutputStreamWriter osw = new OutputStreamWriter(
  136. new FileOutputStream(file));
  137. osw.write("#BBW服务器地址" + "\n");
  138. osw.write("bbwServerIp=127.0.0.1" + "\n");
  139. osw.write("#BBW服务器端口" + "\n");
  140. osw.write("bbwServerPort=4444" + "\n");
  141. osw.write("#支付接出端口Tcp" + "\n");
  142. osw.write("paySendPort=50039" + "\n");
  143. osw.write("#支付接入平台地址" + "\n");
  144. osw.write("payRcvServerIp=127.0.0.1" + "\n");
  145. osw.write("#支付平台接入端口tcp" + "\n");
  146. osw.write("payTcpRcvPort=50040" + "\n");
  147. osw.write("#支付平台接入http端口" + "\n");
  148. osw.write("payHttpRcvPort=9004" + "\n");
  149. osw.write("#AGENt重连次数警告consumer" + "\n");
  150. osw.write("warningNum=10" + "\n");
  151. osw.write("#报文编码格式" + "\n");
  152. osw.write("encoding=UTF8" + "\n");
  153. osw.write("#AGNET异常重连间隔(单位:毫秒)" + "\n");
  154. osw.write("reStartTime=10000" + "\n");
  155. osw.close();
  156. } catch (IOException e) {
  157. e.printStackTrace();
  158. }
  159. }
  160. return file;
  161. }
  162. private void init(){
  163. BBWConfig.bbwServerIp=BBWConfig.properties.getProperty("bbwServerIp");
  164. BBWConfig.bbwServerPort=BBWConfig.properties.getProperty("bbwServerPort");
  165. BBWConfig.paySendPort=BBWConfig.properties.getProperty("paySendPort");
  166. BBWConfig.payRcvServerIp=BBWConfig.properties.getProperty("payRcvServerIp");
  167. BBWConfig.payTcpRcvPort=BBWConfig.properties.getProperty("payTcpRcvPort");
  168. BBWConfig.payHttpRcvPort=BBWConfig.properties.getProperty("payHttpRcvPort");
  169. BBWConfig.encoding=BBWConfig.properties.getProperty("encoding");
  170. BBWConfig.warningNum=BBWConfig.properties.getProperty("warningNum");
  171. }
  172. public static void main(String[] args) {
  173. BBWConfig nc = new BBWConfig();
  174. if (logger.isDebugEnabled()) {
  175. logger.debug("BBWConfig toString \n" + nc.getConfigFile().toString());
  176. }
  177. }
  178. }

 2、读取数据工具类

  1. package com.com.test.bbw;
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. import java.io.BufferedInputStream;
  5. import java.io.BufferedOutputStream;
  6. import java.io.ByteArrayOutputStream;
  7. import java.io.IOException;
  8. public class ConverUtils {
  9. private static final Logger log = LoggerFactory.getLogger(ConverUtils.class);
  10. private static final Integer msgLeng = 5;
  11. /**
  12. * 循环去写数据
  13. *
  14. * @param bos
  15. * @param buff
  16. * @param bufferCapacity
  17. * @throws IOException
  18. */
  19. public static void cycleWriteMessage(BufferedOutputStream bos, byte[] buff, int bufferCapacity) throws IOException {
  20. int len = buff.length;
  21. int count = 0;
  22. int tmpLen = len;
  23. while (true) {
  24. if (tmpLen <= bufferCapacity) {
  25. bos.write(buff, count, tmpLen);
  26. bos.flush();
  27. count += tmpLen;
  28. tmpLen = 0;
  29. } else {
  30. bos.write(buff, count, bufferCapacity);
  31. bos.flush();
  32. count += bufferCapacity;
  33. tmpLen -= bufferCapacity;
  34. }
  35. if (tmpLen == 0)
  36. break;
  37. }
  38. }
  39. /**
  40. * 循环去读数据
  41. *
  42. * @param bis
  43. * @param baos
  44. * @param bufferCapacity
  45. * @param len
  46. * @param socketReaderCircleTimes
  47. * @throws IOException
  48. */
  49. public static String cycleReadMessage(BufferedInputStream bis, StringBuffer msgInfo, int bufferCapacity, int len,
  50. int socketReaderCircleTimes) throws IOException {
  51. int index = 0;
  52. // 读取的明文长度
  53. int numberRead = 0;
  54. // 读取的字节长度
  55. int numberReadByte = 0;
  56. // 明文的长度变量
  57. int tmpLen = len;
  58. byte[] buff = null;
  59. // 定义可变字符串用于存储取到的明文数据
  60. StringBuffer msgTemp = new StringBuffer();
  61. for (int i = 0; i < socketReaderCircleTimes; i++) {
  62. buff = new byte[tmpLen];
  63. numberReadByte = bis.read(buff, 0, tmpLen);
  64. if (numberReadByte <= 0) {
  65. break;
  66. }
  67. // 拿到的字节数据转为16进制数据
  68. String asciiBytesToMsg = byteArr2HexStr(buff);
  69. String msg = convertHexToString(asciiBytesToMsg);
  70. msgTemp.append(msg);
  71. // 判断长度
  72. numberRead = asciiBytesToMsg.length();
  73. // 如果明文长度小于剩余报文头长度
  74. if (numberRead < tmpLen) {
  75. index += numberRead;
  76. tmpLen -= numberRead;
  77. } else {
  78. if (numberRead != tmpLen)
  79. break;
  80. index += numberRead;
  81. tmpLen -= numberRead;
  82. }
  83. if (tmpLen <= 0)
  84. break;
  85. }
  86. // 判断长度
  87. if (msgTemp.length() == len) {
  88. msgInfo.append(msgTemp);
  89. return msgInfo.toString();
  90. }
  91. return null;
  92. }
  93. /**
  94. * 将两个字节数组合并
  95. *
  96. * @param data1
  97. * @param data2
  98. * @return
  99. */
  100. public static byte[] addBytes(byte[] headData, byte[] bodyData) {
  101. byte[] data3 = null;
  102. if(null != bodyData && 0 < bodyData.length){
  103. data3 = new byte[headData.length + bodyData.length];
  104. System.arraycopy(headData, 0, data3, 0, headData.length);
  105. System.arraycopy(bodyData, 0, data3, headData.length, bodyData.length);
  106. }else {
  107. data3 = "00000".getBytes();
  108. }
  109. return data3;
  110. }
  111. /**
  112. * 循环去读报文的长度
  113. *
  114. * @param bis
  115. * @param baos
  116. * @param bufferCapacity
  117. * @param len
  118. * @param socketReaderCircleTimes
  119. * @throws IOException
  120. */
  121. public static void cycleReadMessageHeadLeng(BufferedInputStream bis, ByteArrayOutputStream baos, int bufferCapacity,
  122. int len, int socketReaderCircleTimes) throws IOException {
  123. int numberRead = 0;
  124. int tmpLen = len;
  125. int index = 0;
  126. byte[] buff = null;
  127. for (int i = 0; i < socketReaderCircleTimes; i++) {
  128. if (tmpLen < bufferCapacity) {
  129. buff = new byte[tmpLen];
  130. int available = bis.available();
  131. if(available >0){
  132. numberRead = bis.read(buff, 0, tmpLen);
  133. }else{
  134. continue;
  135. }
  136. } else {
  137. buff = new byte[bufferCapacity];
  138. numberRead = bis.read(buff, 0, bufferCapacity);
  139. }
  140. if (numberRead < 0) {
  141. return;
  142. }
  143. if (numberRead < tmpLen) {
  144. index += numberRead;
  145. tmpLen -= numberRead;
  146. byte[] tmpByte = new byte[numberRead];
  147. System.arraycopy(buff, 0, tmpByte, 0, numberRead);
  148. baos.write(tmpByte);
  149. } else {
  150. if (numberRead != tmpLen)
  151. break;
  152. index += numberRead;
  153. tmpLen -= numberRead;
  154. baos.write(buff);
  155. }
  156. if (tmpLen <= 0)
  157. break;
  158. }
  159. }
  160. /**
  161. * 将报文的2位ASCII码字符码转为10进制
  162. *
  163. * @param bytes
  164. * @return
  165. */
  166. public static int decodeMsgLength(byte[] bytes) {
  167. if (bytes != null && bytes.length == 2) {
  168. return bytes2Short(bytes, 0);
  169. } else {
  170. log.error("bytes of length cannot decode to int value.");
  171. }
  172. return 0;
  173. }
  174. public static short bytes2Short(byte[] b, int offset) {
  175. short n = (short) (((b[offset] < 0 ? b[offset] + 256 : b[offset]) << 8)
  176. + (b[offset + 1] < 0 ? b[offset + 1] + 256 : b[offset + 1]));
  177. return n;
  178. }
  179. public static byte[] encode(int lengthValue, int length) {
  180. if (lengthValue > 0 && length > 0) {
  181. byte[] bytes;
  182. try {
  183. String hexStr = Integer.toHexString(lengthValue);
  184. if (hexStr.length() % 2 != 0) {
  185. hexStr = "0" + hexStr;
  186. }
  187. bytes = hexstr2ByteArr(hexStr);
  188. byte[] ret = new byte[length];
  189. for (int i = 0; i < length; i++) {
  190. ret[i] = 0x00;
  191. }
  192. System.arraycopy(bytes, 0, ret, length - bytes.length, bytes.length);
  193. return ret;
  194. } catch (Exception e) {
  195. log.error("报文长度转化出错");
  196. }
  197. } else {
  198. if(lengthValue == 0){
  199. return "00000".getBytes();
  200. }
  201. log.error("无效的报文长度:"+lengthValue);
  202. }
  203. return new byte[0];
  204. }
  205. public static byte[] hexstr2ByteArr(String strIn) {
  206. byte[] arrB = strIn.getBytes();
  207. int iLen = arrB.length;
  208. byte[] arrOut = new byte[iLen / 2];
  209. for (int i = 0; i < iLen; i += 2) {
  210. String strTmp = new String(arrB, i, 2);
  211. arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
  212. }
  213. return arrOut;
  214. }
  215. /**
  216. * hex字符串转byte数组
  217. *
  218. * @param inHex
  219. * 待转换的Hex字符串
  220. * @return 转换后的byte数组结果
  221. */
  222. public static byte[] hexToByteArray(String inHex) {
  223. if (inHex != null && !inHex.isEmpty()) {
  224. int hexlen = inHex.trim().length();
  225. byte[] result;
  226. if (hexlen % 2 == 1) {
  227. // 奇数
  228. } else {
  229. // 偶数
  230. result = new byte[(hexlen / 2)];
  231. int j = 0;
  232. for (int i = 0; i < hexlen; i += 2) {
  233. result[j] = hexToByte(inHex.substring(i, i + 2));
  234. j++;
  235. }
  236. return result;
  237. }
  238. }
  239. return new byte[0];
  240. }
  241. /**
  242. * Hex字符串转byte
  243. *
  244. * @param inHex
  245. * 待转换的Hex字符串
  246. * @return 转换后的byte
  247. */
  248. public static byte hexToByte(String inHex) {
  249. return (byte) Integer.parseInt(inHex, 16);
  250. }
  251. /**
  252. * ASCII码转换为16进制
  253. *
  254. * @param str
  255. * @return
  256. */
  257. public static String convertStringToHex(String str) {
  258. char[] chars = str.toCharArray();
  259. StringBuffer hex = new StringBuffer();
  260. for (int i = 0; i < chars.length; i++) {
  261. hex.append(Integer.toHexString((int) chars[i]));
  262. }
  263. return hex.toString();
  264. }
  265. /**
  266. * 将字节数组转为16进制数据
  267. *
  268. * @param arrB
  269. * @return
  270. * @throws IOException
  271. */
  272. public static String byteArr2HexStr(byte[] arrB) throws IOException {
  273. int iLen = arrB.length;
  274. StringBuffer sb = new StringBuffer(iLen * 2);
  275. for (int i = 0; i < iLen; ++i) {
  276. int intTmp;
  277. for (intTmp = arrB[i]; intTmp < 0; intTmp += 256) {
  278. }
  279. if (intTmp < 16) {
  280. sb.append("0");
  281. }
  282. sb.append(Integer.toString(intTmp, 16));
  283. }
  284. return sb.toString();
  285. }
  286. /**
  287. *
  288. * 16进制数据转为明文
  289. * @param arrB
  290. * @return
  291. * @throws IOException
  292. */
  293. public static String convertHexToString(String hex) {
  294. StringBuilder sb = new StringBuilder();
  295. StringBuilder temp = new StringBuilder();
  296. for (int i = 0; i < hex.length() - 1; i += 2) {
  297. String output = hex.substring(i, (i + 2));
  298. int decimal = Integer.parseInt(output, 16);
  299. sb.append((char) decimal);
  300. temp.append(decimal);
  301. }
  302. return sb.toString();
  303. }
  304. /**
  305. * 左补齐
  306. *
  307. * @param 原字符串
  308. * @param 左补字符
  309. * @param 补齐长度
  310. * @return 如果原字符串超长,返回原字符串
  311. */
  312. public static String lpad(String str, char ch, int len) {
  313. if (str.length() >= len) {
  314. return str;
  315. }
  316. char[] origChs = str.toCharArray();
  317. char[] chs = new char[len];
  318. int pos = len - origChs.length;
  319. for (int i = 0; i < len; i++) {
  320. if (i < pos) {
  321. chs[i] = ch;
  322. } else {
  323. chs[i] = origChs[i - pos];
  324. }
  325. }
  326. return new String(chs);
  327. }
  328. }

 3、解码

  1. package com.com.test.bbw;
  2. import io.netty.buffer.ByteBuf;
  3. import io.netty.channel.ChannelHandlerContext;
  4. import io.netty.handler.codec.MessageToMessageDecoder;
  5. import java.util.List;
  6. public class MsgPckDecode extends MessageToMessageDecoder<ByteBuf> {
  7. //明文长度
  8. private static final Integer msgLeng = 5;
  9. @Override
  10. protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
  11. final byte[] headMessage;
  12. final byte[] contentMessage;
  13. headMessage = new byte[2];
  14. // 定义可变字符串用于存储取到的明文数据
  15. StringBuffer msgTemp = new StringBuffer();
  16. //获取报文长度
  17. msg.getBytes(msg.readerIndex(), headMessage, 0, 2);
  18. // 将两位报文ASII码数据转为10进制长度
  19. int msgLength = ConverUtils.decodeMsgLength(headMessage);
  20. String msgLengthStr = msgLength+"";
  21. msgLengthStr = ConverUtils.lpad(msgLengthStr, '0', msgLeng);
  22. msgTemp.append(msgLengthStr);
  23. //根据报文长度读取内容
  24. contentMessage = new byte[msgLength];
  25. msg.getBytes(2, contentMessage, 0, msgLength);
  26. // 拿到的字节数据转为16进制数据
  27. String asciiBytesToMsg = ConverUtils.byteArr2HexStr(contentMessage);
  28. String message = ConverUtils.convertHexToString(asciiBytesToMsg);
  29. msgTemp.append(message);
  30. out.add(msgTemp.toString());
  31. }
  32. }
  1. package com.com.test.bbw;
  2. import io.netty.buffer.ByteBuf;
  3. import io.netty.channel.ChannelHandlerContext;
  4. import io.netty.handler.codec.MessageToByteEncoder;
  5. import org.msgpack.MessagePack;
  6. public class MsgPckEncode extends MessageToByteEncoder<Object> {
  7. private static final Integer msgLeng = 5;
  8. @Override
  9. protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf buf) throws Exception {
  10. MessagePack pack = new MessagePack();
  11. String dataStr = (String) msg;
  12. // 第一步:获取报文长度
  13. int msgLength = Integer.parseInt(dataStr.substring(0, msgLeng));
  14. String msgInfo = dataStr.substring(msgLeng);
  15. //将报文 长度转为16进制 ,内容转为ASCII码
  16. String convertStringToHex = ConverUtils.convertStringToHex(msgInfo);
  17. byte[] message = ConverUtils.addBytes(ConverUtils.encode(msgLength, 2), ConverUtils.hexToByteArray(convertStringToHex));
  18. buf.writeBytes(message);
  19. }
  20. }

4、前置与服务B之间长链接,支持断线重连机制 

  1. package com.com.test.bbw;
  2. import io.netty.bootstrap.Bootstrap;
  3. import io.netty.channel.*;
  4. import io.netty.channel.nio.NioEventLoopGroup;
  5. import io.netty.channel.socket.SocketChannel;
  6. import io.netty.channel.socket.nio.NioSocketChannel;
  7. import io.netty.handler.timeout.IdleStateHandler;
  8. import org.slf4j.Logger;
  9. import org.slf4j.LoggerFactory;
  10. import java.util.concurrent.TimeUnit;
  11. public class TCPBBWAdaptor {
  12. private static final Logger log = LoggerFactory.getLogger(TCPBBWAdaptor.class);
  13. private String bbwServerIp;
  14. private int bbwServerPort;/* 端口 */
  15. private String encoding;/* 编码方式 */
  16. private int timeout=10000;/* 超时时间:秒 */
  17. private EventLoopGroup group;
  18. private Bootstrap client;
  19. private Channel channel;
  20. public static Logger getLog() {
  21. return log;
  22. }
  23. private ChannelFuture future;
  24. public TCPBBWAdaptor() {
  25. init();
  26. group = new NioEventLoopGroup();
  27. client = new Bootstrap();
  28. client.group(group);
  29. client.channel(NioSocketChannel.class);
  30. client.option(ChannelOption.SO_KEEPALIVE, true);
  31. client.handler(new ChannelInitializer<SocketChannel>() {
  32. @Override
  33. protected void initChannel(SocketChannel ch) throws Exception {
  34. // 按照\r\n进行解码
  35. //ch.pipeline().addLast(new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, Delimiters.lineDelimiter()[0]));
  36. ch.pipeline().addLast(new IdleStateHandler(0, 0, 5))
  37. .addLast(new MsgPckDecode())
  38. .addLast(new MsgPckEncode())
  39. .addLast(new TcpBBWClientHandler(TCPBBWAdaptor.this));
  40. }
  41. });
  42. }
  43. public Object send(Object msg) {
  44. try {
  45. if (channel != null && channel.isActive()) {
  46. doSend(msg);
  47. } else {
  48. restConnOrConn();
  49. send(msg);
  50. }
  51. } catch (Exception e) {
  52. log.info("连接异常!");
  53. group.shutdownGracefully();
  54. }
  55. return msg;
  56. }
  57. private void doSend(Object msg) {
  58. group.execute(new Runnable() {
  59. @Override
  60. public void run() {
  61. channel.writeAndFlush(msg);
  62. }
  63. });
  64. }
  65. public void restConnOrConn() throws InterruptedException {
  66. future = client.connect(bbwServerIp, bbwServerPort).sync();
  67. future.addListener(new ChannelFutureListener() {
  68. @Override
  69. public void operationComplete(ChannelFuture future) throws Exception {
  70. if (future.isSuccess()) {
  71. channel = future.channel();
  72. } else {
  73. future.channel().eventLoop().schedule(new Runnable() {
  74. @Override
  75. public void run() {
  76. try {
  77. restConnOrConn();
  78. } catch (InterruptedException e) {
  79. // TODO Auto-generated catch block
  80. e.printStackTrace();
  81. }
  82. }
  83. }, 2, TimeUnit.SECONDS);
  84. }
  85. }
  86. });
  87. }
  88. public void init(){
  89. this.bbwServerIp=BBWConfig.getBbwServerIp();
  90. this.bbwServerPort= Integer.parseInt(BBWConfig.getBbwServerPort());
  91. this.encoding=BBWConfig.getEncoding();
  92. }
  93. }
  1. package com.com.test.bbw;
  2. import com.com.test.client.TCPPayAdaptor;
  3. import io.netty.channel.ChannelHandlerContext;
  4. import io.netty.channel.ChannelInboundHandlerAdapter;
  5. import io.netty.handler.timeout.IdleStateEvent;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8. import org.springframework.util.StringUtils;
  9. public class TcpBBWClientHandler extends ChannelInboundHandlerAdapter {
  10. private static final Logger log = LoggerFactory.getLogger(TcpBBWClientHandler.class);
  11. // 明文报文长度
  12. private static final Integer msgLeng = 5;
  13. private TCPBBWAdaptor clinet;
  14. public TcpBBWClientHandler(TCPBBWAdaptor clinet) {
  15. this.clinet = clinet;
  16. }
  17. /**
  18. * 客户端与服务端创建连接的时候调用
  19. */
  20. @Override
  21. public void channelActive(ChannelHandlerContext ctx) throws Exception {
  22. ctx.fireChannelActive();
  23. }
  24. /**
  25. * 客户端与服务端断开连接时调用
  26. */
  27. @Override
  28. public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  29. clinet.restConnOrConn();
  30. }
  31. /**
  32. * 服务端接收客户端发送过来的数据结束之后调用
  33. */
  34. @Override
  35. public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  36. ctx.flush();
  37. }
  38. /**
  39. * 工程出现异常的时候调用
  40. */
  41. @Override
  42. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  43. cause.printStackTrace();
  44. ctx.close();
  45. //重新连接
  46. clinet.restConnOrConn();
  47. }
  48. /**
  49. * 心跳处理方法
  50. */
  51. @Override
  52. public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
  53. // 如果属于心跳处理
  54. if (evt instanceof IdleStateEvent) {
  55. IdleStateEvent event = (IdleStateEvent) evt;
  56. switch (event.state()) {
  57. case READER_IDLE:
  58. break;
  59. case WRITER_IDLE:
  60. break;
  61. case ALL_IDLE:
  62. //发送心跳
  63. sendMsg(ctx);
  64. break;
  65. }
  66. }
  67. super.userEventTriggered(ctx, evt);
  68. }
  69. private void sendMsg(ChannelHandlerContext ctx) {
  70. ctx.channel().writeAndFlush("");
  71. }
  72. @Override
  73. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  74. ctx.channel().eventLoop().execute(new Runnable() {
  75. @Override
  76. public void run() {
  77. final String msgL=(String)msg;
  78. if (!StringUtils.isEmpty(msgL)) {
  79. log.debug("接收到报文为:" +msg);
  80. TCPPayAdaptor payAdaptor=new TCPPayAdaptor();
  81. payAdaptor.send(msg);
  82. }
  83. }
  84. });
  85. }
  86. }

 5、前置与服务A之间短连接,异步调用

  1. package com.com.test.client;
  2. import com.com.test.bbw.BBWConfig;
  3. import io.netty.bootstrap.Bootstrap;
  4. import io.netty.buffer.ByteBuf;
  5. import io.netty.buffer.Unpooled;
  6. import io.netty.channel.*;
  7. import io.netty.channel.nio.NioEventLoopGroup;
  8. import io.netty.channel.socket.SocketChannel;
  9. import io.netty.channel.socket.nio.NioSocketChannel;
  10. import io.netty.handler.codec.string.StringDecoder;
  11. import io.netty.handler.codec.string.StringEncoder;
  12. import io.netty.handler.timeout.IdleStateHandler;
  13. import org.slf4j.Logger;
  14. import org.slf4j.LoggerFactory;
  15. import org.springframework.util.StringUtils;
  16. import java.io.UnsupportedEncodingException;
  17. public class TCPPayAdaptor {
  18. private static final Logger log = LoggerFactory.getLogger(TCPPayAdaptor.class);
  19. private String payRcvServerIp;
  20. private int payTcpRcvPort;/* 端口 */
  21. private String encoding;/* 编码方式 */
  22. private int timeout=20000;/* 超时时间:秒 */
  23. private EventLoopGroup group;
  24. private Bootstrap client;
  25. private Channel channel;
  26. public static Logger getLog() {
  27. return log;
  28. }
  29. private ChannelFuture future;
  30. public TCPPayAdaptor() {
  31. init();
  32. group = new NioEventLoopGroup();
  33. client = new Bootstrap();
  34. client.group(group);
  35. client.channel(NioSocketChannel.class);
  36. client.option(ChannelOption.SO_KEEPALIVE, true);
  37. client.handler(new ChannelInitializer<SocketChannel>() {
  38. @Override
  39. protected void initChannel(SocketChannel ch) throws Exception {
  40. // 按照\r\n进行解码
  41. //ch.pipeline().addLast(new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, Delimiters.lineDelimiter()[0]));
  42. ch.pipeline().addLast(new IdleStateHandler(0, 0, 5))
  43. .addLast(new StringDecoder())
  44. .addLast(new StringEncoder())
  45. .addLast(new TcpPayClientHandler());
  46. }
  47. });
  48. try {
  49. future = client.connect(payRcvServerIp, payTcpRcvPort).sync();
  50. if(future!=null&&future.isSuccess()){
  51. channel=future.channel();
  52. }
  53. } catch (InterruptedException e) {
  54. e.printStackTrace();
  55. }
  56. }
  57. public Object send(Object msg) {
  58. try {
  59. if (channel != null && channel.isActive()) {
  60. doSend(msg);
  61. }
  62. } catch (Exception e) {
  63. log.info("连接异常!");
  64. group.shutdownGracefully();
  65. }
  66. return msg;
  67. }
  68. private void doSend(Object msg) {
  69. try {
  70. final String msgL=(String)msg;
  71. byte[] bytes = msgL.getBytes(encoding);
  72. ByteBuf buf = Unpooled.wrappedBuffer(bytes);
  73. byte[] req = new byte[buf.readableBytes()];
  74. buf.readBytes(req);
  75. String smsg = new String(req, encoding);
  76. if (!StringUtils.isEmpty(smsg)) {
  77. log.debug("接收到报文为:" + smsg);
  78. channel.writeAndFlush(smsg);
  79. }
  80. ByteBuf buffer = Unpooled.buffer();
  81. buffer.writeBytes(req);
  82. } catch (UnsupportedEncodingException e) {
  83. log.info("bbw返回发送异常");
  84. }
  85. }
  86. public void init(){
  87. this.payTcpRcvPort= Integer.parseInt(BBWConfig.getPayTcpRcvPort());
  88. this.payRcvServerIp= BBWConfig.getPayRcvServerIp();
  89. this.encoding= BBWConfig.getEncoding();
  90. }
  91. }
  1. package com.com.test.client;
  2. import io.netty.channel.ChannelHandlerContext;
  3. import io.netty.channel.ChannelInboundHandlerAdapter;
  4. import io.netty.handler.timeout.IdleStateEvent;
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7. import java.lang.reflect.Method;
  8. public class TcpPayClientHandler extends ChannelInboundHandlerAdapter {
  9. private static final Logger log = LoggerFactory.getLogger(TcpPayClientHandler.class);
  10. // 明文报文长度
  11. private static final Integer msgLeng = 5;
  12. /**
  13. * 客户端与服务端创建连接的时候调用
  14. */
  15. @Override
  16. public void channelActive(ChannelHandlerContext ctx) throws Exception {
  17. ctx.fireChannelActive();
  18. }
  19. /**
  20. * 客户端与服务端断开连接时调用
  21. */
  22. @Override
  23. public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  24. ctx.channel().writeAndFlush("");
  25. }
  26. /**
  27. * 服务端接收客户端发送过来的数据结束之后调用
  28. */
  29. @Override
  30. public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  31. ctx.flush();
  32. }
  33. /**
  34. * 工程出现异常的时候调用
  35. */
  36. @Override
  37. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  38. cause.printStackTrace();
  39. ctx.close();
  40. }
  41. }

6、 服务B监听器,用来监听B系统发送给前置消息,用来转发到服务A

  1. package com.com.test.listener;
  2. import com.com.test.server.Server;
  3. import org.apache.commons.logging.Log;
  4. import org.apache.commons.logging.LogFactory;
  5. import org.springframework.boot.ApplicationArguments;
  6. import org.springframework.boot.ApplicationRunner;
  7. import org.springframework.stereotype.Component;
  8. @Component
  9. public class BBWListener implements ApplicationRunner{
  10. private static final Log logger = LogFactory.getLog(BBWListener.class);
  11. @Override
  12. public void run(ApplicationArguments args) throws Exception {
  13. if (logger.isInfoEnabled()) {
  14. logger.info("Starting booting core banking services platform...");
  15. }
  16. // Start
  17. try {
  18. Server server = new Server();
  19. server.start();
  20. } catch (Exception e) {
  21. e.printStackTrace();
  22. logger.error(e);
  23. }
  24. if (logger.isInfoEnabled()) {
  25. logger.info("Started booted bbw banking services platform...");
  26. }
  27. }
  28. }

7、接收到系统B消息服务端

  1. package com.com.test.server;
  2. import com.com.test.bbw.BBWConfig;
  3. import io.netty.bootstrap.ServerBootstrap;
  4. import io.netty.channel.ChannelFuture;
  5. import io.netty.channel.ChannelInitializer;
  6. import io.netty.channel.ChannelOption;
  7. import io.netty.channel.ChannelPipeline;
  8. import io.netty.channel.EventLoopGroup;
  9. import io.netty.channel.nio.NioEventLoopGroup;
  10. import io.netty.channel.socket.ServerSocketChannel;
  11. import io.netty.channel.socket.SocketChannel;
  12. import io.netty.channel.socket.nio.NioServerSocketChannel;
  13. import io.netty.handler.codec.string.StringDecoder;
  14. import io.netty.handler.codec.string.StringEncoder;
  15. import org.apache.commons.logging.Log;
  16. import org.apache.commons.logging.LogFactory;
  17. public class Server {
  18. private static final Log logger = LogFactory.getLog(Server.class);
  19. private int paySendPort;
  20. private String encoding;/* 编码方式 */
  21. private int timeout = 10000;/* 超时时间:秒 */
  22. private int conNum = 1;/* 保持连接数 */
  23. private ServerSocketChannel serverSocketChannel;
  24. private void bind() {
  25. //服务端要建立两个group,一个负责接收客户端的连接,一个负责处理数据传输
  26. //连接处理group
  27. EventLoopGroup boss = new NioEventLoopGroup();
  28. //事件处理group
  29. EventLoopGroup worker = new NioEventLoopGroup();
  30. ServerBootstrap bootstrap = new ServerBootstrap();
  31. // 绑定处理group
  32. bootstrap.group(boss, worker).channel(NioServerSocketChannel.class)
  33. //保持连接数
  34. // .option(ChannelOption.SO_BACKLOG, conNum)
  35. //有数据立即发送
  36. .option(ChannelOption.TCP_NODELAY, true)
  37. //保持连接
  38. .childOption(ChannelOption.SO_KEEPALIVE, false)
  39. //处理新连接
  40. .childHandler(new ChannelInitializer<SocketChannel>() {
  41. @Override
  42. protected void initChannel(SocketChannel sc) throws Exception {
  43. // 增加任务处理
  44. ChannelPipeline p = sc.pipeline();
  45. p.addLast(
  46. //使用了netty自带的编码器和解码器
  47. new StringDecoder(),
  48. new StringEncoder(),
  49. //心跳检测,读超时,写超时,读写超时
  50. //new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS),
  51. //自定义的处理器
  52. new ServerHandler());
  53. }
  54. });
  55. //绑定端口,同步等待成功
  56. ChannelFuture future;
  57. try {
  58. future = bootstrap.bind(paySendPort).sync();
  59. if (future.isSuccess()) {
  60. serverSocketChannel = (ServerSocketChannel) future.channel();
  61. logger.info("服务端启动成功,端口:" + paySendPort);
  62. } else {
  63. logger.info("服务端启动失败!");
  64. }
  65. //等待服务监听端口关闭,就是由于这里会将线程阻塞,导致无法发送信息,所以我这里开了线程
  66. future.channel().closeFuture().sync();
  67. } catch (Exception e) {
  68. e.printStackTrace();
  69. } finally {
  70. //优雅地退出,释放线程池资源
  71. boss.shutdownGracefully();
  72. worker.shutdownGracefully();
  73. }
  74. }
  75. public void init() {
  76. this.paySendPort = Integer.parseInt(BBWConfig.getPaySendPort());
  77. this.encoding = BBWConfig.getEncoding();
  78. }
  79. public void start() {
  80. init();
  81. bind();
  82. }
  83. }

 7、接收到系统B消息客户端,调用

TCPPayAdaptor转发到系统A
  1. package com.com.test.server;
  2. import com.com.test.bbw.TCPBBWAdaptor;
  3. import io.netty.buffer.ByteBuf;
  4. import io.netty.buffer.Unpooled;
  5. import io.netty.channel.ChannelHandlerContext;
  6. import io.netty.channel.ChannelInboundHandlerAdapter;
  7. import io.netty.util.CharsetUtil;
  8. import org.apache.commons.logging.Log;
  9. import org.apache.commons.logging.LogFactory;
  10. import org.springframework.util.StringUtils;
  11. import java.io.UnsupportedEncodingException;
  12. public class ServerHandler extends ChannelInboundHandlerAdapter {
  13. private static final Log logger = LogFactory.getLog(ServerHandler.class);
  14. /**
  15. * 客户端与服务端创建连接的时候调用
  16. */
  17. @Override
  18. public void channelActive(ChannelHandlerContext ctx) throws Exception {
  19. ctx.fireChannelActive();
  20. }
  21. /**
  22. * 一旦建立连接第一个被执行
  23. */
  24. @Override
  25. public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
  26. }
  27. /**
  28. * 客户端与服务端断开连接时调用
  29. */
  30. @Override
  31. public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  32. ctx.close();
  33. }
  34. /**
  35. * 服务端接收客户端发送过来的数据结束之后调用
  36. */
  37. @Override
  38. public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  39. ctx.flush();
  40. }
  41. /**
  42. * 工程出现异常的时候调用
  43. */
  44. @Override
  45. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  46. cause.printStackTrace();
  47. ctx.close();
  48. }
  49. /**
  50. * 服务端处理客户端websocket请求的核心方法,这里接收了客户端发来的信息
  51. */
  52. @Override
  53. public void channelRead(ChannelHandlerContext channelHandlerContext, Object info) throws Exception {
  54. logger.info("接收到了:" + info);
  55. try {
  56. final String msgL=(String)info;
  57. byte[] bytes = msgL.getBytes(CharsetUtil.UTF_8);
  58. ByteBuf buf = Unpooled.wrappedBuffer(bytes);
  59. byte[] req = new byte[buf.readableBytes()];
  60. buf.readBytes(req);
  61. String smsg = new String(req, CharsetUtil.UTF_8);
  62. if (!StringUtils.isEmpty(smsg)) {
  63. logger.debug("接收到报文为:" + smsg);
  64. new TCPBBWAdaptor().send(info);
  65. }
  66. ByteBuf buffer = Unpooled.buffer();
  67. buffer.writeBytes(req);
  68. } catch (Exception e) {
  69. logger.info("bbw返回发送异常");
  70. }
  71. }
  72. }

8、启动类 

  1. import org.springframework.boot.SpringApplication;
  2. import org.springframework.boot.autoconfigure.SpringBootApplication;
  3. import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  4. import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
  5. import org.springframework.context.annotation.ComponentScan;
  6. @ComponentScan(basePackages = {"com"})
  7. @SuppressWarnings("all")
  8. @SpringBootApplication(exclude= {DataSourceAutoConfiguration.class, MongoAutoConfiguration.class})
  9. public class TestApplication {
  10. public static void main(String[] args) {
  11. SpringApplication.run(TestApplication.class, args);
  12. }
  13. }
日志
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

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
  3. <!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
  4. <!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
  5. <!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
  6. <configuration scan="true" scanPeriod="10 seconds">
  7. <!--<include resource="org/springframework/boot/logging/logback/base.xml" />-->
  8. <contextName>logback</contextName>
  9. <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
  10. <property name="log.path" value="D:/nmyslog/nmys" />
  11. <!-- 彩色日志 -->
  12. <!-- 彩色日志依赖的渲染类 -->
  13. <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
  14. <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
  15. <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
  16. <!-- 彩色日志格式 -->
  17. <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}}"/>
  18. <!--输出到控制台-->
  19. <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
  20. <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
  21. <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
  22. <level>info</level>
  23. </filter>
  24. <encoder>
  25. <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
  26. <!-- 设置字符集 -->
  27. <charset>UTF-8</charset>
  28. </encoder>
  29. </appender>
  30. <!--输出到文件-->
  31. <!-- 时间滚动输出 level为 DEBUG 日志 -->
  32. <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  33. <!-- 正在记录的日志文件的路径及文件名 -->
  34. <file>${log.path}/log_debug.log</file>
  35. <!--日志文件输出格式-->
  36. <encoder>
  37. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
  38. <charset>UTF-8</charset> <!-- 设置字符集 -->
  39. </encoder>
  40. <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
  41. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  42. <!-- 日志归档 -->
  43. <fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
  44. <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  45. <maxFileSize>100MB</maxFileSize>
  46. </timeBasedFileNamingAndTriggeringPolicy>
  47. <!--日志文件保留天数-->
  48. <maxHistory>15</maxHistory>
  49. </rollingPolicy>
  50. <!-- 此日志文件只记录debug级别的 -->
  51. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  52. <level>debug</level>
  53. <onMatch>ACCEPT</onMatch>
  54. <onMismatch>DENY</onMismatch>
  55. </filter>
  56. </appender>
  57. <!-- 时间滚动输出 level为 INFO 日志 -->
  58. <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  59. <!-- 正在记录的日志文件的路径及文件名 -->
  60. <file>${log.path}/log_info.log</file>
  61. <!--日志文件输出格式-->
  62. <encoder>
  63. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
  64. <charset>UTF-8</charset>
  65. </encoder>
  66. <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
  67. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  68. <!-- 每天日志归档路径以及格式 -->
  69. <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
  70. <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  71. <maxFileSize>100MB</maxFileSize>
  72. </timeBasedFileNamingAndTriggeringPolicy>
  73. <!--日志文件保留天数-->
  74. <maxHistory>15</maxHistory>
  75. </rollingPolicy>
  76. <!-- 此日志文件只记录info级别的 -->
  77. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  78. <level>info</level>
  79. <onMatch>ACCEPT</onMatch>
  80. <onMismatch>DENY</onMismatch>
  81. </filter>
  82. </appender>
  83. <!-- 时间滚动输出 level为 WARN 日志 -->
  84. <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  85. <!-- 正在记录的日志文件的路径及文件名 -->
  86. <file>${log.path}/log_warn.log</file>
  87. <!--日志文件输出格式-->
  88. <encoder>
  89. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
  90. <charset>UTF-8</charset> <!-- 此处设置字符集 -->
  91. </encoder>
  92. <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
  93. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  94. <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
  95. <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  96. <maxFileSize>100MB</maxFileSize>
  97. </timeBasedFileNamingAndTriggeringPolicy>
  98. <!--日志文件保留天数-->
  99. <maxHistory>15</maxHistory>
  100. </rollingPolicy>
  101. <!-- 此日志文件只记录warn级别的 -->
  102. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  103. <level>warn</level>
  104. <onMatch>ACCEPT</onMatch>
  105. <onMismatch>DENY</onMismatch>
  106. </filter>
  107. </appender>
  108. <!-- 时间滚动输出 level为 ERROR 日志 -->
  109. <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  110. <!-- 正在记录的日志文件的路径及文件名 -->
  111. <file>${log.path}/log_error.log</file>
  112. <!--日志文件输出格式-->
  113. <encoder>
  114. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
  115. <charset>UTF-8</charset> <!-- 此处设置字符集 -->
  116. </encoder>
  117. <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
  118. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  119. <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
  120. <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  121. <maxFileSize>100MB</maxFileSize>
  122. </timeBasedFileNamingAndTriggeringPolicy>
  123. <!--日志文件保留天数-->
  124. <maxHistory>15</maxHistory>
  125. </rollingPolicy>
  126. <!-- 此日志文件只记录ERROR级别的 -->
  127. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  128. <level>ERROR</level>
  129. <onMatch>ACCEPT</onMatch>
  130. <onMismatch>DENY</onMismatch>
  131. </filter>
  132. </appender>
  133. <!--
  134. <logger>用来设置某一个包或者具体的某一个类的日志打印级别、
  135. 以及指定<appender>。<logger>仅有一个name属性,
  136. 一个可选的level和一个可选的addtivity属性。
  137. name:用来指定受此logger约束的某一个包或者具体的某一个类。
  138. level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
  139. 还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
  140. 如果未设置此属性,那么当前logger将会继承上级的级别。
  141. addtivity:是否向上级logger传递打印信息。默认是true。
  142. -->
  143. <!--<logger name="org.springframework.web" level="info"/>-->
  144. <!--<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>-->
  145. <!--
  146. 使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
  147. 第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
  148. 第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
  149. -->
  150. <!--
  151. root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
  152. level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
  153. 不能设置为INHERITED或者同义词NULL。默认是DEBUG
  154. 可以包含零个或多个元素,标识这个appender将会添加到这个logger。
  155. -->
  156. <!--开发环境:打印控制台-->
  157. <springProfile name="dev">
  158. <logger name="com.com.test.bbw" level="debug"/>
  159. </springProfile>
  160. <root level="info">
  161. <appender-ref ref="CONSOLE" />
  162. <appender-ref ref="DEBUG_FILE" />
  163. <appender-ref ref="INFO_FILE" />
  164. <appender-ref ref="WARN_FILE" />
  165. <appender-ref ref="ERROR_FILE" />
  166. </root>
  167. <!--生产环境:输出到文件-->
  168. <!--<springProfile name="pro">-->
  169. <!--<root level="info">-->
  170. <!--<appender-ref ref="CONSOLE" />-->
  171. <!--<appender-ref ref="DEBUG_FILE" />-->
  172. <!--<appender-ref ref="INFO_FILE" />-->
  173. <!--<appender-ref ref="ERROR_FILE" />-->
  174. <!--<appender-ref ref="WARN_FILE" />-->
  175. <!--</root>-->
  176. <!--</springProfile>-->
  177. </configuration>

pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.4.1</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.test</groupId>
  12. <artifactId>test</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>test</name>
  15. <description>Demo project for Spring Boot</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-data-mongodb</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework.boot</groupId>
  26. <artifactId>spring-boot-starter-jdbc</artifactId>
  27. </dependency>
  28. <dependency>
  29. <groupId>org.springframework.boot</groupId>
  30. <artifactId>spring-boot-starter-web</artifactId>
  31. </dependency>
  32. <dependency>
  33. <groupId>org.springframework.kafka</groupId>
  34. <artifactId>spring-kafka</artifactId>
  35. </dependency>
  36. <dependency>
  37. <groupId>io.netty</groupId>
  38. <artifactId>netty-all</artifactId>
  39. </dependency>
  40. <dependency>
  41. <groupId>org.msgpack</groupId>
  42. <artifactId>msgpack</artifactId>
  43. <version>0.6.12</version>
  44. </dependency>
  45. <dependency>
  46. <groupId>ch.qos.logback</groupId>
  47. <artifactId>logback-classic</artifactId>
  48. <version>1.2.3</version>
  49. <scope>compile</scope>
  50. </dependency>
  51. <dependency>
  52. <groupId>org.apache.logging.log4j</groupId>
  53. <artifactId>log4j-to-slf4j</artifactId>
  54. <version>2.10.0</version>
  55. <scope>compile</scope>
  56. </dependency>
  57. <dependency>
  58. <groupId>org.slf4j</groupId>
  59. <artifactId>jul-to-slf4j</artifactId>
  60. <version>1.7.25</version>
  61. <scope>compile</scope>
  62. </dependency>
  63. <dependency>
  64. <groupId>org.springframework.boot</groupId>
  65. <artifactId>spring-boot-starter-test</artifactId>
  66. <scope>test</scope>
  67. </dependency>
  68. <dependency>
  69. <groupId>org.springframework.kafka</groupId>
  70. <artifactId>spring-kafka-test</artifactId>
  71. <scope>test</scope>
  72. </dependency>
  73. </dependencies>
  74. <build>
  75. <plugins>
  76. <plugin>
  77. <groupId>org.springframework.boot</groupId>
  78. <artifactId>spring-boot-maven-plugin</artifactId>
  79. </plugin>
  80. </plugins>
  81. </build>
  82. </project>

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号