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:

/*
* <?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://www.cnblogs.com/LoveShare/p/11388708.html

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值