由於公司外賣業務需要用到順豐的配送體系,技術上需要對接順豐 個人比較感興趣,但是順豐沒有提供sdk,所以研究下自己寫了一個
完整程式碼已上傳github ?:github.com/neatlife/sf…
技術選型
三方sdk編寫有兩種實現方式
- 不依賴框架,更通用,但是整合成本較高
- 依賴框架,比如spring boot,這樣使用起來效率更高
為了提高使用效率,這裡選擇基於spring boot框架進行編寫
前期準備
有很多基於spring boot的sdk了,骨架就不需要自行搭建了,找了下面幾個進行參考
研究api文件
順豐同城api文件地址:commit-openic.sf-express.com/open/api/do…
目前順豐同城的開發者api個人可以註冊,註冊後可以設定回撥地址
找出文件中的關鍵點
在後續設計sdk上,考慮下這些點,可以讓sdk更好用
順豐狀態回撥可能會失敗,通過定時呼叫查詢訂單狀態介面可以補齊狀態
可以實時獲取配送員的座標,這個可用在app上實時顯示配送員位置功能
建立專案
雖然專案是作為和spring boot一起使用的,但是我們並不需要依賴完整的spring boot框架,所以建立一個maven專案就是ok的
指定groupId, ArtifactId
為了享受spring boot的自動配置,需要pom.xml裡面加上spring-boot-autoconfigure庫依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
複製程式碼
加上常用的http,lombok等庫,最終pom檔案內容如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.neatlife</groupId>
<artifactId>sfcity</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.8</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.0.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
複製程式碼
自動配置api的金鑰
把從順豐api後臺獲取的配置資訊寫入配置檔案:src/main/resources/application.properties 所有配置如下
sfcity.developer-id= xxx
sfcity.developer-key= xxx
sfcity.shop-id= xxx
sfcity.api-url= https://commit-openic.sf-express.com
複製程式碼
使用spring boot的自動配置機制,能夠很方便的從配置檔案中讀取配置 核心程式碼如下
@ConfigurationProperties(prefix = "sfcity")
@Data
public class Properties {
private Integer developerId;
private String developerKey;
private String shopId;
private String apiUrl;
}
複製程式碼
參考:
- src/main/java/com/github/neatlife/AutoConfiguration.java
- src/main/java/com/github/neatlife/Properties.java
對映請求引數和響應引數
因為要做一個通用的sdk庫,那麼所有的請求引數和響應引數都需要對映,方便使用
這裡為了演示就拿建立訂單介面舉例了
建立訂單請求實體
響應實體
還有一些關聯的實體一併建立,最終實體效果如下:
http處理工具類
使用resetTemplate進行請求,參考:juejin.im/post/5b88b1… 核心程式碼如下:
public static Response post(Integer appId, String appSecret, String url, Request request) {
String content = JsonUtil.toJsonString(request);
String sign = SignUtil.sign(appId.toString(), appSecret, content);
url = url + "?sign=" + sign;
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
HttpEntity<String> httpEntity = new HttpEntity<>(content, headers);
ResponseEntity<String> httpResponse = restTemplate.postForEntity(url, httpEntity, String.class);
Response response = JsonUtil.toObject(httpResponse.getBody(), Response.class);
if (response.getErrorCode() != 0) {
log.error("errorData: {}", response.getErrorData());
throw new RuntimeException(response.getErrorMsg());
}
return response;
}
複製程式碼
json處理工具類
json處理工具類直接從自己編寫的框架裡拿,參考:github.com/neatlife/jf…
簽名工具類
順豐提供了java的簽名示例程式碼
在其基礎上修改即可,核心程式碼如下
public static String sign(String appId, String appSecret, String content) {
// 假設原始內容JSON為 {"hello":"kitty"}
// content : "{\"hello\":\"kitty\"}"
String toSign = content + "&" + appId + "&" + appSecret;
// toSign : "{\"hello\":\"kitty\"}&1234567890&0123456789abcdef0123456789abcdef";
String md5Result = md5(toSign.getBytes(StandardCharsets.UTF_8));
// md5Result : "ef3435b1480e553480e19e3e162fb0be"
// signResult : "ZWYzNDM1YjE0ODBlNTUzNDgwZTE5ZTNlMTYyZmIwYmU="
return base64Encode(md5Result.getBytes(StandardCharsets.UTF_8));
}
複製程式碼
完整程式碼參考:src/main/java/com/github/neatlife/util/SignUtil.java
定義介面常量
把需要呼叫的介面地址放到統一的常量檔案中,方便管理 核心程式碼如下:
public class ApiUrlConstant {
private static final String CREATE_ORDER_URL = "/open/api/external/createorder";
private static String sfCityHost;
public static String getCreateOrderUrl() {
return sfCityHost + CREATE_ORDER_URL;
}
public static void setSfCityHost(String sfCityHost) {
ApiUrlConstant.sfCityHost = sfCityHost;
}
}
複製程式碼
呼叫順豐建立訂單介面
上面步驟都準備完成後,進行到最重要的呼叫環節了,有了上面的準備,這一步也比較容易了 核心程式碼如下
public CreateOrderResponse createOrder(CreateOrderRequest createOrderRequest) {
createOrderRequest.setDevId(developerId);
createOrderRequest.setShopId(shopId);
Response response = HttpUtil.post(
developerId,
developerKey,
ApiUrlConstant.getCreateOrderUrl(),
createOrderRequest
);
return JsonUtil.toObject(response.getResult(), CreateOrderResponse.class);
}
複製程式碼
編寫自動測試
建立測試檔案:src/test/java/com/github/neatlife/SfClientTest.java 填充測試資料 呼叫建立訂單方法
@Test
public void createOrder() {
CreateOrderResponse createOrderResponse = sfClient.createOrder(createOrderRequest());
Assert.assertNotNull(createOrderResponse.getSfOrderId());
}
private CreateOrderRequest createOrderRequest() {
CreateOrderRequest createOrderRequest = new CreateOrderRequest();
createOrderRequest.setShopOrderId(System.currentTimeMillis() + "");
createOrderRequest.setOrderSource("測試");
createOrderRequest.setPayType(1);
createOrderRequest.setOrderTime(DateUtil.currentSecond().intValue());
createOrderRequest.setIsAppoint(0);
createOrderRequest.setIsInsured(0);
createOrderRequest.setRiderPickMethod(1);
createOrderRequest.setPushTime(DateUtil.currentSecond().intValue());
createOrderRequest.setVersion(17);
createOrderRequest.setShop(
Shop.builder()
.shopName("店鋪名")
.shopPhone("13266666666")
.shopAddress("朝陽區高碑店鎮四惠大廈F1-008")
.shopLng("116.514236")
.shopLat("39.905328")
.build()
);
createOrderRequest.setReceive(
Receive.builder()
.userName("小明")
.userPhone("13288888888")
.userPhone("北京")
.userLng("116.3534196")
.userLat("40.0159778")
.userAddress("朝陽區高碑店鎮四惠大廈F1-008")
.cityName("北京市")
.build()
);
createOrderRequest.setOrderDetail(
OrderDetail.builder()
.totalPrice(100)
.productType(1)
.weightGram(500)
.productNum(1)
.productTypeNum(1)
.productDetail(
Stream.of(
ProductDetail.builder()
.productName("小炒肉")
.productNum(1)
.build()
).collect(Collectors.toList())
)
.build()
);
return createOrderRequest;
}
複製程式碼
填充測試資料時註釋對照順豐文件,保證必填欄位都有值
檢視執行效果:
順豐返回了建立訂單成功的響應?
一些注意的點
自動配置時,把api地址注入介面常量檔案中,方便讀取
http呼叫會有失敗的可能,需要考慮進行請求補償,一般有下面兩種重試方式
- 定時任務,定時進行補償
- 使用訊息佇列的補償機制
建立外賣訂單前,可以先呼叫順豐預建立訂單核查順豐是否會接單
打包
mvn clean package -Dmaven.test.skip=true
檢視效果
然後把jar包拷到需要的專案就可以使用了後續傳到了maven中央倉庫,也可以直接使用maven下載
在spring boot專案中使用jar包
用idea開啟spring boot專案,在專案設定的庫依賴裡引用jar包
然後在啟動類中讓spring boot掃到這個庫,就可以自動配置載入了
其它介面
按照上面建立訂單的步驟編寫+測試即可
上傳maven中央倉庫
參考: blog.csdn.net/ljbmxsm/art…
持續更新...