使用java解析Infor XA ERP SystemLink请求响应报文

    Infor XA ERP的SystemLink响应报文是一段比较复杂的xml,里面记录了操作是否成功的状态以及操作结果或者错误说明。

   对SystemLink解析,就是从响应的xml报文里面解析出操作结果状态,如果操作失败,则提取错误消息。因为Infor XA ERP的SystemLink请求分为事务请求、非事务请求,所以解析也有一点点不同,具体细节这里不再说明。直接上代码,看我是如何用java代码解析报文的

解析抽象类:

package cn.markwins.yinfor.utils.xml;

import java.util.List;

import org.xml.sax.helpers.DefaultHandler;

import cn.markwins.yinfor.utils.vo.systemlink.SystemLinkMessage;

public abstract class SystemLinkStockDefaultHandler extends DefaultHandler{
	/* 返回的消息  */
	protected SystemLinkMessage systemLinkMessage = null;
	protected List<String> systemLinkExceptionList = null;
	public SystemLinkMessage getSystemLinkMessage() {
		return systemLinkMessage;
	}
	
	protected String preTagName = null;
}


解析非事务类型的SystemLink 的xml报文:
package cn.markwins.yinfor.utils.xml;

import java.util.ArrayList;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

import cn.markwins.yinfor.utils.common.StringTools;
import cn.markwins.yinfor.utils.vo.systemlink.SystemLinkMessage;

/**
 * @Description 无事务控制单一的SystemLink响应报文xml解析器
 * @author 李yi辉
 * @date 2016年7月5日
 */
public class SystemLinkTransactionNHandler extends SystemLinkStockDefaultHandler {
	private boolean messageTypeError = false;
	private boolean responseTag = false;
	private boolean exceptionTag = false;
	private boolean messageTag = false;
	private int errMsgIndex = 0;
	
	@Override
	public void startDocument() throws SAXException {
		systemLinkMessage = new SystemLinkMessage();
		systemLinkExceptionList = new ArrayList<>();
		systemLinkMessage.setStatus(true);
	}
	
	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		if(qName.matches("[A-Za-z0-9]+Response$")){
			responseTag = true;
			if("LoginResponse".equals(qName)){
				if("false".equals(attributes.getValue("actionSucceeded"))){
					systemLinkMessage.setStatus(false);
				}
			}
			
		}else{
			switch (qName) {
			case "Exception":
				exceptionTag = true;
				errMsgIndex = 0;
				break;
			case "Response":
				if("true".equals(attributes.getValue("hasErrors"))){
					systemLinkMessage.setStatus(false);
				}
				break;
			case "Message":
				messageTag = true;
				if("error".equals(attributes.getValue("type"))){
					messageTypeError = true;
					++errMsgIndex;
				}
				break;
			default:
				break;
			}
		}
		
		this.preTagName = qName;
	}
	
	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		//异常信息节点
		if(messageTypeError && messageTag && exceptionTag && "Text".equals(this.preTagName)){
			String text = null;
			if(!responseTag){	//还没进入任何Response就出现异常信息,则表示SystemLink服务器异常,处理失败
				systemLinkMessage.setStatus(false);
			}
			if(!systemLinkMessage.getStatus()){
				text = new String(ch, start, length);
			}
			if(!StringTools.isNullOrWhiteSpace(text)){
//				if(systemLinkExceptionList.isEmpty()){	//只取最后一个error类型的消息响应
//					systemLinkExceptionList.add(text);
//				}else{
//					systemLinkExceptionList.set(0, text);
//				}
				if(errMsgIndex == 2 && systemLinkExceptionList.size() < 2){	//如果有2个或2个以上的错误,则第一个错误肯定是泛泛总结描述有错误
					systemLinkExceptionList.set(0, text);
				}else{					//其它情况,则是具体的错误信息
					systemLinkExceptionList.add(text);
				}
			}
		}
	}

	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		if(qName.matches("[A-Za-z0-9]+Response$")){
			responseTag = false;
		}else{
			switch (qName) {
			case "Message":
				messageTag = false;
				messageTypeError = false;
				break;
			case "Exception":
				exceptionTag = false;
				break;
			default:
				break;
			}
		}
		
		this.preTagName = null;
	}
	
	@Override
	public void endDocument() throws SAXException {
		if(!systemLinkMessage.getStatus()){
			systemLinkMessage.setSystemLinkExceptionList(systemLinkExceptionList);
		}
	}

}


解析事务类型的SystemLink响应的xml报文:

package cn.markwins.yinfor.utils.xml;

import java.util.ArrayList;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

import cn.markwins.yinfor.utils.common.StringTools;
import cn.markwins.yinfor.utils.vo.systemlink.SystemLinkMessage;

/**
 * @Description 事务控制的SystemLink响应报文xml解析器
 * @author 李yi辉
 * @date 2016年7月5日
 */
public class SystemLinkTransactionYHandler extends SystemLinkStockDefaultHandler {
	private boolean messageTypeError = false;
	private boolean responseTag = false;
	private boolean exceptionTag = false;
	private boolean messageTag = false;
	private int errMsgIndex = 0;
	private String responseName = null;
	private Integer txReqIndex = null;
	
