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

置顶
2019年08月16日 15:00:47
童子泛舟
阅读数 28

标签:
XML解析WebService第三方API
更多

个人分类:
JavaWeb

版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明。

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. /*
  2. * <?xml version="1.0" encoding="UTF-8"?>
  3. * <AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">
  4. * <Header>
  5. * <DocumentVersion>1.02</DocumentVersion>
  6. * <MerchantIdentifier>A23G8Q8ZIKBK8C</MerchantIdentifier>
  7. * </Header>
  8. * <MessageType>ProcessingReport</MessageType>
  9. * <Message>
  10. * <MessageID>1</MessageID>
  11. * <ProcessingReport>
  12. * <DocumentTransactionID>57320017876</DocumentTransactionID>
  13. * <StatusCode>Complete</StatusCode>
  14. * <ProcessingSummary>
  15. * <MessagesProcessed>15</MessagesProcessed>
  16. * <MessagesSuccessful>13</MessagesSuccessful>
  17. * <MessagesWithError>2</MessagesWithError>
  18. * <MessagesWithWarning>0</MessagesWithWarning>
  19. * </ProcessingSummary>
  20. * <Result>
  21. * <MessageID>3</MessageID>
  22. * <ResultCode>Error</ResultCode>
  23. * <ResultMessageCode>25</ResultMessageCode>
  24. * <ResultDescription>We are unable to process the XML feed because one or more items are invalid. Please re-submit the feed.</ResultDescription>
  25. * </Result>
  26. * <Result>
  27. * <MessageID>4</MessageID>
  28. * <ResultCode>Error</ResultCode>
  29. * <ResultMessageCode>25</ResultMessageCode>
  30. * <ResultDescription>We are unable to process the XML feed because one or more items are invalid. Please re-submit the feed.</ResultDescription>
  31. * </Result>
  32. * </ProcessingReport>
  33. * </Message>
  34. * </AmazonEnvelope>
  35. */

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

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


  1. package com.aukey.supply.chain.domain.test;
  2. import javax.xml.bind.annotation.XmlAccessType;
  3. import javax.xml.bind.annotation.XmlAccessorType;
  4. import javax.xml.bind.annotation.XmlElement;
  5. import javax.xml.bind.annotation.XmlRootElement;
  6. import javax.xml.bind.annotation.XmlType;
  7. @XmlType(propOrder =
  8. { "Header", "MessageType", "Message" }) // 指定序列成的xml节点顺序
  9. @XmlAccessorType(value = XmlAccessType.FIELD) // 访问类型改为字段
  10. @XmlRootElement(name = "AmazonEnvelope")
  11. public class AmazonEnvelope {
  12. @XmlElement
  13. private Header Header;//构造头部
  14. @XmlElement
  15. private String MessageType;
  16. @XmlElement
  17. private Message Message;
  18. public Header getHeader() {
  19. return Header;
  20. }
  21. public void setHeader(Header header) {
  22. Header = header;
  23. }
  24. public String getMessageType() {
  25. return MessageType;
  26. }
  27. public void setMessageType(String messageType) {
  28. MessageType = messageType;
  29. }
  30. public Message getMessage() {
  31. return Message;
  32. }
  33. public void setMessage(Message message) {
  34. Message = message;
  35. }
  36. }

  1. package com.aukey.supply.chain.domain.test;
  2. import javax.xml.bind.annotation.XmlAccessType;
  3. import javax.xml.bind.annotation.XmlAccessorType;
  4. import javax.xml.bind.annotation.XmlElement;
  5. import javax.xml.bind.annotation.XmlType;
  6. @XmlType(propOrder =
  7. { "MessageID", "ProcessingReport"}) // 指定序列成的xml节点顺序
  8. @XmlAccessorType(value = XmlAccessType.FIELD) // 访问类型改为字段
  9. public class Message {
  10. @XmlElement
  11. private String MessageID;
  12. @XmlElement
  13. private ProcessingReport ProcessingReport;
  14. public String getMessageID() {
  15. return MessageID;
  16. }
  17. public void setMessageID(String messageID) {
  18. MessageID = messageID;
  19. }
  20. public ProcessingReport getProcessingReport() {
  21. return ProcessingReport;
  22. }
  23. public void setProcessingReport(ProcessingReport processingReport) {
  24. ProcessingReport = processingReport;
  25. }
  26. }

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


  1. /**
  2. * 构造XML对象 将节点数据组装成一个XML大对象
  3. * @return
  4. */
  5. public static AmazonEnvelope createXmlObject()
  6. {
  7. AmazonEnvelope amazonEnvelope =new AmazonEnvelope();
  8. //子级节点1
  9. Header header =new Header();
  10. header.setDocumentVersion("1.02");
  11. header.setMerchantIdentifier("A23G8Q8ZIKBK8C");
  12. //赋值子级节点1
  13. amazonEnvelope.setHeader(header);
  14. //子级节点1
  15. String messageType="ProcessingReport";
  16. //赋值子级节点1
  17. amazonEnvelope.setMessageType(messageType);
  18. //子级节点1
  19. Message message =new Message();
  20. //赋值子级节点2
  21. message.setMessageID("1");
  22. //子级节点2
  23. ProcessingReport processingReport=new ProcessingReport();
  24. //赋值子级节点2
  25. processingReport.setDocumentTransactionID("57320017876");
  26. //赋值子级节点2
  27. processingReport.setStatusCode("Complete");
  28. //子级节点3
  29. ProcessingSummary processingSummary =new ProcessingSummary();
  30. //赋值子级节点3
  31. processingSummary.setMessagesProcessed("15");
  32. //赋值子级节点3
  33. processingSummary.setMessagesSuccessful("13");
  34. //赋值子级节点3
  35. processingSummary.setMessagesWithError("2");
  36. //赋值子级节点3
  37. processingSummary.setMessagesWithWarning("0");
  38. //子级节点3
  39. List<Result> results=new ArrayList<>();
  40. Result result =new Result();
  41. //赋值子级节点4
  42. result.setMessageID("3");
  43. //赋值子级节点4
  44. result.setResultCode("Error");
  45. //赋值子级节点4
  46. result.setResultDescription("25");
  47. //赋值子级节点4
  48. result.setResultMessageCode("We are unable to process the XML feed because one or more items are invalid. Please re-submit the feed.");
  49. //赋值子级节点3
  50. results.add(result);
  51. //赋值子级节点2
  52. processingReport.setResult(results);
  53. //赋值子级节点2
  54. processingReport.setProcessingSummary(processingSummary);
  55. //赋值子级节点2
  56. message.setProcessingReport(processingReport);
  57. //赋值子级节点1
  58. amazonEnvelope.setMessage(message);
  59. return amazonEnvelope;
  60. }

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


  1. /**
  2. * 构造XML 报文对象
  3. * @param amazonEnvelope
  4. * @return
  5. */
  6. public static String createXml(AmazonEnvelope amazonEnvelope)
  7. {
  8. JAXBContext context;
  9. try {
  10. context = JAXBContext.newInstance(amazonEnvelope.getClass());
  11. Marshaller marshaller = context.createMarshaller();
  12. marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
  13. marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
  14. StringWriter writer = new StringWriter();
  15. marshaller.marshal(amazonEnvelope, writer);
  16. String xml = writer.toString();
  17. return xml;
  18. } catch (JAXBException e) {
  19. e.printStackTrace();
  20. }
  21. return "";
  22. }

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


  1. package com.aukey.supply.chain.web.test;
  2. import java.io.StringReader;
  3. import java.io.StringWriter;
  4. import java.util.ArrayList;
  5. import java.util.HashMap;
  6. import java.util.List;
  7. import java.util.Map;
  8. import javax.xml.bind.JAXBContext;
  9. import javax.xml.bind.JAXBException;
  10. import javax.xml.bind.Marshaller;
  11. import javax.xml.bind.Unmarshaller;
  12. import org.dom4j.Document;
  13. import org.dom4j.DocumentException;
  14. import org.dom4j.DocumentHelper;
  15. import org.dom4j.Element;
  16. import com.alibaba.fastjson.JSON;
  17. import com.aukey.supply.chain.domain.test.AmazonEnvelope;
  18. import com.aukey.supply.chain.domain.test.Header;
  19. import com.aukey.supply.chain.domain.test.Message;
  20. import com.aukey.supply.chain.domain.test.ProcessingReport;
  21. import com.aukey.supply.chain.domain.test.ProcessingSummary;
  22. import com.aukey.supply.chain.domain.test.Result;
  23. import com.aukey.supply.chain.utils.Md5Utils;
  24. import com.aukey.supply.chain.utils.XMLPostUtils;
  25. public class TestAnalyzeXml {
  26. public static void main(String[] args)
  27. {
  28. //组装请求报文XML对象
  29. AmazonEnvelope amazonEnvelope =createXmlObject();
  30. //构造XML文本
  31. String xml= createXml(amazonEnvelope);
  32. try
  33. {
  34. //封装请求报文 然后发送HTTP请求 然后将返回XML字符串 进行解析对应XML格式的节点对象 然后获取对应的节点数据
  35. String urlStr = "http://info.edaeu.com/Api/";
  36. String token="";
  37. String md5;
  38. try {
  39. md5 = Md5Utils.ChangeMd5(token.substring(0, 16) + xml + token.substring(16, 32));
  40. } catch (Exception e) {
  41. md5 = "";
  42. }
  43. String httpPost = XMLPostUtils.httpPost(xml, urlStr+"/"+md5);
  44. JAXBContext getcontext = JAXBContext.newInstance(amazonEnvelope.getClass());
  45. Unmarshaller unmarshaller = getcontext.createUnmarshaller();
  46. StringReader reader = new StringReader(httpPost);
  47. Object object=(AmazonEnvelope)unmarshaller.unmarshal(reader);
  48. } catch (JAXBException e1) {
  49. e1.printStackTrace();
  50. }
  51. try{
  52. Document document = DocumentHelper.parseText(xml);
  53. // 通过document对象获取根节点
  54. Element root = document.getRootElement();
  55. Element message = root.element("Message");
  56. Element processingReport = message.element("ProcessingReport");
  57. @SuppressWarnings("unchecked")
  58. List<Element> results = processingReport.elements("Result");
  59. List<Map<String, Object>> mapResultList=new ArrayList<Map<String,Object>>();
  60. for (Element element : results)
  61. {
  62. Map<String, Object> map =new HashMap<String, Object>();
  63. map.put("MessageID",element.element("MessageID").getTextTrim());
  64. map.put("ResultCode", element.element("ResultCode").getTextTrim());
  65. map.put("ResultMessageCode",element.element("ResultMessageCode").getTextTrim());
  66. map.put("ResultDescription", element.element("ResultDescription").getTextTrim());
  67. mapResultList.add(map);
  68. }
  69. System.out.println(JSON.toJSONString(mapResultList));
  70. } catch (DocumentException e) {
  71. e.printStackTrace();
  72. }
  73. }
  74. }

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

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


  1. package com.aukey.supply.chain.utils;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.InputStream;
  4. import java.io.OutputStream;
  5. import java.io.StringReader;
  6. import java.net.HttpURLConnection;
  7. import java.net.URL;
  8. import javax.xml.bind.JAXBContext;
  9. import javax.xml.bind.Unmarshaller;
  10. import javax.xml.parsers.SAXParserFactory;
  11. import javax.xml.transform.Source;
  12. import javax.xml.transform.sax.SAXSource;
  13. import org.xml.sax.InputSource;
  14. import org.xml.sax.XMLReader;
  15. public class XMLPostUtils
  16. {
  17. public static String httpPost(String xml, String urlStr)
  18. {
  19. try
  20. {
  21. URL url = new URL(urlStr);
  22. // 建立http连接
  23. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  24. // 设置允许输出
  25. conn.setDoOutput(true);
  26. conn.setDoInput(true);
  27. // 设置不用缓存
  28. conn.setUseCaches(false);
  29. // 设置传递方式
  30. conn.setRequestMethod("POST");
  31. // 设置维持长连接
  32. conn.setRequestProperty("Connection", "Keep-Alive");
  33. // 设置文件字符集:
  34. conn.setRequestProperty("Charset", "UTF-8");
  35. // 转换为字节数组
  36. byte[] data = xml.getBytes();
  37. // 设置文件长度
  38. conn.setRequestProperty("Content-Length", String.valueOf(data.length));
  39. // 设置文件类型:
  40. conn.setRequestProperty("contentType", "text/xml");
  41. // 开始连接请求
  42. conn.connect();
  43. OutputStream out = conn.getOutputStream();
  44. // 写入请求的字符串
  45. out.write(data);
  46. out.flush();
  47. out.close();
  48. // 请求返回的状态
  49. if (conn.getResponseCode() == 200)
  50. {
  51. // 请求返回的数据
  52. InputStream in = conn.getInputStream();
  53. try
  54. {
  55. ByteArrayOutputStream s = new ByteArrayOutputStream();
  56. int length = 0;
  57. byte[] buffer = new byte[1024 * 1024];
  58. while ((length = in.read(buffer)) != -1)
  59. {
  60. s.write(buffer, 0, length);
  61. }
  62. return s.toString("UTF-8");
  63. }
  64. catch (Exception e1)
  65. {
  66. e1.printStackTrace();
  67. }
  68. finally
  69. {
  70. in.close();
  71. }
  72. }
  73. else
  74. {
  75. }
  76. }
  77. catch (Exception e)
  78. {
  79. e.printStackTrace();
  80. }
  81. return null;
  82. }
  83. public static <T> T convertXmlToJavaBean(String xml, Class<T> t) throws Exception
  84. {
  85. T obj;
  86. JAXBContext context = JAXBContext.newInstance(t);
  87. StringReader stringReader = new StringReader(xml);
  88. SAXParserFactory sax = SAXParserFactory.newInstance();
  89. sax.setNamespaceAware(false);// 设置忽略明明空间
  90. XMLReader xmlReader = sax.newSAXParser().getXMLReader();
  91. Source source = new SAXSource(xmlReader, new InputSource(stringReader));
  92. Unmarshaller unmarshaller = context.createUnmarshaller();
  93. obj = (T) unmarshaller.unmarshal(source);
  94. return obj;
  95. }
  96. }

  1. package com.aukey.task.centerwarehouse.utils;
  2. import java.security.MessageDigest;
  3. import java.security.NoSuchAlgorithmException;
  4. public class Md5Utils
  5. {
  6. public static String ChangeMd5(String password)
  7. {
  8. try
  9. {
  10. // 得到一个信息摘要器
  11. MessageDigest digest = MessageDigest.getInstance("md5");
  12. byte[] result = digest.digest(password.getBytes());
  13. StringBuffer buffer = new StringBuffer();
  14. // 把每一个byte 做一个与运算 0xff;
  15. for (byte b : result)
  16. {
  17. // 与运算
  18. int number = b & 0xff;// 加盐
  19. String str = Integer.toHexString(number);
  20. if (str.length() == 1)
  21. {
  22. buffer.append("0");
  23. }
  24. buffer.append(str);
  25. }
  26. // 标准的md5加密后的结果
  27. return buffer.toString();
  28. }
  29. catch (NoSuchAlgorithmException e)
  30. {
  31. e.printStackTrace();
  32. return "";
  33. }
  34. }
  35. }

