作者 朱兆平

新舱单辅助管理-ffm报文解析其他部分完成

... ... @@ -11,6 +11,7 @@ import java.util.regex.Pattern;
import com.tianbo.analysis.exception.FFMResolveException;
import com.tianbo.util.Date.DateUtil;
import javassist.compiler.ast.Keyword;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
... ... @@ -81,6 +82,30 @@ public class FFMInfo implements Serializable {
private static final String KEY_WORD_4 = "CONT,LAST";
private static final long serialVersionUID = 1L;
/**
* 报文解析一级缓存
* 记录上一行解析的是ULD还是运单信息行或者其他运单信息节点;
* 初始化解析缓存
*/
Map<String,String> temp = new HashMap<String,String>(){
{
put("keyword", "unknow");
put("ULD", "unknow");
put("AWB", "unknow");
//记录上一行是否是运单信息节点
put("ISAWB", "no");
}
};
//运单信息节点二级缓存
Map<String,String> tempAWB = new HashMap<String,String>(){
{
put("keyword", "unknow");
}
};
public FFMInfo(){
}
... ... @@ -213,6 +238,7 @@ public class FFMInfo implements Serializable {
currentLine++;
wayBillParseStartLine = currentLine;
}else if ("CONT".equals(keyword) || "LAST".equals(keyword) ){
islast = keyword;
keyword_i++;
}
... ... @@ -318,6 +344,29 @@ public class FFMInfo implements Serializable {
}
/**
* 多航班目的站解析
*/
private void multiDestinationParse(String line) throws FFMResolveException {
//校验正则1,取前三位验证是否是机场代码
String pattern_f = "^[A-Z]{3}$|^[A-Z]{3}/\\d{2}[A-Z]{3}\\d{4}";
// 创建 Pattern 对象
Pattern r_f = Pattern.compile(pattern_f);
// 现在创建 matcher 对象
Matcher mF = r_f.matcher(line);
if (mF.find()){
log.debug("5-[FLIGHT] 适配到航班其他目的站");
String flightDes = line.substring(0,3);
if (!KEY_WORD_3.contains(flightDes)){
destinationstation = flightDes;
log.info("5-[FLIGHT] 新航班目的站为[{}]",destinationstation);
}
}
if (StringUtils.isEmpty(destinationstation)){
throw new FFMResolveException("航班目的站节点校验不通过.");
}
}
/**
* 判断是否有散舱
* 有BUP散舱先处理散舱,没有则进入ULD及ULD货物解析阶段
* 假设默认航班有散舱,将散舱的ULD号默认为 "BUP"
... ... @@ -328,32 +377,46 @@ public class FFMInfo implements Serializable {
public List<FFMInfo> resolve_ULD_Waybill() throws FFMResolveException{
log.info("[BILL] 开始解析舱单列表");
String uld = "BUP";
List<FFMInfo> ffmInfoList = new ArrayList<>();
//默认非国际转运
if (this.wayBillParseStartLine ==0){
return ffmInfoList;
}
for (int i = this.wayBillParseStartLine; i < lineList.size(); i++) {
wayBillParseStartLine++;
String line = lineList.get(i);
log.debug("[BILL] 开始解析行[{}]-[{}]",i,line);
String customStatus = "-1";
//行尾部结束标识检查
String keyword = keyword(line);
if ("CONT".equals(keyword) || "LAST".equals(keyword)){
log.info("[END] 已解析到文件结束标识[{}],解析完毕",keyword);
islast = keyword;
break;
}
//判定前面阶段解析的是运单还是uld
String tempKey = temp.get("keyword");
log.info("[BILL] tempKey = {}",tempKey);
if ("AWB".equals(tempKey)){
log.info("[BILL] {},进入处理解析运单其他信息阶段.",line);
waybillOtherInfoParse(line,temp.get("AWB"));
}
multiDestinationParse(line);
if ("ULD".equals(keyword)){
uld = ULDParse(line);
temp.put("keyword","ULD");
temp.put("ULD",uld);
temp.put("ISAWB","no");
continue;
}
FFMInfo ffmInfoParsed = WayBillParse(line,uld);
if (ffmInfoParsed!=null){
temp.put("keyword","AWB");
temp.put("AWB",ffmInfoParsed.getWaybillnomaster());
temp.put("ISAWB","yes");
ffmInfoList.add(ffmInfoParsed);
}
... ... @@ -363,29 +426,7 @@ public class FFMInfo implements Serializable {
return ffmInfoList;
}
/**
* 多航班目的站解析
*/
private void multiDestinationParse(String line) throws FFMResolveException {
//校验正则1,取前三位验证是否是机场代码
String pattern_f = "^[A-Z]{3}$|^[A-Z]{3}/\\d{2}[A-Z]{3}\\d{4}";
// 创建 Pattern 对象
Pattern r_f = Pattern.compile(pattern_f);
// 现在创建 matcher 对象
Matcher mF = r_f.matcher(line);
if (mF.find()){
log.debug("5-[FLIGHT] 适配到航班其他目的站");
String flightDes = line.substring(0,3);
if (!KEY_WORD_3.contains(flightDes)){
destinationstation = flightDes;
log.info("5-[FLIGHT] 新航班目的站为[{}]",destinationstation);
}
}
if (StringUtils.isEmpty(destinationstation)){
throw new FFMResolveException("航班目的站节点校验不通过.");
}
}
/**
* 解析ULD板箱号部分
... ... @@ -453,8 +494,8 @@ public class FFMInfo implements Serializable {
log.error("{}运单模七校验不通过",waybillNo);
throw new FFMResolveException(waybillNo+"运单模七校验不通过");
}
log.debug("运单的下一行为{}",lineList.get(wayBillParseStartLine));
if ("CONT".equals(islast) || "LAST".equals(islast)){
log.info("[AWB-INFO] 运单信息:报文序号:{} 所属航班:{}/{} 航班起始站/目的站:{}/{} 所属板箱:{} 运单号:{} 起始站/目的站:{}/{} 分批标识:{} 分批件重:{}/{} 体积:{} 密度:{} 总件数:{} 货物描述:{}",
order,
flightno,
... ... @@ -472,6 +513,10 @@ public class FFMInfo implements Serializable {
waybillDensity,
waybillTotalPiece,
waybillGoodsDes);
}else {
throw new FFMResolveException("报文缺少LAST标识");
}
return new FFMInfo(
UUID.randomUUID().toString(),
... ... @@ -498,6 +543,232 @@ public class FFMInfo implements Serializable {
}
return null;
}
public void waybillOtherInfoParse(String line,String waybill) throws FFMResolveException {
String keywordPattern = "^OSI|^COR|^OCI|^DEG|^DIM|^/";
Pattern r = Pattern.compile(keywordPattern);
Matcher m = r.matcher(line);
//获取缓存
String lastIsAwb = temp.get("ISAWB");
//具备关键字
if (m.find()){
log.debug("[AWB-OTHER] {}-运单其他信息适配成功,为{}",waybill,line);
/**
* 特殊操作代码获取及校验
* 此行的开头是/符号并且此行的上一行为运单信息
* 如果运单没有特殊操作代码 这里要处理下
* 运单信息行的下一行 不是后续航程和特殊操作这种带/的节点,就是以关键字开头的节点.
*/
if (line.startsWith("/")){
if (waybillMoveInfo(line)){
temp.put("ISAWB","no");
return;
};
if(waybillTransportPriority(line)){
temp.put("ISAWB","no");
return;
}
if("yes".equals(lastIsAwb)){
waybillSPH(line);
}else {
// 以关键字开头的下一行是以/开头,从这里取关键字处理
// 第一次的时候keyword 适配不上 第二次时有标识了
String keyword = tempAWB.get("keyword");
log.debug("[AWB-OTHER] 二级缓存keyword = {}",keyword);
Matcher matcherKeyword = r.matcher(keyword);
//有keyword时 start以keyword为准,行开头标识
if(matcherKeyword.find()){
otherInfoParse(keyword+line);
}
}
}else {
otherInfoParse(line);
}
/**
* 进来这个方法的,处理完毕后行,都不再是运单行
* 解析完毕,缓存重置
*/
temp.put("ISAWB","no");
}
}
private void otherInfoParse(String line) throws FFMResolveException {
String start = line.substring(0,3);
//第一次时 其他信息开始标识
switch (start){
case "COR":
COR_Parse(line);
break;
case "OSI":
OSI_Parse(line);
//有换行节点的写入这个
tempAWB.put("keyword",start);
break;
case "OCI":
OCI_Parse(line);
tempAWB.put("keyword",start);
break;
case "DEG":
break;
case "DIM":
break;
default:
break;
}
}
/**
* 运单特殊操作代码
* @param line
*/
private boolean waybillSPH(String line) throws FFMResolveException {
String keyword = "^/([A-Z]{3})$|^(/[A-Z]{3})+";
// 创建 Pattern 对象
Pattern r = Pattern.compile(keyword);
// 现在创建 matcher 对象
Matcher m = r.matcher(line.trim());
if (m.find()){
String[] specialCodes = line.split("/");
for (int i = 1; i < specialCodes.length; i++) {
String specialCode = specialCodes[i];
if (specialCode.trim().length()==3){
log.debug("[AWB-OTHER-SPH] 运单特殊操作代码为{}",specialCode);
}else {
throw new FFMResolveException(specialCode+"特殊操作代码格式校验错误");
}
}
return true;
}else {
return false;
}
}
/**
* @param line 报文行
* 运单节点后续航程
* /TAOXH6142/17SEP
*/
private boolean waybillMoveInfo(String line) throws FFMResolveException {
String keyword = "^/(\\w{3})(\\w{2})(\\d{3})(\\w{0,2})/(\\d{2})(\\w{3})";
// 创建 Pattern 对象
Pattern r = Pattern.compile(keyword);
// 现在创建 matcher 对象
Matcher m = r.matcher(line);
if (m.find()){
String airport = m.group(1);
String carrier = m.group(2);
String flightno = carrier+m.group(3)+m.group(4);
String flightDate = m.group(5)+m.group(6);
log.debug("[AWB-OTHER-MOV] 运单后续航程信息为{}/{}/{}/{}",airport,carrier,flightno,flightDate);
return true;
}else {
return false;
}
}
/**
* 运输优先级
* @param line
*/
private boolean waybillTransportPriority(String line){
String keyword = "^/([A-Z])$";
// 创建 Pattern 对象
Pattern r = Pattern.compile(keyword);
// 现在创建 matcher 对象
Matcher m = r.matcher(line.trim());
if (m.find()){
String value = m.group(1);
log.debug("[AWB-OTHER-TP] 运单运输优先级为{}",value);
return true;
}else {
return false;
}
}
/**
* OSI Other Service Infomation 其他服务信息
* @param line 报文行
* @return
* @throws FFMResolveException
*/
public String OSI_Parse(String line) throws FFMResolveException {
String keyword = "^(OSI)?/(\\S+)";
// 创建 Pattern 对象
Pattern r = Pattern.compile(keyword);
// 现在创建 matcher 对象
Matcher m = r.matcher(line);
if (m.find()){
String value = line.split("/")[1];
log.debug("[AWB-OTHER-OSI] 运单OSI其他服务信息为{}",value);
return value;
}else {
throw new FFMResolveException("COR海关原产地格式校验错误");
}
}
/**
* @param line 报文行
* COR/海关原产地节点解析
* @return
*/
public String COR_Parse(String line) throws FFMResolveException {
String keyword = "^(COR)?/([A-Z]{0,2})";
// 创建 Pattern 对象
Pattern r = Pattern.compile(keyword);
// 现在创建 matcher 对象
Matcher m = r.matcher(line);
if (m.find()){
String value = m.group(2);
log.debug("[AWB-OTHER-COR] 运单COR海关原产地信息为{}",value);
return value;
}else {
throw new FFMResolveException("COR海关原产地格式校验错误");
}
}
/**
* Other Customs, Security and Regulatory Control Information
* 其他海关信息解析
* @param line
* @return
* @throws FFMResolveException
*/
public boolean OCI_Parse(String line) throws FFMResolveException{
String keyword = "^(OCI)?/(\\w{2})?/(\\w{3})?/(\\w{0,2})?/(\\S+)";
// 创建 Pattern 对象
Pattern r = Pattern.compile(keyword);
// 现在创建 matcher 对象
Matcher m = r.matcher(line);
if (m.find()){
String countryCode = line.split("/")[1];
//信息标识
String infoCode = line.split("/")[2];
//海关信息标识
String customsCode =line.split("/")[3];
//补充海关信息
String value = line.split("/")[4];
log.debug("[AWB-OTHER-OCI] 运单OCI海关其他信息,国家代码:{} , 信息标识:{}, 海关信息标识:{}, 补充海关信息:{} ",
countryCode,
infoCode,
customsCode,
value);
if (value.length()>35){
throw new FFMResolveException(value+"-OCI海关其他信息长度超过35,解析错误");
}
return true;
}else {
throw new FFMResolveException("OCI海关其他信息格式校验错误");
}
}
/**
* 关键字识别
* @param text 每行的内容
... ...
... ... @@ -46,10 +46,10 @@ public class FFMResolveImpl implements FFMResolve {
ffm.setCustomsstatus("002");
log.info("运单{}为国际转运货物",ffm.getWaybillnomaster());
}
// int result = ffmInfoDao.insertSelective(ffm);
// if (result <=0){
// log.error("{}入库失败",ffm.getWaybillnomaster());
// }
int result = ffmInfoDao.insertSelective(ffm);
if (result <=0){
log.error("{}入库失败",ffm.getWaybillnomaster());
}
//todo:重复报文入库逻辑将以删除旧报文插入新报文为准
}
return true;
... ...