https://qiao.sf-express.com/index.html 丰桥系统中申请api接口,获得url(调用地址)、clientCode(顾客编码)、checkword(校验码)。
url:http://bsp-oisp.sf-express.com/bsp-oisp/sfexpressService
1.请求XML报文:
service 属性定义“服务名”;Head元素定义“顾客编码”
<Request service="服务名" lang="zh-CN">
<Head>顾客编码</Head>
<Body>请求数据XML</Body>
2.响应XML报文:
Head元素值为“OK”或“ERR”;OK代表交易成功,ERR代表发生系统或业务异常,交易失败;对于批量交易场景,只能为成功/失败,无部分成功/部分失败
<Response service="服务名">
<Head>OK|ERR</HEAD>
<Body>正常响应数据XML</Body>
<ERROR code="NNNN">错误详细信息</ERROR>
1.下订单接口(OrderService):
①客户系统向顺丰下发订单 ②为订单分配运单号
/**
* 获取顺丰下订单接口xml
* @param params
* @return
*/
private String getOrderServiceRequestXml(Map<String,String> params){
//订单号
String orderNo = params.get("orderNo");
//收件人
String receiverName = params.get("receiverName");
//收件人电话
String receiverMobile = params.get("receiverMobile");
//收件人详细地址
String receiverAddress = params.get("address");
//商品名称
String commodityName = params.get("commodityName");
//商品数量
String orderNum = params.get("orderNum");
StringBuilder strBuilder = new StringBuilder();
strBuilder.append("<Request service='OrderService' lang='zh-CN'>");
strBuilder.append("<Head>" + clientCode + "</Head>");
strBuilder.append("<Body>");
strBuilder.append("<Order").append(" ");
strBuilder.append("orderid='" + orderNo.toString().trim() + "" + "'").append(" ");
//返回顺丰运单号
strBuilder.append("is_gen_bill_no='1'").append(" ");
//寄件方信息
strBuilder.append("j_company='" + j_company + "'").append(" ");
strBuilder.append("j_contact='" + j_contact + "'").append(" ");
strBuilder.append("j_tel='" + j_tel + "'").append(" ");
strBuilder.append("j_address='" + j_province+j_city+j_county+j_address + "'").append(" ");
//收件方信息
strBuilder.append("d_company='" + d_company + "'").append(" ");
strBuilder.append("d_contact='" + receiverName.toString().trim() + "'").append(" ");
strBuilder.append("d_tel='" + receiverMobile.toString().trim() + "'").append(" ");
strBuilder.append("d_address='" + receiverAddress.toString().trim() + "'").append(" ");
strBuilder.append(" > ");
//货物信息
strBuilder.append("<Cargo").append(" ");
strBuilder.append("name='" + commodityName + "'").append(" ");
strBuilder.append("count='" + orderNum.toString() + "'").append(" ");
strBuilder.append("unit='双'").append(">");
strBuilder.append("</Cargo>");
strBuilder.append("</Order>");
strBuilder.append("</Body>");
strBuilder.append("</Request>");
return strBuilder.toString();
}
2.订单结果查询接口(OrderSearchService):
因Internet环境下,网络不是绝对可靠,用户系统下订单到顺丰后,不一定可以收到顺丰系统返回的数据,此接口用于在未收到返回数据时,查询下订单(含筛选)接口客户订单当前的处理情况。重复下单时可调用此接口查询下单顺丰单号
/**
* 获取顺丰订单结果查询接口xml
* @param params
* @return
*/
private String getOrderSearchServiceRequestXml(Map<String,String> params){
String orderNo = params.get("orderNo");
StringBuilder strBuilder = new StringBuilder();
strBuilder.append("<Request service='OrderSearchService' lang='zh-CN'>");
strBuilder.append("<Head>" + clientCode + "</Head>");
strBuilder.append("<Body>");
strBuilder.append("<OrderSearch").append(" ");
strBuilder.append("orderid='" + orderNo.toString().trim() + "" + "'").append(" > ");
strBuilder.append("</OrderSearch>");
strBuilder.append("</Body>");
strBuilder.append("</Request>");
return strBuilder.toString();
}
3.路由查询接口(RouteService):
支持两类查询方式:①根据顺丰运单号查询 ②根据客户订单号查询
/**
* 获取顺丰路由查询接口xml
* @param params
* @return
*/
private String getRouteServiceRequestXml(Map<String,String> params){
String orderNo = params.get("orderNo");
StringBuilder strBuilder = new StringBuilder();
strBuilder.append("<Request service='RouteService' lang='zh-CN'>");
strBuilder.append("<Head>" + clientCode + "</Head>");
strBuilder.append("<Body>");
strBuilder.append("<RouteRequest").append(" ");
strBuilder.append("tracking_type='2'").append(" ");
strBuilder.append("tracking_number='" + orderNo.toString().trim() + "" + "'").append(" >");
strBuilder.append("</RouteRequest>");
strBuilder.append("</Body>");
strBuilder.append("</Request>");
return strBuilder.toString();
}
①把XML报文与checkword前后连接
②把连接后的字符串做MD5编码
③把MD5编码后的数据进行Base64编码,此时编码后的字符串即为校验码
//接口url
@Value("${express.sf.url}")
private String url = "http://bsp-oisp.sf-express.com/bsp-oisp/sfexpressService"
/**
* 顺丰接口
* @param params
* @param type 1-下订单接口 2-订单结果查询接口 3-路由查询接口
* @return
*/
@Override
public SfExpressResponse sfExpressMethod(Map<String,String> params, int type) throws Exception{
logger.info("进入顺丰接口:params={},type={}", JSONObject.toJSONString(params),type);
if (type < 1){
logger.warn("调用接口类型传错");
return null;
}
String requestXml = "";
String methodName = "";
if (type == 1){
//1.获取下单xml
requestXml = getOrderServiceRequestXml(params);
methodName = "orderSerivce";
} else if (type == 2){
//1.获取订单结果查询xml
requestXml = getOrderSearchServiceRequestXml(params);
methodName = "orderSearchService";
} else if (type == 3){
//1.获取订单物流路由
requestXml = getRouteServiceRequestXml(params);
methodName = "routeService";
}
//2.xml+checkword
String verifyCode = requestXml + checkword;
//3.MD5加密 + Base64编码
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(verifyCode.getBytes("utf8"));
verifyCode = Base64Util.encode(md5.digest());
//4.post 请求
Map<String, Object> toHttpParams = new HashMap<>();
toHttpParams.put("xml",requestXml);
toHttpParams.put("verifyCode",verifyCode);
logger.info("请求顺丰接口"+methodName, toHttpParams.toString());
String resultStr = HttpExtUtil.doPost(url, toHttpParams);
logger.info("请求顺丰接口"+methodName+",result="+resultStr);
SfExpressResponse response = (SfExpressResponse)
XMLUtil.convertToObject(SfExpressResponse.class,resultStr);
return response;
}
综合三个接口的response xml,将SfExpressResponse定义如下(树状结构对象):
/**
* 顺丰接口response对象
* author: jing.mn
* date: 2018/4/9 16:17
* copyright wonhigh.net.cn
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Response")
public class SfExpressResponse implements Serializable {
private static final long serialVersionUID = 1L;
//响应状态
@XmlElement(name = "Head")
private String Head;
//响应失败原因
@XmlElement(name = "ERROR")
private ERROR ERROR;
//响应结果
@XmlElement(name = "Body")
private Body Body;
@XmlAccessorType(XmlAccessType.NONE)
public static class ERROR {
@XmlAttribute(name = "code")
private String code;
@XmlValue
private String text;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
@XmlAccessorType(XmlAccessType.NONE)
public static class Body {
@XmlElement(name = "OrderResponse")
private OrderResponse OrderResponse;
@XmlElement(name = "RouteResponse")
private RouteResponse RouteResponse;
public SfExpressResponse.OrderResponse getOrderResponse() {
return OrderResponse;
}
public void setOrderResponse(SfExpressResponse.OrderResponse orderResponse) {
OrderResponse = orderResponse;
}
public SfExpressResponse.RouteResponse getRouteResponse() {
return RouteResponse;
}
public void setRouteResponse(SfExpressResponse.RouteResponse routeResponse) {
RouteResponse = routeResponse;
}
}
@XmlRootElement(name="OrderResponse")
@XmlAccessorType(XmlAccessType.NONE)
public static class OrderResponse {
//订单号
@XmlAttribute(name = "orderid")
private String orderId;
//运单号
@XmlAttribute(name = "mailno")
private String mailNo;
//原寄地区域代码(可用于顺丰电子运单标签打印)
@XmlAttribute(name = "origincode")
private String originCode;
//目的地区域代码(可用于顺丰电子运单标签打印)
@XmlAttribute(name = "destcode")
private String destCode;
//筛单结果:1:人工确认 2:可收派 3:不可以收派
@XmlAttribute(name = "filter_result")
private String filterResult;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getMailNo() {
return mailNo;
}
public void setMailNo(String mailNo) {
this.mailNo = mailNo;
}
public String getOriginCode() {
return originCode;
}
public void setOriginCode(String originCode) {
this.originCode = originCode;
}
public String getDestCode() {
return destCode;
}
public void setDestCode(String destCode) {
this.destCode = destCode;
}
public String getFilterResult() {
return filterResult;
}
public void setFilterResult(String filterResult) {
this.filterResult = filterResult;
}
}
@XmlRootElement(name="RouteResponse")
@XmlAccessorType(XmlAccessType.NONE)
public static class RouteResponse {
//运单号
@XmlAttribute(name = "mailno")
private String mailNo;
//路由
@XmlElement(name = "Route")
private List<Route> Route ;
public String getMailNo() {
return mailNo;
}
public void setMailNo(String mailNo) {
this.mailNo = mailNo;
}
public List<SfExpressResponse.Route> getRoute() {
return Route;
}
public void setRoute(List<SfExpressResponse.Route> route) {
Route = route;
}
}
@XmlRootElement(name="Route")
@XmlAccessorType(XmlAccessType.NONE)
public static class Route {
//路由节点发生的时间
@XmlAttribute(name = "accept_time")
private String acceptTime;
//路由节点具体描述
@XmlAttribute(name = "remark")
private String remark;
//路由节点操作码
@XmlAttribute(name = "opcode")
private String opcode;
public String getAcceptTime() {
return acceptTime;
}
public void setAcceptTime(String acceptTime) {
this.acceptTime = acceptTime;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public String getOpcode() {
return opcode;
}
public void setOpcode(String opcode) {
this.opcode = opcode;
}
}
public String getHead() {
return Head;
}
public void setHead(String head) {
Head = head;
}
public SfExpressResponse.ERROR getERROR() {
return ERROR;
}
public void setERROR(SfExpressResponse.ERROR ERROR) {
this.ERROR = ERROR;
}
public SfExpressResponse.Body getBody() {
return Body;
}
public void setBody(SfExpressResponse.Body body) {
Body = body;
}
}