diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/AlipayController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/AlipayCallbackController.java similarity index 98% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/AlipayController.java rename to ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/AlipayCallbackController.java index 8df4ce822..909de9e42 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/AlipayController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/AlipayCallbackController.java @@ -29,8 +29,8 @@ import java.util.Map; */ @Api(tags = "支付宝回调接口") @RestController -@RequestMapping("/rest/v1/alipay") -public class AlipayController extends XktBaseController { +@RequestMapping("/rest/v1/alipay-callback") +public class AlipayCallbackController extends XktBaseController { private static final String SUCCESS = "success"; private static final String FAILURE = "failure"; diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ExpressCallbackController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ExpressCallbackController.java new file mode 100644 index 000000000..6fba0dae2 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ExpressCallbackController.java @@ -0,0 +1,53 @@ +package com.ruoyi.web.controller.xkt; + +import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.core.controller.XktBaseController; +import com.ruoyi.common.core.redis.RedisCache; +import com.ruoyi.web.controller.xkt.vo.express.ZtoPrintOrderReqVO; +import com.ruoyi.web.controller.xkt.vo.express.ZtoPrintOrderRespVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.TimeUnit; + +/** + * @author liangyq + * @date 2025-04-17 14:18 + */ +@Api(tags = "物流回调接口") +@RestController +@RequestMapping("/rest/v1/express-callback") +public class ExpressCallbackController extends XktBaseController { + + @Autowired + private RedisCache redisCache; + + /** + * 中通-生成面单图片/PDF回推 + *
+ * 采用http协议,字符集编码为UTF-8,ContentType:"application/json",请求方式:POST
+ * 开放平台会根据三方返回的status字段判断此次推送是否成功
+ * 若三方返回false,或触达出现异常,开放平台侧会进行推送重试,重试最大次数为16次
+ *
+ * @param vo
+ * @return
+ */
+ @ApiOperation("中通-生成面单图片/PDF回推")
+ @PostMapping("zto/print-order")
+ public ZtoPrintOrderRespVO ztoPrintOrder(@RequestBody ZtoPrintOrderReqVO vo) {
+ if (StrUtil.isNotEmpty(vo.getBillCode())
+ && StrUtil.isNotEmpty(vo.getResult())) {
+ //缓存30分钟
+ redisCache.setCacheObject("ZTO-"+vo.getBillCode(),vo.getResult(),30, TimeUnit.MINUTES);
+ return ZtoPrintOrderRespVO.success();
+ }
+ return ZtoPrintOrderRespVO.failure();
+ }
+
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/express/ZtoPrintOrderReqVO.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/express/ZtoPrintOrderReqVO.java
new file mode 100644
index 000000000..a90466517
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/express/ZtoPrintOrderReqVO.java
@@ -0,0 +1,27 @@
+package com.ruoyi.web.controller.xkt.vo.express;
+
+import lombok.Data;
+
+/**
+ * @author liangyq
+ * @date 2025-04-17 16:40
+ */
+@Data
+public class ZtoPrintOrderReqVO {
+ /**
+ * 运单号
+ */
+ private String billCode;
+ /**
+ * 打印类型(0:JPG, 1:PDF.默认为PDF)
+ */
+ private String printType;
+ /**
+ * 图片或PDF的Base64编码
+ */
+ private String result;
+ /**
+ * 消息签名dataDigest=base64(md5(result+billCode))
+ */
+ private String dataDigest;
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/express/ZtoPrintOrderRespVO.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/express/ZtoPrintOrderRespVO.java
new file mode 100644
index 000000000..a4e32b195
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/express/ZtoPrintOrderRespVO.java
@@ -0,0 +1,46 @@
+package com.ruoyi.web.controller.xkt.vo.express;
+
+import lombok.Data;
+
+/**
+ * @author liangyq
+ * @date 2025-04-17 16:34
+ */
+@Data
+public class ZtoPrintOrderRespVO {
+ /**
+ * 默认false,中通根据status=true来判断是否推送成功
+ */
+ private Boolean status;
+ /**
+ * 响应说明
+ */
+ private String message;
+ /**
+ * 响应结果
+ */
+ private String result;
+ /**
+ * 响应状态码
+ */
+ private String statusCode;
+
+ public static ZtoPrintOrderRespVO success() {
+ ZtoPrintOrderRespVO vo = new ZtoPrintOrderRespVO();
+ vo.setStatus(true);
+ vo.setMessage("success");
+ vo.setResult("success");
+ vo.setStatusCode("0");
+ return vo;
+ }
+
+ public static ZtoPrintOrderRespVO failure() {
+ ZtoPrintOrderRespVO vo = new ZtoPrintOrderRespVO();
+ vo.setStatus(false);
+ vo.setMessage("failure");
+ vo.setResult("failure");
+ vo.setStatusCode("0");
+ return vo;
+ }
+
+}
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index b8f61328e..cddac173d 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -178,6 +178,14 @@ zto:
accountId: test
accountPassword: ZTO123
+# 圆通配置
+yto:
+ appKey: K9991024989
+ appSecret: u2Z1F7Fh
+ appKey2: TEST
+ appSecret2: 123456
+ gatewayUrl: https://openuat.yto56test.com:6443/
+
# 支付宝配置
alipay:
appId: 9021000144616672
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
index fca5d57b1..efca121e1 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
@@ -116,7 +116,9 @@ public class SecurityConfig
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
//支付宝回调
- .antMatchers("/rest/v1/alipay-notify").permitAll()
+ .antMatchers("/rest/v1/alipay-callback/**").permitAll()
+ //物流回调
+ .antMatchers("/rest/v1/express-callback/**").permitAll()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated();
})
diff --git a/xkt/src/main/java/com/ruoyi/xkt/enums/EExpressChannel.java b/xkt/src/main/java/com/ruoyi/xkt/enums/EExpressChannel.java
index f5c64a89f..126fb58f8 100644
--- a/xkt/src/main/java/com/ruoyi/xkt/enums/EExpressChannel.java
+++ b/xkt/src/main/java/com/ruoyi/xkt/enums/EExpressChannel.java
@@ -11,7 +11,9 @@ import lombok.Getter;
@AllArgsConstructor
public enum EExpressChannel {
- ZTO(1, "中通", 1L, "ZTO");
+ ZTO(1, "中通", 1L, "ZTO"),
+ YTO(2, "圆通", 2L, "YTO"),
+ ;
private final Integer value;
private final String label;
diff --git a/xkt/src/main/java/com/ruoyi/xkt/manager/impl/YtoExpressManagerImpl.java b/xkt/src/main/java/com/ruoyi/xkt/manager/impl/YtoExpressManagerImpl.java
new file mode 100644
index 000000000..d48120183
--- /dev/null
+++ b/xkt/src/main/java/com/ruoyi/xkt/manager/impl/YtoExpressManagerImpl.java
@@ -0,0 +1,132 @@
+package com.ruoyi.xkt.manager.impl;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.xkt.dto.express.ExpressShipReqDTO;
+import com.ruoyi.xkt.enums.EExpressChannel;
+import com.ruoyi.xkt.manager.ExpressManager;
+import com.ruoyi.xkt.thirdpart.yto.YtoCreateOrderParam;
+import com.ruoyi.xkt.thirdpart.yto.YtoPrintOrderParam;
+import com.ruoyi.xkt.thirdpart.yto.YtoPublicRequest;
+import com.ruoyi.xkt.thirdpart.yto.YtoSignUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+
+/**
+ * @author liangyq
+ * @date 2025-04-17 16:55
+ */
+@Slf4j
+@Component
+public class YtoExpressManagerImpl implements ExpressManager {
+
+ @Value("${yto.appKey:}")
+ private String appKey;
+
+ @Value("${yto.appSecret:}")
+ private String appSecret;
+
+ @Value("${yto.appKey2:}")
+ private String appKey2;
+
+ @Value("${yto.appSecret2:}")
+ private String appSecret2;
+
+ @Value("${yto.gatewayUrl:}")
+ private String gatewayUrl;
+
+ @Override
+ public EExpressChannel channel() {
+ return EExpressChannel.YTO;
+ }
+
+ @Override
+ public String shipStoreOrder(ExpressShipReqDTO shipReqDTO) {
+ YtoCreateOrderParam createOrderParam = trans2CreateOrderReq(shipReqDTO);
+ try {
+ String param = JSONUtil.toJsonStr(createOrderParam);
+ String sign = YtoSignUtil.sign("privacy_create_adapter", "v1", param, appSecret);
+ YtoPublicRequest request = YtoPublicRequest.builder()
+ .timestamp(System.currentTimeMillis())
+ .param(param)
+ .format(YtoPublicRequest.EFormat.JSON)
+ .sign(sign).build();
+ String rtnStr = HttpUtil.post(gatewayUrl + "open/privacy_create_adapter/v1/N364gM/" + appKey,
+ JSONUtil.toJsonStr(request));
+ log.info("圆通订单创建返回信息: {}", rtnStr);
+ JSONObject rtnJson = JSONUtil.parseObj(rtnStr);
+ String waybillNo = rtnJson.getStr("mailNo");
+ if (StrUtil.isNotEmpty(waybillNo)) {
+ return waybillNo;
+ }
+ } catch (Exception e) {
+ log.error("圆通订单创建异常", e);
+ }
+ throw new ServiceException("圆通订单创建失败");
+ }
+
+ @Override
+ public String printOrder(String waybillNo) {
+ YtoPrintOrderParam printOrderParam = YtoPrintOrderParam.builder().waybillNo(waybillNo).build();
+ try {
+ String param = JSONUtil.toJsonStr(printOrderParam);
+ String sign = YtoSignUtil.sign("waybill_print_adapter", "v1", param, appSecret);
+ YtoPublicRequest request = YtoPublicRequest.builder()
+ .timestamp(System.currentTimeMillis())
+ .param(param)
+ .format(YtoPublicRequest.EFormat.JSON)
+ .sign(sign).build();
+ String rtnStr = HttpUtil.post(gatewayUrl + "open/waybill_print_adapter/v1/N364gM/" + appKey,
+ JSONUtil.toJsonStr(request));
+ log.info("圆通打印回单返回信息: {}", rtnStr);
+ JSONObject rtnJson = JSONUtil.parseObj(rtnStr);
+ String rtn = rtnJson.getJSONObject("data").getStr("pdfBase64");
+ if (StrUtil.isNotEmpty(rtn)) {
+ return rtn;
+ }
+ } catch (Exception e) {
+ log.error("圆通打印回单异常", e);
+ }
+ throw new ServiceException("圆通打印回单失败");
+ }
+
+
+ private YtoCreateOrderParam trans2CreateOrderReq(ExpressShipReqDTO shipReqDTO) {
+ YtoCreateOrderParam reqDTO = new YtoCreateOrderParam();
+ reqDTO.setLogisticsNo(shipReqDTO.getExpressReqNo());
+
+ reqDTO.setSenderName(shipReqDTO.getOriginContactName());
+ reqDTO.setSenderProvinceName(shipReqDTO.getOriginProvinceName());
+ reqDTO.setSenderCityName(shipReqDTO.getOriginCityName());
+ reqDTO.setSenderCountyName(shipReqDTO.getOriginCountyName());
+ reqDTO.setSenderAddress(shipReqDTO.getOriginDetailAddress());
+ reqDTO.setSenderMobile(shipReqDTO.getOriginContactPhoneNumber());
+
+ reqDTO.setRecipientName(shipReqDTO.getDestinationContactName());
+ reqDTO.setRecipientProvinceName(shipReqDTO.getDestinationProvinceName());
+ reqDTO.setRecipientCityName(shipReqDTO.getDestinationCityName());
+ reqDTO.setRecipientCountyName(shipReqDTO.getDestinationCountyName());
+ reqDTO.setRecipientAddress(shipReqDTO.getDestinationDetailAddress());
+ reqDTO.setRecipientMobile(shipReqDTO.getDestinationContactPhoneNumber());
+
+ int goodsSize = shipReqDTO.getOrderItems().size();
+ if (shipReqDTO.getOrderItems().size() > 20) {
+ throw new ServiceException("圆通每次发货物品在20个以内!");
+ }
+ reqDTO.setGoods(new ArrayList<>(goodsSize));
+ for (ExpressShipReqDTO.OrderItem item : shipReqDTO.getOrderItems()) {
+ YtoCreateOrderParam.OrderGoods goods = new YtoCreateOrderParam.OrderGoods();
+ reqDTO.getGoods().add(goods);
+ goods.setName(item.getName());
+ goods.setQuantity(item.getQuantity());
+ }
+ return reqDTO;
+ }
+
+}
diff --git a/xkt/src/main/java/com/ruoyi/xkt/manager/impl/ZtoExpressManagerImpl.java b/xkt/src/main/java/com/ruoyi/xkt/manager/impl/ZtoExpressManagerImpl.java
index ef0beb0a2..85feccb8d 100644
--- a/xkt/src/main/java/com/ruoyi/xkt/manager/impl/ZtoExpressManagerImpl.java
+++ b/xkt/src/main/java/com/ruoyi/xkt/manager/impl/ZtoExpressManagerImpl.java
@@ -2,24 +2,30 @@ package com.ruoyi.xkt.manager.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
+import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.xkt.dto.express.ExpressShipReqDTO;
import com.ruoyi.xkt.enums.EExpressChannel;
import com.ruoyi.xkt.manager.ExpressManager;
import com.ruoyi.xkt.thirdpart.zto.*;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
+import java.util.concurrent.TimeUnit;
+
/**
* @author liangyq
* @date 2025-04-15 15:45
*/
@Slf4j
@Component
-public class ZtoExpressManagerImpl implements ExpressManager {
+public class ZtoExpressManagerImpl implements ExpressManager, InitializingBean {
private static final String CREATE_ORDER_URI = "zto.open.createOrder";
@@ -42,19 +48,23 @@ public class ZtoExpressManagerImpl implements ExpressManager {
@Value("${zto.accountPassword:}")
private String accountPassword;
+ @Autowired
+ private RedisCache redisCache;
+
+ private ZopClient client;
+
@Override
public EExpressChannel channel() {
- return EExpressChannel.ZTO;
+ return EExpressChannel.YTO;
}
@Override
public String shipStoreOrder(ExpressShipReqDTO shipReqDTO) {
Assert.notNull(shipReqDTO);
Assert.notEmpty(shipReqDTO.getExpressReqNo());
- ZtoCreateOrderReqDTO createOrderReq = trans2CreateOrderReq(shipReqDTO);
- ZopClient client = new ZopClient(appKey, appSecret);
+ ZtoCreateOrderParam createOrderParam = trans2CreateOrderReq(shipReqDTO);
ZopPublicRequest request = new ZopPublicRequest();
- request.setBody(JSONUtil.toJsonStr(createOrderReq));
+ request.setBody(JSONUtil.toJsonStr(createOrderParam));
request.setUrl(gatewayUrl + CREATE_ORDER_URI);
request.setEncryptionType(EncryptionType.MD5);
try {
@@ -75,9 +85,8 @@ public class ZtoExpressManagerImpl implements ExpressManager {
@Override
public String printOrder(String waybillNo) {
Assert.notEmpty(waybillNo);
- ZopClient client = new ZopClient(appKey, appSecret);
ZopPublicRequest request = new ZopPublicRequest();
- request.setBody(JSONUtil.toJsonStr(new ZtoPrintOrderReqDTO(1,waybillNo,true)));
+ request.setBody(JSONUtil.toJsonStr(new ZtoPrintOrderParam(1, waybillNo, true)));
request.setUrl(gatewayUrl + ORDER_PRINT_URI);
request.setEncryptionType(EncryptionType.MD5);
try {
@@ -87,7 +96,12 @@ public class ZtoExpressManagerImpl implements ExpressManager {
boolean success = bodyJson.getBool("status");
if (success) {
//TODO 测试环境接口不通
- return bodyJson.getJSONObject("result").getStr("billCode");
+ //等待推送
+ TimeUnit.SECONDS.sleep(3);
+ String rtn = redisCache.getCacheObject("ZTO_" + waybillNo);
+ if (StrUtil.isNotEmpty(rtn)) {
+ return rtn;
+ }
}
} catch (Exception e) {
log.error("中通订单打印异常", e);
@@ -102,7 +116,6 @@ public class ZtoExpressManagerImpl implements ExpressManager {
* @return
*/
public JSONObject structureNamePhoneAddress(String str) {
- ZopClient client = new ZopClient(appKey, appSecret);
ZopPublicRequest request = new ZopPublicRequest();
JSONObject body = new JSONObject();
body.set("address", str);
@@ -123,8 +136,8 @@ public class ZtoExpressManagerImpl implements ExpressManager {
throw new ServiceException("中通智能解析失败");
}
- private ZtoCreateOrderReqDTO trans2CreateOrderReq(ExpressShipReqDTO expressShipReqDTO) {
- ZtoCreateOrderReqDTO reqDTO = new ZtoCreateOrderReqDTO();
+ private ZtoCreateOrderParam trans2CreateOrderReq(ExpressShipReqDTO expressShipReqDTO) {
+ ZtoCreateOrderParam reqDTO = new ZtoCreateOrderParam();
//合作模式 ,1:集团客户;2:非集团客户
reqDTO.setPartnerType("2");
//partnerType为1时,orderType:1:全网件 2:预约件。 partnerType为2时,orderType:1:全网件 2:预约件(返回运单号) 3:预约件(不返回运单号) 4:星联全网件
@@ -133,7 +146,7 @@ public class ZtoExpressManagerImpl implements ExpressManager {
reqDTO.setPartnerOrderCode(expressShipReqDTO.getExpressReqNo());
//账号信息
- ZtoCreateOrderReqDTO.AccountInfo accountInfo = new ZtoCreateOrderReqDTO.AccountInfo();
+ ZtoCreateOrderParam.AccountInfo accountInfo = new ZtoCreateOrderParam.AccountInfo();
reqDTO.setAccountInfo(accountInfo);
//电子面单账号(partnerType为2,orderType传1,2,4时必传)
accountInfo.setAccountId(accountId);
@@ -145,7 +158,7 @@ public class ZtoExpressManagerImpl implements ExpressManager {
accountInfo.setCustomerId(null);
//发件人信息
- ZtoCreateOrderReqDTO.SenderInfo senderInfo = new ZtoCreateOrderReqDTO.SenderInfo();
+ ZtoCreateOrderParam.SenderInfo senderInfo = new ZtoCreateOrderParam.SenderInfo();
reqDTO.setSenderInfo(senderInfo);
senderInfo.setSenderName(expressShipReqDTO.getOriginCountyName());
senderInfo.setSenderPhone(expressShipReqDTO.getOriginContactPhoneNumber());
@@ -155,7 +168,7 @@ public class ZtoExpressManagerImpl implements ExpressManager {
senderInfo.setSenderAddress(expressShipReqDTO.getOriginDetailAddress());
//收件人信息
- ZtoCreateOrderReqDTO.ReceiveInfo receiveInfo = new ZtoCreateOrderReqDTO.ReceiveInfo();
+ ZtoCreateOrderParam.ReceiveInfo receiveInfo = new ZtoCreateOrderParam.ReceiveInfo();
reqDTO.setReceiveInfo(receiveInfo);
receiveInfo.setReceiverName(expressShipReqDTO.getDestinationContactName());
receiveInfo.setReceiverPhone(expressShipReqDTO.getDestinationContactPhoneNumber());
@@ -166,10 +179,14 @@ public class ZtoExpressManagerImpl implements ExpressManager {
//货物信息
reqDTO.setOrderItems(BeanUtil.copyToList(expressShipReqDTO.getOrderItems(),
- ZtoCreateOrderReqDTO.OrderItem.class));
+ ZtoCreateOrderParam.OrderItem.class));
return reqDTO;
}
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ this.client = new ZopClient(appKey, appSecret);
+ }
}
diff --git a/xkt/src/main/java/com/ruoyi/xkt/thirdpart/yto/YtoCreateOrderParam.java b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/yto/YtoCreateOrderParam.java
new file mode 100644
index 000000000..1dc62c076
--- /dev/null
+++ b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/yto/YtoCreateOrderParam.java
@@ -0,0 +1,179 @@
+package com.ruoyi.xkt.thirdpart.yto;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author liangyq
+ * @date 2025-04-15 19:20
+ */
+@Data
+public class YtoCreateOrderParam {
+ /**
+ * 物流单号,打印拉取运单号前,物流单号和渠道唯一确定一笔快递物流订单。注:最低长度为7
+ */
+ private String logisticsNo;
+ /**
+ * 寄件人姓名
+ */
+ private String senderName;
+ /**
+ * 寄件人省名称
+ */
+ private String senderProvinceName;
+ /**
+ * 寄件人市名称
+ */
+ private String senderCityName;
+ /**
+ * 寄件人区县名称
+ */
+ private String senderCountyName;
+ /**
+ * 寄件人乡镇名称
+ */
+ private String senderTownName;
+ /**
+ * 寄件人详细地址
+ */
+ private String senderAddress;
+ /**
+ * 寄件人联系电话
+ */
+ private String senderMobile;
+ /**
+ * 收件人姓名
+ */
+ private String recipientName;
+ /**
+ * 收件人省名称
+ */
+ private String recipientProvinceName;
+ /**
+ * 收件人市名称
+ */
+ private String recipientCityName;
+ /**
+ * 收件人区县名称
+ */
+ private String recipientCountyName;
+ /**
+ * 收件人乡镇名称
+ */
+ private String recipientTownName;
+ /**
+ * 收件人详细地址
+ */
+ private String recipientAddress;
+ /**
+ * 收件人联系电话
+ */
+ private String recipientMobile;
+ /**
+ * 备注,打印在面单上的备注内容
+ */
+ private String remark;
+ /**
+ * 寄件码或取件码
+ */
+ private String gotCode;
+ /**
+ * 增值服务列表
+ */
+ private List