自动化立体仓库 - WCS系统
#
vincent
2020-06-03 91605535e2a0d2adadea30a6873356e329143f72
#
8个文件已添加
673 ■■■■■ 已修改文件
src/main/java/com/zy/common/model/annotations/bit.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/model/annotations/expr.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/model/annotations/flag.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/model/annotations/little.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/model/annotations/size.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/utils/CommonUtils.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/utils/ReflectUtils.java 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/utils/Struct.java 490 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/model/annotations/bit.java
New file
@@ -0,0 +1,16 @@
package com.zy.common.model.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 标识注解类
 * @author uiu
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})
public @interface bit {
    int value();
}
src/main/java/com/zy/common/model/annotations/expr.java
New file
@@ -0,0 +1,16 @@
package com.zy.common.model.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 标识注解类
 * @author uiu
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})
public @interface expr {
    String value();
}
src/main/java/com/zy/common/model/annotations/flag.java
New file
@@ -0,0 +1,16 @@
package com.zy.common.model.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 标识注解类
 * @author uiu
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})
public @interface flag {
    String value();
}
src/main/java/com/zy/common/model/annotations/little.java
New file
@@ -0,0 +1,14 @@
package com.zy.common.model.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 小端模式注解类
 * @author uiu
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})
public @interface little {}
src/main/java/com/zy/common/model/annotations/size.java
New file
@@ -0,0 +1,16 @@
package com.zy.common.model.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 标识注解类
 * @author uiu
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})
public @interface size {
    int value();
}
src/main/java/com/zy/common/utils/CommonUtils.java
New file
@@ -0,0 +1,30 @@
package com.zy.common.utils;
import java.math.BigDecimal;
/**
 * Created by vincent on 2020-06-03
 */
public class CommonUtils {
    public static Integer parseInt(Object value){
        if(null == value){
            return null;
        }
        String name = value.getClass().getSimpleName().toLowerCase();
        if(name.equals("float")){
            return ((Float)value).intValue();
        } else if(name.equals("double")){
            return ((Double)value).intValue();
        } else if(name.equals("bigdecimal")) {
            return ((BigDecimal)value).intValue();
        } else if(name.equals("long")) {
            return ((Long)value).intValue();
        } else if(name.contains("int")) {
            return (Integer)value;
        } else {
            return Double.valueOf(""+value).intValue();
        }
    }
}
src/main/java/com/zy/common/utils/ReflectUtils.java
New file
@@ -0,0 +1,75 @@
package com.zy.common.utils;
import com.core.common.Cools;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
 * 反射工具类
 * Created by vincent on 2019/1/3
 */
public class ReflectUtils {
    /**
     * 获取指定Class(及其SuperClass)的成员变量
     */
    public static Field[] getAllFields(Class<?> cls){
        return getAllFields(cls, null);
    }
    /**
     * 递归合并基类Field
     */
    private static Field[] getAllFields(Class<?> cls, Field[] params){
        Field[] fields = (params == null) ? cls.getDeclaredFields() : params;
        Class<?> superCls = cls.getSuperclass();
        if (superCls == null || superCls == Object.class){
            return fields;
        }
        Field[] superClsFields = superCls.getDeclaredFields();
        fields = Cools.addAll(fields, superClsFields);
        return getAllFields(superCls, fields);
    }
    /**
     * 删除Field数组的静态成员变量
     */
    public static Field[] removeStaticField(Field[] params){
        List<Field> fields = new ArrayList<>(Arrays.asList(params));
        if (fields.size() == 0){
            return null;
        }
        for (int i = fields.size() - 1; i >= 0; i--) {
            if(fields.get(i) == null){
                fields.remove(i);
            } else if (Modifier.isStatic(fields.get(i).getModifiers())) {
                fields.remove(i);
                i++;
            }
        }
        return fields.toArray(new Field[0]);
    }
    /**
     * 递归获取成员变量对象(包含其基类)
     */
    public static Field getField(Class<?> cls, String fieldName){
        Field field;
        try {
            field = cls.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            Class<?> superCls = cls.getSuperclass();
            if (superCls == null || superCls == Object.class){
                return null;
            }
            return getField(superCls, fieldName);
        }
        return field;
    }
}
src/main/java/com/zy/common/utils/Struct.java
New file
@@ -0,0 +1,490 @@
package com.zy.common.utils;
import com.zy.common.model.annotations.*;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.*;
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;
    }
    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
     * @throws Exception
     */
    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);
    }
    @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();
        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);
            if(size==null && bit==null && expr==null){
                continue;
                //throw new RuntimeException(cls.getSimpleName()+"字段"+field.getName()+"未标记@size|@bit|@expr");
            }
            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,"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) {
        StringBuilder buf = new StringBuilder(bytes.length * 2);
        for(byte b : bytes) { // 使用String的format方法进行转换
            buf.append(String.format("%02x", new Integer(b & 0xff)));
        }
        return buf.toString().toUpperCase();
    }
    public static byte[] toBytes(String str) {
        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++) {
            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;
    }
    /**
     * 求校验和的算法
     * @param b 需要求校验和的字节数组
     * @return 校验和
     */
    public static byte sumCheck(byte[] b,int start, int end){
        int sum = 0;
        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("US-ASCII");
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
    }
    //ascii转换为string
    public static String AscToStr(byte[] bytes){
        StringBuffer sbu = new StringBuffer();
        for(int i=0;i<bytes.length;i++){
            sbu.append(Character.toString((char)bytes[i]));
        }
        return sbu.toString();
    }
}