记录对接京东宙斯API -- 同步订单信息到自身系统
- 目录
- 1. 需求
- 2. 准备工作一: 查看官方文档
- 3. 准备工作二: 申请京东云鼎并入驻
- 4. 创建一个新的项目并部署到云鼎.
- 5. 调用订单API代码.
- 6. JdService
目录
1. 需求
根据产品大大的需求描述:
- 对客户的京东旗舰店里的订单信息同步到自身开发的后台管理中.
- 实现对订单信息简单的搜索功能.
- 实现人工同步的功能.
2. 准备工作一: 查看官方文档
PS: 在寻找AIP时, 可根据需求的不同, 寻找对应的API文档.
找到官方API时, 当时的我感觉调用订单API的方式应该和其他API是一样的, 有了京东宙斯账号就可以, 但…实践调用以后, 很明显我错了.
在调用订单API时, 它返回了一个错误信息给我: 该api是敏感api,请将您的app入驻云鼎平台方可调用
返回的这条信息很明显的告诉我, 要我去申请京东云鼎平台的账号,并且还要入驻.
PS: 入驻云鼎是要钱的, 因为要购买云主机.
3. 准备工作二: 申请京东云鼎并入驻
入驻京东云鼎的具体流程这里我就展开讲述了, 官方有一套很完善的流程.
这是京东官方入驻云鼎的流程, 如果有感兴趣的小伙伴想了解一下可以点击这个链接: 入鼎公告
至此, 准备工作完成.
4. 创建一个新的项目并部署到云鼎.
PS: 之所以要创建一个新的项目并部署到云鼎, 是因为订单API是属于敏感类型的, 只能内部调用.
5. 调用订单API代码.
京东官方订单API文档
/*** @Author 蠕动的小蜗牛* @Description 根据条件检索订单信息 (仅适用于SOP、LBP,SOPL类型,FBP类型请调取FBP订单检索 jingdong.pop.order.search)* @Date 16:45 2019/8/13* @Param [accessToken, startDateStr, endDateStr]* @Param [accessToken, 开始时间, 结束时间, 订单状态, 返回字段, 查询类型, 当前页, 页大小]* @return com.jd.open.api.sdk.domain.order.OrderQueryJsfService.response.enSearch.OrderListResult**/public OrderListResult findAllOrderData(String accessToken, String startDateStr, String endDateStr,String orderState, String optionalFields, Integer dateType,String page, String pageSize){try {JdClient client = new DefaultJdClient(SERVER_URL, accessToken, APPKEY, APPSECRET);PopOrderEnSearchRequest request = new PopOrderEnSearchRequest();/** WAIT_SELLER_STOCK_OUT 等待出库,则start_date可以为否(开始时间和结束时间均为空,默认返回前一个月的订单),order_state为其他值,则start_date必须为是(开始时间和结束时间,不得相差超过1个月。此时间仅针对订单状态及运单号修改的时间) */request.setStartDate(startDateStr);/** WAIT_SELLER_STOCK_OUT 等待出库,则start_date可以为否(开始时间和结束时间均为空,默认返回前一个月的订单),order_state为其他值,则start_date必须为是(开始时间和结束时间,不得相差超过1个月。此时间仅针对订单状态及运单号修改的时间) */request.setEndDate(endDateStr);/** 多订单状态可以用英文逗号隔开,请用英文逗号拼接英文状态传递给jos,而不是数字。1)WAIT_SELLER_STOCK_OUT 等待出库2)WAIT_GOODS_RECEIVE_CONFIRM 等待确认收货3)WAIT_SELLER_DELIVERY 等待发货(只适用于海外购商家,含义为'等待境内发货'标签下的订单,非海外购商家无需使用)4) PAUSE 暂停(loc订单可通过此状态获取)5)FINISHED_L 完成6)TRADE_CANCELED 取消7)LOCKED 已锁定8)POP_ORDER_PAUSE pop业务暂停,如3c号卡/履约/黄金 可传此状态。*/request.setOrderState(orderState); // 测试接口阶段, 查询 已取消的订单/** 需返回的字段列表。可选值,请参考返回结果集中的对象参数描述:orderInfo结构体中的所有字段;字段之间用,分隔 */request.setOptionalFields(optionalFields);/** 查询的页数 */request.setPage(page);/** 每页的条数(最大page_size 100条) */request.setPageSize(pageSize);/** 排序方式,默认升序,1是降序,其它数字都是升序 */request.setSortType(1);/** 查询时间类型,默认按修改时间查询。 1为按订单创建时间查询;其它数字为按订单(订单状态、修改运单号)修改时间 */request.setDateType(dateType);PopOrderEnSearchResponse response = client.execute(request);LOGGER.warn(" 京东旗舰店订单信息: " + JSONUtils.toJsonString(response));if (response.getSearchorderinfoResult() != null) {LOGGER.warn("************ 查询京东旗舰店订单信息成功 ************");OrderListResult searchorderinfoResult = response.getSearchorderinfoResult();return searchorderinfoResult;}} catch (Exception e) {LOGGER.error("************ 查询京东旗舰店订单信息失败 ************", e);e.printStackTrace();}return null;}
6. JdService
package XXXX;import com.alibaba.fastjson.JSONObject;
import com.jd.open.api.sdk.DefaultJdClient;
import com.jd.open.api.sdk.JdClient;
import com.jd.open.api.sdk.domain.delivery.DeliveryCompany;
import com.jd.open.api.sdk.domain.order.OrderNotPayService.response.notPayOrderInfo.OrderDataNotPayInfo;
import com.jd.open.api.sdk.domain.order.OrderNotPayService.response.notPayOrderInfo.PaginatedInfo;
import com.jd.open.api.sdk.domain.order.OrderQueryJsfService.response.enSearch.OrderListResult;
import com.jd.open.api.sdk.domain.order.OrderQueryJsfService.response.get.OrderResult;
import com.jd.open.api.sdk.domain.order.OrderQueryJsfService.response.get.OrderSearchInfo;
import com.jd.open.api.sdk.domain.order.OrderShipmentService.response.shipment.OperatorResult;
import com.jd.open.api.sdk.request.delivery.GetVenderAllDeliveryCompanyRequest;
import com.jd.open.api.sdk.request.imgzone.ImgzoneCategoryQueryRequest;
import com.jd.open.api.sdk.request.imgzone.ImgzonePictureUploadRequest;
import com.jd.open.api.sdk.request.order.PopOrderEnSearchRequest;
import com.jd.open.api.sdk.request.order.PopOrderGetRequest;
import com.jd.open.api.sdk.request.order.PopOrderNotPayOrderInfoRequest;
import com.jd.open.api.sdk.request.order.PopOrderShipmentRequest;
import com.jd.open.api.sdk.response.delivery.GetVenderAllDeliveryCompanyResponse;
import com.jd.open.api.sdk.response.imgzone.ImgzoneCategory;
import com.jd.open.api.sdk.response.imgzone.ImgzoneCategoryQueryResponse;
import com.jd.open.api.sdk.response.imgzone.ImgzonePictureUploadResponse;
import com.jd.open.api.sdk.response.order.PopOrderEnSearchResponse;
import com.jd.open.api.sdk.response.order.PopOrderGetResponse;
import com.jd.open.api.sdk.response.order.PopOrderNotPayOrderInfoResponse;
import com.jd.open.api.sdk.response.order.PopOrderShipmentResponse;
import XXX.Config;
import XXX.JSONUtils;
import XXX.CollectionUtils;
import XXX.DateUtils;
import XXX.HttpUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.net.URLEncoder;
import java.util.*;/*** @ClassName JdService* @Description: 京东API接口相关* @Auther: 蠕动的小蜗牛* @Date: 2019/4/16 16:05* @Version: 1.0**/
@Service
public class JdService {private static final Logger LOGGER = LoggerFactory.getLogger(JdService.class);/*** appKey*/private String APPKEY = "XXX";/*** AppSecret*/private String APPSECRET = "XXX";/*** 接口版本*/private String V = "2.0";/*** 接口URL(线上)*/private String SERVER_URL = "https://api.jd.com/routerjson";@Resourceprivate Config config;/*** @Author 蠕动的小蜗牛* @Description sop出库发货接口 (jingdong.pop.order.shipment)* @Date 10:32 2019/8/17* @Param [accessToken, orderId, logiCoprId, logiNo, installId]* @Param [accessToken, 订单号, 物流公司ID, 运单号, 安装公司]* @return 0 发货失败, 1 发货成功**/public Boolean doShipment(String accessToken, Long orderId, String logiCoprId, String logiNo, Long installId){try {JdClient client = new DefaultJdClient(SERVER_URL, accessToken, APPKEY, APPSECRET);PopOrderShipmentRequest request = new PopOrderShipmentRequest();request.setOrderId(orderId);/** 物流公司ID(只可通过获取商家物流公司接口获得),多个物流公司以|分隔。如:2100|4700。请注意:如果填写厂家自送(1274),则不会保存物流单号,也不会有具体的跟踪信息。 request.setLogiCoprId("2100|4700") */request.setLogiCoprId(logiCoprId);/** 运单号(当厂家自送时运单号可为空,不同物流公司的运单号用|分隔,如果同一物流公司有多个运单号,则用英文逗号分隔) 。如:1200458628372,111232|468778814888,323232323request.setLogiNo("1200458628372,111232|468778814888,323232323 "); */request.setLogiNo(logiNo);request.setInstallId(installId);PopOrderShipmentResponse response = client.execute(request);LOGGER.warn("************* sop出库发货接口: " + JSONUtils.toJsonString(response));OperatorResult sopjosshipmentResult = response.getSopjosshipmentResult();if (sopjosshipmentResult != null) {return sopjosshipmentResult.getSuccess();}return false;} catch (Exception e) {e.printStackTrace();}return false;}/*** @Author 蠕动的小蜗牛* @Description 获取商家物流公司* @Date 11:46 2019/8/17* @Param [accessToken]* @return void**/public List<DeliveryCompany> findAllJdCompanyData(String accessToken){try {JdClient client = new DefaultJdClient(SERVER_URL, accessToken, APPKEY, APPSECRET);GetVenderAllDeliveryCompanyRequest request = new GetVenderAllDeliveryCompanyRequest();request.setFields("id,name,description");GetVenderAllDeliveryCompanyResponse response = client.execute(request);LOGGER.warn("获取商家物流公司: " + JSONUtils.toJsonString(response));List<DeliveryCompany> deliveryList = response.getDeliveryList();if (CollectionUtils.notEmpty(deliveryList)) return deliveryList;} catch (Exception e) {e.printStackTrace();}return null;}/*** @Author 蠕动的小蜗牛* @Description 输入单个SOP订单id,得到所有相关订单信息 (jingdong.pop.order.get) 拼接URI* @Date 16:03 2019/8/14* @Param [accessToken, optionalFields, orderId]* @Param [accessToken, 返回字段, orderId]* @return com.jd.open.api.sdk.domain.order.OrderQueryJsfService.response.get.OrderSearchInfo**/public JSONObject findOrderData(String accessToken, String optionalFields, Long orderId, String pin){// 生成签名String method = "jingdong.pop.order.get";String timestamp = DateUtils.convertDate2String(null, new Date());Map<String, Object> map = new HashMap<>();map.put("optional_fields", optionalFields);map.put("order_id", orderId);map.put("pin", pin);String requestParam = JSONUtils.toJsonString(map);HashMap<String, Object> params = new HashMap<>();params.put("v", V);params.put("method", method);params.put("timestamp", timestamp);params.put("app_key", APPKEY);params.put("app_secret", APPSECRET);params.put("access_token", accessToken);params.put("360buy_param_json", map);String sign = jdSign(params);try {// 拼接URLString url = SERVER_URL + "?v=" + V +"&method=" + method +"&app_key=" + APPKEY +"&access_token=" + accessToken +"&360buy_param_json=" + URLEncoder.encode(requestParam, "UTF-8") +"×tamp=" + URLEncoder.encode(timestamp, "UTF-8") +"&sign=" + sign;JSONObject jsonObject = HttpUtils.doGetJson(url);LOGGER.warn("===============京东API 输入单个SOP订单id,得到所有相关订单信息: " + jsonObject.toString() + "=====================");return jsonObject;} catch (Exception e) {LOGGER.warn("=============== 京东API 输入单个SOP订单id,得到所有相关订单信息!!! =====================");e.printStackTrace();}return null;}/*** @Author 蠕动的小蜗牛* @Description 输入单个SOP订单id,得到所有相关订单信息 (jingdong.pop.order.get)* @Date 16:03 2019/8/14* @Param [accessToken, optionalFields, orderId]* @Param [accessToken, 返回字段, orderId]* @return com.jd.open.api.sdk.domain.order.OrderQueryJsfService.response.get.OrderSearchInfo**/public OrderResult findOrderDetailsData(String accessToken, String optionalFields, Long orderId){try {JdClient client = new DefaultJdClient(SERVER_URL, accessToken, APPKEY, APPSECRET);PopOrderGetRequest request = new PopOrderGetRequest();
// request.setOrderState("WAIT_SELLER_DELIVERY"); // 不是必填if (StringUtils.isBlank(optionalFields)) optionalFields = "pin";request.setOptionalFields(optionalFields);request.setOrderId(orderId); // 订单号,并且有效的订单号PopOrderGetResponse response = client.execute(request);LOGGER.warn("输入单个SOP订单id,得到所有相关订单信息: " + JSONUtils.toJsonString(response));OrderResult orderDetailInfo = response.getOrderDetailInfo();if (orderDetailInfo != null) return orderDetailInfo;} catch (Exception e) {LOGGER.warn("****************** 输入单个SOP订单id,得到所有相关订单信息失败 *****************");e.printStackTrace();}return null;}/*** @Author 蠕动的小蜗牛* @Description 批量查询未付款订单(jingdong.pop.order.notPayOrderInfo)* @Date 15:22 2019/8/14* @Param [accessToken, startDateStr, endDateStr, page, pageSize]* @Param [accessToken, 开始时间, 结束时间, 当前页, 页大小]* @return java.util.List<com.jd.open.api.sdk.domain.order.OrderNotPayService.response.notPayOrderInfo.OrderDataNotPayInfo>**/public List<OrderDataNotPayInfo> findWaitPayOrderData(String accessToken, Date startDateStr, Date endDateStr,Integer page, Integer pageSize){try {JdClient client = new DefaultJdClient(SERVER_URL, accessToken, APPKEY, APPSECRET);PopOrderNotPayOrderInfoRequest request = new PopOrderNotPayOrderInfoRequest();request.setStartDate(startDateStr);request.setEndDate(endDateStr);request.setPage(page);request.setPageSize(pageSize);PopOrderNotPayOrderInfoResponse response = client.execute(request);LOGGER.warn("***************** 批量查询未付款订单: " + JSONUtils.toJsonString(response));PaginatedInfo paginatedInfo = response.getPaginatedInfo();if (paginatedInfo != null) {List<OrderDataNotPayInfo> pageList = paginatedInfo.getPageList();if (CollectionUtils.notEmpty(pageList)) return pageList;}} catch (Exception e) {LOGGER.warn("***************** 批量查询未付款订单失败 *****************");e.printStackTrace();}return null;}/*** @Author 蠕动的小蜗牛* @Description 根据条件检索订单信息 (仅适用于SOP、LBP,SOPL类型,FBP类型请调取FBP订单检索 jingdong.pop.order.search)* @Date 16:45 2019/8/13* @Param [accessToken, startDateStr, endDateStr]* @Param [accessToken, 开始时间, 结束时间, 订单状态, 返回字段, 查询类型, 当前页, 页大小]* @return com.jd.open.api.sdk.domain.order.OrderQueryJsfService.response.enSearch.OrderListResult**/public OrderListResult findAllOrderData(String accessToken, String startDateStr, String endDateStr,String orderState, String optionalFields, Integer dateType,String page, String pageSize){try {JdClient client = new DefaultJdClient(SERVER_URL, accessToken, APPKEY, APPSECRET);PopOrderEnSearchRequest request = new PopOrderEnSearchRequest();/** WAIT_SELLER_STOCK_OUT 等待出库,则start_date可以为否(开始时间和结束时间均为空,默认返回前一个月的订单),order_state为其他值,则start_date必须为是(开始时间和结束时间,不得相差超过1个月。此时间仅针对订单状态及运单号修改的时间) */request.setStartDate(startDateStr);/** WAIT_SELLER_STOCK_OUT 等待出库,则start_date可以为否(开始时间和结束时间均为空,默认返回前一个月的订单),order_state为其他值,则start_date必须为是(开始时间和结束时间,不得相差超过1个月。此时间仅针对订单状态及运单号修改的时间) */request.setEndDate(endDateStr);/** 多订单状态可以用英文逗号隔开,请用英文逗号拼接英文状态传递给jos,而不是数字。1)WAIT_SELLER_STOCK_OUT 等待出库2)WAIT_GOODS_RECEIVE_CONFIRM 等待确认收货3)WAIT_SELLER_DELIVERY 等待发货(只适用于海外购商家,含义为'等待境内发货'标签下的订单,非海外购商家无需使用)4) PAUSE 暂停(loc订单可通过此状态获取)5)FINISHED_L 完成6)TRADE_CANCELED 取消7)LOCKED 已锁定8)POP_ORDER_PAUSE pop业务暂停,如3c号卡/履约/黄金 可传此状态。*/request.setOrderState(orderState); // 测试接口阶段, 查询 已取消的订单/** 需返回的字段列表。可选值,请参考返回结果集中的对象参数描述:orderInfo结构体中的所有字段;字段之间用,分隔 */request.setOptionalFields(optionalFields);/** 查询的页数 */request.setPage(page);/** 每页的条数(最大page_size 100条) */request.setPageSize(pageSize);/** 排序方式,默认升序,1是降序,其它数字都是升序 */request.setSortType(1);/** 查询时间类型,默认按修改时间查询。 1为按订单创建时间查询;其它数字为按订单(订单状态、修改运单号)修改时间 */request.setDateType(dateType);PopOrderEnSearchResponse response = client.execute(request);LOGGER.warn(" 京东旗舰店订单信息: " + JSONUtils.toJsonString(response));if (response.getSearchorderinfoResult() != null) {LOGGER.warn("************ 查询京东旗舰店订单信息成功 ************");OrderListResult searchorderinfoResult = response.getSearchorderinfoResult();return searchorderinfoResult;}} catch (Exception e) {LOGGER.error("************ 查询京东旗舰店订单信息失败 ************", e);e.printStackTrace();}return null;}/*** @Author 蠕动的小蜗牛* @Description 上传单张图片* @Date 11:29 2019/7/17* @Param [accessToken, imageData, pictureCateId, pictureName]* @Param [accessToken, 图片二进制文件流,允许png、jpg、gif、jpeg、bmp图片格式,1M以内,* 上传到的图片分类ID,为空上传至 默认分类,* 图片名称,不超过64字节,为空默认 未命名]* @return com.alibaba.fastjson.JSONObject**/public ImgzonePictureUploadResponse pictureUpload(String accessToken, byte[] imageData, Long pictureCateId, String pictureName){try {JdClient client = new DefaultJdClient(SERVER_URL, accessToken, APPKEY, APPSECRET);ImgzonePictureUploadRequest request = new ImgzonePictureUploadRequest();request.setImageData(imageData);request.setPictureCateId(pictureCateId);request.setPictureName(pictureName);ImgzonePictureUploadResponse response = client.execute(request);LOGGER.warn("===============京东API 上传单张图片: " + JSONUtils.toJsonString(response) + "=====================");return response;} catch (Exception e) {e.printStackTrace();}return null;}/*** @Author 蠕动的小蜗牛* @Description 查询图片分类(所有参数为非必填, 不填时查询所有)* @Date 14:04 2019/7/17* @Param [accessToken, cateId, cateName, parentCateId]* @Param [accessToken, 分类ID, 分类名称,不支持模糊查询, 父分类ID,查询二级分类时为对应父分类id,查询一级分类时为0,查询全部分类的时候为空]* @return com.jd.open.api.sdk.response.imgzone.ImgzoneCategoryQueryResponse**/public List<ImgzoneCategory> imgzoneCategoryQuery(String accessToken, Long cateId, String cateName, Long parentCateId) {try {JdClient client = new DefaultJdClient(SERVER_URL, accessToken, APPKEY, APPSECRET);ImgzoneCategoryQueryRequest request = new ImgzoneCategoryQueryRequest();request.setCateId(cateId);request.setCateName(cateName);request.setParentCateId(parentCateId);ImgzoneCategoryQueryResponse response = client.execute(request);List<ImgzoneCategory> cateList = response.getCateList();if (CollectionUtils.notEmpty(cateList)) {return cateList;}} catch (Exception e) {e.printStackTrace();}return null;}/*** @Author 蠕动的小蜗牛* @Description 京东签名规则* 1. 所有请求参数按照字母先后顺序排列. 例如: 将access_token,app_key,method,timestamp,v 排序为access_token,app_key,method,timestamp,v* 2. 把所有参数名和参数值进行拼装. 例如:access_tokenxxxapp_keyxxxmethodxxxxxxtimestampxxxxxxvx* 3. 把appSecret夹在字符串的两端 例如:appSecret+XXXX+appSecret* 4. 使用MD5进行加密,再转化成大写* @Date 10:24 2019/6/14* @Param [params, appSecret]* @return java.lang.String**/public String jdSign(HashMap<String, Object> params) {StringBuilder valueSb = new StringBuilder();valueSb.append(APPSECRET);// 1. 将参数以参数名的字典升序排序Map<String, Object> sortParams = new TreeMap<>(params);Set<Map.Entry<String, Object>> entrys = sortParams.entrySet();// 2. 遍历排序的字典,并拼接value1+value2......格式for (Map.Entry<String, Object> entry : entrys) {valueSb.append(entry.getValue());}// 3. 把appSecret夹在字符串的两端valueSb.append(APPSECRET);String sign = null;try {// 4. 使用MD5进行加密,再转化成大写String inStr = valueSb.toString();sign = DigestUtils.md5Hex(inStr.getBytes("UTF-8"));} catch (Exception e) {throw new RuntimeException("MD5签名过程中出现错误");}return sign.toUpperCase();}}
PS: 记录日常开发中的点点滴滴…