一、獲取顧客編碼及校驗碼
https://qiao.sf-express.com/index.html 豐橋系統中申請api接口,獲得url(調用地址)、clientCode(顧客編碼)、checkword(校驗碼)。
url:http://bsp-oisp.sf-express.com/bsp-oisp/sfexpressService
二、XML報文說明
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>
三、API接口詳情
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();
}
三、API接口調用
①把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;
}
四、響應XML解析
綜合三個接口的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;
}
}