本编文章的基础数据在java高效组定长报文续篇2–准备一些基础数据
中,这里就不重复列举了。上篇文章的两个报文接口字段有几个特点:
- 大部分字段都是不含中文的字符串,
- 数字型的字符串只有数字和金额
- 有些字段的值的长度本身就是固定的
- 有些字段是选填的,但是无值时需要占位
报文字段分类
根据报文字段特点分类
类型 | 编号 | 填充方式 | 说明 |
---|---|---|---|
普通字符串 | S | 右补空格 | 不含中文的字符串 |
中文字符串 | C | 右补空格 | 可含中文的字符串,如名称,附言等 |
普通数字 | N | 左补零 | 一般是整数 |
浮点型 | M | 左补零 | 原始值带小数点,通常组报文时去掉小数点 |
固定长度字符串 | F | 无需填充 | 状态,类型等字段 |
做出字段分类的目的,一是减少判断字符串中是否含有中文的判断。二是减少填充字符的次数。只有C型的字符串,才需要处理中文问题,其他类型可直接使用字符数作为字节数。对于F型的字段可以不用计算长度,直接拼到报文中。
对于像“附言”这种长度比较长,又因为是选填字段,经常没有值。每次都拼一串很长的空格,会降低效率。在前面的章节中,对于这样的字段在系统运行时只拼一次,然后缓存一下,后面直接使用。不直接缓存的原因是字段的长度不固定。
示例
代码片段中的方法来自 《java高效组定长报文续篇(1)—组定长规则和中文的处理》 和 《java高效组定长报文》中
/**
* 填充一个不含中文的字段
* @param value 字段值
* @param stdLength 字段标准长度(最大长度)
* @return
* @throws UnsupportedEncodingException
*/
public static String fillENValue(String value, int stdLength) {
//要素值的字节数
int sLength = getEnStringLength(value);
if (sLength >= stdLength){
return value;
}
//不足的长度
int restLength = stdLength - sLength;
//paddingSpacesByCache参看上一篇文章《java高效组定长报文》
return FixedMsgUtil.paddingSpacesByCache(restLength, value);
}
public static int getEnStringLength(String s){
if(s == null){
return 0;
}
//字符数即字节数
return s.length();
}
/**
* 填充一个可能含中文的字段
* @param value 字段值
* @param stdLength 字段标准长度(最大长度)
* @param charset 约定字符集
* @return
* @throws UnsupportedEncodingException
*/
public static String fillCNValue(String value, int stdLength, String charset) throws UnsupportedEncodingException{
//要素值的字节数
int sLength = getCNStringLength(value, charset);
if (sLength >= stdLength){
return value;
}
//不足的长度
int restLength = stdLength - sLength;
//paddingSpacesByCache参看上一篇文章《java高效组定长报文》
return FixedMsgUtil.paddingSpacesByCache(restLength, value);
}
/**
* 按报文约定字符集获取字符串字节数(用于中文字符串)
*/
public static int getCNStringLength(String s, String charset) throws UnsupportedEncodingException{
if(s == null){
return 0;
}
//charset 报文约定字符集
return s.getBytes(charset).length;
}
/**
* 填充一个数字字符串(金额型的去掉小数点后再调用这个方法)
* @param value 字段值
* @param stdLength 字段标准长度(最大长度)
* @return
*/
public static String fillMValue(String value, int stdLength) {
//字段值的字节数
int sLength = getEnStringLength(value);
if (sLength >= stdLength){
return value;
}
//不足的长度
int restLength = stdLength - sLength;
//paddingSpacesByCache参看上一篇文章《java高效组定长报文》
return FixedMsgUtil.paddingZerosByCache(restLength, value);
}
组报文示例1:2020年1月1日往小明的账号A00000000001存款101元
//示例: 2020年1月1日往小明的账号A00000000001存款101元
StringBuilder message = new StringBuilder();
//普通字符串,调用fillENValue
message.append(fillENValue("2020010100000001", 20));
//固定长度字符串直接拼
message.append("T001");
message.append("01");
message.append(fillENValue("A00000000001", 32));
//可含中文的字符串,调用fillCNValue
message.append(fillCNValue("小明", 20, "GBK"));
//金额,调用fillMValue
message.append(fillMValue("10100", 15));
//可含中文的字符串,调用fillCNValue
message.append(fillCNValue("", 10, "GBK"));
组报文示例2:20年1月1日小红从账号B00000000002取款202元
// 20年1月1日小红从账号B00000000002取款202元
StringBuilder message = new StringBuilder();
//普通字符串,调用fillENValue
message.append(fillENValue("2020010100000002", 20));
//固定长度字符串直接拼
message.append("T001");
message.append("02");
message.append(fillENValue("A00000000001", 32));
//可含中文的字符串,调用fillCNValue
message.append(fillCNValue("小红", 20, "GBK"));
//金额,调用fillMValue
message.append(fillMValue("20200", 15));
//可含中文的字符串,调用fillCNValue
message.append(fillCNValue("", 10, "GBK"));
总结
报文代码示例中,对于不同类型的字段,调用不同的填充方法;大大减少对中文的处理,同时对于一些固定长度的值,也不需要去判断是否需要填充字符,减少了很多不必要的处理。