	@Override
	public void startDocument() throws SAXException {
		systemLinkMessage = new SystemLinkMessage();
		systemLinkExceptionList = new ArrayList<>();
		systemLinkMessage.setStatus(true);
	}
	
	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		if(qName.matches("[A-Za-z0-9]+Response$")){
			responseTag = true;
			if("LoginResponse".equals(qName)){
				if("false".equals(attributes.getValue("actionSucceeded"))){
					systemLinkMessage.setStatus(false);
				}
			}else{
				responseName = attributes.getValue("name");
				if(!StringTools.isNullOrWhiteSpace(responseName)){
					int dashIndex = responseName.lastIndexOf('_');
					if(dashIndex > 1){
						txReqIndex = Integer.valueOf(responseName.substring(dashIndex + 1, responseName.length()));
					}
				}
			}
		}else{
			switch (qName) {
			case "Exception":
				exceptionTag = true;
				errMsgIndex = 0;
				break;
			case "Response":
				if("true".equals(attributes.getValue("hasErrors"))){
					systemLinkMessage.setStatus(false);
				}
				break;
			case "Message":
				messageTag = true;
				if("error".equals(attributes.getValue("type"))){
					messageTypeError = true;
					++errMsgIndex;
				}
				break;
			default:
				break;
			}
		}
		
		this.preTagName = qName;
	}
	
	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		//异常信息节点
		if(messageTypeError && messageTag && exceptionTag && "Text".equals(this.preTagName)){
			String text = null;
			//还没进入任何Response就出现异常信息,则表示SystemLink服务器异常,处理失败
			if(!responseTag){
				systemLinkMessage.setStatus(false);
			}
			//systemLink响应错误消息
			if(!systemLinkMessage.getStatus()){
				text = new String(ch, start, length);
			}
			if(!StringTools.isNullOrWhiteSpace(text)){
				if(errMsgIndex == 2 && systemLinkExceptionList.size() < 2){	//如果有2个或2个以上的错误,则第一个错误肯定是泛泛总结描述有错误
					systemLinkExceptionList.set(0, text);
				}else{					//其它情况,则是具体的错误信息
					if(txReqIndex != null && txReqIndex > 0){
						text = txReqIndex + ":" + text;
					}
					systemLinkExceptionList.add(text);
				}
			}
		}
	}

	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		if(qName.matches("[A-Za-z0-9]+Response$")){
			responseTag = false;
			responseName = null;
			txReqIndex = null;
		}else{
			switch (qName) {
			case "Message":
				messageTag = false;
				messageTypeError = false;
				break;
			case "Exception":
				exceptionTag = false;
				break;
			default:
				break;
			}
		}
		
		this.preTagName = null;
	}
	
	@Override
	public void endDocument() throws SAXException {
		if(!systemLinkMessage.getStatus()){
			systemLinkMessage.setSystemLinkExceptionList(systemLinkExceptionList);
		}
	}

}

消息处理:

package cn.markwins.yinfor.utils.xml;

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

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.log4j.Logger;

import cn.markwins.yinfor.utils.common.StreamTools;
import cn.markwins.yinfor.utils.common.StringTools;
import cn.markwins.yinfor.utils.vo.systemlink.SystemLinkMessage;

/**
 * @Description SystemLink响应消息解析器
 * @author 李yi辉
 * @date 2016年7月6日
 */
public class SystemLinkRespMessageTools {
	
	private static Logger logger = Logger.getLogger(SystemLinkRespMessageTools.class);
	
	/**
	 * @Description 解析systemLink消息响应
	 * @param systemLinkRespXML systemLink的xml响应消息
	 * @param transactionFlag 解析方式
	 * 							true:事务类型systemLink xml响应
	 * 							false:非事务类型systemLink xml响应
	 * @return SystemLinkMessage 解析后的消息封装
	 */
	public static SystemLinkMessage parseStockSystemLinkRespXML(String systemLinkRespXML, boolean transactionFlag) {
		SystemLinkMessage systemLinkMessage = new SystemLinkMessage();
		systemLinkMessage.setStatus(false);
		List<String> systemLinkExceptionList = new ArrayList<>();
		
		//长时间无响应
		if(StringTools.isNullOrWhiteSpace(systemLinkRespXML)){
			systemLinkExceptionList.add("XA系统长时间无响应,请于Infor XA系统检查是否已过账,并反馈系统管理员");
			systemLinkMessage.setSystemLinkExceptionList(systemLinkExceptionList);
			logger.error("Infor XA SystemLink 长时间无响应,无响应报文");
			return systemLinkMessage;
		}
		
		//响应报文非标准化的xml,sax无法解析,特殊处理
		/*1、com.pjx.xsaa.entry.ServerNotFoundException*/
		if(systemLinkRespXML.contains("com.pjx.xsaa.entry.ServerNotFoundException")){
			systemLinkExceptionList.add("过账失败,Infor XA SystemLink Server未开启,请反馈系统管理员");
			systemLinkMessage.setSystemLinkExceptionList(systemLinkExceptionList);
			return systemLinkMessage;
		}
		
		//解析报文
		try {
			SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
			SAXParser saxParser = saxParserFactory.newSAXParser();
			SystemLinkStockDefaultHandler handler = null;
			
			if(transactionFlag){
				handler = new SystemLinkTransactionYHandler();	//开启systemLink事务的解析器
			}else{
				handler = new SystemLinkTransactionNHandler();	//没启SystemLink事务的解析器
			}
			
			saxParser.parse(StreamTools.getInputStreamFromString(systemLinkRespXML), handler);
			SystemLinkMessage systemLinkMessageParsed = handler.getSystemLinkMessage();
			if(systemLinkMessageParsed == null || systemLinkMessageParsed.getStatus() == null){
				systemLinkExceptionList.add("系统异常,请于XA ERP检查是否已过账,并反馈系统管理员");
				systemLinkMessage.setSystemLinkExceptionList(systemLinkExceptionList);
				logger.error("SystemLink消息解析异常,无法提取解析状态");
				return systemLinkMessage;
			}
			
			systemLinkMessage.setStatus(systemLinkMessageParsed.getStatus());
			systemLinkMessage.setSystemLinkExceptionList(systemLinkMessageParsed.getSystemLinkExceptionList());
		} catch (Exception e) {
			systemLinkMessage.setStatus(false);
			systemLinkExceptionList.add("系统异常,请于XA ERP检查是否已过账,并反馈系统管理员");
			systemLinkMessage.setSystemLinkExceptionList(systemLinkExceptionList);
			logger.error("系统异常,请于Infor XA系统检查是否已过账,并反馈系统管理员--SystemLink消息解析异常", e);
		} 
		
		return systemLinkMessage;
	}
}


