最近项目需要调用外部webservice接口,之前没接触过,研究了2天做个笔记:
1、首先发送请求,格式接口那边已经提供了,期间遇到的问题就是提示“no SOAPAction header” 的错误,请求代码如下:
/**
* 根据参数拼接后发生soap请求
* @param params
* @return
* @throws Exception
*/
public static String SoapRequest(Map<String,Object> params)throws Exception{
String sendMsg = "";
String resultStr = "";
String url = MapUtil.getStrValue(params,"url");
if(StringUtil.isEmpty(url)){
return "";
}
//定义HttpClient
HttpClient client = new HttpClient();
PostMethod postMethod = new PostMethod(url);
try {
Map<String,Object> reqMap = new HashMap<>();
reqMap.put("reqCode",MapUtil.getStrValue(params,"reqCode"));
reqMap.put("offerId",MapUtil.getStrValue(params,"offerId"));
reqMap.put("srvModule",MapUtil.getStrValue(params,"srvModule"));
//这里是项目写了个工具类拼接请求xml报文
sendMsg = XmlConverterUtil.createXmlFromTemplate(reqMap);
// 然后把Soap请求数据添加到PostMethod中
RequestEntity requestEntity = new StringRequestEntity(sendMsg, "text/xml", "UTF-8");
//设置请求头部,否则可能会报 “no SOAPAction header” 的错误
postMethod.setRequestHeader("SOAPAction","");
postMethod.setRequestHeader("Content-Types","text/xml");
// 设置请求体
postMethod.setRequestEntity(requestEntity);
int status = client.executeMethod(postMethod);
// 打印请求状态码
System.out.println("status:" + status);
// 获取响应体输入流
BufferedReader in = new BufferedReader(
new InputStreamReader(postMethod.getResponseBodyAsStream(),"UTF-8"));
resultStr = IOUtils.toString(in);
// 获取请求结果字符串并转换格式,这里一开始有遇到字符转换问题,后面方法可以解决,可
//以不使用
/*resultStr = resultStr.replaceAll("&", "&");
resultStr = resultStr.replaceAll("<", "<").replaceAll(">", ">");
resultStr = resultStr.replaceAll(""", "\"");
resultStr = (String) XmlConverterUtil.decodeStr(resultStr);*/
}catch (Exception e){
e.printStackTrace();
}
return resultStr;
}
2、根据返回的xml报文解析,转成java对象,先看下返回的格式:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns1:callWebServiceResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://hnlocal.webservice.bsn.ztesoft.com ">
<callWebServiceReturn href="#id0"/>
</ns1:callWebServiceResponse>
<multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns2:RespMessage" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns2="http://model.webservice.bsn.ztesoft.com">
<content xsi:type="xsd:string">
<?xml version="1.0" encoding="UTF-8"?>
<CommissionOrderRespType xmlns:xml="http://www.w3.org/XML/1998/namespace"><Alllist><OfferId>200000573</OfferId><OfferName>产品发展类-乐享4G单产品C</OfferName><EffDate>2014-05-04 10:24:24.0</EffDate><PricingSectionName>销售品类型 in 乐享4G套餐</PricingSectionName><RefObjectName>当前销售品类型</RefObjectName><OperatorName>必须订购</OperatorName><AcctItemTypeId>100000038</AcctItemTypeId><name>天翼-首返</name></Alllist><Alllist><OfferId>200000639</OfferId><OfferName>集约化_金昌_4G_19-999元天翼产品</OfferName><EffDate>2014-05-11 17:31:09.0</EffDate><PricingSectionName>零费用周期性事件生成</PricingSectionName><RefObjectName>当前销售品类型</RefObjectName><OperatorName>必须订购</OperatorName><AcctItemTypeId>100000038</AcctItemTypeId><name>天翼-首返</name></Alllist>
</content>
<respCode xsi:type="xsd:string">0</respCode>
<srvFunction xsi:type="xsd:string">query</srvFunction>
<srvModule xsi:type="xsd:string">CommissionOrderQuery</srvModule>
</multiRef>
</soapenv:Body>
</soapenv:Envelope>
上面的报文可以分成两部分,一部分是soap的返回头参数,中间content中的是结果xml,我们主要是要将content里面的内容转成java对象集合,先看下content里面的内容
先上获取到content这部分xml内容的代码:
/**
*
* @param soapXml 请求结果string
* @param c 要转换成的java对象
* @param <T>
* @return
*/
public static <T> T soapXmlToBean(String soapXml,Class<T> c){
Iterator<SOAPElement> iterator = null;
T t = null;
try {
//javax.xml.soap类MessageFactory
MessageFactory msgFactory = MessageFactory.newInstance();
//创建一个soapmessage对象
SOAPMessage reqMsg = msgFactory.createMessage(new MimeHeaders(),
new ByteArrayInputStream(soapXml.getBytes("UTF-8")));
reqMsg.saveChanges();
//取出soapBoby对象
SOAPBody body = reqMsg.getSOAPBody();
遍历子节点
iterator = body.getChildElements();
}catch (Exception e){
e.printStackTrace();
}
while (iterator.hasNext()) {
SOAPElement element = iterator.next();
logger.info("节点名称---:"+element.getNodeName());
if("multiRef".equals(element.getNodeName())){
Iterator<SOAPElement> it = element.getChildElements();
SOAPElement el = null;
while (it.hasNext()) {
el = it.next();
//取到content子节点的值
if ("content".equals(el.getNodeName())) {
logger.info("子节点值---:"+el.getValue());
//这里是调用工具来将content中的xml转换成java对象
t = XmlConverterUtil.analyzeXmlToBean(el.getValue(),c);
break;
}
}
break;
}
}
return t;
}
3、将xml转换成java对象集合,利用JAXBContext将xml解析成java对象集合,思路就是把xml当做一个list<T> ,定义一个存list的对象,然后再定义一个T对象,然后通过JAXBContext进行解析:
@Data
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "CommissionOrderRespType")//根路径
public class CommissionContentResp extends ArrayList<CommissionResp> implements Serializable {
private static final long serialVersionUID = 1L;
@XmlElement(name="Alllist")//子节点名称
public List<CommissionResp> getList(){
return this;
}
}
@Data
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Alllist")//根路径
public class CommissionResp implements Serializable {
private static final long serialVersionUID = 1L;
@XmlElement(name="OfferId")
private String offerId;
@XmlElement(name="OfferName")
private String offerName;//
@XmlElement(name="EffDate")
private String effDate;
@XmlElement(name="PricingSectionName")
private String pricingSectionName;
@XmlElement(name="RefObjectName")
private String refObjectName;
@XmlElement(name="OperatorName")
private String operatorName;
@XmlElement(name="AcctItemTypeId")
private String acctItemTypeId;
@XmlElement(name="name")
private String name;
}
/**
* 解析返回报文,返回对象
* */
public static <T> T analyzeXmlToBean(String xmlStr, Class<T> c){
T t = null;
try {
JAXBContext context = JAXBContext.newInstance(c);
Unmarshaller unmarshaller = context.createUnmarshaller();
t = (T) unmarshaller.unmarshal(new StringReader(xmlStr));
} catch (JAXBException e) {
e.printStackTrace();
}
return t;
}
最后传入content里面的xml内容和CommissionContentResp对象就能解析出结果List<T> ,希望能帮到大家 喜欢的点个赞~
补充:
返回报文含有集合加单个对象,可以这样定义:
@Data
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "ShareMsgQueryRespType")
public class ShareMsgResp extends ArrayList<SourseAcctItem> implements Serializable {
private static final long serialVersionUID = 1L;
//private List<SourseAcctItem> newlist;
@XmlElement(name="Newlist")
private List<SourseAcctItem> newlist;
@XmlElement(name="Alllist")
private ShareContent alllist;
}
返回参数:
<?xml version="1.0" encoding="UTF-8"?>
<ShareMsgQueryRespType>
<Newlist>
<SourseAcctItemTypeId>602040</SourseAcctItemTypeId>
<SourseAcctItemTypeName>其它补退费</SourseAcctItemTypeName>
</Newlist>
<Newlist>
<SourseAcctItemTypeId>611162</SourseAcctItemTypeId>
<SourseAcctItemTypeName>天翼大流量套餐功能费</SourseAcctItemTypeName>
</Newlist>
<Alllist>
<ProductId>900000001</ProductId>
<ProductName>移动电话</ProductName>
<AcctItemTypeId>108021</AcctItemTypeId>
<Name>来电显示 (移动业务)</Name>
<FairValue>5.00000</FairValue>
</Alllist>
</ShareMsgQueryRespType>