解析xml文件四

第三方接口如何封装XML请求 以及解析接口返回的XML

1、封装XML报文对象

博主在调第三方接口时,经常需要封装XML去请求第三方的数据,在Web开发时,需要经常用到,因此也打算写篇文章记录下本人在思考和寻求答案的过程。

1.1  XML的一些基本常识

 一般在参考一些API的文档时,JAVA开发一般是根据特定的API要求去对数据进行封装,在此,我将采用举例的方式来说明,已经应用场景。在封装XML对象时,首先我们得了解封装XML对象试用方式,一般采取Class类注解的形式去实现。如@XmlType、@XmlAccessorType、@XmlRootElement、 @XmlElement等。

@XmlType(propOrder ={ "Header", "MessageType", "Message" }) // 指定序列成的xml节点顺序

@XmlAccessorType(value = XmlAccessType.FIELD) // 访问类型改为字段

@XmlRootElement(name = "AmazonEnvelope")//封装XML对象的根节点

1.2 封装XML针对某些特定API请求参数。这里以对接亚马逊的某些接口举例

以下为我举例加入某接口需要对参数封装XML:

/*
* 	<?xml version="1.0" encoding="UTF-8"?>
*	<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">
*		<Header>
*			<DocumentVersion>1.02</DocumentVersion>
*			<MerchantIdentifier>A23G8Q8ZIKBK8C</MerchantIdentifier>
*		</Header>
*		<MessageType>ProcessingReport</MessageType>
*		<Message>
*			<MessageID>1</MessageID>
*			<ProcessingReport>
*				<DocumentTransactionID>57320017876</DocumentTransactionID>
*				<StatusCode>Complete</StatusCode>
*				<ProcessingSummary>
*					<MessagesProcessed>15</MessagesProcessed>
*					<MessagesSuccessful>13</MessagesSuccessful>
*					<MessagesWithError>2</MessagesWithError>
*					<MessagesWithWarning>0</MessagesWithWarning>
*				</ProcessingSummary>
*				<Result>
*					<MessageID>3</MessageID>
*					<ResultCode>Error</ResultCode>
*					<ResultMessageCode>25</ResultMessageCode>
*					<ResultDescription>We are unable to process the XML feed because one or more items are invalid. Please re-submit the feed.</ResultDescription>
*				</Result>
*				<Result>
*					<MessageID>4</MessageID>
*					<ResultCode>Error</ResultCode>
*					<ResultMessageCode>25</ResultMessageCode>
*					<ResultDescription>We are unable to process the XML feed because one or more items are invalid. Please re-submit the feed.</ResultDescription>
*				</Result>
*			</ProcessingReport>
*		</Message>
*	</AmazonEnvelope>
*/

 如果看到这种XML格式,去封装请求对象如何封装呢?

        我们如果有了解过XML这种语言就知道,XML可以理解为一颗树,有父子根节点构成。其实Spring 内部去解析XML时,也是根据这种特性去解析的。因为我们最原始MVC 需要大量的配置XML 注入bean。以及配置事物等等。我们通过分析可以发现,外部根节点为AmazonEnvelope,子节点Header、MessageType、Message,然后Message节点下又有子节点MessageID、ProcessingReport。依次类推,可以构造AmazonEnvelope大对象,然后以此为根节点建造子节点对象,这里举例两个如下:

package com.aukey.supply.chain.domain.test;
 
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
 
@XmlType(propOrder =
{ "Header", "MessageType", "Message" }) // 指定序列成的xml节点顺序
@XmlAccessorType(value = XmlAccessType.FIELD) // 访问类型改为字段
@XmlRootElement(name = "AmazonEnvelope")
public class AmazonEnvelope {
	 @XmlElement
	 private Header Header;//构造头部
	 
	 @XmlElement
	 private String MessageType;
	 
	 
	 @XmlElement
	 private Message Message;
 
 
	public Header getHeader() {
		return Header;
	}
 
 
	public void setHeader(Header header) {
		Header = header;
	}
 
 
	public String getMessageType() {
		return MessageType;
	}
 
 
	public void setMessageType(String messageType) {
		MessageType = messageType;
	}
 
 
	public Message getMessage() {
		return Message;
	}
 
 
	public void setMessage(Message message) {
		Message = message;
	}
}
package com.aukey.supply.chain.domain.test;
 
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
 
@XmlType(propOrder =
{ "MessageID", "ProcessingReport"}) // 指定序列成的xml节点顺序
@XmlAccessorType(value = XmlAccessType.FIELD) // 访问类型改为字段
public class Message {
	
	@XmlElement
	private String MessageID;
	
	@XmlElement
	private ProcessingReport ProcessingReport;
 
	public String getMessageID() {
		return MessageID;
	}
 
	public void setMessageID(String messageID) {
		MessageID = messageID;
	}
 
	public ProcessingReport getProcessingReport() {
		return ProcessingReport;
	}
 