通用的发送、解析工具

package cn.markwins.yinfor.utils.net;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.log4j.Logger;
import org.junit.Test;

import cn.markwins.yinfor.cas.domain.User;
import cn.markwins.yinfor.global.GlobalParameters;
import cn.markwins.yinfor.sys.domain.SystemLinkFileBean;
import cn.markwins.yinfor.utils.common.ConfigFileTools;
import cn.markwins.yinfor.utils.common.FileTools;
import cn.markwins.yinfor.utils.common.ReflectTools;
import cn.markwins.yinfor.utils.common.StringTools;
import cn.markwins.yinfor.utils.vo.response.CommonMessage;
import cn.markwins.yinfor.utils.vo.response.CommonMessageType;
import cn.markwins.yinfor.utils.vo.systemlink.SystemLinkMessage;
import cn.markwins.yinfor.utils.xml.SystemLinkRespMessageTools;

/**
 * @Description 发送SystemLink请求
 * @author 李yi辉
 * @date 2016年6月24日
 */
public class SystemLinkTools {

	private static Logger logger = Logger.getLogger(SystemLinkTools.class);
	
	/**
	 * @Description 单一systemLink请求
	 * @param user 登陆用户
	 * @param bean 业务bean
	 * @param systemLinkXMLFilePath systemLink请求的xml文件路径
	 * @return CommonMessage<String> 请求响应
	 */
	public static CommonMessage<String> postSystemLinkNoTransactionRequest(User user, Object bean, String systemLinkXMLFilePath){
		CommonMessage<String> commonMsg = new CommonMessage<>();
		commonMsg.setStatus(false);
		commonMsg.setType(CommonMessageType.E);
		
		//1、判断文件、业务bean是否有数据
		if(user == null || StringTools.isNullOrWhiteSpace(systemLinkXMLFilePath)){
			commonMsg.setErrCode("SYS50901");
			commonMsg.setMessage("空的xml文件或用户登录信息" + systemLinkXMLFilePath + " " + (bean != null ? bean.getClass().getSimpleName() : ""));
			return commonMsg;
		}
		boolean loginRequest = false;
		if("/SystemLink_Login.xml".equals(systemLinkXMLFilePath)){
			loginRequest = true;
		}else{
			if(bean == null){
				commonMsg.setErrCode("SYS50901");
				commonMsg.setMessage("业务bean信息为空" + systemLinkXMLFilePath);
				return commonMsg;
			}
		}
		
		//2、读取systemLink xml文件
		String systemLinkXMLFile = FileTools.readFileContent(systemLinkXMLFilePath);
		if(StringTools.isNullOrWhiteSpace(systemLinkXMLFile)){
			commonMsg.setErrCode("SYS50901");
			commonMsg.setMessage("读取" + systemLinkXMLFilePath +"文件内容失败");
			return commonMsg;
		}
		
		//3、将登陆用户及业务bean信息设置到xml里面对应的占位符
		String xmlAfterReg = mulSetter(systemLinkXMLFile, user, bean, loginRequest);
		if(StringTools.isNullOrWhiteSpace(xmlAfterReg) || hasSystemLinkBeanReg(xmlAfterReg)){
			commonMsg.setErrCode("SYS50901");
			commonMsg.setMessage("提取文件属性失败:" + systemLinkXMLFilePath + ":" + (bean != null ? bean.getClass().getSimpleName() : "NULL"));
			return commonMsg;
		}
		
		//4、向XA SystemLink server 发送 Http Post请求
		String currentTimeID = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
		logger.info(currentTimeID + "----------SystemLink request报文:\n" + xmlAfterReg);
		String systemLinkServerURL = ConfigFileTools.getCfgValue(GlobalParameters.SYSTEMLINK_FILE, GlobalParameters.SYSTEMLINK_URL);
		if(StringTools.isNullOrWhiteSpace(systemLinkServerURL)){
			systemLinkServerURL = "http://192.168.0.10:36001/SystemLink/servlet/SystemLinkServlet";
		}
		Map<Boolean, String> postStatusMap = HttpTools.postXMLRequest(systemLinkServerURL, xmlAfterReg);
		if(postStatusMap == null || postStatusMap.isEmpty()){
			commonMsg.setErrCode("SYS50902");
			commonMsg.setMessage("SLI Server地址错误或xml空报文");
			return commonMsg;
		}
		if(!postStatusMap.containsKey(true)){	//响应失败http code
			commonMsg.setErrCode("SYS50902");
			commonMsg.setMessage(postStatusMap.get(false));
			return commonMsg;
		}
		String systemLinkRespXML = postStatusMap.get(true);
		logger.info(currentTimeID + "----------SystemLink response报文:\n" + systemLinkRespXML);
		
		//5、解析systemLink响应
		SystemLinkMessage systemLinkMessage = SystemLinkRespMessageTools.parseStockSystemLinkRespXML(systemLinkRespXML, false);
		if(systemLinkMessage == null){
			commonMsg.setErrCode("SYS50903");
			commonMsg.setMessage("提取SystemLink响应状态异常,请通知系统管理员");
			return commonMsg;
		}
		if(!systemLinkMessage.getStatus()){	//SystemLink结果请求响应,失败原因
			commonMsg.setErrCode("SYS50999");
			List<String> systemLinkExceptionList = systemLinkMessage.getSystemLinkExceptionList();
			if(systemLinkExceptionList != null && !systemLinkExceptionList.isEmpty()){
				StringBuffer systemLinkErrMsgBuf = new StringBuffer();
				for(String systemLinkErrMsg : systemLinkExceptionList){
					if(!StringTools.isNullOrWhiteSpace(systemLinkErrMsg)){
						systemLinkErrMsgBuf.append("\n<br>" + systemLinkErrMsg);
					}
				}
				commonMsg.setMessage(systemLinkErrMsgBuf.toString());
			}
		}
		
		//6、没有异常,设置systemLink请求响应的成功码
		if(StringTools.isNullOrWhiteSpace(commonMsg.getErrCode())){
			commonMsg.setStatus(true);
			commonMsg.setType(CommonMessageType.I);
		}
		
		return commonMsg;
	}
	
