Administrator
3 天以前 aa33e56e37cd19b88ae8eea69c5ebc7c6da8b1d2
src/main/java/com/zy/common/utils/Struct.java
@@ -21,487 +21,487 @@
 * @author vincent
 */
public class Struct implements java.io.Serializable {
   private transient Map<String,byte[]> decodeByteMapping = new HashMap<>();
   private transient Map<String,byte[]> encodeByteMapping = new HashMap<>();
   // 解码前的原生字节数组
   private transient byte[] dataBytes = null;
   private transient byte[] decodeBytes = null;
   private transient byte[] encodeBytes = null;
   private transient byte[] unusedBytes = null;
   public Class getClassType(String name){
      return null;
   }
    private transient Map<String, byte[]> decodeByteMapping = new HashMap<>();
    private transient Map<String, byte[]> encodeByteMapping = new HashMap<>();
    // 解码前的原生字节数组
    private transient byte[] dataBytes = null;
    private transient byte[] decodeBytes = null;
    private transient byte[] encodeBytes = null;
    private transient byte[] unusedBytes = null;
   /**
    * 判断大小端
    * @return true: 小端 / false: 大端
    */
   public boolean isReverse() {
      return this.getClass().getAnnotation(little.class)!=null;
   }
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static <T extends Struct> T decode(Class<? extends Struct> cls, byte[] bytes) throws Exception {
        Struct instance = cls.newInstance();
        return instance.decode(bytes);
    }
   /**
    * 获取字节数组
    */
   public byte[] toBytes() throws Exception {
      return encode(this);
   }
   public Map<String,String> toDecodeHexMapping() throws Exception{
      if(this.decodeByteMapping==null)this.decodeByteMapping=new HashMap<>();
      Map<String, String> mapping = getHex(this.decodeByteMapping);
      if(this.decodeBytes!=null){
         mapping.put("byte[]", Struct.toHex(this.decodeBytes));
      }
      return mapping;
   }
   public Map<String,String> toEncodeHexMapping() throws Exception{
      if(this.encodeBytes==null)this.encode(this);
      if(this.encodeByteMapping==null)this.encodeByteMapping=new HashMap<>();
      Map<String, String> mapping = getHex(this.encodeByteMapping);
      mapping.put("byte[]", Struct.toHex(this.encodeBytes));
      return mapping;
   }
   public Map<String,String> getHex(Map<String,byte[]> bytemapping) throws Exception {
      Map<String,String> map = new LinkedHashMap<>();
      Field[] fields = this.getClass().getFields();
      for (Field field : fields) {
         byte[] bytes = bytemapping.get(field.getName());
         if(bytes!=null){
            map.put(field.getName(), Struct.toHex(bytes));
         }
      }
      return map;
   }
   // 转java对象到数组
   public byte[] encode(Struct entity) throws Exception {
      ByteArrayOutputStream baOs = new ByteArrayOutputStream();
      write(new DataOutputStream(baOs), entity);
      entity.encodeBytes = baOs.toByteArray();
      return entity.encodeBytes;
   }
   /**
    * 写数据到输出流
    *
    * @param dos
    * @param entity
    */
   public void write(DataOutputStream dos, Struct entity) throws Exception {
      if(entity==null)return;
      if(entity.encodeByteMapping==null)entity.encodeByteMapping=new HashMap<>();
      Field[] fields = entity.getClass().getFields();
      EvaluationContext context = new StandardEvaluationContext();
      for (Field field : Objects.requireNonNull(ReflectUtils.removeStaticField(fields))) {
         field.setAccessible(true);
         String name = field.getName();
         Class<?> type = field.getType();
         String typeName = type.getSimpleName();
         if(typeName.equals("Struct")){
            if(entity.getClassType(name)!=null){
               type = entity.getClassType(name);
               typeName = type.getSimpleName();
            }else if(field.get(entity)!=null){
               type = field.get(entity).getClass();
               typeName = type.getSimpleName();
            }
         }
         size size = field.getAnnotation(size.class);
         bit bit = field.getAnnotation(bit.class);
         expr expr = field.getAnnotation(expr.class);
         flag flag = field.getAnnotation(flag.class);
         if(size==null && bit==null && expr==null){
            continue;
         }
         int bited = 0;//已写位数
         int length = 0;//定义的长度
         if(size!=null){
            length = size.value();
            bited+=size.value()*8;
         }else if(bit!=null){
            //按位写方式未实现处理
            throw new RuntimeException("按位写方式未实现处理");
         }else if(expr!=null){
            ExpressionParser parser = new SpelExpressionParser();
            Expression exp = parser.parseExpression(expr.value());
            Integer len = null;
            try{
               len = CommonUtils.parseInt(exp.getValue(context, entity));
            }catch (Exception e){
               len = 0;
            }
            if(len!=null){
               if(len==-1)continue;
               length = len;
               bited+=len*8;
            }
         }
         context.setVariable(name, field.get(entity));
         byte[] bytes = new byte[length];
         if (typeName.equals("int") || typeName.equals("Integer")){
            dos.write(bytes=convert(length,field.getInt(entity)));
         }else if (typeName.equals("long") || typeName.equals("Long")){
            dos.write(bytes=convert(length,field.getLong(entity)));
         }else if (typeName.equals("short") || typeName.equals("Short")){
            dos.write(bytes=convert(length,field.getShort(entity)));
         }else if (typeName.equals("byte") || typeName.equals("Byte")){
            dos.write(bytes=convert(length,field.getByte(entity)));
         }else if (typeName.equals("String")) {
            String str = (String) field.get(entity);
            if (str == null)
               str = "";
            str = str.replaceAll(" ", " ");
            byte[] bts = null;
            if(flag!=null && flag.value().equals("ASCII")){
               bts = Struct.StrToAsc(str);
            }else if(flag!=null && flag.value().equals("BCD")){
               bts = Struct.str2Bcd(str);
            }else{
               bts = str.getBytes();
            }
            if(length==0){//如果长度未设置,以当前实际的字节为准
               bytes = new byte[bts.length];
            }
            System.arraycopy(bts, 0, bytes, 0, bts.length);
            dos.write(bytes);
         } else if (typeName.equals("byte[]")) {
            byte[] bts = (byte[]) field.get(entity);
            if(bts!=null){
               if(length==0){//如果长度未设置,以当前实际的字节为准
                  bytes = new byte[bts.length];
               }
               System.arraycopy(bts, 0, bytes, 0, bts.length);
               dos.write(bytes);
            }
         }else if (type.isArray()) {
            ByteArrayOutputStream baOs1 = new ByteArrayOutputStream();
            DataOutputStream dos1 = new DataOutputStream(baOs1);
            for (Object object : (Object[]) field.get(entity)){
               write(dos1, (Struct) object);
            }
            byte[] bts  = baOs1.toByteArray();
            if(length==0){//如果长度未设置,以当前实际的字节为准
               bytes = new byte[bts.length];
            }
            System.arraycopy(bts, 0, bytes, 0, bts.length);
            dos.write(bytes);
         } else {
            byte[] bts = encode((Struct) field.get(entity));
            if(length==0){//如果长度未设置,以当前实际的字节为准
               bytes = new byte[bts.length];
            }
            System.arraycopy(bts, 0, bytes, 0, bts.length);
            dos.write(bytes);
         }
         entity.encodeByteMapping.put(name, bytes);
      }
   }
   public byte[] convert(int size, long value) throws Exception{
      ByteArrayOutputStream baOs = new ByteArrayOutputStream();
      DataOutputStream dos = new DataOutputStream(baOs);
      switch(size){
      case 1://byte
         dos.write((byte) value);
         break;
      case 2://short
         dos.writeShort(this.isReverse() ? Short.reverseBytes((short)value) : (short)value);
         break;
      case 4://int
         dos.writeInt(this.isReverse() ? Integer.reverseBytes((int)value) : (int)value);
         break;
      case 8://long
         dos.writeLong(this.isReverse() ? Long.reverseBytes((long)value) : (long)value);
         break;
      }
      return baOs.toByteArray();
   }
   public long convertEx(long value,int size) throws Exception{
      switch(size){
      case 1://byte
         return value;
      case 2://short
         return (this.isReverse() ? Short.reverseBytes((short)value) : (short)value);
      case 4://int
         return (this.isReverse() ? Integer.reverseBytes((int)value) : (int)value);
      case 8://long
         return (this.isReverse() ? Long.reverseBytes((long)value) : (long)value);
      }
      return 0;
   }
   @SuppressWarnings({ "unchecked", "rawtypes" })
   public static <T extends Struct> T decode(Class<? extends Struct> cls,byte[] bytes) throws Exception{
      Struct instance = cls.newInstance();
      return instance.decode(bytes);
   }
   /**
    * 解码: 字节数组 ====>> java对象
    */
   @SuppressWarnings({ "unchecked", "rawtypes" })
   public <T extends Struct> T decode(byte[] bytes) throws Exception{
      this.dataBytes = bytes;
      Struct instance = this;
      Class<? extends Struct> cls = this.getClass();
      Field[] fields = cls.getFields();
      if(this.decodeByteMapping==null)instance.decodeByteMapping=new HashMap();
      // spring el表达式
      EvaluationContext context = new StandardEvaluationContext();
      context.setVariable("_", bytes.length);
      int bited = 0;//已读位数
      for(Field field: Objects.requireNonNull(ReflectUtils.removeStaticField(fields))){
         size size = field.getAnnotation(size.class);
         bit bit = field.getAnnotation(bit.class);
         expr expr = field.getAnnotation(expr.class);
         flag flag = field.getAnnotation(flag.class);
         // 没有size、bit、expr注解的变量不进行解析
         if(size==null && bit==null && expr==null){
            continue;
         }
         String name = field.getName();
         Class<?> type = field.getType();
         String typeName = type.getSimpleName();
         if(typeName.equals("Struct")){
            if(instance.getClassType(name)!=null){
               type = instance.getClassType(name);
               typeName = type.getSimpleName();
            }
         }
         context.setVariable("__", bytes.length-bited/8);
         byte[] bts = null;
         if(size!=null){
            bts = new byte[size.value()];
            System.arraycopy(bytes, bited/8, bts, 0, size.value());
            bited+=size.value()*8;
         }else if(bit!=null){
            int val = 0;
            String strBin = "";
            for(int i=bited;i<bited+bit.value();i++){//逐位扫描
               if((bytes[i/8] & (1 << (i%8))) != 0){//如果位为1
                  strBin+="1";
               }else{
                  strBin+="0";
               }
               val = Integer.parseInt(strBin, 2);
            }
            byte[] result = new byte[4];
            result[3] = (byte)(val);
            result[2] = (byte)(val >> 8);
            result[1] = (byte)(val >> 16);
            result[0] = (byte)(val >> 24);
            bts = new byte[(int)Math.ceil((double)bit.value()/8.0)];
            System.arraycopy(result, result.length-bts.length, bts, 0, bts.length);
            bited+=bit.value();
         }else if(expr!=null){
            ExpressionParser parser = new SpelExpressionParser();
            Expression exp = parser.parseExpression(expr.value());
            Integer len = CommonUtils.parseInt(exp.getValue(context,instance));
            if(len!=null){
               if(len==-1)continue;
               bts = new byte[len];
               System.arraycopy(bytes, bited/8, bts, 0, len);
               bited+=len*8;
            }
         }
         if(bts.length==0)continue;
         DataInputStream dis = new DataInputStream(new ByteArrayInputStream(bts));
         if (typeName.equals("int") || typeName.equals("Integer")){
            field.setInt(instance,(int) convertEx(dis.readInt(),4));
         }else if (typeName.equals("long") || typeName.equals("Long")){
            field.setLong(instance, convertEx(dis.readLong(),8));
         }else if (typeName.equals("short") || typeName.equals("Short")){
            field.setShort(instance, (short) convertEx(dis.readShort(),2));
         }else if (typeName.equals("byte") || typeName.equals("Byte")){
            field.setByte(instance, (byte) convertEx(dis.readByte(),1));
         }else if (typeName.equals("byte[]")){
            field.set(instance, bts);
         }else if (typeName.equals("String")) {
            String strStr = new String(bts, StandardCharsets.UTF_8);
            if(flag!=null && flag.value().equals("BCD")){
               strStr = bcd2Str(bts);
            }else if(flag!=null && flag.value().equals("ASCII")){
               strStr = Struct.AscToStr(bts);
            }
            strStr = strStr.replaceAll("[\u0000]", "");
            field.set(instance, strStr);
         }else if (type.isArray()) {
            byte[] arrayBytes = bts;
            List list = new ArrayList();
            while(arrayBytes.length>0 && list.size()<256){
               Struct item = decode((Class<? extends Struct>) type.getComponentType(),arrayBytes);
               list.add(item);
               arrayBytes = item.unusedBytes;
            }
            Object array = Array.newInstance(type.getComponentType(), list.size());
            for(int i=0;i<list.size();i++){
               Array.set(array, i, list.get(i));
            }
            field.set(instance, array);
         }else if(type==Struct.class || Struct.class.isAssignableFrom(type)){
            byte[] arrayBytes = bts;
            Struct item = decode((Class<? extends Struct>) type,arrayBytes);
            field.set(instance, item);
         }else{
            throw new RuntimeException(cls.getSimpleName()+"字段"+field.getName()+"类型未知");
         }
         instance.decodeByteMapping.put(name, bts);
         context.setVariable(name, field.get(instance));
      }
      byte[] useBytes = new byte[bited/8];
      System.arraycopy(bytes, 0 , useBytes, 0, bited/8);
      instance.decodeBytes = useBytes;
      byte[] unusedBytes = new byte[bytes.length-(bited/8)];
      if(unusedBytes.length>0){
         System.arraycopy(bytes, useBytes.length , unusedBytes, 0, unusedBytes.length);
      }
      instance.unusedBytes = unusedBytes;
      return (T) instance;
   }
   // 字节数组 ===>> 转为十六进制字符串
   public static String toHex(byte[] bytes) {
    // 字节数组 ===>> 转为十六进制字符串
    public static String toHex(byte[] bytes) {
        StringBuilder buf = new StringBuilder(bytes.length * 2);
        for(byte b : bytes) { // 使用String的format方法进行转换
        for (byte b : bytes) { // 使用String的format方法进行转换
            buf.append(String.format("%02x", b & 0xff));
        }
        return buf.toString().toUpperCase();
    }
    public static byte[] toBytes(String str) {
        if(str == null || str.trim().equals("")) return new byte[0];
        if (str == null || str.trim().equals("")) return new byte[0];
        byte[] bytes = new byte[str.length() / 2];
        for(int i = 0; i < str.length() / 2; i++) {
        for (int i = 0; i < str.length() / 2; i++) {
            String subStr = str.substring(i * 2, i * 2 + 2);
            bytes[i] = (byte) Integer.parseInt(subStr, 16);
        }
        return bytes;
    }
    /**
    * @功能: BCD码转为10进制串(阿拉伯数据)
    * @参数: BCD码
    * @结果: 10进制串
    */
   public static String bcd2Str(byte[] bytes) {
      StringBuffer temp = new StringBuffer(bytes.length * 2);
      for (int i = 0; i < bytes.length; i++) {
         temp.append((byte) ((bytes[i] & 0xf0) >>> 4));
         temp.append((byte) (bytes[i] & 0x0f));
      }
      return temp.toString().substring(0, 1).equalsIgnoreCase("0") ? temp
            .toString().substring(1) : temp.toString();
   }
   /**
    * @功能: 10进制串转为BCD码
    * @参数: 10进制串
    * @结果: BCD码
    */
   public static byte[] str2Bcd(String asc) {
      int len = asc.length();
      int mod = len % 2;
      if (mod != 0) {
         asc = "0" + asc;
         len = asc.length();
      }
      byte abt[] = new byte[len];
      if (len >= 2) {
         len = len / 2;
      }
      byte bbt[] = new byte[len];
      abt = asc.getBytes();
      int j, k;
      for (int p = 0; p < asc.length() / 2; p++) {
         if ((abt[2 * p] >= '0') && (abt[2 * p] <= '9')) {
            j = abt[2 * p] - '0';
         } else if ((abt[2 * p] >= 'a') && (abt[2 * p] <= 'z')) {
            j = abt[2 * p] - 'a' + 0x0a;
         } else {
            j = abt[2 * p] - 'A' + 0x0a;
         }
         if ((abt[2 * p + 1] >= '0') && (abt[2 * p + 1] <= '9')) {
            k = abt[2 * p + 1] - '0';
         } else if ((abt[2 * p + 1] >= 'a') && (abt[2 * p + 1] <= 'z')) {
            k = abt[2 * p + 1] - 'a' + 0x0a;
         } else {
            k = abt[2 * p + 1] - 'A' + 0x0a;
         }
         int a = (j << 4) + k;
         byte b = (byte) a;
         bbt[p] = b;
      }
      return bbt;
   }
    public static class TestMessage {
      public @size(1) byte begin = 0x7e;//起始符
      public @size(2) short type = 0;//消息ID
      public @bit(2) byte retain;//消息体属性>保留
      public @bit(1) byte subpkg;//消息体属性>是否分包,0表示不分包
      public @bit(3) byte encrypt;//消息体属性>加密方式,0表示不加密
      public @bit(10) short length;//消息体长度
      public @size(6) @flag("BCD") String number;//手机号码
      public @size(2) short serial;//消息流水号
      public @expr("#subpkg==1?2:0") short pkgs;//分包数
      public @expr("#subpkg==1?2:0") short index;//包序号
      public @expr("#length") byte[] data;//数据部分
      public @size(1) byte verify;//校验码
      public @size(1) byte end = 0x7e;//结束符
   }
    public static byte getXor(byte[] datas,int start, int end){
       byte temp=datas[start];
       for (int i = start+1; i <end; i++) {
          temp ^=datas[i];
       }
       return temp;
    /**
     * @功能: BCD码转为10进制串(阿拉伯数据)
     * @参数: BCD码
     * @结果: 10进制串
     */
    public static String bcd2Str(byte[] bytes) {
        StringBuffer temp = new StringBuffer(bytes.length * 2);
        for (int i = 0; i < bytes.length; i++) {
            temp.append((byte) ((bytes[i] & 0xf0) >>> 4));
            temp.append((byte) (bytes[i] & 0x0f));
        }
        return temp.toString().substring(0, 1).equalsIgnoreCase("0") ? temp
                .toString().substring(1) : temp.toString();
    }
    /**
     * @功能: 10进制串转为BCD码
     * @参数: 10进制串
     * @结果: BCD码
     */
    public static byte[] str2Bcd(String asc) {
        int len = asc.length();
        int mod = len % 2;
        if (mod != 0) {
            asc = "0" + asc;
            len = asc.length();
        }
        byte abt[] = new byte[len];
        if (len >= 2) {
            len = len / 2;
        }
        byte bbt[] = new byte[len];
        abt = asc.getBytes();
        int j, k;
        for (int p = 0; p < asc.length() / 2; p++) {
            if ((abt[2 * p] >= '0') && (abt[2 * p] <= '9')) {
                j = abt[2 * p] - '0';
            } else if ((abt[2 * p] >= 'a') && (abt[2 * p] <= 'z')) {
                j = abt[2 * p] - 'a' + 0x0a;
            } else {
                j = abt[2 * p] - 'A' + 0x0a;
            }
            if ((abt[2 * p + 1] >= '0') && (abt[2 * p + 1] <= '9')) {
                k = abt[2 * p + 1] - '0';
            } else if ((abt[2 * p + 1] >= 'a') && (abt[2 * p + 1] <= 'z')) {
                k = abt[2 * p + 1] - 'a' + 0x0a;
            } else {
                k = abt[2 * p + 1] - 'A' + 0x0a;
            }
            int a = (j << 4) + k;
            byte b = (byte) a;
            bbt[p] = b;
        }
        return bbt;
    }
    public static byte getXor(byte[] datas, int start, int end) {
        byte temp = datas[start];
        for (int i = start + 1; i < end; i++) {
            temp ^= datas[i];
        }
        return temp;
    }
    /**
     * 求校验和的算法
     * @param b 需要求校验和的字节数组
     * @return 校验和
     */
    public static byte sumCheck(byte[] b,int start, int end){
    public static byte sumCheck(byte[] b, int start, int end) {
        int sum = 0;
        for(int i = start; i < end; i++){
        for (int i = start; i < end; i++) {
            sum = sum + b[i];
        }
        return (byte) (sum & 0xff);
    }
  //字符串转换为ascii
    public static byte[] StrToAsc(String content){
      try {
      return content.getBytes(StandardCharsets.US_ASCII);
   } catch (Exception e) {
      e.printStackTrace();
      return null;
   }
    //字符串转换为ascii
    public static byte[] StrToAsc(String content) {
        try {
            return content.getBytes(StandardCharsets.US_ASCII);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    //ascii转换为string
    public static String AscToStr(byte[] bytes){
       StringBuffer sbu = new StringBuffer();
      for (byte aByte : bytes) {
         sbu.append(Character.toString((char) aByte));
      }
        return sbu.toString();
    public static String AscToStr(byte[] bytes) {
        StringBuffer sbu = new StringBuffer();
        for (byte aByte : bytes) {
            sbu.append(Character.toString((char) aByte));
        }
        return sbu.toString();
    }
    public Class getClassType(String name) {
        return null;
    }
    /**
     * 判断大小端
     * @return true: 小端 / false: 大端
     */
    public boolean isReverse() {
        return this.getClass().getAnnotation(little.class) != null;
    }
    /**
     * 获取字节数组
     */
    public byte[] toBytes() throws Exception {
        return encode(this);
    }
    public Map<String, String> toDecodeHexMapping() throws Exception {
        if (this.decodeByteMapping == null) this.decodeByteMapping = new HashMap<>();
        Map<String, String> mapping = getHex(this.decodeByteMapping);
        if (this.decodeBytes != null) {
            mapping.put("byte[]", Struct.toHex(this.decodeBytes));
        }
        return mapping;
    }
    public Map<String, String> toEncodeHexMapping() throws Exception {
        if (this.encodeBytes == null) this.encode(this);
        if (this.encodeByteMapping == null) this.encodeByteMapping = new HashMap<>();
        Map<String, String> mapping = getHex(this.encodeByteMapping);
        mapping.put("byte[]", Struct.toHex(this.encodeBytes));
        return mapping;
    }
    public Map<String, String> getHex(Map<String, byte[]> bytemapping) throws Exception {
        Map<String, String> map = new LinkedHashMap<>();
        Field[] fields = this.getClass().getFields();
        for (Field field : fields) {
            byte[] bytes = bytemapping.get(field.getName());
            if (bytes != null) {
                map.put(field.getName(), Struct.toHex(bytes));
            }
        }
        return map;
    }
    // 转java对象到数组
    public byte[] encode(Struct entity) throws Exception {
        ByteArrayOutputStream baOs = new ByteArrayOutputStream();
        write(new DataOutputStream(baOs), entity);
        entity.encodeBytes = baOs.toByteArray();
        return entity.encodeBytes;
    }
    /**
     * 写数据到输出流
     *
     * @param dos
     * @param entity
     */
    public void write(DataOutputStream dos, Struct entity) throws Exception {
        if (entity == null) return;
        if (entity.encodeByteMapping == null) entity.encodeByteMapping = new HashMap<>();
        Field[] fields = entity.getClass().getFields();
        EvaluationContext context = new StandardEvaluationContext();
        for (Field field : Objects.requireNonNull(ReflectUtils.removeStaticField(fields))) {
            field.setAccessible(true);
            String name = field.getName();
            Class<?> type = field.getType();
            String typeName = type.getSimpleName();
            if (typeName.equals("Struct")) {
                if (entity.getClassType(name) != null) {
                    type = entity.getClassType(name);
                    typeName = type.getSimpleName();
                } else if (field.get(entity) != null) {
                    type = field.get(entity).getClass();
                    typeName = type.getSimpleName();
                }
            }
            size size = field.getAnnotation(size.class);
            bit bit = field.getAnnotation(bit.class);
            expr expr = field.getAnnotation(expr.class);
            flag flag = field.getAnnotation(flag.class);
            if (size == null && bit == null && expr == null) {
                continue;
            }
            int bited = 0;//已写位数
            int length = 0;//定义的长度
            if (size != null) {
                length = size.value();
                bited += size.value() * 8;
            } else if (bit != null) {
                //按位写方式未实现处理
                throw new RuntimeException("按位写方式未实现处理");
            } else if (expr != null) {
                ExpressionParser parser = new SpelExpressionParser();
                Expression exp = parser.parseExpression(expr.value());
                Integer len = null;
                try {
                    len = CommonUtils.parseInt(exp.getValue(context, entity));
                } catch (Exception e) {
                    len = 0;
                }
                if (len != null) {
                    if (len == -1) continue;
                    length = len;
                    bited += len * 8;
                }
            }
            context.setVariable(name, field.get(entity));
            byte[] bytes = new byte[length];
            if (typeName.equals("int") || typeName.equals("Integer")) {
                dos.write(bytes = convert(length, field.getInt(entity)));
            } else if (typeName.equals("long") || typeName.equals("Long")) {
                dos.write(bytes = convert(length, field.getLong(entity)));
            } else if (typeName.equals("short") || typeName.equals("Short")) {
                dos.write(bytes = convert(length, field.getShort(entity)));
            } else if (typeName.equals("byte") || typeName.equals("Byte")) {
                dos.write(bytes = convert(length, field.getByte(entity)));
            } else if (typeName.equals("String")) {
                String str = (String) field.get(entity);
                if (str == null)
                    str = "";
                str = str.replaceAll(" ", " ");
                byte[] bts = null;
                if (flag != null && flag.value().equals("ASCII")) {
                    bts = Struct.StrToAsc(str);
                } else if (flag != null && flag.value().equals("BCD")) {
                    bts = Struct.str2Bcd(str);
                } else {
                    bts = str.getBytes();
                }
                if (length == 0) {//如果长度未设置,以当前实际的字节为准
                    bytes = new byte[bts.length];
                }
                System.arraycopy(bts, 0, bytes, 0, bts.length);
                dos.write(bytes);
            } else if (typeName.equals("byte[]")) {
                byte[] bts = (byte[]) field.get(entity);
                if (bts != null) {
                    if (length == 0) {//如果长度未设置,以当前实际的字节为准
                        bytes = new byte[bts.length];
                    }
                    System.arraycopy(bts, 0, bytes, 0, bts.length);
                    dos.write(bytes);
                }
            } else if (type.isArray()) {
                ByteArrayOutputStream baOs1 = new ByteArrayOutputStream();
                DataOutputStream dos1 = new DataOutputStream(baOs1);
                for (Object object : (Object[]) field.get(entity)) {
                    write(dos1, (Struct) object);
                }
                byte[] bts = baOs1.toByteArray();
                if (length == 0) {//如果长度未设置,以当前实际的字节为准
                    bytes = new byte[bts.length];
                }
                System.arraycopy(bts, 0, bytes, 0, bts.length);
                dos.write(bytes);
            } else {
                byte[] bts = encode((Struct) field.get(entity));
                if (length == 0) {//如果长度未设置,以当前实际的字节为准
                    bytes = new byte[bts.length];
                }
                System.arraycopy(bts, 0, bytes, 0, bts.length);
                dos.write(bytes);
            }
            entity.encodeByteMapping.put(name, bytes);
        }
    }
    public byte[] convert(int size, long value) throws Exception {
        ByteArrayOutputStream baOs = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(baOs);
        switch (size) {
            case 1://byte
                dos.write((byte) value);
                break;
            case 2://short
                dos.writeShort(this.isReverse() ? Short.reverseBytes((short) value) : (short) value);
                break;
            case 4://int
                dos.writeInt(this.isReverse() ? Integer.reverseBytes((int) value) : (int) value);
                break;
            case 8://long
                dos.writeLong(this.isReverse() ? Long.reverseBytes((long) value) : (long) value);
                break;
        }
        return baOs.toByteArray();
    }
    public long convertEx(long value, int size) throws Exception {
        switch (size) {
            case 1://byte
                return value;
            case 2://short
                return (this.isReverse() ? Short.reverseBytes((short) value) : (short) value);
            case 4://int
                return (this.isReverse() ? Integer.reverseBytes((int) value) : (int) value);
            case 8://long
                return (this.isReverse() ? Long.reverseBytes((long) value) : (long) value);
        }
        return 0;
    }
    /**
     * 解码: 字节数组 ====>> java对象
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public <T extends Struct> T decode(byte[] bytes) throws Exception {
        this.dataBytes = bytes;
        Struct instance = this;
        Class<? extends Struct> cls = this.getClass();
        Field[] fields = cls.getFields();
        if (this.decodeByteMapping == null) instance.decodeByteMapping = new HashMap();
        // spring el表达式
        EvaluationContext context = new StandardEvaluationContext();
        context.setVariable("_", bytes.length);
        int bited = 0;//已读位数
        for (Field field : Objects.requireNonNull(ReflectUtils.removeStaticField(fields))) {
            size size = field.getAnnotation(size.class);
            bit bit = field.getAnnotation(bit.class);
            expr expr = field.getAnnotation(expr.class);
            flag flag = field.getAnnotation(flag.class);
            // 没有size、bit、expr注解的变量不进行解析
            if (size == null && bit == null && expr == null) {
                continue;
            }
            String name = field.getName();
            Class<?> type = field.getType();
            String typeName = type.getSimpleName();
            if (typeName.equals("Struct")) {
                if (instance.getClassType(name) != null) {
                    type = instance.getClassType(name);
                    typeName = type.getSimpleName();
                }
            }
            context.setVariable("__", bytes.length - bited / 8);
            byte[] bts = null;
            if (size != null) {
                bts = new byte[size.value()];
                System.arraycopy(bytes, bited / 8, bts, 0, size.value());
                bited += size.value() * 8;
            } else if (bit != null) {
                int val = 0;
                String strBin = "";
                for (int i = bited; i < bited + bit.value(); i++) {//逐位扫描
                    if ((bytes[i / 8] & (1 << (i % 8))) != 0) {//如果位为1
                        strBin += "1";
                    } else {
                        strBin += "0";
                    }
                    val = Integer.parseInt(strBin, 2);
                }
                byte[] result = new byte[4];
                result[3] = (byte) (val);
                result[2] = (byte) (val >> 8);
                result[1] = (byte) (val >> 16);
                result[0] = (byte) (val >> 24);
                bts = new byte[(int) Math.ceil((double) bit.value() / 8.0)];
                System.arraycopy(result, result.length - bts.length, bts, 0, bts.length);
                bited += bit.value();
            } else if (expr != null) {
                ExpressionParser parser = new SpelExpressionParser();
                Expression exp = parser.parseExpression(expr.value());
                Integer len = CommonUtils.parseInt(exp.getValue(context, instance));
                if (len != null) {
                    if (len == -1) continue;
                    bts = new byte[len];
                    System.arraycopy(bytes, bited / 8, bts, 0, len);
                    bited += len * 8;
                }
            }
            if (bts.length == 0) continue;
            DataInputStream dis = new DataInputStream(new ByteArrayInputStream(bts));
            if (typeName.equals("int") || typeName.equals("Integer")) {
                field.setInt(instance, (int) convertEx(dis.readInt(), 4));
            } else if (typeName.equals("long") || typeName.equals("Long")) {
                field.setLong(instance, convertEx(dis.readLong(), 8));
            } else if (typeName.equals("short") || typeName.equals("Short")) {
                field.setShort(instance, (short) convertEx(dis.readShort(), 2));
            } else if (typeName.equals("byte") || typeName.equals("Byte")) {
                field.setByte(instance, (byte) convertEx(dis.readByte(), 1));
            } else if (typeName.equals("byte[]")) {
                field.set(instance, bts);
            } else if (typeName.equals("String")) {
                String strStr = new String(bts, StandardCharsets.UTF_8);
                if (flag != null && flag.value().equals("BCD")) {
                    strStr = bcd2Str(bts);
                } else if (flag != null && flag.value().equals("ASCII")) {
                    strStr = Struct.AscToStr(bts);
                }
                strStr = strStr.replaceAll("[\u0000]", "");
                field.set(instance, strStr);
            } else if (type.isArray()) {
                byte[] arrayBytes = bts;
                List list = new ArrayList();
                while (arrayBytes.length > 0 && list.size() < 256) {
                    Struct item = decode((Class<? extends Struct>) type.getComponentType(), arrayBytes);
                    list.add(item);
                    arrayBytes = item.unusedBytes;
                }
                Object array = Array.newInstance(type.getComponentType(), list.size());
                for (int i = 0; i < list.size(); i++) {
                    Array.set(array, i, list.get(i));
                }
                field.set(instance, array);
            } else if (type == Struct.class || Struct.class.isAssignableFrom(type)) {
                byte[] arrayBytes = bts;
                Struct item = decode((Class<? extends Struct>) type, arrayBytes);
                field.set(instance, item);
            } else {
                throw new RuntimeException(cls.getSimpleName() + "字段" + field.getName() + "类型未知");
            }
            instance.decodeByteMapping.put(name, bts);
            context.setVariable(name, field.get(instance));
        }
        byte[] useBytes = new byte[bited / 8];
        System.arraycopy(bytes, 0, useBytes, 0, bited / 8);
        instance.decodeBytes = useBytes;
        byte[] unusedBytes = new byte[bytes.length - (bited / 8)];
        if (unusedBytes.length > 0) {
            System.arraycopy(bytes, useBytes.length, unusedBytes, 0, unusedBytes.length);
        }
        instance.unusedBytes = unusedBytes;
        return (T) instance;
    }
    public static class TestMessage {
        public @size(1) byte begin = 0x7e;//起始符
        public @size(2) short type = 0;//消息ID
        public @bit(2) byte retain;//消息体属性>保留
        public @bit(1) byte subpkg;//消息体属性>是否分包,0表示不分包
        public @bit(3) byte encrypt;//消息体属性>加密方式,0表示不加密
        public @bit(10) short length;//消息体长度
        public @size(6)
        @flag("BCD") String number;//手机号码
        public @size(2) short serial;//消息流水号
        public @expr("#subpkg==1?2:0") short pkgs;//分包数
        public @expr("#subpkg==1?2:0") short index;//包序号
        public @expr("#length") byte[] data;//数据部分
        public @size(1) byte verify;//校验码
        public @size(1) byte end = 0x7e;//结束符
    }
}