Egan闲了一段时间后,逗比经理居然来找Egan闲聊了
逗比经理居然说爱上Egan……
Egan摸了摸自己的刘海
又是一个不眠夜
Egan看着SOAP文件,想起前段时间刚学的【使用命令wsimport构建WebService客户端】,咦,是不是可以用用。
只要来一个soap文件我就生成一次对应的Java客户端,我真是太聪明了
那我手动处理?不行不行,我有点偏题了。
我在看看这个soap对应的xml文件
soap wsdl文件大概的样子是这样的
整理了一下,大概有几种需要解析的节点类型
但是呢,soap一切是从service节点开始的,从服务(service)中拿到地址(address)进行请求。
整个类的结构理出来差不多就是以下的类图结构了,从下到上看过来,把所有可能出现的情况罗列出来了.
但是每个节点在xml里面是属于同级结构,还需要把他们串起来,才能达到以上类图的样子。
那必须有以下两个步骤
-
解析所有相关的节点
-
将所以节点关联起来
除了以上两个步骤外,每个节点都有自己的属性:name
那么以此可以得到每个节点都必须有一个属性两个动作
得到一个接口
public interface SoapElement {
/**
* 获取节点名称
*
* @return 节点名称
*/
String getName();
/**
* 解析
*
* @param node 需要解析的节点
* @return 解析好的节点
*/
SoapElement parsing(Element node);
/**
* 关联自身内部对象,需要对应的内部对象
*
* @param elements 所有的属性节点
*/
void relate(Map<String, SoapElement> elements);
}
接着每个节点都有自己的name并且都是取节点上的name属性操作,那么以此可以得到一个设置获取name的动作的基础节点
public abstract class BaseElement implements SoapElement {
protected final static String NAME = "name";
protected String name;
@Override
public String getName() {
return name;
}
/**
* 设置节点名称
* @param name 名称
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取“:”后面的值,用于获取节点类型名,
* 如wsdl:message 那么返回 message
* @param value 转化前
* @return 转化后
*/
public static final String getValue(String value) {
if (StringUtils.isEmpty(value)) {
return null;
}
return value.substring(value.indexOf(":") + 1);
}
}
定义Element节点类,只负责解析Element节点与Element子节点得到所有的参数名与参数类型
跟着上面类图来从上到下
接下来Types类,一个Types对应多个Element
Message类,这里可能有parts子节点,这个子节点直接存放参数名与参数类型,根据节点判断是否需要Element
Message分为两部分,输入与输出并存放至Operation类中
然后Operation解析来自于PortType。
接着Binding
最后一个service
所有的组件编写完成,完工
解析每一个节点的时候需要通过名字去转换成上面的节点组件,一个一个if去判断好像一点都不优雅。
Element item = (Element) node;
String tagName = BaseElement.getValue(item.getTagName());
SoapElement element = null;
if ("types".equals(tagName)) {
element = new Types();
}else if ("element".equals(tagName)) {
element = new com.egzosn.contract.xml.soap.bean.Element();
}else if ("message".equals(tagName)) {
element = new Message();
}
咦!写个枚举类吧,并且定义解析方法,代理下每个组件的解析方法
\
最后写解析并获取根节点获取Service的入口
/**
* 获取SOAP服务
* @param content SOAP的xml内容
* @return SOAP服务
*/
public static final Service getService(InputStream content) throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
org.w3c.dom.Document doc = documentBuilder.parse(content);
doc.getDocumentElement().normalize();
return getService(doc.getDocumentElement());
}
/**
* 通过element获取 soap服务
* @param root soap根节点
* @return soap服务
*/
public static final Service getService(Element root) {
if (!root.hasChildNodes()) {
return null;
}
NodeList childNodes = root.getChildNodes();
//用与存储所有的soap节点
Map<String, SoapElement> soapElements = new HashMap<String, SoapElement>();
Service service = null;
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (node.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
Element item = (Element) node;
String tagName = BaseElement.getValue(item.getTagName());
SoapChild wsdlChild = SoapChild.valueOf(tagName);
SoapElement element = wsdlChild.parsing(item);
if (SoapChild.service == wsdlChild) {
service = (Service) element;
service.setNamespace(root.getAttribute("targetNamespace"));
}
soapElements.put(tagName + ":" + element.getName(), element);
}
//将所有的节点串连起来
for (SoapElement element : soapElements.values()) {
element.relate(soapElements);
}
return service;
}
大功告成!
唉!这个点了
收拾收拾,明早写下把数据进行入库吧,撑不住了
______________________________________END_______________________________________
有兴趣的同学可以留言并分享哦
最近小E正在学习小程序相关的知识并开发了自己的小程序,有兴趣的同学可以加小E的VX并备注“小程序”,小E的VX: Egzasn
也可以关注小E的公众号: 墨鲸说话