	/**
	 * @Description 将用户登录信息及业务bean信息设置到对应的xml占位符里面
	 * @param systemLinkXMLFile 请求的systemLink xml文件
	 * @param user 登录用户信息
	 * @param bean 业务bean
	 * @param loginRequest 是否登录请求,当是登录请求,可以不用考虑业务bean
	 * @return String 替换后的xml
	 */
	private static String mulSetter(String systemLinkXMLFile, User user, Object bean, boolean loginRequest){
		boolean beanOK = true;
		if(!loginRequest && bean == null){	//登录请求可以不设置bean,其他情况的SystemLink请求必须设置对应的bean
			beanOK = false;
		} 
		if(beanOK && user != null && !StringTools.isNullOrWhiteSpace(systemLinkXMLFile)){
			//1、业务数据设置
			User cloneUser = null;
			Object cloneBean = null;
			try {
				cloneUser =  (User) BeanUtils.cloneBean(user);
				if(!("1".equals(cloneUser.getLoginType()))){	//非XA登录,取默认用户名及密码
					String systemUser = ConfigFileTools.getCfgValue(GlobalParameters.SYSTEMLINK_FILE, GlobalParameters.SYSTEMLINK_USER);
					String systemPassword = ConfigFileTools.getCfgValue(GlobalParameters.SYSTEMLINK_FILE, GlobalParameters.SYSTEMLINK_PASSWORD);
					if(!StringTools.isNullOrWhiteSpace(systemUser) && !StringTools.isNullOrWhiteSpace(systemPassword)){
						cloneUser.setUsridk(systemUser);
						cloneUser.setLoginPassword(systemPassword);
					}
				}
				if(bean != null){
					cloneBean = BeanUtils.cloneBean(bean);
				}
			} catch (Exception e) {
				logger.error("SystemLink单一请求方式,拷贝对象失败", e);
				return systemLinkXMLFile;
			} 
			//2、替换所有 &%filed%& 的占位符
			StringBuffer systemLinkXMLFileBuf = new StringBuffer();
			Pattern p = Pattern.compile("&%[a-zA-z0-9\\.]+%&");
			Matcher m = p.matcher(systemLinkXMLFile);
			while(m.find()){
				String regVariable = m.group();
				String filed = regVariable.substring(2,regVariable.length() - 2);
				if(filed.startsWith("user.")){	//登录用户的值
					filed = filed.split("\\.")[1];
					m.appendReplacement(systemLinkXMLFileBuf, ReflectTools.invokeGetter(cloneUser, filed).toString());
				}else{ //业务bean的值
					Object relatedObj = cloneBean;
					String relatedFiled = filed;
					//先查看是否related关联对象属性, ex:relatedCustomerOrderExtension.fdcust
					Pattern rp = Pattern.compile("^related[a-zA-Z0-9]+(\\.[a-zA-Z0-9]+){1,}");
					Matcher rm = rp.matcher(filed);
					if(rm.matches()){
						String[] splitRelated = filed.substring(7).split("\\.");
						int length = splitRelated.length;
						int index = 0;
						for(String s : splitRelated){
							++index;
							if(index < length){	//非最后1个,找关联对象
								relatedObj = ReflectTools.invokeGetter(relatedObj, StringTools.firstLetterToLow(s));
							}else{	//最后1个了,找属性
								relatedFiled = s.trim();
							}
						}
					}
					//然后找最后对象->属性的值
					Object filedObject = null;
					String filedObjectValue = "";
					if(relatedObj != null && relatedFiled != null){
						filedObject = ReflectTools.invokeRelatedGetter(relatedObj, relatedFiled);
						if(filedObject != null){
							if(filedObject instanceof java.util.Date){	/* 日期转换为yyyyMMdd格式 */
								SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd");
								filedObjectValue = sf.format(filedObject);
							}else if(filedObject instanceof java.lang.Boolean){
								if((boolean) filedObject){	/* true->1、false->0 */
									filedObjectValue = "1";
								}else{
									filedObjectValue = "0";
								}
							}else{
								filedObjectValue = filedObject.toString();
							}
						}
					}
					
					//通配占位符值设置
					m.appendReplacement(systemLinkXMLFileBuf, filedObjectValue);
				}
			}
			m.appendTail(systemLinkXMLFileBuf);
			
			//4、返回替换值后的systemLink请求的xml报文
			return systemLinkXMLFileBuf.toString();
		}
		
		return systemLinkXMLFile;
	}
	