	public void setProcessingReport(ProcessingReport processingReport) {
		ProcessingReport = processingReport;
	}
	
}

对象封装完成之后,API一般需要请求参数,因此我们建完实体对象后,需要按照不同节点要求赋值,示例如下:

/**
	 * 构造XML对象 将节点数据组装成一个XML大对象
	 * @return
	 */
	public static AmazonEnvelope createXmlObject() 
	{
		AmazonEnvelope amazonEnvelope =new AmazonEnvelope();
		
		//子级节点1
		Header header =new Header();
		header.setDocumentVersion("1.02");
		header.setMerchantIdentifier("A23G8Q8ZIKBK8C");
		//赋值子级节点1
		amazonEnvelope.setHeader(header);
		
		//子级节点1
		String messageType="ProcessingReport";
		//赋值子级节点1
		amazonEnvelope.setMessageType(messageType);
		
		//子级节点1
		Message message =new Message();
		//赋值子级节点2
		message.setMessageID("1");
		
		//子级节点2
		ProcessingReport processingReport=new ProcessingReport();
		
		//赋值子级节点2
		processingReport.setDocumentTransactionID("57320017876");
		//赋值子级节点2
		processingReport.setStatusCode("Complete");
		
		//子级节点3
		ProcessingSummary processingSummary =new ProcessingSummary();
		//赋值子级节点3
		processingSummary.setMessagesProcessed("15");
		//赋值子级节点3
		processingSummary.setMessagesSuccessful("13");
		//赋值子级节点3
		processingSummary.setMessagesWithError("2");
		//赋值子级节点3
		processingSummary.setMessagesWithWarning("0");
		
		//子级节点3
		List<Result> results=new ArrayList<>();
		Result result =new Result();
		//赋值子级节点4
		result.setMessageID("3");
		//赋值子级节点4
		result.setResultCode("Error");
		//赋值子级节点4
		result.setResultDescription("25");
		//赋值子级节点4
		result.setResultMessageCode("We are unable to process the XML feed because one or more items are invalid. Please re-submit the feed.");
		
		//赋值子级节点3
		results.add(result);
		
		
		//赋值子级节点2
		processingReport.setResult(results);
		
		//赋值子级节点2
		processingReport.setProcessingSummary(processingSummary);
		
		//赋值子级节点2
		message.setProcessingReport(processingReport);
		
		//赋值子级节点1
		amazonEnvelope.setMessage(message);
		
		return amazonEnvelope;
	}

对象赋值完成后,需要把当前的XML对象封装整个XML,一般设置字符编码等。 并且组装成一个String 这里JAXBContext文本对象来完成:

/**
	 * 构造XML 报文对象
	 * @param amazonEnvelope
	 * @return
	 */
	public static String createXml(AmazonEnvelope amazonEnvelope) 
	{
		JAXBContext context;
		try {
			context = JAXBContext.newInstance(amazonEnvelope.getClass());
			Marshaller marshaller = context.createMarshaller();
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
			marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
			StringWriter writer = new StringWriter();
			marshaller.marshal(amazonEnvelope, writer);
			String xml = writer.toString();
			return xml;
		} catch (JAXBException e) {
			e.printStackTrace();
		}
		return "";
	}

封装XML完成之后,就可以调取第三方的API并DOM解析返回了,这里说明为了方便,将请求对象和解析对象置为同一个。下面看主类全套调用逻辑:

package com.aukey.supply.chain.web.test;
 
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
 
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
 
import com.alibaba.fastjson.JSON;
import com.aukey.supply.chain.domain.test.AmazonEnvelope;
import com.aukey.supply.chain.domain.test.Header;
import com.aukey.supply.chain.domain.test.Message;
import com.aukey.supply.chain.domain.test.ProcessingReport;
import com.aukey.supply.chain.domain.test.ProcessingSummary;
import com.aukey.supply.chain.domain.test.Result;
import com.aukey.supply.chain.utils.Md5Utils;
import com.aukey.supply.chain.utils.XMLPostUtils;
 
