JSP 的本質原理解析:"編寫的時候是JSP,心裡想解讀的是 java 源碼" @ 每博一文案 活明白的人,一生只做好了這兩件事: 每個瞬間都充滿了選擇和承擔,就算面前是一座獨木橋,也必須選擇是前進後退,亦或是留在原地此時此刻你所經歷的一切。 這是過往無數個選擇後的結果,哪些小的選擇匯聚在了一起,最 ...
一、概況
作為Java世界使用最廣泛的網路通信框架Netty,其性能和效率是有目共睹的,好多大公司都在使用如蘋果、谷歌、Facebook、Twitter、阿裡巴巴等,所以不僅僅是因為Netty有高效的性能與效率,更重要的是:屏蔽了底層的複雜度,簡單易懂的編程模型,適應更廣泛的應用場景,以及活躍的開發者社區。
本篇博客是作為Netty之數據編碼的續篇,上一篇以拋磚引玉的方式講解了怎麼使用Netty的核心緩衝區ByteBuf怎麼編碼存儲各種基本數據,本篇就是與之對應的怎麼從緩衝區ByteBuf中的編碼數據解碼出來,因為我們的Java代碼中處理數據一般不是按照位元組流來處理,所以需要解碼恢復出數據然後再進行處理。
二、代碼實現
1. 解碼工具類
1 package com.ethan.cws.common.utils; 2 3 import com.ethan.cws.common.enums.TypeEnum; 4 import io.netty.buffer.ByteBuf; 5 import io.netty.buffer.ByteBufUtil; 6 import io.netty.util.CharsetUtil; 7 8 import java.util.ArrayList; 9 import java.util.Arrays; 10 import java.util.List; 11 12 /** 13 * 解碼工具類 14 * 15 * @author ethancws 16 * @date 17 */ 18 public final class DecodeUtils { 19 20 /** 21 * FEP data數據文件尾碼名 22 */ 23 public final static String FILE_SUFFIX_EXTEND = ".xml"; 24 25 /** 26 * 文件名 27 */ 28 public final static String FILE_NAME = "Filename"; 29 30 private DecodeUtils() { 31 32 } 33 34 /** 35 * 解碼 36 * 37 * @param symbol 符號 38 * @param byteNum 位元組數 39 * @param buff 數據 40 * @param type 枚舉類型字元串 41 * @param endian 編碼 42 * @return 解碼數據 43 */ 44 public static Object decode(String symbol, int byteNum, ByteBuf buff, 45 String type, boolean endian) { 46 Object value = null; 47 //類型枚舉 48 final TypeEnum typeEnum = TypeEnum.match(type); 49 switch (typeEnum) { 50 case TYPE_STRING: 51 case TYPE_ENUM_STRING: 52 case TYPE_DATE_STRING: 53 value = readString(byteNum, buff, symbol); 54 break; 55 case TYPE_HEX_STRING: 56 case TYPE_ENUM_HEX_STRING: 57 value = readHexString(byteNum, buff); 58 break; 59 case TYPE_USHORT: 60 value = readUnSignShort(buff, endian); 61 break; 62 case TYPE_SHORT: 63 value = readShort(buff, endian); 64 break; 65 case TYPE_INT: 66 case TYPE_ENUM_INT: 67 value = readInt(buff, endian); 68 break; 69 case TYPE_UINT: 70 value = readUnSignInt(buff, endian); 71 break; 72 case TYPE_BYTE: 73 case TYPE_ENUM_BYTE: 74 value = readByte(buff); 75 break; 76 case TYPE_UBYTE: 77 value = readUnSignByte(buff); 78 break; 79 case TYPE_BIT: 80 value = readBit(byteNum, buff); 81 break; 82 case TYPE_MULTI_BIT: 83 value = readMultiBit(byteNum, buff); 84 break; 85 case TYPE_BCD8421: 86 value = readBcd8421(byteNum, buff); 87 break; 88 89 } 90 91 return value; 92 } 93 94 /** 95 * 讀無符號byte 96 * 97 * @param buff 編碼數據 98 * @return 解碼數據 99 */ 100 public static short readUnSignByte(ByteBuf buff) { 101 byte by = buff.readByte(); 102 return (short) (by & 0x0FF); 103 } 104 105 /** 106 * 讀byte 107 * 108 * @param buff 編碼數據 109 * @return 解碼數據 110 */ 111 public static byte readByte(ByteBuf buff) { 112 return buff.readByte(); 113 } 114 115 /** 116 * 讀無符號int 117 * 118 * @param buff 編碼數據 119 * @param endian 位元組序 120 * @return 解碼數據 121 */ 122 public static long readUnSignInt(ByteBuf buff, boolean endian) { 123 int intValue = endian ? buff.readIntLE() : buff.readInt(); 124 return intValue & 0x0FFFFFFFFL; 125 } 126 127 /** 128 * 讀int 129 * 130 * @param buff 編碼數據 131 * @param endian 位元組序 132 * @return 解碼數據 133 */ 134 public static int readInt(ByteBuf buff, boolean endian) { 135 return endian ? buff.readIntLE() : buff.readInt(); 136 } 137 138 /** 139 * 讀short 140 * 141 * @param buff 編碼數據 142 * @param endian 位元組序 143 * @return 解碼數據 144 */ 145 public static short readShort(ByteBuf buff, boolean endian) { 146 return endian ? buff.readShortLE() : buff.readShort(); 147 } 148 149 /** 150 * 讀無符號short 151 * 152 * @param buff 編碼數據 153 * @param endian 位元組序 154 * @return 解碼數據 155 */ 156 public static int readUnSignShort(ByteBuf buff, boolean endian) { 157 short shortValue = endian ? buff.readShortLE() : buff.readShort(); 158 return shortValue & 0x0FFFF; 159 } 160 161 /** 162 * 讀Hex字元串 163 * 164 * @param num 位元組長度 165 * @param buff 編碼數據 166 * @return 字元串 167 */ 168 public static String readHexString(int num, ByteBuf buff) { 169 String value = ByteBufUtil.hexDump(buff, 0, num); 170 readByteBuf(num, buff); 171 return value; 172 } 173 174 /** 175 * 讀Hex字元串沒有數據緩衝區偏移 176 * 177 * @param num 位元組長度 178 * @param buff 編碼數據 179 * @return 字元串 180 */ 181 public static String readHexStringWithoutOffset(int num, ByteBuf buff) { 182 return ByteBufUtil.hexDump(buff, 0, num); 183 } 184 185 /** 186 * 獲取文件名稱 187 * 188 * @param fileName 字元 189 * @return 文件名稱 190 */ 191 private static String acquireFileName(String fileName) { 192 String fileSuffixExtend = FILE_SUFFIX_EXTEND; 193 int index = fileName.lastIndexOf(fileSuffixExtend); 194 index += fileSuffixExtend.length(); 195 fileName = fileName.substring(1, index); 196 return fileName; 197 } 198 199 /** 200 * 讀字元串 201 * 202 * @param num 位元組長度 203 * @param buff 編碼數據 204 * @param symbol 編碼標識 205 * @return 字元串 206 */ 207 public static String readString(int num, ByteBuf buff, String symbol) { 208 final CharSequence charSequence = buff.getCharSequence(0, num, CharsetUtil.UTF_8); 209 String value = charSequence.toString(); 210 if (FILE_NAME.equals(symbol)) { 211 value = acquireFileName(value); 212 } 213 //移動讀指針 214 readByteBuf(num, buff); 215 return value; 216 } 217 218 219 /** 220 * 移動讀指針 221 * 222 * @param num 移動位元組數 223 * @param buff 數據緩衝區ByteBuf 224 */ 225 private static void readByteBuf(int num, ByteBuf buff) { 226 assert num >= 1; 227 if (num == 1) { 228 buff.readByte(); 229 } else { 230 buff.readBytes(num); 231 } 232 } 233 234 /** 235 * 讀bit 236 * 237 * @param num 位元組長度 238 * @param buff 數據緩衝區ByteBuf 239 * @return bit位索引 240 */ 241 public static int readBit(int num, ByteBuf buff) { 242 ByteBuf buffCopy = buff.copy(0, num); 243 int index = 0; 244 for (; num > 0; num--) { 245 byte b = buffCopy.readByte(); 246 if (b != 0) { 247 index += b / 2; 248 --num; 249 break; 250 } 251 } 252 index += num * 8; 253 //移動讀指針 254 readByteBuf(num, buff); 255 return index; 256 } 257 258 /** 259 * 讀多位bit 260 * 261 * @param num 位元組長度 262 * @param buff 數據緩衝區ByteBuf 263 * @return 二進位數據為1的索引數組 264 */ 265 public static int[] readMultiBit(int num, ByteBuf buff) { 266 ByteBuf buffCopy = buff.copy(0, num); 267 List<Integer> list = new ArrayList<>(); 268 int size = num; 269 final int fixedNum = num; 270 for (; num > 0; num--) { 271 size--; 272 int b = readUnSignByte(buffCopy); 273 if (b != 0) { 274 String str = Integer.toBinaryString(b); 275 str = fullFillByteString(str); 276 gatherIndexes(str, size, list); 277 } 278 } 279 //移動讀指針 280 readByteBuf(fixedNum, buff); 281 return Arrays.stream(list.toArray(new Integer[0])).mapToInt(Integer::valueOf).toArray(); 282 } 283 284 /** 285 * 補全byte二進位8位字元串 286 * 287 * @param str 字元串 288 * @return 補全8位後的字元串 289 */ 290 private static String fullFillByteString(String str) { 291 int len = 8; 292 int length = str.length(); 293 if (length < 8) { 294 StringBuilder strBuilder = new StringBuilder(str); 295 for (int i = 0; i < len - length; i++) { 296 strBuilder.insert(0, "0"); 297 } 298 str = strBuilder.toString(); 299 } 300 return str; 301 } 302 303 /** 304 * 收集索引存入List 305 * 306 * @param str byte二進位字元串 307 * @param size 剩餘byte長度 308 * @param list 集合List 309 */ 310 private static void gatherIndexes(String str, int size, List<Integer> list) { 311 int len = 8, lenFixed = 8; 312 for (char ch : str.toCharArray()) { 313 int totalIndex = 0; 314 len--; 315 if (ch == 48) { 316 continue; 317 } 318 totalIndex = len + size * lenFixed; 319 list.add(totalIndex); 320 } 321 } 322 323 /** 324 * 讀Bcd碼 325 * 326 * @param num 位元組長度 327 * @param buff 數據緩衝區ByteBuf 328 * @return Bcd碼解碼數據 329 */ 330 public static String readBcd8421(int num, ByteBuf buff) { 331 return readHexString(num, buff); 332 } 333 }
2. 數據類型枚舉類
1 package com.ethan.cws.common.enums; 2 3 /** 4 * 數據枚舉 5 * 6 * @author ethancws 7 * @date 8 */ 9 public enum TypeEnum { 10 /** 11 * 字元串 12 */ 13 TYPE_STRING("string"), 14 15 /** 16 * Binary-Coded Decimal 17 * bcd碼 8421碼 18 * 4位二進位數表示1位十進位數 19 */ 20 TYPE_BCD8421("bcd8421"), 21 /** 22 * 時間字元串 23 */ 24 TYPE_DATE_STRING("date_string"), 25 /** 26 * 枚舉byte 27 */ 28 TYPE_ENUM_BYTE("enum|byte"), 29 30 /** 31 * 枚舉int 32 */ 33 TYPE_ENUM_INT("enum|int"), 34 35 /** 36 * 枚舉字元串 37 */ 38 TYPE_ENUM_STRING("enum|string"), 39 40 /** 41 * 枚舉HEX字元串 42 */ 43 TYPE_ENUM_HEX_STRING("enum|hex_string"), 44 45 /** 46 * HEX字元串 47 */ 48 TYPE_HEX_STRING("hex_string"), 49 50 /** 51 * -2^31~2^31-1 52 * -2,147,483,648~2,147,483,647 53 */ 54 TYPE_INT("int"), 55 /** 56 * 0~2^32 57 * 0~4294967296L 58 */ 59 TYPE_UINT("uint"), 60 /** 61 * -2^15~2^15-1 62 * -32768~32767 63 */ 64 TYPE_SHORT("short"), 65 /** 66 * 0~65535 67 */ 68 TYPE_USHORT("ushort"), 69 /** 70 * -2^7~2^7-1 71 * -128~127 72 */ 73 TYPE_BYTE("byte"), 74 75 /** 76 * 0~256 77 */ 78 TYPE_UBYTE("ubyte"), 79 80 /** 81 * 多位同選 82 */ 83 TYPE_MULTI_BIT("multi_bit"), 84 /** 85 * 位 86 */ 87 TYPE_BIT("bit"); 88 89 private String val; 90 91 TypeEnum(String val) { 92 this.val = val; 93 } 94 95 96 /** 97 * 字元串匹配枚舉類型 98 * 99 * @param value 字元串 100 * @return 對應枚舉 101