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;
}
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;
}
}