近期接到个需求,项目中需要集成零几年建设的OA系统。 OA系统使用的接口全部都是webservice接口,在此分享一下webservice接口调用过程中遇到的问题及调用方式。
笔者也是第一次接触webservice接口,搜索了大量的资料,最后使用如下两种方式进行的交互。
笔者接触到的OA系统,接口参数没有统一 1、有的入参使用XML方式,有的入参是JSON字符串, 2、有的有命名空间,有的没有命名空间 3、有的返回了JSON字符串,有的返回了XML~ em....(@#%¥#@%#¥%),为了适配这个老东西,下面展出两种方式的调用代码,。
业务流程是web端调用我的HTTP接口,然后HTTP接口去调用OA的webservice接口拿数据。 但是webservice接口返回的参数是XML形式的,所以需要使用工具转成JSON,返回给web浏览器。 笔者使用的工具是hutool下的SoapClient工具包(Hutool还是挺强大)调用webservice接口,jdom、fastjson做XML转换JSON。
POM如下:
com.alibaba fastjson //版本自己找哈~cn.hutool hutool-all 5.8.20 org.jdom jdom 2.0.2
Controller忽略不展示了
Service 实现 如下:
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import cn.hutool.http.webservice.SoapClient; import javax.xml.namespace.QName; import java.util.*; @Service @Slf4j public class OAServiceImpl implements OAService { //@Override public JSONObject getGWList(OAReqVO reqVO) { Mapmap = new HashMap<>(); //笔者系统中的业务参数,对方需要用到的json参数 map.put("参数3-1","1"); map.put("参数3-2","2"); map.put("参数3-3","3"); Map mapReq = new HashMap<>(); mapReq.put("content",map); JSONObject writeContent = new JSONObject(mapReq); log.info("接口入参:"+writeContent); String result = null; try { //对方接口地址 SoapClient soapClient = SoapClient.create("http://xxx.xxx.xxx/xxxController/init.done") // 对端 提供的方法名,命名空间(如果有命名空间记得找他们要) .setMethod("方法名", "http://xxx.xxx.com.cn") // 设置参数名称及参数值 .setParam("token", "token-123123123") .setParam("systemId","系统标识") //上面中的writeContent,对端业务系统使用 .setParam("content",writeContent.toString()) // 设置超时时间 .setConnectionTimeout(15000) .setReadTimeout(15000) .timeout(15000); // 还有其他可以配置,根据自己的需求配置 result = soapClient.send(); log.info("OA返回信息={}", result); // 返回的是xml形式的,所以在此处转一下json JSONObject jsonObject = XmlToJsonUtil.xml2Json(result); //拿到数据 下面做自己的业务处理,笔者就直接return了。 log.info("OA返回信息JSON转换={}", jsonObject); return jsonObject ; }catch (Exception e) { log.error("接口调用失败:"+e.getMessage(),e); JSONObject jsonObject = new JSONObject(); jsonObject.put("code","1002"); jsonObject.put("mesText",""); jsonObject.put("mesType","0"); jsonObject.put("mes","获取失败"); return jsonObject; } } }
XmlToJsonUtil:
package cn.com.XXXX.utils; import com.alibaba.fastjson.JSONObject; import org.apache.commons.lang3.StringUtils; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.JDOMException; import org.jdom2.input.SAXBuilder; import org.springframework.stereotype.Component; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.LinkedList; import java.util.List; @Component public class XmlToJsonUtil { public static JSONObject xml2Json(String xmlStr) throws JDOMException, IOException { if (StringUtils.isBlank(xmlStr)) { return null; } xmlStr = xmlStr.replaceAll("\n", ""); byte[] xml = xmlStr.getBytes(StandardCharsets.UTF_8); JSONObject json = new JSONObject(); InputStream is = new ByteArrayInputStream(xml); SAXBuilder sb = new SAXBuilder(); Document doc = sb.build(is); Element root = doc.getRootElement(); json.put(root.getName(), iterateElement(root)); return json; } private static JSONObject iterateElement(Element element) { Listnode = element.getChildren(); JSONObject obj = new JSONObject(); List list = null; for (Element child : node) { list = new LinkedList(); String text = child.getTextTrim(); if (StringUtils.isBlank(text)) { if (child.getChildren().size() == 0) { continue; } if (obj.containsKey(child.getName())) { list = (List) obj.get(child.getName()); } list.add(iterateElement(child)); //遍历child的子节点 obj.put(child.getName(), list); } else { if (obj.containsKey(child.getName())) { Object value = obj.get(child.getName()); try { list = (List) value; } catch (ClassCastException e) { list.add(value); } } if (child.getChildren().size() == 0) { //child无子节点时直接设置text obj.put(child.getName(), text); } else { list.add(text); obj.put(child.getName(), list); } } } return obj; } }
如此一番操作就能调用了~
注:下面这个接口没用使用命名空间
废话不多说,直接上代码
pom依赖:
dom4j dom4j 1.6.1 com.google.code.gson gson 2.9.0 org.apache.cxf cxf-spring-boot-starter-jaxws 3.2.1 org.apache.cxf cxf-rt-transports-http 3.2.1
controller忽略
service实现如下:
import org.apache.cxf.endpoint.Client; import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; import org.apache.cxf.transport.http.HTTPConduit; import org.apache.cxf.transports.http.configuration.HTTPClientPolicy; //如需复制,import 与代码 请分开复制~ @Override public String webserviceTest() { //封装xml报文体,可以自己拼装例如: //请求参数 String req = "\n" + " "; //或者编辑好JSON,使用下面的JsonToXml 的工具类进行xml转换 //创建请求实例 JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance(); try{ Client client = factory.createClient("http://xxx.xxx.com/sdadsa"); HTTPConduit conduit = (HTTPConduit) client.getConduit(); HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy(); httpClientPolicy.setConnectionTimeout(10000); //连接超时 httpClientPolicy.setAllowChunking(false); //取消块编码 httpClientPolicy.setReceiveTimeout(10000); //响应超时 conduit.setClient(httpClientPolicy); Object[] objects = new Object[0]; //请求接口 objects = client.invoke(loginMethod, req); log.info("返回数据= {}" , objects[0].toString() ); //做自己的业务逻辑处理,如果返回的是XML,需要转JSON,可以使用上面的XML转JSON的工具类进行操作。笔者直接return了 return objects[0].toString(); }catch (Exception e){ log.error("系统交互异常:{}",e.getMessage(),e); return "交互异常,请联系管理员"; } }\n" + " \n" + "123 \n" + "123 \n" + "
json转xml工具类:
package cn.com.XXXX.utils; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import org.dom4j.Element; import org.springframework.stereotype.Component; import java.util.Map; import java.util.Set; @Component public class JsonToXml { /** * 将json字符串转换成xml * * @param json * json字符串 * @param parentElement * xml根节点 * @throws Exception */ public static Element jsonToXml(String json, Element parentElement) throws Exception { JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject(); Element ee = toXml(jsonObject, parentElement, null); return ee; } /** * 将json字符串转换成xml * * @param jsonElement * 待解析json对象元素 * @param parentElement * 上一层xml的dom对象 * @param name * 父节点 */ public static Element toXml(JsonElement jsonElement, Element parentElement, String name) { if (jsonElement instanceof JsonArray) { //是json数据,需继续解析 JsonArray sonJsonArray = (JsonArray)jsonElement; for (int i = 0; i < sonJsonArray.size(); i++) { JsonElement arrayElement = sonJsonArray.get(i); toXml(arrayElement, parentElement, name); } }else if (jsonElement instanceof JsonObject) { //说明是一个json对象字符串,需要继续解析 JsonObject sonJsonObject = (JsonObject) jsonElement; Element currentElement = null; if (name != null) { currentElement = parentElement.addElement(name); } Set> set = sonJsonObject.entrySet(); for (Map.Entry s : set) { toXml(s.getValue(), currentElement != null ? currentElement : parentElement, s.getKey()); } } else { //说明是一个键值对的key,可以作为节点插入了 addAttribute(parentElement, name, jsonElement.getAsString()); } return parentElement; } /** * * @param element 父节点 * @param name 子节点的名字 * @param value 子节点的值 */ public static void addAttribute(Element element, String name, String value) { //增加子节点,并为子节点赋值 Element el = element.addElement(name); el.addText(value); } }
谈谈遇到的问题, 1:跟OA交互时候,传参没有驼峰,OA系统收不到这个没有驼峰的参数 解决方案:给字段进行驼峰。 2:xml转JSON后会有多个层级,取最里层的参数比较麻烦 解决方案:使用JSONPath.read()方法,能快速去除最里层的参数,注意判空。 如:String respDesc = JSONPath.read(SessionHeader, "$.Response[:1].RspDesc[0]").toString(); 3:其他问题 切记 一定要把所有接口交互前想到的问题都问清楚,最好双方能出个文档,评审完文档后进行开发~, 多沟通才是解决问题的重要方式。
以上就是笔者跟老系统交互的两种方式,欢迎各位讨论交流~