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. /*
  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. }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM