JooLun Plus 百科 ⬇ 源码下载

04.17 快递 100 接入

JooLun 于 2026-10-21 14:40:14 +08:00 修改了此页面

快递100账号准备

  • 登录快递100后台
  • 现在账号还只是测试客户,按提示开通成正式客户即可(我们开通的时候是充值了100块钱,以官方实际条件为准)

  • 商城配置快递100Key授权码、secret、商城需要用到的快递公司:后台-->【系统管理】-->【快递物流配置】;必配
  • 店铺可以配置物流月结账号实现发货时自动获取电子面单:后台-->【商城模块】-->【店铺管理】-->【物流月结账号】;选配

用到的快递100功能

  • 信息订阅功能:动态显示物流轨迹信息
  • 电子面单功能:自动获取电子面单发货

快递100收费标准

快递信息订阅功能

使用逻辑

  • 后台发货,通过快递100订阅接口对运单进行跟踪,当运单状态发生变化的时候,快递100会将物流轨迹信息推送到我们的回调接口
  • 注意:订单发货时只是进行了订阅不会立马有物流信息,要等快递100的推送;如发货后长时间没有物流信息,可登录快递100管理后台查看推送明细
  • 配置回调地址,nacos后台application-dev.yml配置文件
base:
  mall:
    # 支付、物流回调地址,即后台外网地址,要保证外网能访问
    notifyHost: http://test.abse.com