	/**
	 * @Description 一次发送多个systemLink请求,且启动事务管理 
	 *	发送systemLink请求分6个步骤
	 *		1、先准备SystemLink xml模板即xml通配符对应的占位符业务bean
	 *		2、然后读取 SystemLink xml文件内容
	 *		3、bean属性值替换占位符
	 *		4、最后读取 </Request> xml结束标签 及登出内容,结果添加到前面所有的请求xml后面
	 *		5、发送SystemLink请求,请求内容即为上述的整个xml
	 *      6、处理响应
	 * @param systemLinkXMLFileList SystemLink xml文件列表及各文件对应的bean
	 * @return CommonMessage<String> 响应结果
	 */
	public static CommonMessage<String> postSystemLinkTransactionRequest(ArrayList<SystemLinkFileBean> systemLinkXMLFileList){
		CommonMessage<String> commonMsg = new CommonMessage<>();
		commonMsg.setStatus(false);
		commonMsg.setType(CommonMessageType.E);
		
		//1、读取systemlLink xml请求模板文件,并根据map的bean属性替换对应的占位符的值
		if(systemLinkXMLFileList == null || systemLinkXMLFileList.isEmpty()){	//至少有1个登录的systemLink xml
			commonMsg.setErrCode("SYS50901");
			commonMsg.setMessage("没有指定任何xml请求文件列表");
			return commonMsg;
		}
		StringBuffer xmlFileBuf = new StringBuffer();
		boolean logoutXMLExists = false;
		for(SystemLinkFileBean systemLinkFileBean : systemLinkXMLFileList){
			if(systemLinkFileBean == null || !systemLinkFileBean.isActi()){
				commonMsg.setErrCode("SYS50901");
				commonMsg.setMessage("空的xml文件或业务数据" + (systemLinkFileBean != null ? systemLinkFileBean.getXmlFilePath() : ""));
				return commonMsg;
			}
			//1.1、读取xml文件的内容
			String systemLinkXMLFilePath = systemLinkFileBean.getXmlFilePath();
			String curSystemLinkXMLFile = FileTools.readFileContent(systemLinkXMLFilePath);
			if(StringTools.isNullOrWhiteSpace(curSystemLinkXMLFile)){
				commonMsg.setErrCode("SYS50901");
				commonMsg.setMessage("读取" + systemLinkXMLFilePath +"文件内容失败");
				return commonMsg;
			}
			if(GlobalParameters.SYSTEMLINK_LOGOUT.equals(systemLinkXMLFilePath)){
				logoutXMLExists = true;
			}
			//1.2、提取bean属性,设置到xml文件对应通配占位符的值
			Object bean = systemLinkFileBean.getBean();
			int txReqIndex = systemLinkFileBean.getTxReqIndex();
			String xmlAfterReg = singleSetter(curSystemLinkXMLFile, bean, txReqIndex) + "\n";
			if(StringTools.isNullOrWhiteSpace(xmlAfterReg) || hasSystemLinkBeanReg(xmlAfterReg)){
				commonMsg.setErrCode("SYS50901");
				commonMsg.setMessage("提取文件属性失败:" + systemLinkXMLFilePath + ":" + (bean != null ? bean.getClass().getSimpleName() : "NULL"));
				return commonMsg;
			}
			xmlFileBuf.append(xmlAfterReg);
		}
		//1.3、自动加SystemLink_Logout.xml登出及xml关闭</标签...
		if(!logoutXMLExists){
			String logoutSystemLinkXMLFile = FileTools.readFileContent(GlobalParameters.SYSTEMLINK_LOGOUT);
			if(StringTools.isNullOrWhiteSpace(logoutSystemLinkXMLFile)){
				commonMsg.setErrCode("SYS50901");
				commonMsg.setMessage("读取" + logoutSystemLinkXMLFile +"文件内容失败");
				return commonMsg;
			}else{
				xmlFileBuf.append(logoutSystemLinkXMLFile); 
			}
		}
		String currentTimeID = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
		logger.info(currentTimeID + "----------SystemLink request报文:\n" + xmlFileBuf);
		
		//2、向XA SystemLink server 发送 Http Post请求
		String systemLinkServerURL = ConfigFileTools.getCfgValue(GlobalParameters.SYSTEMLINK_FILE, GlobalParameters.SYSTEMLINK_URL);
		if(StringTools.isNullOrWhiteSpace(systemLinkServerURL)){
			systemLinkServerURL = "http://192.168.0.10:36001/SystemLink/servlet/SystemLinkServlet";
		}
		Map<Boolean, String> postStatusMap = HttpTools.postXMLRequest(systemLinkServerURL, xmlFileBuf.toString());
		if(postStatusMap == null || postStatusMap.isEmpty()){
			commonMsg.setErrCode("SYS50902");
			commonMsg.setMessage("SLI Server地址错误或xml空报文");
			return commonMsg;
		}
		if(!postStatusMap.containsKey(true)){	//响应失败http code
			commonMsg.setErrCode("SYS50902");
			commonMsg.setMessage(postStatusMap.get(false));
			return commonMsg;
		}
		String systemLinkRespXML = postStatusMap.get(true);
		logger.info(currentTimeID + "----------SystemLink response报文:\n" + systemLinkRespXML);
		
		//3、解析响应结果
		SystemLinkMessage systemLinkMessage = SystemLinkRespMessageTools.parseStockSystemLinkRespXML(systemLinkRespXML, true);
		if(systemLinkMessage == null){
			commonMsg.setErrCode("SYS50903");
			commonMsg.setMessage("提取SystemLink响应状态异常,请通知系统管理员");
			return commonMsg;
		}
		if(!systemLinkMessage.getStatus()){	//SystemLink结果请求响应,失败原因
			commonMsg.setErrCode("SYS50999");
			List<String> systemLinkExceptionList = systemLinkMessage.getSystemLinkExceptionList();
			if(systemLinkExceptionList != null && !systemLinkExceptionList.isEmpty()){
				StringBuffer systemLinkErrMsgBuf = new StringBuffer();
				for(String systemLinkErrMsg : systemLinkExceptionList){
					if(!StringTools.isNullOrWhiteSpace(systemLinkErrMsg)){
						systemLinkErrMsgBuf.append("\n<br>" + systemLinkErrMsg);
					}
				}
				commonMsg.setMessage(systemLinkErrMsgBuf.toString());
			}
		}
		
		//4、没有异常,设置systemLink请求响应的成功码
		if(StringTools.isNullOrWhiteSpace(commonMsg.getErrCode())){
			commonMsg.setStatus(true);
			commonMsg.setType(CommonMessageType.I);
		}
		
		return commonMsg;
	}
	