public class TestAnalyzeXml {
	public static void main(String[] args) 
	{
		//组装请求报文XML对象
		AmazonEnvelope amazonEnvelope =createXmlObject();
		
		//构造XML文本
		String xml= createXml(amazonEnvelope);
		
        try 
        {
        	//封装请求报文 然后发送HTTP请求 然后将返回XML字符串 进行解析对应XML格式的节点对象 然后获取对应的节点数据
        	String urlStr = "http://info.edaeu.com/Api/";
        	String token="";
        	String md5;
            try {
                md5 = Md5Utils.ChangeMd5(token.substring(0, 16) + xml + token.substring(16, 32));
            } catch (Exception e) {
                md5 = "";
            }
            String httpPost = XMLPostUtils.httpPost(xml, urlStr+"/"+md5);
            JAXBContext getcontext = JAXBContext.newInstance(amazonEnvelope.getClass());
            Unmarshaller unmarshaller = getcontext.createUnmarshaller();
            StringReader reader = new StringReader(httpPost);
			Object object=(AmazonEnvelope)unmarshaller.unmarshal(reader);
		} catch (JAXBException e1) {
			e1.printStackTrace();
		}
		
		try{
			Document document = DocumentHelper.parseText(xml);
			// 通过document对象获取根节点
		    Element root = document.getRootElement();
		    Element message = root.element("Message");
		    Element processingReport = message.element("ProcessingReport");
		    @SuppressWarnings("unchecked")
		    List<Element> results = processingReport.elements("Result");
		    List<Map<String, Object>> mapResultList=new ArrayList<Map<String,Object>>();
		    for (Element element : results) 
		    {
				Map<String, Object> map =new HashMap<String, Object>();
				map.put("MessageID",element.element("MessageID").getTextTrim());
				map.put("ResultCode", element.element("ResultCode").getTextTrim());
				map.put("ResultMessageCode",element.element("ResultMessageCode").getTextTrim());
				map.put("ResultDescription", element.element("ResultDescription").getTextTrim());
				mapResultList.add(map);
			}
		    System.out.println(JSON.toJSONString(mapResultList));
		    
		} catch (DocumentException e) {
			e.printStackTrace();
		}					
	}			
}

以上获取完数据,差不多解析调用就完成了。整个封装XML并调用API,以及返回解析API返回的XML就完成了!

福利(附带Http请求XML封装工具类以及MD5加密类):

package com.aukey.supply.chain.utils;
 
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.URL;
 
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
 
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
 
public class XMLPostUtils
{
 
    public static String httpPost(String xml, String urlStr)
    {
        try
        {
            URL url = new URL(urlStr);
            // 建立http连接
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            // 设置允许输出
            conn.setDoOutput(true);
 
            conn.setDoInput(true);
 
            // 设置不用缓存
            conn.setUseCaches(false);
            // 设置传递方式
            conn.setRequestMethod("POST");
            // 设置维持长连接
            conn.setRequestProperty("Connection", "Keep-Alive");
            // 设置文件字符集:
            conn.setRequestProperty("Charset", "UTF-8");
            // 转换为字节数组
            byte[] data = xml.getBytes();
            // 设置文件长度
            conn.setRequestProperty("Content-Length", String.valueOf(data.length));
            // 设置文件类型:
            conn.setRequestProperty("contentType", "text/xml");
            // 开始连接请求
            conn.connect();
            OutputStream out = conn.getOutputStream();
            // 写入请求的字符串
            out.write(data);
            out.flush();
            out.close();
 
            // 请求返回的状态
            if (conn.getResponseCode() == 200)
            {
                // 请求返回的数据
                InputStream in = conn.getInputStream();
                try
                {
                    ByteArrayOutputStream s = new ByteArrayOutputStream();
                    int length = 0;
                    byte[] buffer = new byte[1024 * 1024];
                    while ((length = in.read(buffer)) != -1)
                    {
                        s.write(buffer, 0, length);
                    }
                    return s.toString("UTF-8");
 
                }
                catch (Exception e1)
                {
                    e1.printStackTrace();
                }
                finally
                {
                    in.close();
                }
            }
            else
            {
            }
 
        }
        catch (Exception e)
        {
            e.printStackTrace();
 
        }
        return null;
    }
 
    public static <T> T convertXmlToJavaBean(String xml, Class<T> t) throws Exception
    {
        T obj;
        JAXBContext context = JAXBContext.newInstance(t);
        StringReader stringReader = new StringReader(xml);
        SAXParserFactory sax = SAXParserFactory.newInstance();
        sax.setNamespaceAware(false);// 设置忽略明明空间
        XMLReader xmlReader = sax.newSAXParser().getXMLReader();
        Source source = new SAXSource(xmlReader, new InputSource(stringReader));
        Unmarshaller unmarshaller = context.createUnmarshaller();
        obj = (T) unmarshaller.unmarshal(source);
        return obj;
    }
 
}
package com.aukey.task.centerwarehouse.utils;
 
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
 
public class Md5Utils
{
    public static String ChangeMd5(String password)
    {
 
        try
        {
            // 得到一个信息摘要器
            MessageDigest digest = MessageDigest.getInstance("md5");
            byte[] result = digest.digest(password.getBytes());
            StringBuffer buffer = new StringBuffer();
            // 把每一个byte 做一个与运算 0xff;
            for (byte b : result)
            {
                // 与运算
                int number = b & 0xff;// 加盐
                String str = Integer.toHexString(number);
                if (str.length() == 1)
                {
                    buffer.append("0");
                }
                buffer.append(str);
            }
 
            // 标准的md5加密后的结果
            return buffer.toString();
        }
        catch (NoSuchAlgorithmException e)
        {
            e.printStackTrace();
            return "";
        }
 
    }
}

参考:https://blog.csdn.net/qq_24818689/article/details/99677155

猜你喜欢

转载自blog.csdn.net/KAITUOZHEMJ/article/details/113358954
今日推荐