〇、场景
1、紧接上篇 Java——聚水潭API调用(SDK)Sku商品信息
2、需求:调用聚水潭Orders API接口拉取数据,并存入到本地数据库。
3、技术:Spring Boot + MyBatis-Plus + MySQL
一、SDK调用说明
1、聚水潭开放平台SDK集成了API的请求封装、摘要签名,以及简单的响应解释等功能,使用SDK可以轻松完成API的调用,API结果的获取。
2、SDK只能用于API接口的调用,不能用于授权接口的调用。
通过该链接地址访问SDK详细说明,并下载SDK。链接: link,或访问聚水潭官方文档。
二、Orders订单信息API
环境 | Http请求地址 |
---|---|
正式环境 | https://openapi.jushuitan.com/open/orders/single/query |
测试环境 | https://dev-api.jushuitan.com/open/orders/single/query |
三、将下载后的SDK Jar包添加至项目中
打开 File 菜单,点击 Project Structure,点击 Modules,点击 Dependencies,点击 + 号,选择
JARs or Directories...
,找到下载SDK Jar包,点击OK添加成功
四、上代码
1、pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.13</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
2、MySQL数据表
-- 聚水潭Access_Token
CREATE TABLE access_token (
id BIGINT(20) PRIMARY KEY COMMENT 'id',
expires_in VARCHAR(20) comment 'access_token有效期',
access_token VARCHAR(255) comment '访问令牌',
scope VARCHAR(20) comment '固定值all',
refresh_token VARCHAR(255) comment '更新令牌',
expiration_time VARCHAR(20) comment '过期时间'
);
-- 聚水潭订单
CREATE TABLE orders (
id VARCHAR(20) PRIMARY KEY COMMENT 'id',
o_id VARCHAR(30) comment '聚水潭订单号',
so_id VARCHAR(30) comment '线上订单号',
l_id VARCHAR(30) comment '快递单号',
order_date VARCHAR(30) comment '订单日期',
type VARCHAR(25) comment '订单类型',
shop_id VARCHAR(30) comment '店铺编号',
shop_name VARCHAR(30) comment '店铺名称',
order_from VARCHAR(25) comment '订单来源',
order_status VARCHAR(25) comment '订单状态',
shop_status VARCHAR(25) comment '平台订单状态',
co_id VARCHAR(20) comment '公司编号',
lc_id VARCHAR(20) comment '物流公司编号',
logistics_company VARCHAR(20) comment '快递公司',
wms_co_id VARCHAR(20) comment '发货仓编码',
pay_amount DOUBLE comment '应付金额',
paid_amount DOUBLE comment '实际支付金额',
modified VARCHAR(30) comment '修改时间',
longTime LONG comment '长时间',
referrer_id VARCHAR(30) comment '主播id',
labels VARCHAR(200) comment '标签',
remark VARCHAR(500) comment '备注',
create_date VARCHAR(30) comment '创建日期',
isSyn TINYINT(1) comment '是否同步'
);
-- 聚水潭订单明细
CREATE TABLE orders_detail (
id VARCHAR(20) PRIMARY KEY COMMENT 'id',
seq BIGINT(20) comment '序号',
parent_id VARCHAR(20) comment '父id',
o_id VARCHAR(30) comment '聚水潭订单号',
sku_id VARCHAR(30) comment '商品编码',
sku_name VARCHAR(100) comment '商品名称',
is_gift TINYINT(1) comment '是否赠品',
base_price DOUBLE comment '基本售价(原价)',
price DOUBLE comment '单价',
amount DOUBLE comment '金额',
qty DOUBLE comment '数量'
);
-- 日志
CREATE TABLE log (
id BIGINT(20) PRIMARY KEY COMMENT 'id',
requestTime VARCHAR(20) comment '请求时间',
msg VARCHAR(255) comment '日志信息'
);
3、使用MyBatis-Plus生成entity、mapper、service文件,这里entity和mapper文件就不展示出来了。
- AccessTokenSerivce.java
import com.xjmy.jushuitan.entity.AccessToken;
import com.xjmy.jushuitan.mapper.AccessTokenMapper;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.Date;
@Service
public class AccessTokenService {
@Autowired
AccessTokenMapper accessTokenMapper;
/**
* 插入数据
* @param jsonObject JSON数据
*/
public void insertData(JSONObject jsonObject) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
AccessToken accessToken = new AccessToken();
accessToken.setAccessToken(jsonObject.getString("access_token")); //访问令牌
accessToken.setRefreshToken(jsonObject.getString("refresh_token")); //更新令牌
accessToken.setScope(jsonObject.getString("scope")); //固定值all
accessToken.setExpiresIn(jsonObject.getString("expires_in")); //access_token有效期
Long expirationTime = System.currentTimeMillis() / 1000 + Long.valueOf(jsonObject.getString("expires_in")) - 3600;
//过期时间设置提前设置1小时
Date date = new Date(expirationTime * 1000);
accessToken.setExpirationTime(sdf.format(date)); //过期时间
//保存到数据库
accessTokenMapper.insert(accessToken);
System.out.println("access_token数据保存成功!");
}
/**
* 查询AccessToken
* @return
*/
public String selectAccessToken() {
AccessToken accessToken = accessTokenMapper.selectOne(null);
return accessToken.getAccessToken();
}
/**
* 查询RefreshToken
* @return
*/
public String selectRefreshToken() {
AccessToken accessToken = accessTokenMapper.selectOne(null);
return accessToken.getRefreshToken();
}
/**
* 删除AccessToken
*/
public void deleteAccessToken() {
accessTokenMapper.delete(null);
}
/**
* 查询一条数据
*/
public AccessToken selectOne() {
AccessToken accessTokenObj = accessTokenMapper.selectOne(null);
return accessTokenObj;
}
}
- ApiService.java
import com.jushuitan.api.*;
import com.jushuitan.api.util.AuthUtil;
import com.xjmy.jushuitan.utils.OtherUtils;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @Description: 聚水潭API
*/
@Service
public class ApiService {
@Autowired
AccessTokenService accessTokenService;
@Autowired
LogService logService;
/**
* @param url 具体API URL地址
* @param biz 参数
*/
public String requestApi(String url, String biz) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String result = "";
// 实例化client
ApiClient client = new DefaultApiClient();
// 设置超时时间
((DefaultApiClient)client).setReadTimeout(3000);
((DefaultApiClient)client).setConnectTimeout(2000);
// 替换为POP分配给应用的app_key,app_secret,accessToken等
String appKey = "";
String appSecret = "";
ApiResponse response = null; //API响应结果
// 执行接口调用
try {
// 构建请求对象
ApiRequest request = new ApiRequest.Builder(url, appKey, appSecret).biz(biz).build();
// 查询数据库中accessToken
String accessToken = accessTokenService.selectAccessToken();
if (!StringUtils.isEmpty(accessToken)) {
response = client.execute(request, accessToken);
JSONObject responseJson = JSONObject.fromObject(response.getBody());
// 判断该accessToken是否失效,失效则调用refreshToken()刷新accessToken
if (responseJson.getInt("code") == 100) {
// 获取存在数据库中的 refreshToken
String refreshToken = accessTokenService.selectRefreshToken();
// 构建获取AccessToken请求对象
AuthRequest authRequest = new AuthRequest.Builder(appKey,appSecret).code(OtherUtils.get6UUID()).refreshToken(refreshToken).build();
// 刷新AccessToken
String accessTokenInfo = AuthUtil.refreshToken(authRequest);
JSONObject accessTokenJson = JSONObject.fromObject(accessTokenInfo);
if ("0".equals(accessTokenJson.getString("code"))) {
String data = accessTokenJson.getString("data");
JSONObject dataJson = JSONObject.fromObject(data);
accessToken = dataJson.getString("access_token");
// 清空access_token表数据
accessTokenService.deleteAccessToken();
// 重新新增数据
accessTokenService.insertData(dataJson);
}
response = client.execute(request, accessToken);
}
} else {
AuthRequest authRequest = new AuthRequest.Builder(appKey,appSecret).code(OtherUtils.get6UUID()).build();
String initAccessToken = AuthUtil.getInitToken(authRequest);
JSONObject initAccessTokenJson = JSONObject.fromObject(initAccessToken);
if ("0".equals(initAccessTokenJson.getString("code"))) {
String data = initAccessTokenJson.getString("data");
JSONObject dataJson = JSONObject.fromObject(data);
accessToken = dataJson.getString("access_token");
// 重新新增数据
accessTokenService.insertData(dataJson);
}
response = client.execute(request, accessToken);
}
result = response.getBody();
} catch (Exception e) {
String requestTime = sdf.format(new Date());
String msg = e.getMessage();
logService.insertData(requestTime,msg);
}
return result;
}
}
- OtherUtils.java
import java.util.UUID;
public class OtherUtils {
/**
* 获取6位UUID字符串
* @return
*/
public static String get6UUID() {
String uuid = UUID.randomUUID().toString();
String randomString = uuid.replaceAll("-", "").substring(0, 6);
return randomString;
}
/**
* 获得20个长度的十六进制的UUID
* @return UUID
*/
public static String get20UUID(){
UUID id=UUID.randomUUID();
String[] idd=id.toString().split("-");
return idd[0]+idd[1]+idd[2]+idd[3];
}
/**
* 获得12个长度的十六进制的UUID
* @return UUID
*/
public static String get12UUID(){
UUID id=UUID.randomUUID();
String[] idd=id.toString().split("-");
return idd[0]+idd[1];
}
}
- OrdersService.java
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.xjmy.jushuitan.entity.Orders;
import com.xjmy.jushuitan.entity.OrdersDetail;
import com.xjmy.jushuitan.entity.Sku;
import com.xjmy.jushuitan.mapper.OrdersDetailMapper;
import com.xjmy.jushuitan.mapper.OrdersMapper;
import com.xjmy.jushuitan.mapper.SkuMapper;
import com.xjmy.jushuitan.utils.OtherUtils;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
@Slf4j
@Service
public class OrdersService {
@Autowired
OrdersMapper ordersMapper;
@Autowired
OrdersDetailMapper ordersDetailMapper;
@Autowired
SkuMapper skuMapper;
@Autowired
ApiService apiService;
@Autowired
LogService logService;
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static final SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");
/**
* 执行
* @param modified_begin 修改开始日期
* @param modified_end 修改结束日期
*/
public void apiThread(String modified_begin,String modified_end) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String url = "https://openapi.jushuitan.com/open/orders/single/query";// 正式地址
Integer page_index = 1;
Integer page_size = 50;
//JSON参数
JSONObject paramsJson = new JSONObject();
paramsJson.put("page_index",page_index); //页码
paramsJson.put("page_size",page_size);//每页多少条数据
paramsJson.put("modified_begin",modified_begin);//修改开始时间
paramsJson.put("modified_end",modified_end);//修改结束时间
paramsJson.put("date_type",3); //(0:修改时间modified,2:订单日期order_date,3:发货时间send_date;非必填,默认0)
paramsJson.put("status","Sent");//订单状态:已发货
String biz = paramsJson.toString();
try {
// 获取API接口返回报文
String apiResult = apiService.requestApi(url,biz);
if (!StringUtils.isEmpty(apiResult)) {
// 将报文字符串转成JSON
JSONObject resultJson = JSONObject.fromObject(apiResult);
// 判断该API返回报文结果是否是调用API成功
if ("执行成功".equals(resultJson.getString("msg")) && resultJson.getInt("code") == 0) {
// 解析第一层data
String dataStr = resultJson.getString("data");
JSONObject dataJson = JSONObject.fromObject(dataStr);
// 页数
int page_count = dataJson.getInt("page_count");
// 数据量
int data_count = dataJson.getInt("data_count");
for (int j = 1;j <= page_count;j++) {
//JSON参数
paramsJson = new JSONObject();
paramsJson.put("page_index",j); //页码
paramsJson.put("page_size",page_size);//每页多少条数据
paramsJson.put("modified_begin",modified_begin);//修改开始时间
paramsJson.put("modified_end",modified_end);//修改结束时间
paramsJson.put("date_type",3); //(0:修改时间modified,2:订单日期order_date,3:发货时间send_date;非必填,默认0)
paramsJson.put("status","Sent");//订单状态:已发货
biz = paramsJson.toString();
// 获取API接口返回报文
apiResult = apiService.requestApi(url,biz);
resultJson = JSONObject.fromObject(apiResult);
if ("执行成功".equals(resultJson.getString("msg")) && resultJson.getInt("code") == 0) {
// 解析第一层data
dataStr = resultJson.getString("data");
dataJson = JSONObject.fromObject(dataStr);
// 解析第二层orders
String ordersData = dataJson.getString("orders");
JSONArray ordersArrays = JSONArray.fromObject(ordersData);
for (int i = 0;i < ordersArrays.size();i++){
JSONObject orderJson = ordersArrays.getJSONObject(i);
System.out.println("聚水潭单号"+i+":"+orderJson.getString("o_id"));
System.out.println("线上单号"+i+":"+orderJson.getString("so_id"));
//新增订单
insertOrders(orderJson);
}
}
}
log.info("Orders订单数据拉取成功! 拉取期间:{}——{},数据量:{}",modified_begin,modified_end,data_count);
log.info("===========================================================");
} else {
String requestTime = sdf.format(new Date());
String msg = resultJson.getInt("code") + ";" + resultJson.getString("msg");
logService.insertData(requestTime,"同步Orders订单任务失败,错误信息:" + msg);
}
}
} catch (Exception e) {
String requestTime = sdf.format(new Date());
logService.insertData(requestTime,"同步Orders订单任务异常,异常信息:" + e.getMessage());
}
}
/**
* 新增订单信息
*/
public void insertOrders(JSONObject jsonObj) throws Exception {
//查询该订单是否存在
QueryWrapper<Orders> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("o_id",jsonObj.getString("o_id"));
Orders orders = ordersMapper.selectOne(queryWrapper);
if (orders != null) {
return;
}
String id = OtherUtils.get20UUID(); //UUID
String items = jsonObj.getString("items"); //解析JSON字符串
JSONArray itemsArrays = JSONArray.fromObject(items);
int row = 0;
for (int i = 0;i < itemsArrays.size();i++) {
JSONObject itemsJson = itemsArrays.getJSONObject(i);
//新增订单明细详情
row = insertOrdersDetail(itemsJson, i, id);
}
if (row == 0) { //新增订单详情中如商品在数据库中不存在,则该订单不存入数据库中
return;
}
//新增订单
insertOrdersBill(jsonObj,id);
}
/**
* 新增订单信息
* @param jsonObj 数据来源
* @param id id
* @throws Exception
*/
public void insertOrdersBill(JSONObject jsonObj,String id) throws Exception {
Orders newOrders = new Orders();
newOrders.setId(id);//id
newOrders.setOId(jsonObj.getString("o_id"));//聚水潭订单号
newOrders.setSoId(jsonObj.getString("so_id"));//线上订单号
newOrders.setLId(jsonObj.getString("l_id"));//快递单号
newOrders.setOrderDate(jsonObj.getString("order_date"));//订单日期
newOrders.setType(jsonObj.getString("type"));//订单类型
newOrders.setOrderFrom(jsonObj.getString("order_from"));//订单来源
newOrders.setOrderStatus(jsonObj.getString("status"));//订单状态
newOrders.setShopStatus(jsonObj.getString("shop_status"));//平台订单状态
newOrders.setShopId(jsonObj.getString("shop_id"));//店铺编号
newOrders.setShopName(jsonObj.getString("shop_name"));//店铺名称
newOrders.setCoId(jsonObj.getString("co_id"));//公司编号
newOrders.setLcId(jsonObj.getString("lc_id"));//物流公司编号
newOrders.setWmsCoId(jsonObj.getString("wms_co_id"));//发货仓编号
newOrders.setLogisticsCompany(jsonObj.getString("logistics_company"));//快递公司
newOrders.setPayAmount(jsonObj.getDouble("pay_amount"));//应付金额
newOrders.setPaidAmount(jsonObj.getDouble("paid_amount"));//实际支付金额
newOrders.setModified(jsonObj.getString("modified"));//修改时间
Long modifiedTime = sdf.parse(jsonObj.getString("modified")).getTime();
newOrders.setLongtime(modifiedTime.toString()); //时间戳
newOrders.setReferrerId(jsonObj.getString("referrer_id"));//主播id
newOrders.setLabels(jsonObj.getString("labels"));//标签
newOrders.setRemark(jsonObj.getString("remark"));//备注
newOrders.setIssyn(false);//是否同步
newOrders.setCreateDate(sdf2.format(new Date()));//创建日期
ordersMapper.insert(newOrders);
}
/**
* 新增订单详情
*/
public int insertOrdersDetail(JSONObject jsonObj,int seq,String parentID) {
String sku_id = jsonObj.getString("sku_id");
//判断该订单详情中的商品是否在本地数据库SKU商品表中存在,不存在则该订单不拉取存入数据库中
QueryWrapper<Sku> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("sku_id", sku_id);
Sku sku = skuMapper.selectOne(queryWrapper);
if (sku == null) {
return 0;
}
OrdersDetail ordersDetail = new OrdersDetail();
String id = OtherUtils.get12UUID();
ordersDetail.setId(id);//
ordersDetail.setSeq((long) seq+1);//序号
ordersDetail.setParentId(parentID);//父id
ordersDetail.setOId(jsonObj.getString("o_id"));//聚水潭订单号
ordersDetail.setSkuId(jsonObj.getString("sku_id"));//原始商品编码
ordersDetail.setSkuName(jsonObj.getString("name"));//原始商品名称
ordersDetail.setIsGift(jsonObj.getBoolean("is_gift"));//是否赠品
ordersDetail.setBasePrice(jsonObj.getDouble("base_price"));//基本售价(原价)
ordersDetail.setPrice(jsonObj.getDouble("price"));//单价
ordersDetail.setAmount(jsonObj.getDouble("amount"));//金额
ordersDetail.setQty(jsonObj.getDouble("qty"));//数量
return ordersDetailMapper.insert(ordersDetail);
}
}
- Test.java
@Test
void contextLoads() {
String startDate = "2024-03-13 16:05:00";
String endDate = "2024-03-13 16:06:00";
ordersService.apiThread(startDate,endDate);
}
- 返回结果
本人也是初次调用聚水潭API,代码并不完美,提供参考。