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

前端之家收集整理的这篇文章主要介绍了WebService如何封装XML请求 以及解析接口返回的XML前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

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

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接https://blog.csdn.net/qq_24818689/article/details/99677155

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. @H_403_72@
/*
  • * <?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>
  • @H_428_502@
  • * <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大对象,然后以此为根节点建造子节点对象,这里举例两个如下:

         
         
         
    1. @H_403_72@
    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;
  • @H_428_502@
  • }
  • 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;
  • }
  • }
  •      
         
         
    1. @H_403_72@
    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;
  • }
  • @H_428_502@
  • public ProcessingReport getProcessingReport() {
  • return ProcessingReport;
  • }
  • public void setProcessingReport(ProcessingReport processingReport) {
  • ProcessingReport = processingReport;
  • }
  • }
  • 对象封装完成之后,API一般需要请求参数,因此我们建完实体对象后,需要按照不同节点要求赋值,示例如下:

         
         
         
    1. @H_403_72@
    /**
  • * 构造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
  • @H_428_502@
  • 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文本对象来完成:

         
         
         
    1. @H_403_72@
    /**
  • * 构造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解析返回了,这里说明为了方便,将请求对象和解析对象置为同一个。下面看主类全套调用逻辑:

         
         
         
    1. @H_403_72@
    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;
  • @H_428_502@
  • 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加密类):

         
         
    1. @H_403_72@
      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. @H_428_502@
      // 建立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. @H_336_5026@
      }
    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. @H_403_72@
      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. @H_428_502@
      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相关文章