最近要对接医院his接口,记录一下从组装报文到解析报文的流程
1.根据his方接口编写接口文档
我们是his给我们一份现有的接口,自己定义需要的接口和返回的字段,让his进行开发
接口名称 | 通过患者两项信息获取患者信息 |
---|---|
交易代码 | 10001 |
接口提供方 | 院方his系统 |
接口描述 | 根据患者信息,获取患者在医院的患者详细信息 注: 验证条件:身份证+姓名 |
l 请求xml文件示例
QFKJ
QFKJ
QFKJ
10001
张三丰
130345198003103254
l 请求参数xml节点说明
扫描二维码关注公众号,回复:
15751863 查看本文章
节点名称 | 类型 | 节点描述 | 必传 |
---|---|---|---|
PatientName | String | 患者姓名 | 是 |
IdCard | String | 身份证号 | 是 |
l 应答消息xml文件示例
0
成功</ ResultContent >
1
65948789
老王头
13344343355
130345198003103254
男
1993-09-23
五虎山大王宫
2.熟悉his的wsdl文档
一般his会提供一个wsdl接口地址,用浏览器打开是一个xml文档,开头有一下内容:
<wsdl:types>
<s:schema elementFormDefault="qualified" targetNamespace="http://a.com.cn/">
<s:element name="a">
targetNamespace 为命名空间 <s:element name=“a”>这里a的值为接口名字(一般his会给每一个调用方分配一个账户)
3.java后端引入依赖并编写相关工具类
<!-- webservice远程调用 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>3.2.5</version>
</dependency>
<!-- xml解析依赖 -->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.1</version>
</dependency>
<!-- xml解析依赖 -->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.1</version>
</dependency>
工具类编写
发送报文工具类
@Slf4j
public class WebServiceUtil {
//调用方法
public static String sendRequest(String xml, String requesturl){
log.debug("HIS入参XML:"+xml);
try {
JaxWsDynamicClientFactory clientFactory = JaxWsDynamicClientFactory.newInstance();
// wsdlUrl webservice地址,加上?wsdl后缀
Client client = clientFactory.createClient(requesturl);
// name_space 命名空间
QName qName = new QName(targetNamespace,localPart);
//参数数组
Object[] param = new Object[]{xml}; //这里的xml是你组装的xml报文
Object[] res = client.invoke(qName, param);
//返回结果字符串
log.debug("HIS返回结果XML:"+res[0]);
return String.valueOf(res[0]);
} catch (Exception e) {
log.debug("[" + Thread.currentThread().getName() + "|" + "WebServiceUtil.sendRequest()" + "]");
throw new ServiceException("调用his接口报错,联系管理员");
}
}
}
Client client = clientFactory.createClient(requesturl);
这里的requesturl为his提供的接口地址 例如:
http://IP地址:8070/InsurSelfSvr.asmx?WSDL
QName qName = new QName(targetNamespace,localPart);
这里的targetNamespace为第一步的命名空间 localPart为第一步的接口名 可以往上查看第一步内容
xml转换工具类
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
public class XmlUtil {
// 解析xml报文
public static Map getRoot(String xml) throws Exception {
Document doc= DocumentHelper.parseText(xml);
JSONObject json=new JSONObject();
XmlUtil.dom4j2Json(doc.getRootElement(),json);
return JSON.parseObject(json.toString(),Map.class);
}
/**
* xml转json
* @param element
* @param json
*/
public static void dom4j2Json(Element element, JSONObject json){
//如果是属性
for(Object o:element.attributes()){
Attribute attr=(Attribute)o;
if(!StringUtils.isBlank(attr.getValue())){
json.put("@"+attr.getName(), attr.getValue());
}
}
List<Element> chdEl=element.elements();
if(chdEl.isEmpty()&&!StringUtils.isBlank(element.getText())){//如果没有子元素,只有一个值
json.put(element.getName(), element.getText());
}
for(Element e:chdEl){//有子元素
if(!e.elements().isEmpty()){//子元素也有子元素
JSONObject chdjson=new JSONObject();
dom4j2Json(e,chdjson);
Object o=json.get(e.getName());
if(o!=null){
JSONArray jsona=null;
if(o instanceof JSONObject){//如果此元素已存在,则转为jsonArray
JSONObject jsono=(JSONObject)o;
json.remove(e.getName());
jsona=new JSONArray();
jsona.add(jsono);
jsona.add(chdjson);
}
if(o instanceof JSONArray){
jsona=(JSONArray)o;
jsona.add(chdjson);
}
json.put(e.getName(), jsona);
}else{
if(!chdjson.isEmpty()){
json.put(e.getName(), chdjson);
}
}
}else{//子元素没有子元素
for(Object o:element.attributes()){
Attribute attr=(Attribute)o;
if(!StringUtils.isBlank(attr.getValue())){
json.put("@"+attr.getName(), attr.getValue());
}
}
if(!e.getText().isEmpty()){
json.put(e.getName(), e.getText());
}
}
}
}
public static String toXml(Object model, boolean isFormatOut) throws JAXBException, IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream(1024);
marshal(model, output, isFormatOut);
output.flush();
return new String(output.toByteArray(), "UTF-8");
}
public static void marshal(Object model, OutputStream output) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(model.getClass());
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
jaxbMarshaller.marshal(model, output);
}
public static void marshal(Object model, OutputStream output, boolean isFormatOut) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(model.getClass());
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, isFormatOut);
jaxbMarshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
jaxbMarshaller.marshal(model, output);
}
解析报文工具类
这里我采用的是xml转json再转map的方法,可以参考xpath(本人尝试过,但没做出来)
这里千万注意 这个解析方法具有业务针对性 如果采用我的方法 请修改后使用
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.business.config.utils.XmlUtil;
import com.ruoyi.common.exception.ServiceException;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ReponseXml {
// 解析xml结果报文
public static List<Map<String, Object>> parseXml(String xml) throws Exception {
Document doc= DocumentHelper.parseText(xml);
JSONObject json=new JSONObject();
XmlUtil.dom4j2Json(doc.getRootElement(),json);
Map resultMap = JSON.parseObject(json.toString(), Map.class);
if (!"0".equals(resultMap.get("ResultCode"))){
throw new ServiceException((String) resultMap.get("ResultContent")); //这里ResultContent为我们业务的指定字段 以下解析具有业务独特性
}
List<Map<String,Object>> responseList = new ArrayList<>();
String[] items = xml.split("Item>");
if (items.length==1) return null;
if (items.length==3){
JSONObject item = json.getJSONObject("Records").getJSONObject("Item");
responseList.add(json2map(item));
return responseList;
}else{
JSONArray jsonObject = json.getJSONObject("Records").getJSONArray("Item");
jsonObject.stream().forEach(o->{
responseList.add(json2map((JSONObject) o));
});
return responseList;
}
}
//解析xml请求报文
public static Map<String, Object> parseReqXml(String xml) throws Exception {
Document doc= DocumentHelper.parseText(xml);
JSONObject json=new JSONObject();
XmlUtil.dom4j2Json(doc.getRootElement(),json);
Map resultMap = JSON.parseObject(json.toString(), Map.class);
Map<String,Object> param = (Map<String, Object>) resultMap.get("Param");
param.put("TransactionCode",resultMap.get("TransactionCode"));
return param;
}
public static Map<String,Object> json2map(JSONObject object){
Map<String,Object> map = new HashMap<>();
object.entrySet().stream().forEach(o->{
map.put(o.getKey(),o.getValue());
});
return map;
}
}
4.组装xml报文类
我是一个接口对应一个实体自己一一对应的,应该有更好的方法
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name="Request")
@Data
public class Request10002Xml {
@XmlElement(name="ExtUserID") //账户id his提供 一般为固定值
private String extUserID;
@XmlElement(name="ExtUserPwd")
private String extUserPwd; //账户密码 his提供 一般为固定值
@XmlElement(name="ExtOrgCode")
private String extOrgCode; //公司代码 his提供 一般为固定值
@XmlElement(name="TransactionCode")
private String transactionCode; //交易代码 his提供 一般为固定值
@XmlElement(name="Param")
private Xml10002 param;
public Request10002Xml (){
WeiXinProperties properties = SpringUtils.getBean(WeiXinProperties.class);
this.transactionCode="10002";
this.extUserID= properties.getExtUserID();
this.extUserPwd=properties.getExtUserPwd();
this.extOrgCode=properties.getExtOrgCode();
}
@Data
@XmlAccessorType(XmlAccessType.FIELD)
public static class Xml10002{
@XmlElement(name="PatientName")
private String patientName;
@XmlElement(name="Telephone")
private String telephone;
@XmlElement(name="IdCard")
private String idCard;
@XmlElement(name="Sex")
private String sex;
@XmlElement(name="Birthday")
private String birthday;
@XmlElement(name="Address")
private String address;
}
}
组装报文
Request10002Xml request10002Xml = new Request10002Xml();
Request10002Xml.Xml10002 xml10002 = new Request10002Xml.Xml10002();
xml10002.setPatientName(registerUser.getUserName());
xml10002.setTelephone(registerUser.getPhonenumber());
xml10002.setIdCard(idNumber);
xml10002.setSex(registerUser.getSex().equals("0") ? "男" : "女");
xml10002.setBirthday(DateUtils.parseDateToStr("yyyy-MM-dd", birthDay));
xml10002.setAddress(StringUtils.isBlank(registerUser.getAddress()) ? " " : registerUser.getAddress());
request10002Xml.setParam(xml10002);
//组装Xml
String reqXml = XmlUtil.toXml(request10002Xml, true);
String resultXml = WebServiceUtil.sendRequest(reqXml, properties.getHisUrl());
解析报文
//解析Xml
List<Map<String, Object>> maps = ReponseXml.parseXml(resultXml);
5.自己的业务处理
…