	/**
	 * @Description 将systemLink xml里面所有通配符 &%属性%& 用对应属性值替代
	 * @param systemLinkXMLFile
	 * @param bean 从此bean中找对应属性的值
	 * @return String 处理后的systemLink xml
	 */
	private static String singleSetter(String systemLinkXMLFile, Object bean, int txReqIndex){
		if(bean != null){
			//1、bean copy->realBean,引用不影响原来的对象值
			Object cloneBean = null;
			try {
				cloneBean = BeanUtils.cloneBean(bean);
			} catch (Exception e) {
				logger.error("拷贝对象失败:" + bean.getClass().getName(), e);
				return systemLinkXMLFile;
			} 
			
			//2、用户登录方式处理
			if(cloneBean != null && cloneBean instanceof User){
				User user = (User) cloneBean;
				if(!("1".equals(user.getLoginType()))){	//非XA登录方式,取默认用户名及密码
					String systemUser = ConfigFileTools.getCfgValue(GlobalParameters.SYSTEMLINK_FILE, GlobalParameters.SYSTEMLINK_USER);
					String systemPassword = ConfigFileTools.getCfgValue(GlobalParameters.SYSTEMLINK_FILE, GlobalParameters.SYSTEMLINK_PASSWORD);
					if(!StringTools.isNullOrWhiteSpace(systemUser) && !StringTools.isNullOrWhiteSpace(systemPassword)){
						user.setUsridk(systemUser);
						user.setLoginPassword(systemPassword);
					}
				}
			}
			
			//3、通过反射将bean属性值替换成占位符
			if(cloneBean != null){
				//3-1、正则通配占位符
				StringBuffer systemLinkXMLFileBuf = new StringBuffer();
				Pattern p = Pattern.compile("&%[a-zA-z0-9\\.]+%&");
				Matcher m = p.matcher(systemLinkXMLFile);
				//3-2、替换所有 &%filed%& 的占位符
				while(m.find()){
					String regVariable = m.group();
					String filed = regVariable.substring(2,regVariable.length() - 2);
					if(!StringTools.isNullOrWhiteSpace(filed)){
/*						
						if(filed.startsWith("_RequestName")){ //请求name,在一个systemLink里面不能重复,ex:Create name = 'createWarehouseLocation'
							String beanName = cloneBean.getClass().getSimpleName();
							String curMillisecond = new SimpleDateFormat("ssSSS").format(new Date()) + (int) (Math.random()*100);
							String requestName = systemLinkXMLFile.substring(0, m.start()-7).trim();
							String _RequestName = requestName + beanName + curMillisecond;
							System.out.println("xml_RequestName:" + _RequestName);
							m.appendReplacement(systemLinkXMLFileBuf, _RequestName);
*/
						if("txReqIndex".equals(filed)){ //请求name,在一个systemLink里面不能重复,ex:Create name = 'createWarehouseLocation'
							m.appendReplacement(systemLinkXMLFileBuf,"_" + txReqIndex);
						}else{	//找对应bean的属性
							Object relatedObj = cloneBean;
							String relatedFiled = filed;
							//先查看是否related关联对象属性, ex:relatedCustomerOrderExtension.fdcust
							Pattern rp = Pattern.compile("^related[a-zA-Z0-9]+(\\.[a-zA-Z0-9]+){1,}");
							Matcher rm = rp.matcher(filed);
							if(rm.matches()){
								String[] splitRelated = filed.substring(7).split("\\.");
								int length = splitRelated.length;
								int index = 0;
								for(String s : splitRelated){
									++index;
									if(index < length){	//非最后1个,找关联对象
										relatedObj = ReflectTools.invokeGetter(relatedObj, StringTools.firstLetterToLow(s));
									}else{	//最后1个了,找属性
										relatedFiled = s.trim();
									}
								}
							}
							//然后找最后对象->属性的值
							Object filedObject = null;
							String filedObjectValue = "";
							if(relatedObj != null && relatedFiled != null){
								filedObject = ReflectTools.invokeRelatedGetter(relatedObj, relatedFiled);
								if(filedObject != null){
									if(filedObject instanceof java.util.Date){	/* 日期转换为yyyyMMdd格式 */
										SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd");
										filedObjectValue = sf.format(filedObject);
									}else if(filedObject instanceof java.lang.Boolean){
										if((boolean) filedObject){	/* true->1、false->0 */
											filedObjectValue = "1";
										}else{
											filedObjectValue = "0";
										}
									}else{
										filedObjectValue = filedObject.toString();
									}
								}
							}
							
							//通配占位符值设置
							m.appendReplacement(systemLinkXMLFileBuf, filedObjectValue);
						}	
					}
				}
				m.appendTail(systemLinkXMLFileBuf);
				
				//3-3、返回替换通配占位符的结果
				return systemLinkXMLFileBuf.toString();
			}
			
		}
		
		return systemLinkXMLFile;
	}
	
