第三方接口如何封装XML请求 以及解析接口返回的XML 您所在的位置:网站首页 解析接口是什么 第三方接口如何封装XML请求 以及解析接口返回的XML

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

2023-12-12 11:06| 来源: 网络整理| 查看: 265

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:

/* * * * * 1.02 * A23G8Q8ZIKBK8C * * ProcessingReport * * 1 * * 57320017876 * Complete * * 15 * 13 * 2 * 0 * * * 3 * Error * 25 * We are unable to process the XML feed because one or more items are invalid. Please re-submit the feed. * * * 4 * Error * 25 * We are unable to process the XML feed because one or more items are invalid. Please re-submit the feed. * * * * */

        如果看到这种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 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 results = processingReport.elements("Result"); List mapResultList=new ArrayList(); for (Element element : results) { Map map =new HashMap(); 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 convertXmlToJavaBean(String xml, Class 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 ""; } } }

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有