WebService如何封装XML请求 以及解析接口返回的XML的更多相关文章

  1. php 向asmx发送请求 || php 发送xml请求, 以及处理返回的xml结果

    var $live_url = 'https://processing.ukash.com/RPPGateway/process.asmx'; $source = array( 'SecurityTo ...

  2. 【Golang 接口自动化03】 解析接口返回XML

    上一篇我们学习了怎么发送各种数据类型的http请求,这一篇我们来介绍怎么来解析接口返回的XML的数据. 解析接口返回数据 定义结构体 假设我们现在有一个接口返回的数据resp如下: <?xml ...

  3. 【Golang 接口自动化04】 解析接口返回JSON串

    前言 上一次我们一起学习了如何解析接口返回的XML数据,这一次我们一起来学习JSON的解析方法. JSON(Javascript Object Notation)是一种轻量级的数据交换语言,以文字为基 ...

  4. [C#]Winform后台提交数据且获取远程接口返回的XML数据,转换成DataSet

    #region 接口返回的Xml转换成DataSet /// <summary> /// 返回的Xml转换成DataSet /// </summary> /// <par ...

  5. XML系列之--解析电文格式的XML(二)

    上一节介绍了XML的结构以及如何创建.讲到了XML可作为一种简单文本存储数据,把数据存储起来,以XML的方式进行传递.当接收到XML时,必不可少的就是对其进行解析,捞取有效数据,或者将第三方数据以节点 ...

  6. C# 处理接口返回的XML格式数据

    using System.Xml; //引入命名空间 //模拟接口返回的数据 string str=@"<JZD_Message xmlns:xsd=""http: ...

  7. javascript 解析ajax返回的xml和json格式的数据

    写个例子,以备后用 一.JavaScript 解析返回的xml格式的数据: 1.javascript版本的ajax发送请求 (1).创建XMLHttpRequest对象,这个对象就是ajax请求的核心 ...

  8. andriod开发,简单的封装网络请求并监听返回.

    一.为什么封装 因为android 4.0 以后的发送网络请求必须要放到异步线程中,而异步线程必须跟handle合作才能更新主线程中的UI,所以建议用一个类继承handler来异步处理网络请求. 二. ...

  9. phpStudy4——前端页面使用Ajax请求并解析php返回的json数据

    项目需求: 在html页面显示所有用户列表信息. 需求分析: 1. html页面使用ajax向后端php请求用户数据 2. php脚本查询数据库,并将查询后的结果以json格式返回前端html页面 3 ...

随机推荐

  1. 小记------phoenix安装搭建

        1.下载与hbase对应版本的phoenix      http://phoenix.apache.org/download.html   2.解压  tar -zxvf apache-pho ...

  2. 洛谷P2659 美丽的序列 单调栈模板

    P2659 美丽的序列 题目链接 https://www.luogu.org/problemnew/show/P2659 题目描述 为了研究这个序列的美丽程度,GD定义了一个序列的"美丽度& ...

  3. Centos7下,宿主机nginx配合docker环境的php-fpm

    一.安装docker并启动 yum install docker systemctl start docker 二.安装nginxCentOS 7默认不能从yum中安装nginx,原因可以自己搜索一下 ...

  4. python--关于正则表达式的学习小结

    python中提供了re这个模块提供对正则表达式的支持. 一.正则表达式常用到的一些语法(并非全部): . 匹配任意单个字符 [...] 匹配单个字符集 \w 匹配单词字符,即[a-zA-Z0-9] ...

  5. vue开发环境配置跨域,一步到位

    本文要实现的是:使用vue-cli搭建的项目在开发时配置跨域,上线后不做任何任何修改,接口也可以访问,前端跨域解决方案 production:产品 生产环境 development:开发 开发环境 1 ...

  6. linux 安装apache

    APR and APR-Util包 下载地址:http://apr.apache.org PCRE 下载地址:http://www.pcre.org Apache Server2.4 下载地址:htt ...

  7. 计算机概论 64bit和32bit的CPU的不同

    32位(WOW32).64位(WOW64,x64)指的是两种不同的CPU架构. 32位的CPU能够在每个时钟周期传输32位数据,而64位的CPU能够在每个时钟周期传输64位数据. 32位系统可以访问2 ...

  8. ideaIU-2019.2.exe-安装目录和设置目录结构的说明

    一.查看安装目录结构 bin: 容器,执行文件和启动参数等 help:快捷键文档和其他帮助文档 jbr: 含有java运行环境 lib:idea 依赖的类库 license:各个插件许可 plugin ...

  9. 怎样快捷获取元素节点body

    1. 使用: document.body document.body.nodeName; // "BODY" 2. 使用: document.getElementsByTagNam ...

  10. Inversion 多校签到题

    存下值和下标后排序,每次从坐后面开始取就可以了. ac代码: #include <algorithm> #include <cstdio> #include <cstri ...