	/**
	 * @Description 校验xml内容里面是否还有未处理完的占位通配符
	 * @param systemLinkXMLFile 待校验的xml内容
	 * @return boolean
	 */
	private static boolean hasSystemLinkBeanReg(String systemLinkXMLFile){
		if(!StringTools.isNullOrWhiteSpace(systemLinkXMLFile)){
			Pattern p = Pattern.compile("&%[a-zA-z0-9\\.]*%&");
			Matcher m = p.matcher(systemLinkXMLFile);
			if(m.find()){
				return true;
			}
		}
		return false;
	}
	
	/**
	 * @author terrylee
	 * @Description SystemLink唯一码产生机制,映射规则如下
	 * @return String SystemLink唯一码,10位数字
	 *	字符集	0	1	2	3	4	5	6	7	8	9	A	B	C	D	E	F	G	H	I	J	K	L	M	N	O	P	Q	R	S	T	U	V	W	X	Y	Z	{	}	[	]	(	)	\	/	&	^	~	:	#	$	!	|	+	-	?	.	,	@	`	_
	 *	年份 1位								   			2016	2017	2018	2019	2020	2021	2022	2023	2024	2025	2026	2027	2028	2029	2030	2031	2032	2033	2034	2035	2036	2037	2038	2039	2040	2041	2042	2043	2044	2045	2046	2047	2048	2049	2050	2051	2052	2053	2054	2055	2056	2057	2058	2059	2060	2061	2062	2063	2064	2065
	 *	月份 1位		1	2	3	4	5	6	7	8	9	10	11	12																																															
	 *	日期 1位		1	2	3	4	5	6	7	8	9	10	11	12	13	14	15	16	17	18	19	20	21	22	23	24	25	26	27	28	29	30	31																												
	 *	小时 1位	0	1	2	3	4	5	6	7	8	9	10	11	12	13	14	15	16	17	18	19	20	21	22	23																																				
	 *	分钟 1位	0	1	2	3	4	5	6	7	8	9	10	11	12	13	14	15	16	17	18	19	20	21	22	23	24	25	26	27	28	29	30	31	32	33	34	35	36	37	38	39	40	41	42	43	44	45	46	47	48	49	50	51	52	53	54	55	56	57	58	59
	 *	秒数 1位	0	1	2	3	4	5	6	7	8	9	10	11	12	13	14	15	16	17	18	19	20	21	22	23	24	25	26	27	28	29	30	31	32	33	34	35	36	37	38	39	40	41	42	43	44	45	46	47	48	49	50	51	52	53	54	55	56	57	58	59
	 *	毫秒 3位	0	1	2	3	4	5	6	7	8	9																																																		
	 *	校验位或随机数 1位	0	1	2	3	4	5	6	7	8	9																																																		
	 * @throws Exception 
	 */
	@SuppressWarnings("static-access")
	@Test
	public static String getSystemLinkSeq(){			   
		StringBuffer systemLinkSeqBuf = new StringBuffer();
												   //01234567890123456
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
 		String currentDate = sdf.format(new Date());
 		String currentYear = currentDate.substring(0, 4);
 		String currentMonth = currentDate.substring(4, 6);
 		String currentDay = currentDate.substring(6, 8);
 		String currentHour = currentDate.substring(8, 10);
 		String currentMinute = currentDate.substring(10, 12);
 		String currentSecond = currentDate.substring(12, 14);
 		String currentMillisecond = currentDate.substring(14);
		
 		//年 
 		int year = Integer.valueOf(currentYear);
 		if(year < 2016) year = 2016;
 		char yearMapping = 'A';  //2016对应A
 		if(year < 2042){	//2016-2041,按照ascii符规格自动计算
 	 		yearMapping = (char) (yearMapping + (year - 2016));
 		}else{	//2042后散列无规则的ascii符
 			yearMapping = asciiMapping(year);
 		}
 		systemLinkSeqBuf.append(yearMapping);
 		
 		//月、日、时、分、秒
 		systemLinkSeqBuf.append(seqMapping(currentMonth))
 			.append(seqMapping(currentDay))
 			.append(seqMapping(currentHour))
 			.append(seqMapping(currentMinute))
 			.append(seqMapping(currentSecond));
 		//毫秒
 		systemLinkSeqBuf.append(currentMillisecond);
 		//随机数
 		systemLinkSeqBuf.append((int)(Math.random()*10));
 		try {
			Thread.currentThread().sleep(1); //睡眠1毫秒,保证同一单据的各项程序批量产生时毫秒级别不重复
		} catch (InterruptedException e) {
			logger.error("生成SystemLink唯一Token码时,发生中断异常", e);
		}
 		return systemLinkSeqBuf.toString();
	}
	