核心代码

  • 发货时订阅物流:joolun-mall/joolun-mall-admin/src/main/java/com/joolun/cloud/mall/admin/service/impl/OrderInfoServiceImpl.java中的delivery方法
			//订阅快递100:https://gitee.com/kuaidi100-api/java-demo
			String callbackurl = StrUtil.format("{}{}{}{}{}", mallConfigProperties.getNotifyHost(),
					MallConstants.SERVER_ROUTE_NAME_MALLAPI,
					MallConstants.ORDER_LOGISTICSR_NOTIFY_URL,
					"?tenantId=",
					orderLogistics.getTenantId());//回调地址
			SubscribeParameters subscribeParameters = new SubscribeParameters();
			subscribeParameters.setCallbackurl(callbackurl);
			subscribeParameters.setPhone(orderLogistics.getTelNum());

			SubscribeParam subscribeParam = new SubscribeParam();
			subscribeParam.setParameters(subscribeParameters);
			subscribeParam.setCompany(entity.getLogistics());
			subscribeParam.setNumber(entity.getLogisticsNo());
			subscribeParam.setKey(onfigLogistics.getLogisticsKey());

			SubscribeReq subscribeReq = new SubscribeReq();
			subscribeReq.setSchema(ApiInfoConstant.SUBSCRIBE_SCHEMA);
			subscribeReq.setParam(JSONUtil.toJsonStr(subscribeParam));

			IBaseClient subscribe = new Subscribe();
			subscribe.execute(subscribeReq);
  • 物流信息回调,更新物流轨迹信息:joolun-mall/joolun-mall-api/src/main/java/com/joolun/cloud/mall/api/controller/OrderInfoController.java

    /**
	 * 物流信息回调
	 * @param request
	 * @return
	 */
	@ApiOperation(value = "物流信息回调")
	@PostMapping("/notify-logisticsr")
	public String notifyLogisticsr(HttpServletRequest request, HttpServletResponse response) {
		String param = request.getParameter("param");
		String logisticsId = request.getParameter("logisticsId");
		String tenantId = request.getParameter("tenantId");
		TenantContextHolder.setTenantId(tenantId);
		log.info("物流信息回调:"+param);
		Map<String,Object> map = new HashMap<String,Object>();
		map.put("result",false);
		map.put("returnCode","500");
		map.put("message","保存失败");
		try {
			JSONObject jsonObject = JSONUtil.parseObj(param);
			orderInfoService.notifyLogisticsr(logisticsId, jsonObject);
			map.put("result",true);
			map.put("returnCode","200");
			map.put("message","保存成功");
			//这里必须返回,否则认为失败,过30分钟又会重复推送。
			response.getWriter().print(JSONUtil.parseObj(map));
		} catch (Exception e) {
			map.put("message","保存失败" + e.getMessage());
			//保存失败,服务端等30分钟会重复推送。
			try {
				response.getWriter().print(JSONUtil.parseObj(map));
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}
		return null;
	}

电子面单

使用逻辑

  • 当后台发货选择【自动获取电子面单】时,将通过电子面单API自动获取物流单号(快递单号)

核心代码

  • 发货时订阅物流:joolun-mall/joolun-mall-admin/src/main/java/com/joolun/cloud/mall/admin/service/impl/OrderInfoServiceImpl.java中的delivery方法
	if(MallConstants.DELIVERY_TYPE_1.equals(orderDeliveryDTO.getDeliveryType())){//发物流
			ConfigLogistics configLogistics = configLogisticsService.getOne();
			//调快递100自动获取电子面单
			if(MallConstants.LABEL_WAY_2.equals(orderDeliveryDTO.getLabelWay())){
				//收货人
				ManInfo recManInfo  = new ManInfo();
				recManInfo.setName(orderLogistics.getRecName());
				recManInfo.setMobile(orderLogistics.getRecTel());
				recManInfo.setPrintAddr(orderLogistics.getRecAddress());
				//寄件人,取店铺里的信息
				ManInfo sendManInfo = new ManInfo();
				sendManInfo.setName(orderDeliveryDTO.getSendName());
				sendManInfo.setMobile(orderDeliveryDTO.getSendTel());
				sendManInfo.setPrintAddr(orderDeliveryDTO.getSendAddress());

				OrderReq orderReq = new OrderReq();
				orderReq.setKuaidicom(orderDeliveryDTO.getLogisticsCode());
				orderReq.setCount(1);
				orderReq.setTempId(orderDeliveryDTO.getLabelTemplateId());
				orderReq.setSendMan(sendManInfo);
				orderReq.setRecMan(recManInfo);
				if(orderDeliveryDTO.getWeight() != null){
					orderReq.setWeight(orderDeliveryDTO.getWeight().doubleValue());
				}
				orderReq.setCargo(StrUtil.subWithLength(orderInfo.getName(), 0, 20));
				orderReq.setPrintType(PrintType.HTML);
				//获取物流月结账号
				BaseUser baseUser = SecurityUtils.getUser();
				//供应商账号则查询供应商物流账号
				if(CommonConstants.USER_TYPE_3.equals(baseUser.getType())){
					SupplierLogisticsAccount supplierLogisticsAccount = supplierLogisticsAccountService.getById(orderDeliveryDTO.getShopLogisticsAccountId());
					orderReq.setPartnerId(supplierLogisticsAccount.getAccountId());
					orderReq.setPartnerKey(supplierLogisticsAccount.getAccountKey());
					orderReq.setNet(supplierLogisticsAccount.getNet());
					orderReq.setCode(supplierLogisticsAccount.getCode());
				}else{
					ShopLogisticsAccount shopLogisticsAccount = shopLogisticsAccountService.getById(orderDeliveryDTO.getShopLogisticsAccountId());
					orderReq.setPartnerId(shopLogisticsAccount.getAccountId());
					orderReq.setPartnerKey(shopLogisticsAccount.getAccountKey());
					orderReq.setNet(shopLogisticsAccount.getNet());
					orderReq.setCode(shopLogisticsAccount.getCode());
				}

				String param = JSONUtil.toJsonStr(orderReq);
				String t = System.currentTimeMillis() + "";

				PrintReq printReq = new PrintReq();
				printReq.setT(t);
				printReq.setKey(configLogistics.getLogisticsKey());
				printReq.setSign(SignUtils.printSign(param,t,configLogistics.getLogisticsKey(),configLogistics.getLogisticsSecret()));
				printReq.setMethod(ApiInfoConstant.ORDER);
				printReq.setParam(param);

				IBaseClient baseClient = new LabelV2();
				HttpResult httpResult = baseClient.execute(printReq);
				if(httpResult.getStatus() == 200){
					JSONObject jSONObject = JSONUtil.parseObj(httpResult.getBody());
					if(jSONObject.getInt("code") == 200 && jSONObject.getBool("success")){
						JSONObject data = jSONObject.getJSONObject("data");
						//获取快递单号
						orderDeliveryDTO.setLogisticsNo(data.getStr("kuaidinum"));
						orderLogistics.setLabelUrl(data.getStr("label"));
					}else{
						throw new RuntimeException(jSONObject.getStr("message"));
					}
				}else{
					throw new RuntimeException(httpResult.getError());
				}
			}
			orderLogistics.setLabelWay(orderDeliveryDTO.getLabelWay());
			orderLogistics.setLogisticsCode(orderDeliveryDTO.getLogisticsCode());
			orderLogistics.setLogisticsNo(orderDeliveryDTO.getLogisticsNo());
			orderLogistics.setStatus(OrderLogisticsEnum.STATUS_1.getValue());
			configLogistics.getLogisticsCompany().forEach(logistics -> {
				JSONObject jsLogistics = JSONUtil.parseObj(logistics);
				if(StrUtil.equals(jsLogistics.get("code").toString(), orderDeliveryDTO.getLogisticsCode())){
					orderLogistics.setLogisticsName(jsLogistics.get("name").toString());
				}
			});
			orderLogisticsService.saveOrUpdate(orderLogistics);
			orderLogisticsDetailService.remove(Wrappers.<OrderLogisticsDetail>lambdaQuery()
					.eq(OrderLogisticsDetail::getLogisticsId,orderLogistics.getId()));//删除旧的物流路由
			//订单详情更新订单物流ID
			orderItem.setLogisticsId(orderLogistics.getId());

			//订阅快递100:https://gitee.com/kuaidi100-api/java-demo
			String callbackurl = StrUtil.format("{}{}{}{}{}", mallConfigProperties.getNotifyHost(),
					MallConstants.SERVER_ROUTE_NAME_MALLAPI,
					MallConstants.ORDER_LOGISTICSR_NOTIFY_URL,
					"?tenantId=",
					orderInfo.getTenantId());//回调地址
			SubscribeParameters subscribeParameters = new SubscribeParameters();
			subscribeParameters.setCallbackurl(callbackurl);
			subscribeParameters.setPhone(orderLogistics.getRecTel());

			SubscribeParam subscribeParam = new SubscribeParam();
			subscribeParam.setParameters(subscribeParameters);
			subscribeParam.setCompany(orderDeliveryDTO.getLogisticsCode());
			subscribeParam.setNumber(orderDeliveryDTO.getLogisticsNo());
			subscribeParam.setKey(configLogistics.getLogisticsKey());

			SubscribeReq subscribeReq = new SubscribeReq();
			subscribeReq.setSchema(ApiInfoConstant.SUBSCRIBE_SCHEMA);
			subscribeReq.setParam(JSONUtil.toJsonStr(subscribeParam));

			IBaseClient subscribe = new Subscribe();
			HttpResult httpResult = subscribe.execute(subscribeReq);
			if(httpResult.getStatus() == 200){
				JSONObject jSONObject = JSONUtil.parseObj(httpResult.getBody());
				if(!"200".equals(jSONObject.get("returnCode"))){
					throw new RuntimeException(jSONObject.getStr("message"));
				}
			}else{
				throw new RuntimeException(httpResult.getError());
			}
		}