pipIrr-platform/pipIrr-common/src/main/java/com/dy/common/mw/protocol/p206V1_0_0/CodeV1_0_1.java
@@ -30,6 +30,8 @@ public static final String cd_93 = "93" ;//遥控关闭阀门 public static final String cd_97 = "97" ;//APP远程开阀 public static final String cd_98 = "98" ;//APP远程关阀 public static final String cd_99 = "99" ;//定时关阀开阀 public static final String cd_A0 = "A0" ;//定量关阀开阀 public static final String cd_3C = "3C" ;//设置水价 public static final String cd_6C = "6C" ;//查询水价 public static final String cd_3D = "3D" ;//设置黑名单 @@ -63,11 +65,13 @@ (code.equals(cd_93) ? "遥控关闭阀门" : (code.equals(cd_97) ? "APP远程开阀" : (code.equals(cd_98) ? "APP远程关阀" : (code.equals(cd_99) ? "定时关阀开阀" : (code.equals(cd_A0) ? "定量关阀开阀" : (code.equals(cd_3C) ? "设置水价" : (code.equals(cd_6C) ? "查询水价" : (code.equals(cd_3D) ? "设置黑名单" : (code.equals(cd_C0) ? "自报实时数据" : ""))))))))))))))))))))))))))))))) ; ""))))))))))))))))))))))))))))))))) ; return name ; } pipIrr-platform/pipIrr-common/src/main/java/com/dy/common/mw/protocol/p206V1_0_0/downVos/Com99Vo.java
New file @@ -0,0 +1,17 @@ package com.dy.common.mw.protocol.p206V1_0_0.downVos; import lombok.Data; /** * @Author: liurunyu * @Date: 2024/5/28 21:30 * @Description 定时关阀开阀 */ @Data public class Com99Vo { public String icCardNo ;//17位虚拟IC卡编号(协议是10位数字) public Integer moneyRemain;//剩余金额(取值范围0.00~999999.99,单位为元) public Double waterPrice;//水价(取值范围0.00~99.99元/m3) public Integer minutes ;//用水时长(0~9999分钟) public String orderNo ;//订单号(16位数字) } pipIrr-platform/pipIrr-common/src/main/java/com/dy/common/mw/protocol/p206V1_0_0/downVos/ComA0Vo.java
New file @@ -0,0 +1,17 @@ package com.dy.common.mw.protocol.p206V1_0_0.downVos; import lombok.Data; /** * @Author: liurunyu * @Date: 2024/5/28 21:30 * @Description 定时关阀开阀 */ @Data public class ComA0Vo { public String icCardNo ;//17位虚拟IC卡编号(协议是10位数字) public Integer moneyRemain;//剩余金额(取值范围0.00~999999.99,单位为元) public Double waterPrice;//水价(取值范围0.00~99.99元/m3) public Integer waterAmount ;//预用水量(0~9999 m3) public String orderNo ;//订单号(16位数字) } pipIrr-platform/pipIrr-common/src/main/java/com/dy/common/mw/protocol/p206V1_0_0/parse/Cd_99_Down.java
New file @@ -0,0 +1,168 @@ package com.dy.common.mw.protocol.p206V1_0_0.parse; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.dy.common.mw.protocol.*; import com.dy.common.mw.protocol.p206V1_0_0.CodeV1_0_1; import com.dy.common.mw.protocol.p206V1_0_0.CommonV1_0_1; import com.dy.common.mw.protocol.p206V1_0_0.ParseParamsForDownV1_0_1; import com.dy.common.mw.protocol.p206V1_0_0.ProtocolConstantV206V1_0_0; import com.dy.common.mw.protocol.p206V1_0_0.downVos.Com97Vo; import com.dy.common.mw.protocol.p206V1_0_0.downVos.Com99Vo; import com.dy.common.mw.protocol.p206V1_0_0.parse.global.GlCreate; import com.dy.common.util.ByteUtil; /** * @Author liurunyu * @Date 2024/06/12 9:30 * @Description */ @AnnotationCodeDown(ifAny={ CodeV1_0_1.cd_99 }) public class Cd_99_Down implements CodeParse { @Override public MidResult[] parse(Boolean isLowPower, CodeParseParams params, CodeParseCallback callback) throws Exception { ParseParamsForDownV1_0_1 para = (ParseParamsForDownV1_0_1) params ; MidResultToRtu midRs = new MidResultToRtu() ; byte[] bs = this.doParse(midRs, para) ; midRs.rtuResultSendWebUrl = para.rtuResultSendWebUrl ;//rtu返回命令结果 发向目的地web URL midRs.protocolName = para.protocolName ;//协议名称 midRs.rtuAddr = para.rtuAddr ;//Rtu地址 midRs.commandId = para.commandId ;//命令ID,发起命令的客户端(web端)生成,以匹配命令结果 midRs.downCode = para.commandCode ;//下行命令功能码; midRs.downBuffer = bs ;//下行命令数据 midRs.downBufHex = ByteUtil.bytes2Hex(bs, true) ;//下行命令数据十六进制形式 midRs.hasResponse = true ;//是否有应答 midRs.maxSendTimes = null ;//命令最大发送次数(当收不到应答时,将重发),如果不设置,命令缓存器进行补充设置 midRs.isCachForOffLine = false ;//RTU不在线,命令是否缓存,低功耗时为true if(isLowPower != null && isLowPower.booleanValue()){ //低功耗时,尽快发送 midRs.isQuickSend = true ; } return new MidResult[]{midRs} ; } /** * 构造下行数据 * @param midRs 参数 * @param para 参数 * @return 字节数组 * @throws Exception 异常 */ public byte[] doParse(MidResultToRtu midRs, ParseParamsForDownV1_0_1 para) throws Exception { CommonV1_0_1 commonV1_0_1 = new CommonV1_0_1() ; byte[] bytes ; byte[] bsHead = new byte[ProtocolConstantV206V1_0_0.lenHead2Code] ; byte index = 0 ; bsHead[index] = ProtocolConstantV206V1_0_0.P_Head_Byte ; index++ ; bsHead[index] = 0 ;//帧长度 index++ ; bsHead[index] = ProtocolConstantV206V1_0_0.P_Head_Byte ; index++ ; bsHead[index] = commonV1_0_1.createCtrl((byte)0, (byte)0) ; index++ ; GlCreate.createRtuAddr(para.rtuAddr, bsHead, index); index += 5 ; ByteUtil.hex2Bytes(para.commandCode, bsHead, index) ; JSONObject obj = (JSONObject)para.param; String json = obj.toJSONString(); Com99Vo cvo = JSON.parseObject(json, Com99Vo.class) ; if(cvo == null){ throw new Exception("json转Com97Vo为null") ; } if(cvo.icCardNo == null){ throw new Exception("虚拟IC卡编号不能为空") ; } if(cvo.moneyRemain == null){ throw new Exception("剩余金额不能为空") ; } if(cvo.waterPrice == null){ throw new Exception("水价不能为空") ; } if(cvo.minutes == null){ throw new Exception("用水时长不能为空") ; } if(cvo.minutes < 0 || cvo.minutes > 9999){ throw new Exception("用水时长取值范围是0~9999分钟") ; } String[] icCardNoGrp = CommonV1_0_1.dealIcCardNo(cvo.icCardNo) ; if(icCardNoGrp[0] != null){ midRs.param = icCardNoGrp[0] ; } byte[] bs = new byte[13] ; index = 0 ; ByteUtil.string2BCD_LE(bs, icCardNoGrp[1], index) ; index += 5 ; Integer money = Double.valueOf(cvo.moneyRemain * 100.0D).intValue() ; byte[] bTemp = ByteUtil.int2BCD_LE(money) ; int bTempLen = bTemp.length ; int count = 0 ; for(int i = 0 ; i < bTempLen; i++){ bs[index++] = bTemp[i] ; count ++ ; if(count >= 4){ break ; } } for(; count < 4; count++){ bs[index++] = 0 ; } Integer price = Double.valueOf(cvo.waterPrice * 100.0D).intValue() ; bTemp = ByteUtil.int2BCD_LE(price) ; bTempLen = bTemp.length ; count = 0 ; for(int i = 0 ; i < bTempLen; i++){ bs[index++] = bTemp[i] ; count ++ ; if(count >= 2){ break ; } } for(; count < 2; count++){ bs[index++] = 0 ; } bTemp = ByteUtil.int2BCD_LE(cvo.minutes) ; bTempLen = bTemp.length ; count = 0 ; for(int i = 0 ; i < bTempLen; i++){ bs[index++] = bTemp[i] ; count ++ ; if(count >= 2){ break ; } } for(; count < 2; count++){ bs[index++] = 0 ; } bytes = ByteUtil.bytesMerge(bsHead, bs) ; GlCreate.createLen(bytes);//长度放字节数组中 byte[] bsTail = GlCreate.createCrcTail(bytes) ;//CRC和尾叠加字节数组中 bytes = ByteUtil.bytesMerge(bytes, bsTail) ; return bytes ; } } pipIrr-platform/pipIrr-common/src/main/java/com/dy/common/mw/protocol/p206V1_0_0/parse/Cd_99_Up.java
New file @@ -0,0 +1,72 @@ package com.dy.common.mw.protocol.p206V1_0_0.parse; import com.dy.common.mw.protocol.*; import com.dy.common.mw.protocol.p206V1_0_0.*; import com.dy.common.mw.protocol.p206V1_0_0.upVos.DataCd98Vo; import com.dy.common.mw.protocol.p206V1_0_0.upVos.DataCd99Vo; import com.dy.common.util.ByteUtil; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** * @Author liurunyu * @Date 2024/06/12 9:30 * @Description */ @AnnotationCodeUp(ifAny={ CodeV1_0_1.cd_99 }) @SuppressWarnings("unused") public class Cd_99_Up implements CodeParse { private static final Logger log = LogManager.getLogger(Cd_99_Up.class); /** * 分析上行数据 */ @Override public MidResult[] parse(Boolean isLowPower, CodeParseParams params, CodeParseCallback callback)throws Exception { ParseParamsForUpV1_0_1 para = (ParseParamsForUpV1_0_1)params ; int bsLen = new CommonV1_0_1().parseDataLen(para.upBuffer) ; if(bsLen > 0){ this.doParse(para.upBuffer, bsLen, para.upCode, para.data) ; } log.info("分析上行数据<" + CodeV1_0_1.getCodeName(para.upCode) + " RTU地址=" + para.rtuAddr + ">:\n" + para.data.toString()); MidResultFromRtu midRs = new MidResultFromRtu() ; midRs.protocolName = para.protocolName ;//协议名称 midRs.rtuAddr = para.rtuAddr ;//Rtu地址 midRs.upCode = para.upCode ;//上行数据中的功能码 midRs.upHex = para.upHex ;//上行数据十六进制形式 midRs.upBuffer = para.upBuffer ;//上行数据字节数组 midRs.data = para.data ;//解析后的数据 midRs.reportOrResponse_trueOrFalse = false ;//主动上报 callback.callback(midRs.reportOrResponse_trueOrFalse); return new MidResult[]{midRs} ; } /** * 执行分析 * @param bs 字节数组 * @param bsLen 字节长度(总包长,包括包头和包尾) * @param dataCode 功能码 * @param data 数据 * @throws Exception 异常 */ protected void doParse(byte[] bs, int bsLen, String dataCode, Data data) throws Exception { DataV1_0_1 dV1 = (DataV1_0_1)data.getSubData() ; DataCd99Vo cdData = new DataCd99Vo() ; dV1.subData = cdData ; //虚拟卡号 cdData.cardNo = ByteUtil.BCD2String_LE(bs, ProtocolConstantV206V1_0_0.dataIndex, ProtocolConstantV206V1_0_0.dataIndex+4) ; if(bs[ProtocolConstantV206V1_0_0.dataIndex + 5] == (byte)0xAA){ cdData.success = true ; }else{ cdData.success = false ; } } } pipIrr-platform/pipIrr-common/src/main/java/com/dy/common/mw/protocol/p206V1_0_0/parse/Cd_A0_Down.java
New file @@ -0,0 +1,168 @@ package com.dy.common.mw.protocol.p206V1_0_0.parse; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.dy.common.mw.protocol.*; import com.dy.common.mw.protocol.p206V1_0_0.CodeV1_0_1; import com.dy.common.mw.protocol.p206V1_0_0.CommonV1_0_1; import com.dy.common.mw.protocol.p206V1_0_0.ParseParamsForDownV1_0_1; import com.dy.common.mw.protocol.p206V1_0_0.ProtocolConstantV206V1_0_0; import com.dy.common.mw.protocol.p206V1_0_0.downVos.Com99Vo; import com.dy.common.mw.protocol.p206V1_0_0.downVos.ComA0Vo; import com.dy.common.mw.protocol.p206V1_0_0.parse.global.GlCreate; import com.dy.common.util.ByteUtil; /** * @Author liurunyu * @Date 2024/06/12 9:30 * @Description */ @AnnotationCodeDown(ifAny={ CodeV1_0_1.cd_A0 }) public class Cd_A0_Down implements CodeParse { @Override public MidResult[] parse(Boolean isLowPower, CodeParseParams params, CodeParseCallback callback) throws Exception { ParseParamsForDownV1_0_1 para = (ParseParamsForDownV1_0_1) params ; MidResultToRtu midRs = new MidResultToRtu() ; byte[] bs = this.doParse(midRs, para) ; midRs.rtuResultSendWebUrl = para.rtuResultSendWebUrl ;//rtu返回命令结果 发向目的地web URL midRs.protocolName = para.protocolName ;//协议名称 midRs.rtuAddr = para.rtuAddr ;//Rtu地址 midRs.commandId = para.commandId ;//命令ID,发起命令的客户端(web端)生成,以匹配命令结果 midRs.downCode = para.commandCode ;//下行命令功能码; midRs.downBuffer = bs ;//下行命令数据 midRs.downBufHex = ByteUtil.bytes2Hex(bs, true) ;//下行命令数据十六进制形式 midRs.hasResponse = true ;//是否有应答 midRs.maxSendTimes = null ;//命令最大发送次数(当收不到应答时,将重发),如果不设置,命令缓存器进行补充设置 midRs.isCachForOffLine = false ;//RTU不在线,命令是否缓存,低功耗时为true if(isLowPower != null && isLowPower.booleanValue()){ //低功耗时,尽快发送 midRs.isQuickSend = true ; } return new MidResult[]{midRs} ; } /** * 构造下行数据 * @param midRs 参数 * @param para 参数 * @return 字节数组 * @throws Exception 异常 */ public byte[] doParse(MidResultToRtu midRs, ParseParamsForDownV1_0_1 para) throws Exception { CommonV1_0_1 commonV1_0_1 = new CommonV1_0_1() ; byte[] bytes ; byte[] bsHead = new byte[ProtocolConstantV206V1_0_0.lenHead2Code] ; byte index = 0 ; bsHead[index] = ProtocolConstantV206V1_0_0.P_Head_Byte ; index++ ; bsHead[index] = 0 ;//帧长度 index++ ; bsHead[index] = ProtocolConstantV206V1_0_0.P_Head_Byte ; index++ ; bsHead[index] = commonV1_0_1.createCtrl((byte)0, (byte)0) ; index++ ; GlCreate.createRtuAddr(para.rtuAddr, bsHead, index); index += 5 ; ByteUtil.hex2Bytes(para.commandCode, bsHead, index) ; JSONObject obj = (JSONObject)para.param; String json = obj.toJSONString(); ComA0Vo cvo = JSON.parseObject(json, ComA0Vo.class) ; if(cvo == null){ throw new Exception("json转Com97Vo为null") ; } if(cvo.icCardNo == null){ throw new Exception("虚拟IC卡编号不能为空") ; } if(cvo.moneyRemain == null){ throw new Exception("剩余金额不能为空") ; } if(cvo.waterPrice == null){ throw new Exception("水价不能为空") ; } if(cvo.waterAmount == null){ throw new Exception("预用水量不能为空") ; } if(cvo.waterAmount < 0 || cvo.waterAmount > 9999){ throw new Exception("预用水量取值范围是0~9999m3") ; } String[] icCardNoGrp = CommonV1_0_1.dealIcCardNo(cvo.icCardNo) ; if(icCardNoGrp[0] != null){ midRs.param = icCardNoGrp[0] ; } byte[] bs = new byte[13] ; index = 0 ; ByteUtil.string2BCD_LE(bs, icCardNoGrp[1], index) ; index += 5 ; Integer money = Double.valueOf(cvo.moneyRemain * 100.0D).intValue() ; byte[] bTemp = ByteUtil.int2BCD_LE(money) ; int bTempLen = bTemp.length ; int count = 0 ; for(int i = 0 ; i < bTempLen; i++){ bs[index++] = bTemp[i] ; count ++ ; if(count >= 4){ break ; } } for(; count < 4; count++){ bs[index++] = 0 ; } Integer price = Double.valueOf(cvo.waterPrice * 100.0D).intValue() ; bTemp = ByteUtil.int2BCD_LE(price) ; bTempLen = bTemp.length ; count = 0 ; for(int i = 0 ; i < bTempLen; i++){ bs[index++] = bTemp[i] ; count ++ ; if(count >= 2){ break ; } } for(; count < 2; count++){ bs[index++] = 0 ; } bTemp = ByteUtil.int2BCD_LE(cvo.waterAmount) ; bTempLen = bTemp.length ; count = 0 ; for(int i = 0 ; i < bTempLen; i++){ bs[index++] = bTemp[i] ; count ++ ; if(count >= 2){ break ; } } for(; count < 2; count++){ bs[index++] = 0 ; } bytes = ByteUtil.bytesMerge(bsHead, bs) ; GlCreate.createLen(bytes);//长度放字节数组中 byte[] bsTail = GlCreate.createCrcTail(bytes) ;//CRC和尾叠加字节数组中 bytes = ByteUtil.bytesMerge(bytes, bsTail) ; return bytes ; } } pipIrr-platform/pipIrr-common/src/main/java/com/dy/common/mw/protocol/p206V1_0_0/parse/Cd_A0_Up.java
New file @@ -0,0 +1,72 @@ package com.dy.common.mw.protocol.p206V1_0_0.parse; import com.dy.common.mw.protocol.*; import com.dy.common.mw.protocol.p206V1_0_0.*; import com.dy.common.mw.protocol.p206V1_0_0.upVos.DataCd99Vo; import com.dy.common.mw.protocol.p206V1_0_0.upVos.DataCdA0Vo; import com.dy.common.util.ByteUtil; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** * @Author liurunyu * @Date 2024/06/12 9:30 * @Description */ @AnnotationCodeUp(ifAny={ CodeV1_0_1.cd_A0 }) @SuppressWarnings("unused") public class Cd_A0_Up implements CodeParse { private static final Logger log = LogManager.getLogger(Cd_A0_Up.class); /** * 分析上行数据 */ @Override public MidResult[] parse(Boolean isLowPower, CodeParseParams params, CodeParseCallback callback)throws Exception { ParseParamsForUpV1_0_1 para = (ParseParamsForUpV1_0_1)params ; int bsLen = new CommonV1_0_1().parseDataLen(para.upBuffer) ; if(bsLen > 0){ this.doParse(para.upBuffer, bsLen, para.upCode, para.data) ; } log.info("分析上行数据<" + CodeV1_0_1.getCodeName(para.upCode) + " RTU地址=" + para.rtuAddr + ">:\n" + para.data.toString()); MidResultFromRtu midRs = new MidResultFromRtu() ; midRs.protocolName = para.protocolName ;//协议名称 midRs.rtuAddr = para.rtuAddr ;//Rtu地址 midRs.upCode = para.upCode ;//上行数据中的功能码 midRs.upHex = para.upHex ;//上行数据十六进制形式 midRs.upBuffer = para.upBuffer ;//上行数据字节数组 midRs.data = para.data ;//解析后的数据 midRs.reportOrResponse_trueOrFalse = false ;//主动上报 callback.callback(midRs.reportOrResponse_trueOrFalse); return new MidResult[]{midRs} ; } /** * 执行分析 * @param bs 字节数组 * @param bsLen 字节长度(总包长,包括包头和包尾) * @param dataCode 功能码 * @param data 数据 * @throws Exception 异常 */ protected void doParse(byte[] bs, int bsLen, String dataCode, Data data) throws Exception { DataV1_0_1 dV1 = (DataV1_0_1)data.getSubData() ; DataCdA0Vo cdData = new DataCdA0Vo() ; dV1.subData = cdData ; //虚拟卡号 cdData.cardNo = ByteUtil.BCD2String_LE(bs, ProtocolConstantV206V1_0_0.dataIndex, ProtocolConstantV206V1_0_0.dataIndex+4) ; if(bs[ProtocolConstantV206V1_0_0.dataIndex + 5] == (byte)0xAA){ cdData.success = true ; }else{ cdData.success = false ; } } } pipIrr-platform/pipIrr-common/src/main/java/com/dy/common/mw/protocol/p206V1_0_0/upVos/DataCd99Vo.java
New file @@ -0,0 +1,28 @@ package com.dy.common.mw.protocol.p206V1_0_0.upVos; import lombok.Data; /** * @Author liurunyu * @Date 2024/01/13 10:08 * @LastEditTime 2024/01/13 10:08 * @Description */ @Data public class DataCd99Vo { public String cardNo ;//虚拟卡号 public boolean success; public String toString(){ StringBuilder sb = new StringBuilder() ; sb.append(" 定时关阀开阀应答:\n"); sb.append(" 虚拟卡号:"); sb.append(cardNo); sb.append("\n"); sb.append(" 结果:"); sb.append(success?"执行":"失败"); sb.append("\n"); return sb.toString() ; } } pipIrr-platform/pipIrr-common/src/main/java/com/dy/common/mw/protocol/p206V1_0_0/upVos/DataCdA0Vo.java
New file @@ -0,0 +1,28 @@ package com.dy.common.mw.protocol.p206V1_0_0.upVos; import lombok.Data; /** * @Author liurunyu * @Date 2024/01/13 10:08 * @LastEditTime 2024/01/13 10:08 * @Description */ @Data public class DataCdA0Vo { public String cardNo ;//虚拟卡号 public boolean success; public String toString(){ StringBuilder sb = new StringBuilder() ; sb.append(" 定量关阀开阀应答:\n"); sb.append(" 虚拟卡号:"); sb.append(cardNo); sb.append("\n"); sb.append(" 结果:"); sb.append(success?"执行":"失败"); sb.append("\n"); return sb.toString() ; } } pipIrr-platform/pipIrr-common/src/main/java/com/dy/common/util/HttpUtils.java
File was deleted pipIrr-platform/pipIrr-mw/pipIrr-mw-rtu/src/main/java/com/dy/rtuMw/server/rtuData/p206V1_0_0/TkFindP206V1_0_0.java
@@ -18,7 +18,7 @@ public void execute(Object data) { Data d = (Data)data ; if(d.getProtocol() != null && d.getProtocol().equals(ProtocolConstantV206V1_0_0.protocolName)){ //this.toNextTasks(data); this.toNextTasks(data); }else{ //不是本协议的数据 } pipIrr-platform/pipIrr-mw/pipIrr-mw-rtu/src/main/resources/log4j2.yml
@@ -9,7 +9,7 @@ value: ./logs #日志文件存储名称 - name: project.name value: aceMw value: rtuMw #定义输出器,可以输出到控制台和文件. Appenders: @@ -18,7 +18,6 @@ #Appender命名 name: CONSOLE target: SYSTEM_OUT charset: UTF-8 ThresholdFilter: level: debug #输出日志级别,输出日志时,首先由Loggers.Root.level或Loggers.Logger.level判断是否输出,然后再由本level判断是否输出 onMatch: ACCEPT #onMatch=ACCEPT 大于等于 "level" 配置的等级地日志输出 @@ -65,10 +64,10 @@ - ref: ROLLING_FILE #输出日志时,首先由本level判断是否输出,然后再由上面的Appenders.RollingFile.ThresholdFilter.level判断是否输出 # 为类包路径配置特殊的Log级别,方便调试, # 不受Loggers.Root.level限制 Logger: - name: com.dy.pipIrrGlobal.daoBa additivity: false #去除重复的log level: debug #输出日志级别 AppenderRef: - ref: CONSOLE #输出日志时,首先由本.level判断是否输出,然后再由上面的Appenders.Console.ThresholdFilter.level判断是否输出 - ref: ROLLING_FILE #输出日志时,首先由本level判断是否输出,然后再由上面的Appenders.RollingFile.ThresholdFilter.level判断是否输出 # Logger: # - name: com.dy.pipIrrGlobal.daoBa # additivity: false #去除重复的log # level: debug #输出日志级别 # AppenderRef: # - ref: CONSOLE #输出日志时,首先由本.level判断是否输出,然后再由上面的Appenders.Console.ThresholdFilter.level判断是否输出 # - ref: ROLLING_FILE #输出日志时,首先由本level判断是否输出,然后再由上面的Appenders.RollingFile.ThresholdFilter.level判断是否输出