	/**
	 * @Description 月、日、时、分、秒 映射
	 * @param num 月、日、时、分、秒
	 * @return char 根据规则,月、日、时、分、秒映射后的字符
	 */
	private static char seqMapping(String num){
		if(StringTools.isNullOrWhiteSpace(num) || num.trim().length() != 2){
			return '0';
		}
		//01、02....09时
		if(num.startsWith("0")){
			return num.charAt(1);
		}
		//10后
		char mapped = 'A';
		int dateNum = Integer.valueOf(num);
		if(dateNum < 36){	//10-35,按照ascii符规格自动计算
			mapped = (char) (mapped + (dateNum - 10));
		}else{	//36后散列无规则的ascii符
			mapped = asciiMapping(dateNum);
		}
		
		return mapped;
	}
	
	/**
	 * @Description 根据散列规则,将源数字匹配到指定的ascii符
	 * {	}	     [	    ]	    (	    )	    %	     /	    &	    ^	    <	    :	    #	    >	    !	    |	    +	    -	    ?	    .	    ,	    @	    `	    _
     * 2042	2043	2044	2045	2046	2047	2048	2049	2050	2051	2052	2053	2054	2055	2056	2057	2058	2059	2060	2061	2062	2063	2064	2065
     * 36	37	     38	    39	    40	    41	    42	    43	    44	    45	    46	    47	    48	    49	    50	    51	    52	    53	    54	    55	    56	    57	    58	    59
	 * @param num 来源数字
	 * @return char 映射后的ascii码符
	 */
	private static char asciiMapping(int num){
		char mapped = '{';
		if(num == 2043 || num == 37){
			mapped = '}';
		}else if(num == 2044 || num == 38){
			mapped = '[';
		}else if(num == 2045 || num == 39){
			mapped = ']';
		}else if(num == 2046 || num == 40){
			mapped = '(';
		}else if(num == 2047 || num == 41){
			mapped = ')';
		}else if(num == 2048 || num == 42){
			mapped = '%';
		}else if(num == 2049 || num == 43){
			mapped = '/';
		}else if(num == 2050 || num == 44){
			mapped = '&';
		}else if(num == 2051 || num == 45){
			mapped = '^';
		}else if(num == 2052 || num == 46){
			mapped = '<';
		}else if(num == 2053 || num == 47){
			mapped = ':';
		}else if(num == 2054 || num == 48){
			mapped = '#';
		}else if(num == 2055 || num == 49){
			mapped = '>';
		}else if(num == 2056 || num == 50){
			mapped = '!';
		}else if(num == 2057 || num == 51){
			mapped = '|';
		}else if(num == 2058 || num == 52){
			mapped = '+';
		}else if(num == 2059 || num == 53){
			mapped = '-';
		}else if(num == 2060 || num == 54){
			mapped = '?';
		}else if(num == 2061 || num == 55){
			mapped = '.';
		}else if(num == 2062 || num == 56){
			mapped = ',';
		}else if(num == 2063 || num == 57){
			mapped = '@';
		}else if(num == 2064 || num == 58){
			mapped = '`';
		}else if(num == 2065 || num == 59){
			mapped = '_';
		}
		return mapped;
	}
}




http://blog.csdn.net/yihuiworld


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值