zoukankan      html  css  js  c++  java
  • IS08583报文协议包的解析和封装java源代码

    转自:http://www.cnblogs.com/dengzhaozhe/archive/2009/05/09/1453251.html

    前段时间做了一个涉及到IS08583报文协议的项目,自己总结写了这篇附有java源代码的文章,希望能给大家提供一些帮助,本文分四个部分介绍IS08583报文协议包的处理及如何解析请求包及怎样封装返回包,

    一:IS08583包介绍:

         ISO8583包(简称8583包)是一个国际标准的包格式,最多由128个字段域组成,每个域都有统一的规定,并有定长与变长之分。
         8583包前面一段为位图,用来确定包的字段域组成情况。其中位图是8583包的灵魂,它是打包解包确定字段域的关键, 而了解每个字段域的属性则是填写数据的基础。   

     1:位图说明:

         位置:在8583包的第1 位
         格式:定长  
         类型:B16(二进制16位,16*8=128bit)  
         描述:  
         如将位图的第一位设为'1',表示使用扩展位图(128个域),否则表示只使用基本位图(64个域)。  
         如使用某数据域,应在位图中将相应的位设位'1',如使用41域,需将位图的41位设为'1'。  
         选用条件:如使用65到128域,需设位图域第一位为'1'  
    2:域的定义:  
    typedef struct ISO8583  
    {  
        int bit_flag;            /*域数据类型0 -- string, 1 -- int, 2 -- binary*/  
        char *data_name;  /*域名*/  
        int length;             /*数据域长度*/  
        int length_in_byte;/*实际长度(如果是变长)*/  
        int variable_flag;   /*是否变长标志0:否 2:2位变长, 3:3位变长*/  
        int datatyp;         /*0 -- string, 1 -- int, 2 -- binary*/  
        char *data;         /*存放具体值*/  
        int attribute;      /*保留*/  
    } ISO8583;

    二:定义BitMap类

    类说明:根据ISO8583 包的域定义,定义BitMap类存储每个域的信息。例如:

    package com.lottery.pos.model;

    public  class BitMap {
     private int bit; //位
     private int bittype; //数据类型 1 ascii 2 binary
     private int variable;  //是否变长0 不是 2 两位变长 3 三位变长
     private int len; //数据长度
     private byte[] dat; //数据
     
     public int getBit() {
      return bit;
     }
     public void setBit(int bit) {
      this.bit = bit;
     }
     public int getBittype() {
      return bittype;
     }
     public void setBittype(int bittype) {
      this.bittype = bittype;
     }
     public int getVariable() {
      return variable;
     }
     public void setVariable(int variable) {
      this.variable = variable;
     }
     public byte[] getDat() {
      return dat;
     }
     public void setDat(byte[] dat) {
      this.dat = dat;
     }
     public int getLen() {
      return len;
     }
     public void setLen(int len) {
      this.len = len;
     }

     
    }

    三:定义PortConfig类

    类说明:定义配置信息类。根据此类解析和封装数据。例如:

    package com.lottery.pos.model;

    public class PortConfig {
     /**
      * 存放所有接口的配置信息
      * [][0] bit     位:在Map中的位
      * [][1] type   类型:1 ascii 2 binary
      * [][2] len    长度:(对定长有效)
      * [][3] varLen 变长:0非变长 2位变长 3位变长
      */
     // 定义一个二位数组存放配置信息。
     public static final  int[][] config= {
       {11,1,6,0},
       {12,1,6,0},
       {13,1,4,0},
       {32,1,11,0},
       {37,1,12,0},
       {39,1,2,0},
       {40,2,50,2},
       {41,1,8,0},
       {48,1,52,3},
       {120,2,128,3},
       };

    四:定义BitMapiso类

    类说明:此类提供解析请求包和封装信息包两个方法,例如:

    package com.lottery.pos.utils;

    import java.util.ArrayList;
    import java.util.List;

    import com.lottery.pos.model.BitMap;

    public class BitMapiso {

     /**
      * 解析请求包
      * @param body
      * @param config
      * @return List
      */
     @SuppressWarnings("unchecked")
     public static List unpackRequest(byte[] body, int[][] config) {
      List outList = new ArrayList();
      // 取得除信息类型以外的包信息。也就是取得位图的初始位置。
      byte[] realbody = new byte[body.length - 4];
      System.arraycopy(body, 4, realbody, 0, realbody.length);
      // 取得位图
      byte[] map = null;
      byte[] map8 = new byte[8];
      System.arraycopy(realbody, 0, map8, 0, 8);
      boolean[] bmap8 = LoUtils.getBinaryFromByte(map8);
      if (bmap8[1]) {
      // 如果第一位为1,则是可扩展位图,设为16字节长度。
       map = new byte[16];
       System.arraycopy(realbody, 0, map, 0, 16);
      } else {
       map = map8;
      }
      boolean[] bmap = LoUtils.getBinaryFromByte(map);

      int tmplen = map.length;
      for (int i = 2; i < bmap.length; i++) {
       if (bmap[i]) {
        //BitMap bitMap = null;
        // 寻找位图中的1对应的数据
        int bit=-1;
        for (int j = 0; j < config.length; j++) {
         if (config[j][0] == i) {
          bit=j;
          break;
         }
        }
        BitMap outBitMap = new BitMap();
        outBitMap.setBit(i);
        outBitMap.setBittype(config[bit][1]);
        //len对变长是无用的。
        outBitMap.setLen(config[bit][2]);
        outBitMap.setVariable(config[bit][3]);
        byte[] nextData = null;
        if (config[bit][3] > 0) {
         //取出变长部分的值。
         int varLen = config[bit][3];
         if (config[bit][1] == 2) {
          varLen = varLen - 1;
         }
         byte[] varValue = new byte[varLen];
         System.arraycopy(realbody, tmplen, varValue, 0, varValue.length);
         int datLen = 0;
         if (config[bit][1] == 2) {
          datLen = LoUtils.bcdToint(varValue);
         } else {
          datLen = byteToInt(varValue);
         }

         tmplen += varLen;
         // 取出变长部分后带的值。
         nextData = new byte[datLen];

         System.arraycopy(realbody, tmplen, nextData, 0,nextData.length);
         tmplen += nextData.length;
        } else {
         nextData = new byte[config[bit][2]];
         System.arraycopy(realbody, tmplen, nextData, 0,nextData.length);
         tmplen += config[bit][2];
        }
        outBitMap.setDat(nextData);
        outList.add(outBitMap);
       }
      }

      return outList;
     }

     /**
      * 打包响应包,不包括消息类型
      * @param list
      * @return byte[]
      */
     @SuppressWarnings("unchecked")
     public static byte[] PackResponse(List list) {
      int len = 16;
      for (int i = 0; i < list.size(); i++) {
       BitMap bitMap = (BitMap) list.get(i);
       // 计算请求包总长度
       if (bitMap.getBittype() == 2) {
        if (bitMap.getVariable() > 0) {
         len += bitMap.getVariable() - 1 + bitMap.getDat().length;
        } else {
         len += bitMap.getVariable() + bitMap.getDat().length;
        }
       } else {
        len += bitMap.getVariable() + bitMap.getDat().length;
       }
      }
      byte[] body = new byte[len];
      // 位图
      boolean[] bbitMap = new boolean[129];
      bbitMap[1] = true;
      int temp = (bbitMap.length - 1) / 8;
      for (int j = 0; j < list.size(); j++) {
       BitMap bitMap = (BitMap) list.get(j);
       bbitMap[bitMap.getBit()] = true;
       byte[] bitmap = LoUtils.getByteFromBinary(bbitMap);
       System.arraycopy(bitmap, 0, body, 0, bitmap.length);
       // 数据
       if (bitMap.getVariable() > 0) {
        // 数据是可变长的:拼变长的值
        byte[] varValue = null;
        if (bitMap.getBittype() == 2) {
         varValue = LoUtils.StrToBCDBytes(String.format("%0"+ bitMap.getVariable() + "d",bitMap.getDat().length));
        } else {
         varValue = String.format("%0" + bitMap.getVariable() + "d",bitMap.getDat().length).getBytes();
        }
        System.arraycopy(varValue, 0, body, temp, varValue.length);
        temp += varValue.length;
        // 拼变长部分后所带的数的值。
        System.arraycopy(bitMap.getDat(), 0, body, temp, bitMap.getDat().length);
        temp += bitMap.getDat().length;
       } else {
        // 数据是固定长度的。
        byte dat[] =new byte[bitMap.getLen()];
        if (bitMap.getDat().length!=bitMap.getLen()){     
         System.arraycopy(bitMap.getDat(), 0, dat, 0, bitMap.getLen());
        }else{
         dat=bitMap.getDat();
        } 
        System.arraycopy(dat, 0, body, temp, dat.length);
        temp += bitMap.getDat().length;
       }
      }
      return body;
     }

    package com.lottery.utils;

    import java.io.BufferedInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;

    import javax.servlet.http.HttpServletRequest;

    import sun.misc.BASE64Decoder;
    import sun.misc.BASE64Encoder;

    /**
     * 编码与数据类型类
     *
     * @author LLH
     */
    public class LoUtils
    {
     private static BASE64Encoder encoder = new BASE64Encoder ();
     private static BASE64Decoder decoder = new BASE64Decoder ();
     
     /**
      * BASE64 编码
      *
      * @param s
      * @return
      */
     public static String encodeBufferBase64(byte [] buff)
     {
      return buff == null ? null : encoder.encode (buff);
     }
     
     /**
      * BASE64解码
      *
      * @param s
      * @return
      */
     public static byte [] decodeBufferBase64(String s)
     {
      try
      {
       return s == null ? null : decoder.decodeBuffer (s);
      }catch (IOException e)
      {
       e.printStackTrace ();
      }
      return null;
     }
     
     /**
      * BASE64 字节数组编码
      *
      * @param s
      * @return String
      */
     public static String encodeBase64(byte [] s)
     {
      if(s == null)
       return null;
      String res = new BASE64Encoder ().encode (s);
      res = res.replace ("\n","");
      res = res.replace ("\r","");
      return res;
     }
     
     /**
      * BASE64解码
      *
      * @param s
      * @return
      */
     public static byte [] decodeBase64(byte [] buff)
     {
      if(buff == null)
       return null;
      BASE64Decoder decoder = new BASE64Decoder ();
      try
      {
       byte [] b = decoder.decodeBuffer (new String (buff));
       
       return b;
      }catch (Exception e)
      {
       return null;
      }
     }
     
     /**
      * 将reauest里的数据包转成字符串
      *
      * @param request
      * @return String
      */
     public static String getRequestBodyTxt(HttpServletRequest request)
     {
      // 接收手机传过来的参数
      BufferedInputStream bufferedInputStream = null;
      // 此类实现了一个输出流,其中的数据被写入一个字节数组
      ByteArrayOutputStream bytesOutputStream = null;
      String body = null;
      try
      {
       
       // BufferedInputStream 输入流
       bufferedInputStream = new BufferedInputStream (
        request.getInputStream ());
       bytesOutputStream = new ByteArrayOutputStream ();
       // 写入数据
       int ch;
       while ((ch = bufferedInputStream.read ()) != -1)
       {
        bytesOutputStream.write (ch);
       }
       // 转换为String类型
       body = new String (bytesOutputStream.toByteArray (),"UTF-8");
      }catch (Exception ex)
      {
       ex.printStackTrace ();
      }
      finally
      {
       // 关闭此输入流并释放与该流关联的所有系统资源。
       try
       {
        bytesOutputStream.flush ();
        bytesOutputStream.close ();
        bufferedInputStream.close ();
       }catch (IOException e)
       {
        e.printStackTrace ();
       }
      }
      return body;
     }
     
     /**
      * 将reauest里的数据包转成字节数组
      *
      * @param request
      * @return
      */
     public static byte [] getRequestBodyByte(HttpServletRequest request)
     {
      // 接收手机传过来的参数
      BufferedInputStream bufferedInputStream = null;
      // 此类实现了一个输出流,其中的数据被写入一个字节数组
      ByteArrayOutputStream bytesOutputStream = null;
      byte [] body = null;
      try
      {
       // BufferedInputStream 输入流
       bufferedInputStream = new BufferedInputStream (
        request.getInputStream ());
       bytesOutputStream = new ByteArrayOutputStream ();
       // 写入数据
       int ch;
       while ((ch = bufferedInputStream.read ()) != -1)
       {
        bytesOutputStream.write (ch);
       }
       // 转换为String类型
       body = bytesOutputStream.toByteArray ();
      }catch (Exception ex)
      {
       ex.printStackTrace ();
      }
      finally
      {
       // 关闭此输入流并释放与该流关联的所有系统资源。
       try
       {
        bytesOutputStream.flush ();
        bytesOutputStream.close ();
        bufferedInputStream.close ();
       }catch (IOException e)
       {
        e.printStackTrace ();
       }
      }
      return body;
     }
     
     public static String getEigthBitsStringFromByte(int b)
     {
      // if this is a positive number its bits number will be less
      // than 8
      // so we have to fill it to be a 8 digit binary string
      // b=b+100000000(2^8=256) then only get the lower 8 digit
      b |= 256; // mark the 9th digit as 1 to make sure the string
      // has at
      // least 8 digits
      String str = Integer.toBinaryString (b);
      int len = str.length ();
      return str.substring (len - 8,len);
     }
     
     public static byte getByteFromEigthBitsString(String str)
     {
      // if(str.length()!=8)
      // throw new Exception("It's not a 8 length string");
      byte b;
      // check if it's a minus number
      if(str.substring (0,1).equals ("1"))
      {
       // get lower 7 digits original code
       str = "0" + str.substring (1);
       b = Byte.valueOf (str,2);
       // then recover the 8th digit as 1 equal to plus
       // 1000000
       b |= 128;
      }
      else
      {
       b = Byte.valueOf (str,2);
      }
      return b;
     }
     
     /**
      * 将一个16字节数组转成128二进制数组
      *
      * @param b
      * @return
      */
     public static boolean [] getBinaryFromByte(byte [] b)
     {
      boolean [] binary = new boolean [b.length * 8 + 1];
      String strsum = "";
      for (int i = 0;i < b.length;i++ )
      {
       strsum += getEigthBitsStringFromByte (b [i]);
      }
      for (int i = 0;i < strsum.length ();i++ )
      {
       if(strsum.substring (i,i + 1).equalsIgnoreCase ("1"))
       {
        binary [i + 1] = true;
       }
       else
       {
        binary [i + 1] = false;
       }
      }
      return binary;
     }
     
     /**
      * 将一个128二进制数组转成16字节数组
      *
      * @param binary
      * @return
      */
     public static byte [] getByteFromBinary(boolean [] binary)
     {
      
      int num = (binary.length - 1) / 8;
      if((binary.length - 1) % 8 != 0)
      {
       num = num + 1;
      }
      byte [] b = new byte [num];
      String s = "";
      for (int i = 1;i < binary.length;i++ )
      {
       if(binary [i])
       {
        s += "1";
       }
       else
       {
        s += "0";
       }
      }
      String tmpstr;
      int j = 0;
      for (int i = 0;i < s.length ();i = i + 8)
      {
       tmpstr = s.substring (i,i + 8);
       b [j] = getByteFromEigthBitsString (tmpstr);
       j = j + 1;
      }
      return b;
     }
     
     /**
      * 将一个byte位图转成字符串
      *
      * @param b
      * @return
      */
     public static String getStrFromBitMap(byte [] b)
     {
      String strsum = "";
      for (int i = 0;i < b.length;i++ )
      {
       strsum += getEigthBitsStringFromByte (b [i]);
      }
      return strsum;
     }
     
     /**
      * bytes转换成十六进制字符串
      *
      * @param b
      * @return
      */
     public static String byte2HexStr(byte [] b)
     {
      String hs = "";
      String stmp = "";
      for (int n = 0;n < b.length;n++ )
      {
       stmp = (Integer.toHexString (b [n] & 0XFF));
       if(stmp.length () == 1)
        hs = hs + "0" + stmp;
       else
        hs = hs + stmp;
      }
      return hs.toUpperCase ();
     }
     
     private static byte uniteBytes(String src0, String src1)
     {
      byte b0 = Byte.decode ("0x" + src0).byteValue ();
      b0 = (byte) (b0 << 4);
      byte b1 = Byte.decode ("0x" + src1).byteValue ();
      byte ret = (byte) (b0 | b1);
      return ret;
     }
     
     /**
      * 十六进制字符串转换成bytes
      *
      * @param src
      * @return
      */
     public static byte [] hexStr2Bytes(String src)
     {
      int m = 0, n = 0;
      int l = src.length () / 2;
      byte [] ret = new byte [l];
      for (int i = 0;i < l;i++ )
      {
       m = i * 2 + 1;
       n = m + 1;
       ret [i] = uniteBytes (src.substring (i * 2,m),
        src.substring (m,n));
      }
      return ret;
     }
     
     /**
      * 将String转成BCD码
      *
      * @param s
      * @return
      */
     public static byte [] StrToBCDBytes(String s)
     {
      
      if(s.length () % 2 != 0)
      {
       s = "0" + s;
      }
      ByteArrayOutputStream baos = new ByteArrayOutputStream ();
      char [] cs = s.toCharArray ();
      for (int i = 0;i < cs.length;i += 2)
      {
       int high = cs [i] - 48;
       int low = cs [i + 1] - 48;
       baos.write (high << 4 | low);
      }
      return baos.toByteArray ();
     }
     
     /**
      * 将BCD码转成int
      *
      * @param b
      * @return
      */
     public static int bcdToint(byte [] b)
     {
      StringBuffer sb = new StringBuffer ();
      for (int i = 0;i < b.length;i++ )
      {
       int h = ((b [i] & 0xff) >> 4) + 48;
       sb.append ((char) h);
       int l = (b [i] & 0x0f) + 48;
       sb.append ((char) l);
      }
      return Integer.parseInt (sb.toString ());
     }
     
     /**
      * 输出调试信息
      *
      * @param str
      */
     public static void trace(String str)
     {
    //  System.out.println ("["
    //   + (new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss.S")).format (new Date ())
    //   + "]>" + str);
     }
    }

    源代码测试没有问题。

  • 相关阅读:
    day50_BOS项目_02
    day51_BOS项目_03
    Criteria 和 DetachedCriteria 的区别
    ecplise中如何关闭Tomcat的自动重启/加载
    Tomcat的Start可以启动起来,但是Debug启动突然启动不起来,一直停在 Class<T>.getDeclaredConstructors0(boolean) line: not available [native method] 的解决办法
    windows下读取Linux分区软件
    15 条实用 Linux/Unix 磁带管理命令
    Nginx安装与配置文件解析
    专注docker安全:Security Scanning
    清除linux系统的多余引导
  • 原文地址:https://www.cnblogs.com/xinzhuangzi/p/4100407.html
Copyright © 2011-2022 走看看