From 98907b33aa04ed4d590c565fe30a1dae0dfd2fa5 Mon Sep 17 00:00:00 2001 From: "pikachu1995@126.com" Date: Thu, 16 Feb 2023 18:16:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AD=98=E5=82=A8=E6=96=B0=E5=A2=9E=EF=BC=9A?= =?UTF-8?q?=E8=85=BE=E8=AE=AF=E4=BA=91=E3=80=81=E5=8D=8E=E4=B8=BA=E4=BA=91?= =?UTF-8?q?=20=E7=9F=AD=E4=BF=A1=E6=96=B0=E5=A2=9E=EF=BC=9A=E8=85=BE?= =?UTF-8?q?=E8=AE=AF=E4=BA=91=E3=80=81=E5=8D=8E=E4=B8=BA=E4=BA=91=20?= =?UTF-8?q?=E7=89=A9=E6=B5=81=E6=96=B0=E5=A2=9E=EF=BC=9A=E5=BF=AB=E9=80=92?= =?UTF-8?q?100=20=E7=89=A9=E6=B5=81=E6=9F=A5=E8=AF=A2=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E5=BF=AB=E9=80=92=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E5=9C=B0=E5=9B=BE=E8=BD=A8=E8=BF=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../order/OrderBuyerController.java | 10 + framework/pom.xml | 22 +- .../java/cn/lili/common/enums/ResultCode.java | 4 +- .../modules/file/entity/enums/OssEnum.java | 6 +- .../file/plugin/FilePluginFactory.java | 6 + .../file/plugin/impl/AliFilePlugin.java | 14 +- .../file/plugin/impl/HuaweiFilePlugin.java | 128 +++++++ .../file/plugin/impl/TencentFilePlugin.java | 122 +++++++ .../modules/kdBrid/service/KdNiaoService.java | 17 - .../modules/logistics/LogisticsPlugin.java | 53 +++ .../logistics/LogisticsPluginFactory.java | 56 +++ .../logistics/entity/dto/LabelOrderDTO.java | 31 ++ .../logistics/entity/enums/LogisticsEnum.java | 15 + .../plugin/kdniao/KdniaoPlugin.java} | 237 +++++++------ .../plugin/kuaidi100/Kuaidi100Plugin.java | 184 ++++++++++ .../kuaidi100/utils/Kuaidi100SignUtils.java | 73 ++++ .../serviceimpl/AfterSaleServiceImpl.java | 3 +- .../order/order/service/OrderService.java | 25 +- .../order/serviceimpl/OrderServiceImpl.java | 31 +- .../java/cn/lili/modules/sms/SmsUtil.java | 10 - .../modules/sms/entity/enums/SmsEnum.java | 15 + .../sms/impl/SmsUtilAliImplService.java | 234 +------------ .../SmsPlugin.java} | 40 ++- .../modules/sms/plugin/SmsPluginFactory.java | 59 ++++ .../modules/sms/plugin/impl/AliSmsPlugin.java | 265 ++++++++++++++ .../sms/plugin/impl/HuaweiSmsPlugin.java | 323 ++++++++++++++++++ .../sms/plugin/impl/TencentSmsPlugin.java | 254 ++++++++++++++ .../sms/serviceimpl/SmsSignServiceImpl.java | 21 +- .../serviceimpl/SmsTemplateServiceImpl.java | 22 +- ...aidiSetting.java => LogisticsSetting.java} | 24 +- .../modules/system/entity/dto/OssSetting.java | 62 +++- .../modules/system/entity/dto/SmsSetting.java | 53 ++- .../system/entity/enums/SettingEnum.java | 7 +- .../system/service/LogisticsService.java | 9 +- .../serviceimpl/LogisticsServiceImpl.java | 304 ++++------------- .../setting/SettingManagerController.java | 14 +- pom.xml | 4 + .../order/OrderStoreController.java | 10 +- 38 files changed, 2058 insertions(+), 709 deletions(-) create mode 100644 framework/src/main/java/cn/lili/modules/file/plugin/impl/HuaweiFilePlugin.java create mode 100644 framework/src/main/java/cn/lili/modules/file/plugin/impl/TencentFilePlugin.java delete mode 100644 framework/src/main/java/cn/lili/modules/kdBrid/service/KdNiaoService.java create mode 100644 framework/src/main/java/cn/lili/modules/logistics/LogisticsPlugin.java create mode 100644 framework/src/main/java/cn/lili/modules/logistics/LogisticsPluginFactory.java create mode 100644 framework/src/main/java/cn/lili/modules/logistics/entity/dto/LabelOrderDTO.java create mode 100644 framework/src/main/java/cn/lili/modules/logistics/entity/enums/LogisticsEnum.java rename framework/src/main/java/cn/lili/modules/{kdBrid/serviceImpl/KdNiaoServiceImpl.java => logistics/plugin/kdniao/KdniaoPlugin.java} (61%) create mode 100644 framework/src/main/java/cn/lili/modules/logistics/plugin/kuaidi100/Kuaidi100Plugin.java create mode 100644 framework/src/main/java/cn/lili/modules/logistics/plugin/kuaidi100/utils/Kuaidi100SignUtils.java create mode 100644 framework/src/main/java/cn/lili/modules/sms/entity/enums/SmsEnum.java rename framework/src/main/java/cn/lili/modules/sms/{AliSmsUtil.java => plugin/SmsPlugin.java} (68%) create mode 100644 framework/src/main/java/cn/lili/modules/sms/plugin/SmsPluginFactory.java create mode 100644 framework/src/main/java/cn/lili/modules/sms/plugin/impl/AliSmsPlugin.java create mode 100644 framework/src/main/java/cn/lili/modules/sms/plugin/impl/HuaweiSmsPlugin.java create mode 100644 framework/src/main/java/cn/lili/modules/sms/plugin/impl/TencentSmsPlugin.java rename framework/src/main/java/cn/lili/modules/system/entity/dto/{KuaidiSetting.java => LogisticsSetting.java} (50%) diff --git a/buyer-api/src/main/java/cn/lili/controller/order/OrderBuyerController.java b/buyer-api/src/main/java/cn/lili/controller/order/OrderBuyerController.java index 1dfcb000..3e62ecc4 100644 --- a/buyer-api/src/main/java/cn/lili/controller/order/OrderBuyerController.java +++ b/buyer-api/src/main/java/cn/lili/controller/order/OrderBuyerController.java @@ -116,6 +116,16 @@ public class OrderBuyerController { return ResultUtil.data(orderService.getTraces(orderSn)); } + @ApiOperation(value = "查询地图版物流踪迹") + @ApiImplicitParams({ + @ApiImplicitParam(name = "orderSn", value = "订单编号", required = true, dataType = "String", paramType = "path") + }) + @PostMapping(value = "/getMapTraces/{orderSn}") + public ResultMessage getMapTraces(@NotBlank(message = "订单编号不能为空") @PathVariable String orderSn) { + OperationalJudgment.judgment(orderService.getBySn(orderSn)); + return ResultUtil.data(orderService.getMapTraces(orderSn)); + } + @PreventDuplicateSubmissions @ApiOperation(value = "开票") diff --git a/framework/pom.xml b/framework/pom.xml index 5e0b4b74..9f127491 100644 --- a/framework/pom.xml +++ b/framework/pom.xml @@ -437,8 +437,26 @@ minio ${minio.version} - - + + com.huaweicloud + esdk-obs-java + ${huaweicloud.version} + + + com.qcloud + cos_api + ${cos.version} + + + com.tencentcloudapi + tencentcloud-sdk-java + ${tencentcloud.version} + + + com.github.kuaidi100-api + sdk + ${kuaidi100-api.version} + diff --git a/framework/src/main/java/cn/lili/common/enums/ResultCode.java b/framework/src/main/java/cn/lili/common/enums/ResultCode.java index 1693f24e..b93239fb 100644 --- a/framework/src/main/java/cn/lili/common/enums/ResultCode.java +++ b/framework/src/main/java/cn/lili/common/enums/ResultCode.java @@ -193,7 +193,7 @@ public enum ResultCode { ORDER_NOT_USER(31007, "非当前会员的订单"), ORDER_TAKE_ERROR(31008, "当前订单无法核销"), MEMBER_ADDRESS_NOT_EXIST(31009, "订单无收货地址,请先配置收货地址"), - STORE_ADDRESS_NOT_EXIST(31009,"订单没有自提地址,请先选择自提地址"), + STORE_ADDRESS_NOT_EXIST(31009, "订单没有自提地址,请先选择自提地址"), ORDER_DELIVER_NUM_ERROR(31010, "没有待发货的订单"), ORDER_NOT_SUPPORT_DISTRIBUTION(31011, "购物车中包含不支持配送的商品,请重新选择收货地址,或者重新选择商品"), ORDER_NOT_EXIST_VALID(31041, "购物车中无有效商品,请检查购物车内商品,或者重新选择商品"), @@ -202,6 +202,8 @@ public enum ResultCode { ORDER_ITEM_NOT_EXIST(31014, "当前订单项不存在!"), POINT_NOT_ENOUGH(31015, "当前会员积分不足购买当前积分商品!"), + ORDER_LABEL_ORDER_ERROR(31016, "订单不能打印电子面单"), + /** * 支付 diff --git a/framework/src/main/java/cn/lili/modules/file/entity/enums/OssEnum.java b/framework/src/main/java/cn/lili/modules/file/entity/enums/OssEnum.java index 748faeca..585b04da 100644 --- a/framework/src/main/java/cn/lili/modules/file/entity/enums/OssEnum.java +++ b/framework/src/main/java/cn/lili/modules/file/entity/enums/OssEnum.java @@ -1,7 +1,5 @@ package cn.lili.modules.file.entity.enums; -import com.aliyun.oss.OSS; - /** * OssEnum * @@ -11,7 +9,7 @@ import com.aliyun.oss.OSS; */ public enum OssEnum { /** - * + * 上传渠道 */ - ALI_OSS, MINIO; + ALI_OSS, MINIO, HUAWEI_OBS, TENCENT_COS; } diff --git a/framework/src/main/java/cn/lili/modules/file/plugin/FilePluginFactory.java b/framework/src/main/java/cn/lili/modules/file/plugin/FilePluginFactory.java index 63e4da08..929116f1 100644 --- a/framework/src/main/java/cn/lili/modules/file/plugin/FilePluginFactory.java +++ b/framework/src/main/java/cn/lili/modules/file/plugin/FilePluginFactory.java @@ -4,7 +4,9 @@ import cn.hutool.json.JSONUtil; import cn.lili.common.exception.ServiceException; import cn.lili.modules.file.entity.enums.OssEnum; import cn.lili.modules.file.plugin.impl.AliFilePlugin; +import cn.lili.modules.file.plugin.impl.HuaweiFilePlugin; import cn.lili.modules.file.plugin.impl.MinioFilePlugin; +import cn.lili.modules.file.plugin.impl.TencentFilePlugin; import cn.lili.modules.system.entity.dos.Setting; import cn.lili.modules.system.entity.dto.OssSetting; import cn.lili.modules.system.entity.enums.SettingEnum; @@ -47,6 +49,10 @@ public class FilePluginFactory { return new MinioFilePlugin(ossSetting); case ALI_OSS: return new AliFilePlugin(ossSetting); + case HUAWEI_OBS: + return new HuaweiFilePlugin(ossSetting); + case TENCENT_COS: + return new TencentFilePlugin(ossSetting); default: throw new ServiceException(); } diff --git a/framework/src/main/java/cn/lili/modules/file/plugin/impl/AliFilePlugin.java b/framework/src/main/java/cn/lili/modules/file/plugin/impl/AliFilePlugin.java index e195a2a0..31ae2c7d 100644 --- a/framework/src/main/java/cn/lili/modules/file/plugin/impl/AliFilePlugin.java +++ b/framework/src/main/java/cn/lili/modules/file/plugin/impl/AliFilePlugin.java @@ -44,9 +44,9 @@ public class AliFilePlugin implements FilePlugin { */ private OSS getOssClient() { return new OSSClientBuilder().build( - ossSetting.getEndPoint(), - ossSetting.getAccessKeyId(), - ossSetting.getAccessKeySecret()); + ossSetting.getAliyunOSSEndPoint(), + ossSetting.getAliyunOSSAccessKeyId(), + ossSetting.getAliyunOSSAccessKeySecret()); } @@ -56,14 +56,14 @@ public class AliFilePlugin implements FilePlugin { * @return */ private String getUrlPrefix() { - return "https://" + ossSetting.getBucketName() + "." + ossSetting.getEndPoint() + "/"; + return "https://" + ossSetting.getAliyunOSSBucketName() + "." + ossSetting.getAliyunOSSEndPoint() + "/"; } @Override public String pathUpload(String filePath, String key) { OSS ossClient = getOssClient(); try { - ossClient.putObject(ossSetting.getBucketName(), key, new File(filePath)); + ossClient.putObject(ossSetting.getAliyunOSSBucketName(), key, new File(filePath)); } catch (OSSException oe) { log.error("Caught an OSSException, which means your request made it to OSS, " + "but was rejected with an error response for some reason."); @@ -94,7 +94,7 @@ public class AliFilePlugin implements FilePlugin { try { ObjectMetadata meta = new ObjectMetadata(); meta.setContentType("image/jpg"); - ossClient.putObject(ossSetting.getBucketName(), key, inputStream, meta); + ossClient.putObject(ossSetting.getAliyunOSSBucketName(), key, inputStream, meta); } catch (OSSException oe) { log.error("Caught an OSSException, which means your request made it to OSS, " + "but was rejected with an error response for some reason."); @@ -125,7 +125,7 @@ public class AliFilePlugin implements FilePlugin { try { ossClient.deleteObjects( - new DeleteObjectsRequest(ossSetting.getBucketName()).withKeys(key)); + new DeleteObjectsRequest(ossSetting.getAliyunOSSBucketName()).withKeys(key)); } catch (OSSException oe) { log.error("Caught an OSSException, which means your request made it to OSS, " + "but was rejected with an error response for some reason."); diff --git a/framework/src/main/java/cn/lili/modules/file/plugin/impl/HuaweiFilePlugin.java b/framework/src/main/java/cn/lili/modules/file/plugin/impl/HuaweiFilePlugin.java new file mode 100644 index 00000000..62e2c64d --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/file/plugin/impl/HuaweiFilePlugin.java @@ -0,0 +1,128 @@ +package cn.lili.modules.file.plugin.impl; + +import cn.lili.common.enums.ResultCode; +import cn.lili.common.exception.ServiceException; +import cn.lili.modules.file.entity.enums.OssEnum; +import cn.lili.modules.file.plugin.FilePlugin; +import cn.lili.modules.system.entity.dto.OssSetting; + +import com.obs.services.ObsClient; +import com.obs.services.exception.ObsException; +import com.obs.services.model.*; +import lombok.extern.slf4j.Slf4j; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +/** + * 华为obs 文件操作 + * + * @author Bulbasaur + * + * + */ + +@Slf4j +public class HuaweiFilePlugin implements FilePlugin { + + private OssSetting ossSetting; + + public HuaweiFilePlugin(OssSetting ossSetting) { + this.ossSetting = ossSetting; + } + + @Override + public OssEnum pluginName() { + return OssEnum.HUAWEI_OBS; + } + + /** + * 获取oss client + * + * @return + */ + private ObsClient getObsClient() { + return new ObsClient(ossSetting.getHuaweicloudOBSAccessKey(), ossSetting.getHuaweicloudOBSSecretKey(), ossSetting.getAliyunOSSEndPoint()); + } + + + @Override + public String pathUpload(String filePath, String key) { + ObsClient obsClient = getObsClient(); + try { + obsClient.putObject(ossSetting.getHuaweicloudOBSBucketName(), key, new File(filePath)); + } catch (ObsException ce) { + log.error("Error Message: " + ce.getMessage()); + throw new ServiceException(ResultCode.OSS_EXCEPTION_ERROR); + } finally { + try { + // 关闭OBS连接 + obsClient.close(); + } catch (IOException e) { + log.error("OBS关闭连接报错!" + e.getMessage()); + throw new ServiceException(ResultCode.OSS_EXCEPTION_ERROR); + } + } + return getUrlPrefix() + key; + } + + @Override + public String inputStreamUpload(InputStream inputStream, String key) { + ObsClient obsClient = getObsClient(); + try { + obsClient.putObject(new PutObjectRequest(ossSetting.getHuaweicloudOBSBucketName(), key, inputStream)); + } catch (ObsException obsException) { + throw new ServiceException(ResultCode.OSS_EXCEPTION_ERROR); + } finally { + try { + // 关闭OBS连接 + obsClient.close(); + } catch (IOException e) { + log.error("OBS关闭连接报错!" + e.getMessage()); + throw new ServiceException(ResultCode.OSS_EXCEPTION_ERROR); + } + } + + return getUrlPrefix() + key; + } + + @Override + public void deleteFile(List keys) { + ObsClient obsClient = getObsClient(); + ListVersionsResult result; + try { + DeleteObjectsRequest deleteRequest = new DeleteObjectsRequest(ossSetting.getHuaweicloudOBSBucketName()); + //deleteRequest.setQuiet(true); // 注意此demo默认是详细模式,如果要使用简单模式,请添加本行代码 + for (String key : keys) { + deleteRequest.addKeyAndVersion(key); + } + DeleteObjectsResult deleteResult = obsClient.deleteObjects(deleteRequest); + // 获取删除成功的对象 + log.info("删除成功:" + deleteResult.getDeletedObjectResults()); + // 获取删除失败的对象 + log.info("删除失败:" + deleteResult.getErrorResults()); + } catch (ObsException obsException) { + throw new ServiceException(ResultCode.OSS_DELETE_ERROR); + } finally { + try { + // 关闭OBS连接 + obsClient.close(); + } catch (IOException e) { + log.error("OBS关闭连接报错!" + e.getMessage()); + throw new ServiceException(ResultCode.OSS_EXCEPTION_ERROR); + } + } + } + + + /** + * 获取配置前缀 + * + * @return + */ + private String getUrlPrefix() { + return "https://" + ossSetting.getHuaweicloudOBSBucketName() + "." + ossSetting.getHuaweicloudOBSEndPoint() + "/"; + } +} diff --git a/framework/src/main/java/cn/lili/modules/file/plugin/impl/TencentFilePlugin.java b/framework/src/main/java/cn/lili/modules/file/plugin/impl/TencentFilePlugin.java new file mode 100644 index 00000000..61dda55d --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/file/plugin/impl/TencentFilePlugin.java @@ -0,0 +1,122 @@ +package cn.lili.modules.file.plugin.impl; + +import cn.lili.common.enums.ResultCode; +import cn.lili.common.exception.ServiceException; +import cn.lili.modules.file.entity.enums.OssEnum; +import cn.lili.modules.file.plugin.FilePlugin; +import cn.lili.modules.system.entity.dto.OssSetting; +import com.qcloud.cos.COSClient; +import com.qcloud.cos.ClientConfig; +import com.qcloud.cos.auth.BasicCOSCredentials; +import com.qcloud.cos.auth.COSCredentials; +import com.qcloud.cos.exception.CosClientException; +import com.qcloud.cos.exception.CosServiceException; +import com.qcloud.cos.http.HttpProtocol; +import com.qcloud.cos.model.DeleteObjectsRequest; +import com.qcloud.cos.model.ObjectMetadata; +import com.qcloud.cos.model.PutObjectRequest; +import com.qcloud.cos.region.Region; +import lombok.extern.slf4j.Slf4j; + +import java.io.File; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * 腾讯cos 文件操作 + * + * @author Bulbasaur + */ + +@Slf4j +public class TencentFilePlugin implements FilePlugin { + + private OssSetting ossSetting; + + public TencentFilePlugin(OssSetting ossSetting) { + this.ossSetting = ossSetting; + } + + @Override + public OssEnum pluginName() { + return OssEnum.TENCENT_COS; + } + + /** + * 获取oss client + * + * @return + */ + private COSClient getCOSClient() { + // 1 初始化用户身份信息(secretId, secretKey)。 + COSCredentials cred = new BasicCOSCredentials(ossSetting.getTencentCOSSecretId(), ossSetting.getTencentCOSSecretKey()); + // 2 设置 bucket 的地域, COS 地域的简称请参见 https://cloud.tencent.com/document/product/436/6224 + ClientConfig clientConfig = new ClientConfig(new Region("COS_REGION")); + // 这里建议设置使用 https 协议 + clientConfig.setHttpProtocol(HttpProtocol.https); + // 3 生成 cos 客户端。 + return new COSClient(cred, clientConfig); + } + + + /** + * 获取配置前缀 + * + * @return + */ + private String getUrlPrefix() { + return "https://" + ossSetting.getTencentCOSBucket() + "." + ossSetting.getTencentCOSEndPoint() + "/"; + } + + @Override + public String pathUpload(String filePath, String key) { + COSClient cosClient = getCOSClient(); + try { + cosClient.putObject(ossSetting.getTencentCOSBucket(), key, new File(filePath)); + } catch (CosServiceException oe) { + throw new ServiceException(ResultCode.OSS_EXCEPTION_ERROR); + } catch (CosClientException ce) { + throw new ServiceException(ResultCode.OSS_EXCEPTION_ERROR); + } finally { + cosClient.shutdown(); + } + return getUrlPrefix() + key; + } + + @Override + public String inputStreamUpload(InputStream inputStream, String key) { + COSClient cosClient = getCOSClient(); + try { + ObjectMetadata meta = new ObjectMetadata(); + meta.setContentType("image/jpg"); + cosClient.putObject(ossSetting.getTencentCOSBucket(), key, inputStream, meta); + } catch (CosServiceException oe) { + throw new ServiceException(ResultCode.OSS_EXCEPTION_ERROR); + } catch (CosClientException ce) { + throw new ServiceException(ResultCode.OSS_EXCEPTION_ERROR); + } finally { + cosClient.shutdown(); + } + return getUrlPrefix() + key; + } + + @Override + public void deleteFile(List keys) { + COSClient cosClient = getCOSClient(); + + try { + List delObjects = new ArrayList<>(); + for (String key:keys) { + delObjects.add(new DeleteObjectsRequest.KeyVersion(key)); + } + cosClient.deleteObjects(new DeleteObjectsRequest(ossSetting.getTencentCOSBucket()).withKeys(delObjects)); + } catch (CosServiceException oe) { + throw new ServiceException(ResultCode.OSS_EXCEPTION_ERROR); + } catch (CosClientException ce) { + throw new ServiceException(ResultCode.OSS_EXCEPTION_ERROR); + } finally { + cosClient.shutdown(); + } + } +} diff --git a/framework/src/main/java/cn/lili/modules/kdBrid/service/KdNiaoService.java b/framework/src/main/java/cn/lili/modules/kdBrid/service/KdNiaoService.java deleted file mode 100644 index 0bb776b8..00000000 --- a/framework/src/main/java/cn/lili/modules/kdBrid/service/KdNiaoService.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.lili.modules.kdBrid.service; - -/** - * 快递鸟电子面单业务层实现 - * - * @author chc - * @since 2022-4-12 10:12:43 - */ -public interface KdNiaoService { - /** - * 生成电子面单 - * @param orderSn 订单编号 - * @param logisticsId 物流公司 - * @return 电子面单模板 - */ - String createElectronicsFaceSheet(String orderSn, String logisticsId) throws Exception; -} diff --git a/framework/src/main/java/cn/lili/modules/logistics/LogisticsPlugin.java b/framework/src/main/java/cn/lili/modules/logistics/LogisticsPlugin.java new file mode 100644 index 00000000..d77bc8f9 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/logistics/LogisticsPlugin.java @@ -0,0 +1,53 @@ +package cn.lili.modules.logistics; + +import cn.lili.modules.logistics.entity.dto.LabelOrderDTO; +import cn.lili.modules.logistics.entity.enums.LogisticsEnum; +import cn.lili.modules.system.entity.dos.Logistics; +import cn.lili.modules.system.entity.vo.Traces; + +/** + * 物流插件接口 + * + * @author Bulbasaur + * @author Bulbasaur + * @since 2023-02-16 + */ +public interface LogisticsPlugin { + + + /** + * 插件名称 + */ + LogisticsEnum pluginName(); + + /** + * 实时查询快递 + * + * @param logistics 物流公司 + * @param expNo + * @param phone + * @return 物流信息 + */ + Traces pollQuery(Logistics logistics, String expNo, String phone); + + /** + * 实时查询地图轨迹 + * + * @param logistics 物流公司 + * @param expNo 单号 + * @param phone 收件人手机号 + * @param from 出发地信息,最小颗粒到市级,例如:广东省深圳市 + * @param to 目的地信息,最小颗粒到市级,例如:广东省深圳市 + * @return 物流信息 + */ + Traces pollMapTrack(Logistics logistics, String expNo, String phone, String from, String to); + + /** + * 电子面单打印 + * + * @param labelOrderDTO 电子面单DTO + * @return + */ + String labelOrder(LabelOrderDTO labelOrderDTO); + +} diff --git a/framework/src/main/java/cn/lili/modules/logistics/LogisticsPluginFactory.java b/framework/src/main/java/cn/lili/modules/logistics/LogisticsPluginFactory.java new file mode 100644 index 00000000..b40c4ebb --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/logistics/LogisticsPluginFactory.java @@ -0,0 +1,56 @@ +package cn.lili.modules.logistics; + +import cn.hutool.json.JSONUtil; +import cn.lili.common.exception.ServiceException; +import cn.lili.modules.logistics.entity.enums.LogisticsEnum; +import cn.lili.modules.logistics.plugin.kdniao.KdniaoPlugin; +import cn.lili.modules.logistics.plugin.kuaidi100.Kuaidi100Plugin; +import cn.lili.modules.system.entity.dos.Setting; +import cn.lili.modules.system.entity.dto.LogisticsSetting; +import cn.lili.modules.system.entity.enums.SettingEnum; +import cn.lili.modules.system.service.SettingService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 文件服务抽象工厂 直接返回操作类 + * + * @author Bulbasaur + * @version v1.0 + * 2022-06-06 11:35 + */ + +@Component +public class LogisticsPluginFactory { + + + @Autowired + private SettingService settingService; + + + /** + * 获取logistics client + * + * @return + */ + public LogisticsPlugin filePlugin() { + + LogisticsSetting logisticsSetting = null; + try { + Setting setting = settingService.get(SettingEnum.LOGISTICS_SETTING.name()); + logisticsSetting = JSONUtil.toBean(setting.getSettingValue(), LogisticsSetting.class); + switch (LogisticsEnum.valueOf(logisticsSetting.getType())) { + case KDNIAO: + return new KdniaoPlugin(logisticsSetting); + case KUAIDI100: + return new Kuaidi100Plugin(logisticsSetting); + default: + throw new ServiceException(); + } + } catch (Exception e) { + throw new ServiceException(); + } + } + + +} diff --git a/framework/src/main/java/cn/lili/modules/logistics/entity/dto/LabelOrderDTO.java b/framework/src/main/java/cn/lili/modules/logistics/entity/dto/LabelOrderDTO.java new file mode 100644 index 00000000..c1072d65 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/logistics/entity/dto/LabelOrderDTO.java @@ -0,0 +1,31 @@ +package cn.lili.modules.logistics.entity.dto; + +import cn.lili.modules.order.order.entity.dos.Order; +import cn.lili.modules.order.order.entity.dos.OrderItem; +import cn.lili.modules.store.entity.dos.StoreLogistics; +import cn.lili.modules.store.entity.dto.StoreDeliverGoodsAddressDTO; +import cn.lili.modules.system.entity.dos.Logistics; +import lombok.Data; + +import java.util.List; + +/** + * 电子面单DTO + * + * @author Bulbasaur + * @since 2023-02-16 + */ +@Data +public class LabelOrderDTO { + + //订单 + Order order; + //订单货物 + List orderItems; + //物流公司 + Logistics logistics; + //店铺物流公司配置 + StoreLogistics storeLogistics; + //店铺发件地址 + StoreDeliverGoodsAddressDTO storeDeliverGoodsAddressDTO; +} diff --git a/framework/src/main/java/cn/lili/modules/logistics/entity/enums/LogisticsEnum.java b/framework/src/main/java/cn/lili/modules/logistics/entity/enums/LogisticsEnum.java new file mode 100644 index 00000000..2783c27e --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/logistics/entity/enums/LogisticsEnum.java @@ -0,0 +1,15 @@ +package cn.lili.modules.logistics.entity.enums; + +/** + * LogisticsEnum + * + * @author Bulbasaur + * @version v1.0 + * 2022-06-06 11:23 + */ +public enum LogisticsEnum { + /** + * 快递查询渠道 + */ + KDNIAO, KUAIDI100; +} diff --git a/framework/src/main/java/cn/lili/modules/kdBrid/serviceImpl/KdNiaoServiceImpl.java b/framework/src/main/java/cn/lili/modules/logistics/plugin/kdniao/KdniaoPlugin.java similarity index 61% rename from framework/src/main/java/cn/lili/modules/kdBrid/serviceImpl/KdNiaoServiceImpl.java rename to framework/src/main/java/cn/lili/modules/logistics/plugin/kdniao/KdniaoPlugin.java index 482fcf2d..a2f13e75 100644 --- a/framework/src/main/java/cn/lili/modules/kdBrid/serviceImpl/KdNiaoServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/logistics/plugin/kdniao/KdniaoPlugin.java @@ -1,35 +1,22 @@ -package cn.lili.modules.kdBrid.serviceImpl; +package cn.lili.modules.logistics.plugin.kdniao; import cn.hutool.core.text.CharSequenceUtil; import cn.lili.common.enums.ResultCode; import cn.lili.common.exception.ServiceException; -import cn.lili.common.security.OperationalJudgment; -import cn.lili.modules.kdBrid.service.KdNiaoService; -import cn.lili.modules.member.service.StoreLogisticsService; -import cn.lili.modules.order.order.aop.OrderLogPoint; +import cn.lili.modules.logistics.LogisticsPlugin; +import cn.lili.modules.logistics.entity.dto.LabelOrderDTO; +import cn.lili.modules.logistics.entity.enums.LogisticsEnum; import cn.lili.modules.order.order.entity.dos.Order; import cn.lili.modules.order.order.entity.dos.OrderItem; -import cn.lili.modules.order.order.entity.enums.DeliverStatusEnum; -import cn.lili.modules.order.order.entity.enums.OrderStatusEnum; -import cn.lili.modules.order.order.service.OrderItemService; -import cn.lili.modules.order.order.service.OrderService; import cn.lili.modules.store.entity.dos.StoreLogistics; import cn.lili.modules.store.entity.dto.StoreDeliverGoodsAddressDTO; -import cn.lili.modules.store.service.StoreDetailService; import cn.lili.modules.system.entity.dos.Logistics; -import cn.lili.modules.system.entity.dos.Setting; -import cn.lili.modules.system.entity.dto.KuaidiSetting; -import cn.lili.modules.system.entity.enums.SettingEnum; -import cn.lili.modules.system.service.LogisticsService; -import cn.lili.modules.system.service.SettingService; +import cn.lili.modules.system.entity.dto.LogisticsSetting; +import cn.lili.modules.system.entity.vo.Traces; +import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import com.google.gson.Gson; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import java.io.*; import java.net.HttpURLConnection; @@ -42,111 +29,116 @@ import java.util.List; import java.util.Map; /** - * 快递鸟电子面单业务层实现 + * 快递鸟插件 * - * @author chc - * @since 2022-4-12 10:12:43 + * @author Bulbasaur */ -@Service @Slf4j -public class KdNiaoServiceImpl implements KdNiaoService { - /** - * 订单货物 - */ - @Autowired - OrderItemService orderItemService; +public class KdniaoPlugin implements LogisticsPlugin { - /** - * 订单 - */ @Autowired - OrderService orderService; - - /** - * 物流公司 - */ - @Autowired - LogisticsService logisticsService; - - /** - * 商家店铺 - */ - @Autowired - StoreDetailService storeDetailService; - - /** - * 配置 - */ - @Autowired - SettingService settingService; - - /** - * 店铺-物流 - */ - @Autowired - StoreLogisticsService storeLogisticsService; + private LogisticsSetting logisticsSetting; + public KdniaoPlugin(LogisticsSetting logisticsSetting) { + this.logisticsSetting = logisticsSetting; + } @Override - @OrderLogPoint(description = "'订单['+#orderSn+']发货,打印电子面单'", orderSn = "#orderSn") - @Transactional(rollbackFor = Exception.class) - public String createElectronicsFaceSheet(String orderSn, String logisticsId) throws Exception { - //电子面单模板 - String printTemplate = null; - //获取订单及子订单 - Order order = OperationalJudgment.judgment(orderService.getBySn(orderSn)); - List orderItems = orderItemService.getByOrderSn(orderSn); + public LogisticsEnum pluginName() { + return LogisticsEnum.KDNIAO; + } - Setting setting = settingService.get(SettingEnum.KUAIDI_SETTING.name()); - if (CharSequenceUtil.isBlank(setting.getSettingValue())) { - throw new ServiceException(ResultCode.LOGISTICS_NOT_SETTING); + @Override + public Traces pollQuery(Logistics logistics, String expNo, String phone) { + try { + String requestData = "{'OrderCode':'','ShipperCode':'" + logistics.getCode() + + "','LogisticCode':'" + expNo + "'" + + ",'CustomerName':'" + phone.substring(phone.length() - 4) + "'" + + "}"; + //请求地址-测试地址 + String testReqURL = "http://sandboxapi.kdniao.com:8080/kdniaosandbox/gateway/exterfaceInvoke.json"; + //请求地址-正式地址 + String reqURL = "https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx"; + Map params = new HashMap<>(8); + params.put("RequestData", urlEncoder(requestData, "UTF-8")); + params.put("EBusinessID", logisticsSetting.getKdniaoEbusinessID()); + params.put("RequestType", "1002"); + String dataSign = encrypt(requestData, logisticsSetting.getKdniaoAppKey(), "UTF-8"); + params.put("DataSign", urlEncoder(dataSign, "UTF-8")); + params.put("DataType", "2"); + + String result = sendPost(reqURL, params); + Map map = (Map) JSON.parse(result); + return new Traces(logistics.getName(), expNo, (List) map.get("Traces")); + } catch (Exception e) { + e.printStackTrace(); } - KuaidiSetting kuaidiSetting = new Gson().fromJson(setting.getSettingValue(), KuaidiSetting.class); + return null; + } - //ID - String EBusinessID = kuaidiSetting.getEbusinessID(); - - //KEY - String AppKey = kuaidiSetting.getAppKey(); - - //请求url - String ReqURL = kuaidiSetting.getSheetReqURL(); - - //如果订单未发货,并且订单状态值等于待发货 - if (order.getDeliverStatus().equals(DeliverStatusEnum.UNDELIVERED.name()) && order.getOrderStatus().equals(OrderStatusEnum.UNDELIVERED.name())) { + @Override + public Traces pollMapTrack(Logistics logistics, String expNo, String phone, String from, String to) { + try { + //请求地址-测试地址 + String testReqURL = "http://sandboxapi.kdniao.com:8080/kdniaosandbox/gateway/exterfaceInvoke.json"; + //请求地址-正式地址 + String reqURL = "https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx"; + String RequestData = "{" + + "'OrderCode': ''," + + "'CustomerName': '" + phone.substring(phone.length() - 4) + "'," + + "'ShipperCode': '" + logistics.getCode() + "'," + + "'LogisticCode': '" + expNo + "'," + + "'SenderCityName': '" + from + "'," + + "'ReceiverCityName': '" + to + "'," + + "'IsReturnCoordinates': 1," + + "'IsReturnRouteMap': 1," + + "}"; + // 组装系统级参数 + Map params = new HashMap(); + params.put("RequestData", urlEncoder(RequestData, "UTF-8")); + params.put("EBusinessID", logisticsSetting.getKdniaoEbusinessID()); + params.put("RequestType", "8003"); + String dataSign = encrypt(RequestData, logisticsSetting.getKdniaoAppKey(), "UTF-8"); + params.put("DataSign", urlEncoder(dataSign, "UTF-8")); + // params.put("DataType", "2"); + // 以form表单形式提交post请求,post请求体中包含了应用级参数和系统级参数 + String result = sendPost(reqURL, params); + log.error(result); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + @Override + public String labelOrder(LabelOrderDTO labelOrderDTO) { + try { + //订单 + Order order = labelOrderDTO.getOrder(); + //订单货物 + List orderItems = labelOrderDTO.getOrderItems(); //获取对应物流 - Logistics logistics = logisticsService.getById(logisticsId); - - //物流为空,抛出异常 - if (logistics == null) { - throw new ServiceException(ResultCode.ORDER_LOGISTICS_ERROR); - } - - //获取店家的物流信息 - LambdaQueryWrapper lambdaQueryWrapper = Wrappers.lambdaQuery(); - lambdaQueryWrapper.eq(StoreLogistics::getLogisticsId, logisticsId); - lambdaQueryWrapper.eq(StoreLogistics::getStoreId, order.getStoreId()); - StoreLogistics storeLogistics = storeLogisticsService.getOne(lambdaQueryWrapper); - - //获取店家信息 - StoreDeliverGoodsAddressDTO storeDeliverGoodsAddressDTO = storeDetailService.getStoreDeliverGoodsAddressDto(order.getStoreId()); + Logistics logistics = labelOrderDTO.getLogistics(); //收件人地址 String[] ConsigneeAddress = order.getConsigneeAddressPath().split(","); + //获取店家信息 + StoreDeliverGoodsAddressDTO storeDeliverGoodsAddressDTO = labelOrderDTO.getStoreDeliverGoodsAddressDTO(); //发件人地址 String[] consignorAddress = storeDeliverGoodsAddressDTO.getSalesConsignorAddressPath().split(","); + //店铺-物流公司设置 + StoreLogistics storeLogistics = labelOrderDTO.getStoreLogistics(); //组装快递鸟应用级参数 String resultDate = "{" + - "'OrderCode': '" + orderSn + "'," + //订单编码 + "'OrderCode': '" + order.getSn() + "'," + //订单编码 "'ShipperCode': '" + logistics.getCode() + "'," + //快递公司编码 - "'CustomerName': '"+storeLogistics.getCustomerName()+"'," +//客户编码 - "'CustomerPwd': '"+storeLogistics.getCustomerPwd()+"'," + //客户密码 - "'MonthCode': '"+storeLogistics.getMonthCode()+"'," + //密钥 - "'SendSite': '"+storeLogistics.getSendSite()+"'," + //归属网点 - "'SendStaff': '"+storeLogistics.getSendStaff()+"'," + //收件快递员 - "'PayType': "+storeLogistics.getPayType()+"," + - "'ExpType': "+storeLogistics.getExpType()+"," + + "'CustomerName': '" + storeLogistics.getCustomerName() + "'," +//客户编码 + "'CustomerPwd': '" + storeLogistics.getCustomerPwd() + "'," + //客户密码 + "'MonthCode': '" + storeLogistics.getMonthCode() + "'," + //密钥 + "'SendSite': '" + storeLogistics.getSendSite() + "'," + //归属网点 + "'SendStaff': '" + storeLogistics.getSendStaff() + "'," + //收件快递员 + "'PayType': " + storeLogistics.getPayType() + "," + + "'ExpType': " + storeLogistics.getExpType() + "," + //发件人信息 "'Sender': {" + "'Name': '" + storeDeliverGoodsAddressDTO.getSalesConsignorName() + "'," + @@ -176,45 +168,49 @@ public class KdNiaoServiceImpl implements KdNiaoService { "},"; } resultDate = resultDate + "]," + - "'Quantity': "+orderItems.size()+"," + //包裹数 - "'IsReturnPrintTemplate':1,"+ //生成电子面单模板 - "'Remark': '" + order.getRemark() + "'"+//商家备注 + "'Quantity': " + orderItems.size() + "," + //包裹数 + "'IsReturnPrintTemplate':1," + //生成电子面单模板 + "'Remark': '" + order.getRemark() + "'" +//商家备注 "}"; //组织系统级参数 Map params = new HashMap<>(); + //请求地址-测试地址 + String testReqURL = "http://sandboxapi.kdniao.com:8080/kdniaosandbox/gateway/exterfaceInvoke.json"; + //请求地址-正式地址 + String reqURL = "https://api.kdniao.com/api/EOrderService"; + //进行格式加密 params.put("RequestData", urlEncoder(resultDate, "UTF-8")); - params.put("EBusinessID", EBusinessID); + params.put("EBusinessID", logisticsSetting.getKdniaoEbusinessID()); params.put("RequestType", "1007"); - String dataSign = encrypt(resultDate, AppKey, "UTF-8"); + String dataSign = encrypt(resultDate, logisticsSetting.getKdniaoAppKey(), "UTF-8"); params.put("DataSign", dataSign); params.put("DataType", "2"); // 以form表单形式提交post请求,post请求体中包含了应用级参数和系统级参数 - String result = sendPost(ReqURL, params); - if(CharSequenceUtil.isEmpty(result) || CharSequenceUtil.isBlank(result)){ + String result = sendPost(reqURL, params); + if (CharSequenceUtil.isEmpty(result) || CharSequenceUtil.isBlank(result)) { throw new ServiceException(ResultCode.LOGISTICS_CHECK_SETTING); } //根据公司业务处理返回的信息...... JSONObject obj = JSONObject.parseObject(result); - log.info("电子面单响应:{}",result); - if(!"100".equals(obj.getString("ResultCode"))){ + log.info("电子面单响应:{}", result); + if (!"100".equals(obj.getString("ResultCode"))) { return obj.getString("Reason"); } JSONObject orderJson = JSONObject.parseObject(obj.getString("Order")); - //电子面单模板 - printTemplate = obj.getString("PrintTemplate"); - - //进行发货 - orderService.delivery(orderSn, orderJson.getString("LogisticCode"), logisticsId); + return obj.getString("PrintTemplate"); + } catch (Exception e) { + e.printStackTrace(); } - return printTemplate; + return null; } + /** * MD5加密 * @@ -323,7 +319,7 @@ public class KdNiaoServiceImpl implements KdNiaoService { result.append(line); } } catch (Exception e) { - e.printStackTrace(); + log.error("向指定 URL 发送POST方法的请求错误", e); } //使用finally块来关闭输出流、输入流 finally { @@ -381,5 +377,4 @@ public class KdNiaoServiceImpl implements KdNiaoService { } return sb.toString(); } - } diff --git a/framework/src/main/java/cn/lili/modules/logistics/plugin/kuaidi100/Kuaidi100Plugin.java b/framework/src/main/java/cn/lili/modules/logistics/plugin/kuaidi100/Kuaidi100Plugin.java new file mode 100644 index 00000000..62e8b633 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/logistics/plugin/kuaidi100/Kuaidi100Plugin.java @@ -0,0 +1,184 @@ +package cn.lili.modules.logistics.plugin.kuaidi100; + +import cn.lili.modules.logistics.LogisticsPlugin; +import cn.lili.modules.logistics.entity.dto.LabelOrderDTO; +import cn.lili.modules.logistics.entity.enums.LogisticsEnum; +import cn.lili.modules.logistics.plugin.kuaidi100.utils.Kuaidi100SignUtils; +import cn.lili.modules.order.order.entity.dos.Order; +import cn.lili.modules.order.order.entity.dos.OrderItem; +import cn.lili.modules.store.entity.dos.StoreLogistics; +import cn.lili.modules.store.entity.dto.StoreDeliverGoodsAddressDTO; +import cn.lili.modules.system.entity.dos.Logistics; +import cn.lili.modules.system.entity.dto.LogisticsSetting; +import cn.lili.modules.system.entity.vo.Traces; +import com.google.gson.Gson; +import com.kuaidi100.sdk.api.LabelV2; +import com.kuaidi100.sdk.api.QueryTrack; +import com.kuaidi100.sdk.api.QueryTrackMap; +import com.kuaidi100.sdk.contant.ApiInfoConstant; +import com.kuaidi100.sdk.contant.PrintType; +import com.kuaidi100.sdk.core.IBaseClient; +import com.kuaidi100.sdk.pojo.HttpResult; +import com.kuaidi100.sdk.request.ManInfo; +import com.kuaidi100.sdk.request.PrintReq; +import com.kuaidi100.sdk.request.QueryTrackParam; +import com.kuaidi100.sdk.request.QueryTrackReq; +import com.kuaidi100.sdk.request.labelV2.OrderReq; +import com.kuaidi100.sdk.response.QueryTrackData; +import com.kuaidi100.sdk.response.QueryTrackMapResp; +import com.kuaidi100.sdk.response.QueryTrackResp; +import com.kuaidi100.sdk.response.samecity.OrderResp; +import com.kuaidi100.sdk.utils.SignUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 快递100插件 + * + * @author Bulbasaur + */ +@Slf4j +public class Kuaidi100Plugin implements LogisticsPlugin { + + + @Autowired + private LogisticsSetting logisticsSetting; + + public Kuaidi100Plugin(LogisticsSetting logisticsSetting) { + this.logisticsSetting = logisticsSetting; + } + + @Override + public LogisticsEnum pluginName() { + return LogisticsEnum.KUAIDI100; + } + + @Override + public Traces pollQuery(Logistics logistics, String expNo, String phone) { + try { + QueryTrackReq queryTrackReq = new QueryTrackReq(); + QueryTrackParam queryTrackParam = new QueryTrackParam(); + queryTrackParam.setCom(logistics.getCode()); + queryTrackParam.setNum(expNo); + queryTrackParam.setPhone(phone); + String param = new Gson().toJson(queryTrackParam); + + queryTrackReq.setParam(param); + queryTrackReq.setCustomer(logisticsSetting.getKuaidi100Customer()); + queryTrackReq.setSign(Kuaidi100SignUtils.querySign(param, logisticsSetting.getKuaidi100Key(), logisticsSetting.getKuaidi100Customer())); + + IBaseClient baseClient = new QueryTrack(); + HttpResult httpResult = baseClient.execute(queryTrackReq); + QueryTrackResp queryTrackResp = new Gson().fromJson(httpResult.getBody(), QueryTrackResp.class); + log.info(String.valueOf(queryTrackResp.getData())); + + List traces = new ArrayList<>(); + for (QueryTrackData queryTrackData : queryTrackResp.getData()) { + Map map = new HashMap(); + map.put("AcceptTime", queryTrackData.getTime()); + map.put("AcceptStation", queryTrackData.getContext()); + map.put("Remark", null); + traces.add(map); + } + return new Traces(logistics.getName(), expNo, traces); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + @Override + public Traces pollMapTrack(Logistics logistics, String expNo, String phone, String from, String to) { + try { + QueryTrackReq queryTrackReq = new QueryTrackReq(); + QueryTrackParam queryTrackParam = new QueryTrackParam(); + queryTrackParam.setCom(logistics.getCode()); + queryTrackParam.setNum(expNo); + queryTrackParam.setPhone(phone); + queryTrackParam.setFrom(from); + queryTrackParam.setTo(to); + queryTrackParam.setResultv2("5"); + String param = new Gson().toJson(queryTrackParam); + + queryTrackReq.setParam(param); + queryTrackReq.setCustomer(logisticsSetting.getKuaidi100Customer()); + queryTrackReq.setSign(SignUtils.querySign(param, logisticsSetting.getKuaidi100Key(), logisticsSetting.getKuaidi100Customer())); + + IBaseClient baseClient = new QueryTrackMap(); + HttpResult result = baseClient.execute(queryTrackReq); + + QueryTrackMapResp queryTrackMapResp = new Gson().fromJson(result.getBody(), QueryTrackMapResp.class); + System.out.println(queryTrackMapResp); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + @Override + public String labelOrder(LabelOrderDTO labelOrderDTO) { + try { + //订单 + Order order = labelOrderDTO.getOrder(); + //订单货物 + List orderItems = labelOrderDTO.getOrderItems(); + //获取对应物流 + Logistics logistics = labelOrderDTO.getLogistics(); + //收件人地址 + String[] consigneeAddress = order.getConsigneeAddressPath().split(","); + //获取店家信息 + StoreDeliverGoodsAddressDTO storeDeliverGoodsAddressDTO = labelOrderDTO.getStoreDeliverGoodsAddressDTO(); + //发件人地址 + String[] consignorAddress = storeDeliverGoodsAddressDTO.getSalesConsignorAddressPath().split(","); + //店铺-物流公司设置 + StoreLogistics storeLogistics = labelOrderDTO.getStoreLogistics(); + + + ManInfo recManInfo = new ManInfo(); + recManInfo.setName(order.getConsigneeName()); + recManInfo.setMobile(order.getConsigneeMobile()); + recManInfo.setPrintAddr(consigneeAddress[0] + consigneeAddress[1] + consigneeAddress[2] + consigneeAddress[3] + order.getConsigneeDetail()); + + ManInfo sendManInfo = new ManInfo(); + sendManInfo.setName(storeDeliverGoodsAddressDTO.getSalesConsignorName()); + sendManInfo.setMobile(storeDeliverGoodsAddressDTO.getSalesConsignorMobile()); + sendManInfo.setPrintAddr(consignorAddress[0] + consignorAddress[1] + consignorAddress[2] + consignorAddress[3] + storeDeliverGoodsAddressDTO.getSalesConsignorDetail()); + + OrderReq orderReq = new OrderReq(); + orderReq.setKuaidicom(logistics.getCode()); + orderReq.setCount(1); + // orderReq.setSiid(siid); + //orderReq.setTempId("60f6c17c7c223700131d8bc3"); + orderReq.setSendMan(sendManInfo); + orderReq.setRecMan(recManInfo); + + orderReq.setPrintType(PrintType.CLOUD); + + String param = new Gson().toJson(orderReq); + String t = System.currentTimeMillis() + ""; + + PrintReq printReq = new PrintReq(); + printReq.setT(t); + printReq.setKey(logisticsSetting.getKuaidi100Key()); + printReq.setSign(SignUtils.printSign(param, t, logisticsSetting.getKuaidi100Key(), logisticsSetting.getKuaidi100Customer())); + printReq.setMethod(ApiInfoConstant.ORDER); + printReq.setParam(param); + + IBaseClient baseClient = new LabelV2(); + HttpResult result = baseClient.execute(printReq); + System.out.println(result.getBody()); + QueryTrackMapResp queryTrackMapResp = new Gson().fromJson(result.getBody(), QueryTrackMapResp.class); + OrderResp orderResp = new Gson().fromJson(result.getBody(), OrderResp.class); + + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + +} diff --git a/framework/src/main/java/cn/lili/modules/logistics/plugin/kuaidi100/utils/Kuaidi100SignUtils.java b/framework/src/main/java/cn/lili/modules/logistics/plugin/kuaidi100/utils/Kuaidi100SignUtils.java new file mode 100644 index 00000000..b90470ec --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/logistics/plugin/kuaidi100/utils/Kuaidi100SignUtils.java @@ -0,0 +1,73 @@ +package cn.lili.modules.logistics.plugin.kuaidi100.utils; + +import org.apache.commons.codec.digest.DigestUtils; + +/** + * @Author: api.kuaidi100.com + * @Date: 2020-07-14 16:54 + */ +public class Kuaidi100SignUtils { + + /** + * 快递100加密方式统一为MD5后转大写 + * + * @param msg + * @return + */ + public static String sign(String msg) { + return DigestUtils.md5Hex(msg).toUpperCase(); + } + + /** + * 查询加密 + * + * @param param + * @param key + * @param customer + * @return + */ + public static String querySign(String param, String key, String customer) { + return sign(param + key + customer); + } + + /** + * 打印/下单 加密 + * + * @param param + * @param t + * @param key + * @param secret + * @return: java.lang.String + * @author: api.kuaidi100.com + * @time: 2020/12/3 9:23 + */ + public static String printSign(String param, String t, String key, String secret) { + return sign(param + t + key + secret); + } + + /** + * 云平台 加密 + * + * @param key + * @param secret + * @return: java.lang.String + * @author: api.kuaidi100.com + * @time: 2020/12/3 9:23 + */ + public static String cloudSign(String key, String secret) { + return sign(key + secret); + } + + /** + * 短信加密 + * + * @param key + * @param userId + * @return: java.lang.String + * @author: api.kuaidi100.com + * @time: 2020/12/3 9:32 + */ + public static String smsSign(String key, String userId) { + return sign(key + userId); + } +} diff --git a/framework/src/main/java/cn/lili/modules/order/aftersale/serviceimpl/AfterSaleServiceImpl.java b/framework/src/main/java/cn/lili/modules/order/aftersale/serviceimpl/AfterSaleServiceImpl.java index c6724bc4..c6f9507c 100644 --- a/framework/src/main/java/cn/lili/modules/order/aftersale/serviceimpl/AfterSaleServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/order/aftersale/serviceimpl/AfterSaleServiceImpl.java @@ -269,8 +269,7 @@ public class AfterSaleServiceImpl extends ServiceImpl { * 根据促销查询订单 * * @param orderPromotionType 订单类型 - * @param payStatus 支付状态 - * @param parentOrderSn 依赖订单编号 - * @param orderSn 订单编号 + * @param payStatus 支付状态 + * @param parentOrderSn 依赖订单编号 + * @param orderSn 订单编号 * @return 订单信息 */ List queryListByPromotion(String orderPromotionType, String payStatus, String parentOrderSn, String orderSn); @@ -75,9 +75,9 @@ public interface OrderService extends IService { * 根据促销查询订单 * * @param orderPromotionType 订单类型 - * @param payStatus 支付状态 - * @param parentOrderSn 依赖订单编号 - * @param orderSn 订单编号 + * @param payStatus 支付状态 + * @param parentOrderSn 依赖订单编号 + * @param orderSn 订单编号 * @return 订单信息 */ long queryCountByPromotion(String orderPromotionType, String payStatus, String parentOrderSn, String orderSn); @@ -91,7 +91,6 @@ public interface OrderService extends IService { List queryListByPromotion(String pintuanId); - /** * 查询导出订单列表 * @@ -174,6 +173,14 @@ public interface OrderService extends IService { */ Traces getTraces(String orderSn); + /** + * 获取地图版 物流踪迹 + * + * @param orderSn 订单编号 + * @return 物流踪迹 + */ + Traces getMapTraces(String orderSn); + /** * 订单核验 * @@ -288,9 +295,9 @@ public interface OrderService extends IService { /** * 检查是否开始虚拟成团 * - * @param pintuanId 拼团活动id + * @param pintuanId 拼团活动id * @param requiredNum 成团人数 - * @param fictitious 是否开启成团 + * @param fictitious 是否开启成团 * @return 是否成功 */ boolean checkFictitiousOrder(String pintuanId, Integer requiredNum, Boolean fictitious); diff --git a/framework/src/main/java/cn/lili/modules/order/order/serviceimpl/OrderServiceImpl.java b/framework/src/main/java/cn/lili/modules/order/order/serviceimpl/OrderServiceImpl.java index 783efbc9..1c202c1f 100644 --- a/framework/src/main/java/cn/lili/modules/order/order/serviceimpl/OrderServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/order/order/serviceimpl/OrderServiceImpl.java @@ -16,7 +16,6 @@ import cn.lili.common.properties.RocketmqCustomProperties; import cn.lili.common.security.OperationalJudgment; import cn.lili.common.security.context.UserContext; import cn.lili.common.security.enums.UserEnums; -import cn.lili.common.utils.ObjectUtil; import cn.lili.common.utils.SnowFlake; import cn.lili.modules.goods.entity.dto.GoodsCompleteMessage; import cn.lili.modules.member.entity.dto.MemberAddressDTO; @@ -41,6 +40,8 @@ import cn.lili.modules.order.trade.service.OrderLogService; import cn.lili.modules.payment.entity.enums.PaymentMethodEnum; import cn.lili.modules.promotion.entity.dos.Pintuan; import cn.lili.modules.promotion.service.PintuanService; +import cn.lili.modules.store.entity.dto.StoreDeliverGoodsAddressDTO; +import cn.lili.modules.store.service.StoreDetailService; import cn.lili.modules.system.aspect.annotation.SystemLogPoint; import cn.lili.modules.system.entity.dos.Logistics; import cn.lili.modules.system.entity.vo.Traces; @@ -149,6 +150,9 @@ public class OrderServiceImpl extends ServiceImpl implements @Autowired private ApplicationEventPublisher applicationEventPublisher; + @Autowired + private StoreDetailService storeDetailService; + @Override @Transactional(rollbackFor = Exception.class) public void intoDB(TradeDTO tradeDTO) { @@ -297,7 +301,7 @@ public class OrderServiceImpl extends ServiceImpl implements Order order = OperationalJudgment.judgment(this.getBySn(orderSn)); //如果订单促销类型不为空&&订单是拼团订单,并且订单未成团,则抛出异常 if (OrderPromotionTypeEnum.PINTUAN.name().equals(order.getOrderPromotionType()) - && !CharSequenceUtil.equalsAny(order.getOrderStatus(),OrderStatusEnum.UNDELIVERED.name(),OrderStatusEnum.STAY_PICKED_UP.name())) { + && !CharSequenceUtil.equalsAny(order.getOrderStatus(), OrderStatusEnum.UNDELIVERED.name(), OrderStatusEnum.STAY_PICKED_UP.name())) { throw new ServiceException(ResultCode.ORDER_CAN_NOT_CANCEL); } if (CharSequenceUtil.equalsAny(order.getOrderStatus(), @@ -461,8 +465,19 @@ public class OrderServiceImpl extends ServiceImpl implements //获取订单信息 Order order = this.getBySn(orderSn); //获取踪迹信息 - String str = order.getConsigneeMobile(); - return logisticsService.getLogistic(order.getLogisticsCode(), order.getLogisticsNo(), str.substring(str.length() - 4)); + return logisticsService.getLogisticTrack(order.getLogisticsCode(), order.getLogisticsNo(), order.getConsigneeMobile()); + } + + @Override + public Traces getMapTraces(String orderSn) { + //获取订单信息 + Order order = this.getBySn(orderSn); + //获取店家信息 + StoreDeliverGoodsAddressDTO storeDeliverGoodsAddressDTO = storeDetailService.getStoreDeliverGoodsAddressDto(order.getStoreId()); + String from = storeDeliverGoodsAddressDTO.getSalesConsignorAddressPath().substring(0, storeDeliverGoodsAddressDTO.getSalesConsignorAddressPath().indexOf(",") - 1); + String to = order.getConsigneeAddressPath().substring(0, order.getConsigneeAddressPath().indexOf(",") - 1); + //获取踪迹信息 + return logisticsService.getLogisticMapTrack(order.getLogisticsCode(), order.getLogisticsNo(), order.getConsigneeMobile(), from, to); } @Override @@ -484,7 +499,7 @@ public class OrderServiceImpl extends ServiceImpl implements public Order take(String verificationCode) { String storeId = OperationalJudgment.judgment(UserContext.getCurrentUser()).getStoreId(); Order order = this.getOne(new LambdaQueryWrapper().eq(Order::getVerificationCode, verificationCode).eq(Order::getStoreId, storeId)); - if(order == null){ + if (order == null) { throw new ServiceException(ResultCode.ORDER_NOT_EXIST); } order.setOrderStatus(OrderStatusEnum.COMPLETED.name()); @@ -497,7 +512,7 @@ public class OrderServiceImpl extends ServiceImpl implements public Order getOrderByVerificationCode(String verificationCode) { String storeId = Objects.requireNonNull(UserContext.getCurrentUser()).getStoreId(); return this.getOne(new LambdaQueryWrapper() - .in(Order::getOrderStatus, OrderStatusEnum.TAKE.name(),OrderStatusEnum.STAY_PICKED_UP.name()) + .in(Order::getOrderStatus, OrderStatusEnum.TAKE.name(), OrderStatusEnum.STAY_PICKED_UP.name()) .eq(Order::getStoreId, storeId) .eq(Order::getVerificationCode, verificationCode)); } @@ -961,9 +976,9 @@ public class OrderServiceImpl extends ServiceImpl implements public void normalOrderConfirm(String orderSn) { OrderStatusEnum orderStatusEnum = null; Order order = this.getBySn(orderSn); - if(DeliveryMethodEnum.SELF_PICK_UP.name().equals(order.getDeliveryMethod())){ + if (DeliveryMethodEnum.SELF_PICK_UP.name().equals(order.getDeliveryMethod())) { orderStatusEnum = OrderStatusEnum.STAY_PICKED_UP; - }else if (DeliveryMethodEnum.LOGISTICS.name().equals(order.getDeliveryMethod())){ + } else if (DeliveryMethodEnum.LOGISTICS.name().equals(order.getDeliveryMethod())) { orderStatusEnum = OrderStatusEnum.UNDELIVERED; } //修改订单 diff --git a/framework/src/main/java/cn/lili/modules/sms/SmsUtil.java b/framework/src/main/java/cn/lili/modules/sms/SmsUtil.java index fbafeb10..0f0c4621 100644 --- a/framework/src/main/java/cn/lili/modules/sms/SmsUtil.java +++ b/framework/src/main/java/cn/lili/modules/sms/SmsUtil.java @@ -3,7 +3,6 @@ package cn.lili.modules.sms; import cn.lili.modules.verification.entity.enums.VerificationEnums; import java.util.List; -import java.util.Map; /** * 短信接口 @@ -35,15 +34,6 @@ public interface SmsUtil { */ boolean verifyCode(String mobile, VerificationEnums verificationEnums, String uuid, String code); - /** - * 短信发送 - * - * @param mobile 接收手机号 - * @param param 参数 - * @param templateCode 模版code - * @param signName 签名名称 - */ - void sendSmsCode(String signName, String mobile, Map param, String templateCode); /** * 短信批量发送 diff --git a/framework/src/main/java/cn/lili/modules/sms/entity/enums/SmsEnum.java b/framework/src/main/java/cn/lili/modules/sms/entity/enums/SmsEnum.java new file mode 100644 index 00000000..894e6b37 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/sms/entity/enums/SmsEnum.java @@ -0,0 +1,15 @@ +package cn.lili.modules.sms.entity.enums; + +/** + * 短信通道枚举 + * + * @author Bulbasaur + * @since 2023-02-16 + */ +public enum SmsEnum { + + /** + * 短信渠道 + */ + ALI, HUAWEI, TENCENT; +} diff --git a/framework/src/main/java/cn/lili/modules/sms/impl/SmsUtilAliImplService.java b/framework/src/main/java/cn/lili/modules/sms/impl/SmsUtilAliImplService.java index 513748c3..74d4e40f 100644 --- a/framework/src/main/java/cn/lili/modules/sms/impl/SmsUtilAliImplService.java +++ b/framework/src/main/java/cn/lili/modules/sms/impl/SmsUtilAliImplService.java @@ -1,7 +1,6 @@ package cn.lili.modules.sms.impl; import cn.hutool.core.util.StrUtil; -import cn.hutool.json.JSONUtil; import cn.lili.cache.Cache; import cn.lili.cache.CachePrefix; import cn.lili.common.enums.ResultCode; @@ -9,28 +8,21 @@ import cn.lili.common.exception.ServiceException; import cn.lili.common.properties.SmsTemplateProperties; import cn.lili.common.properties.SystemSettingProperties; import cn.lili.common.security.context.UserContext; -import cn.lili.common.utils.Base64Utils; import cn.lili.common.utils.CommonUtil; import cn.lili.modules.member.entity.dos.Member; import cn.lili.modules.member.service.MemberService; -import cn.lili.modules.sms.AliSmsUtil; import cn.lili.modules.sms.SmsUtil; -import cn.lili.modules.sms.entity.dos.SmsSign; -import cn.lili.modules.sms.entity.dos.SmsTemplate; import cn.lili.modules.system.entity.dos.Setting; import cn.lili.modules.system.entity.dto.SmsSetting; import cn.lili.modules.system.entity.enums.SettingEnum; import cn.lili.modules.system.service.SettingService; import cn.lili.modules.verification.entity.enums.VerificationEnums; -import com.aliyun.dysmsapi20170525.models.*; -import com.aliyun.teaopenapi.models.Config; import com.google.gson.Gson; import com.xkcoding.http.util.StringUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -44,7 +36,7 @@ import java.util.Map; */ @Component @Slf4j -public class SmsUtilAliImplService implements SmsUtil, AliSmsUtil { +public class SmsUtilAliImplService implements SmsUtil { @Autowired private Cache cache; @@ -122,9 +114,9 @@ public class SmsUtilAliImplService implements SmsUtil, AliSmsUtil { //如果是测试模式 默认验证码 6个1 if (systemSettingProperties.getIsTestModel()) { code = "111111"; - log.info("测试模式 - 接收手机:{},验证码:{}",mobile,code); + log.info("测试模式 - 接收手机:{},验证码:{}", mobile, code); } else { - log.info("接收手机:{},验证码:{}",mobile,code); + log.info("接收手机:{},验证码:{}", mobile, code); //发送短信 this.sendSmsCode(smsSetting.getSignName(), mobile, params, templateCode); } @@ -145,232 +137,14 @@ public class SmsUtilAliImplService implements SmsUtil, AliSmsUtil { } - @Override - public void sendSmsCode(String signName, String mobile, Map param, String templateCode) { - - com.aliyun.dysmsapi20170525.Client client = this.createClient(); - SendSmsRequest sendSmsRequest = new SendSmsRequest() - .setSignName(signName) - .setPhoneNumbers(mobile) - .setTemplateCode(templateCode) - .setTemplateParam(JSONUtil.toJsonStr(param)); - try { - SendSmsResponse response = client.sendSms(sendSmsRequest); - if (!("OK").equals(response.getBody().getCode())) { - throw new ServiceException(response.getBody().getMessage()); - } - } catch (Exception e) { - log.error("发送短信错误", e); - } - } - @Override public void sendBatchSms(String signName, List mobile, String templateCode) { - com.aliyun.dysmsapi20170525.Client client = this.createClient(); - - List sign = new ArrayList(); - - sign.addAll(mobile); - sign.replaceAll(e -> signName); - - //手机号拆成多个小组进行发送 - List> mobileList = new ArrayList<>(); - - //签名名称多个小组 - List> signNameList = new ArrayList<>(); - - //循环分组 - for (int i = 0; i < (mobile.size() / 100 + (mobile.size() % 100 == 0 ? 0 : 1)); i++) { - int endPoint = Math.min((100 + (i * 100)), mobile.size()); - mobileList.add(mobile.subList((i * 100), endPoint)); - signNameList.add(sign.subList((i * 100), endPoint)); - } - -// //发送短信 - for (int i = 0; i < mobileList.size(); i++) { - SendBatchSmsRequest sendBatchSmsRequest = new SendBatchSmsRequest() - .setPhoneNumberJson(JSONUtil.toJsonStr(mobileList.get(i))) - .setSignNameJson(JSONUtil.toJsonStr(signNameList.get(i))) - .setTemplateCode(templateCode); - try { - client.sendBatchSms(sendBatchSmsRequest); - } catch (Exception e) { - log.error("批量发送短信错误", e); - } - } - } - - @Override - public void addSmsSign(SmsSign smsSign) throws Exception { - //设置参数添加短信签名 - com.aliyun.dysmsapi20170525.Client client = this.createClient(); - //营业执照 - AddSmsSignRequest.AddSmsSignRequestSignFileList signFileList0 = new AddSmsSignRequest.AddSmsSignRequestSignFileList() - .setFileContents(Base64Utils.encode(smsSign.getBusinessLicense())) - .setFileSuffix(smsSign.getBusinessLicense().substring(smsSign.getBusinessLicense().lastIndexOf(".") + 1)); - //授权委托书 - AddSmsSignRequest.AddSmsSignRequestSignFileList signFileList1 = new AddSmsSignRequest.AddSmsSignRequestSignFileList() - .setFileContents(Base64Utils.encode(smsSign.getLicense())) - .setFileSuffix(smsSign.getLicense().substring(smsSign.getLicense().lastIndexOf(".")) + 1); - //添加短信签名 - AddSmsSignRequest addSmsSignRequest = new AddSmsSignRequest() - .setSignName(smsSign.getSignName()) - .setSignSource(smsSign.getSignSource()) - .setRemark(smsSign.getRemark()) - .setSignFileList(java.util.Arrays.asList( - signFileList0, - signFileList1 - )); - AddSmsSignResponse response = client.addSmsSign(addSmsSignRequest); - if (!("OK").equals(response.getBody().getCode())) { - throw new ServiceException(response.getBody().getMessage()); - } - } - - @Override - public void deleteSmsSign(String signName) throws Exception { - com.aliyun.dysmsapi20170525.Client client = this.createClient(); - DeleteSmsSignRequest deleteSmsSignRequest = new DeleteSmsSignRequest() - .setSignName(signName); - - DeleteSmsSignResponse response = client.deleteSmsSign(deleteSmsSignRequest); - if (!("OK").equals(response.getBody().getCode())) { - throw new ServiceException(response.getBody().getMessage()); - } - - } - - @Override - public Map querySmsSign(String signName) throws Exception { - //设置参数查看短信签名 - com.aliyun.dysmsapi20170525.Client client = this.createClient(); - QuerySmsSignRequest querySmsSignRequest = new QuerySmsSignRequest().setSignName(signName); - - QuerySmsSignResponse response = client.querySmsSign(querySmsSignRequest); - if (!("OK").equals(response.getBody().getCode())) { - throw new ServiceException(response.getBody().getMessage()); - } - Map map = new HashMap<>(2); - map.put("SignStatus", response.getBody().getSignStatus()); - map.put("Reason", response.getBody().getReason()); - return map; - } - - @Override - public void modifySmsSign(SmsSign smsSign) throws Exception { - //设置参数添加短信签名 - com.aliyun.dysmsapi20170525.Client client = this.createClient(); - - ModifySmsSignRequest.ModifySmsSignRequestSignFileList signFileList0 = new ModifySmsSignRequest.ModifySmsSignRequestSignFileList() - .setFileContents(Base64Utils.encode(smsSign.getBusinessLicense())) - .setFileSuffix(smsSign.getBusinessLicense().substring(smsSign.getBusinessLicense().lastIndexOf(".") + 1)); - ModifySmsSignRequest.ModifySmsSignRequestSignFileList signFileList1 = new ModifySmsSignRequest.ModifySmsSignRequestSignFileList() - .setFileContents(Base64Utils.encode(smsSign.getLicense())) - .setFileSuffix(smsSign.getLicense().substring(smsSign.getBusinessLicense().lastIndexOf(".") + 1)); - ModifySmsSignRequest modifySmsSign = new ModifySmsSignRequest() - .setSignName(smsSign.getSignName()) - .setSignSource(smsSign.getSignSource()) - .setRemark(smsSign.getRemark()) - .setSignFileList(java.util.Arrays.asList( - signFileList0, - signFileList1 - )); - ModifySmsSignResponse response = client.modifySmsSign(modifySmsSign); - if (!("OK").equals(response.getBody().getCode())) { - throw new ServiceException(response.getBody().getMessage()); - } - } - - @Override - public void modifySmsTemplate(SmsTemplate smsTemplate) throws Exception { - com.aliyun.dysmsapi20170525.Client client = this.createClient(); - ModifySmsTemplateRequest modifySmsTemplateRequest = new ModifySmsTemplateRequest() - .setTemplateType(smsTemplate.getTemplateType()) - .setTemplateName(smsTemplate.getTemplateName()) - .setTemplateContent(smsTemplate.getTemplateContent()) - .setRemark(smsTemplate.getRemark()) - .setTemplateCode(smsTemplate.getTemplateCode()); - - ModifySmsTemplateResponse response = client.modifySmsTemplate(modifySmsTemplateRequest); - if (!("OK").equals(response.getBody().getCode())) { - throw new ServiceException(response.getBody().getMessage()); - } - } - - @Override - public Map querySmsTemplate(String templateCode) throws Exception { - com.aliyun.dysmsapi20170525.Client client = this.createClient(); - QuerySmsTemplateRequest querySmsTemplateRequest = new QuerySmsTemplateRequest() - .setTemplateCode(templateCode); - QuerySmsTemplateResponse response = client.querySmsTemplate(querySmsTemplateRequest); - - if (!("OK").equals(response.getBody().getCode())) { - throw new ServiceException(response.getBody().getMessage()); - } - Map map = new HashMap<>(4); - map.put("TemplateStatus", response.getBody().getTemplateStatus()); - map.put("Reason", response.getBody().getReason()); - map.put("TemplateCode", response.getBody().getTemplateCode()); - return map; - } - - @Override - public String addSmsTemplate(SmsTemplate smsTemplate) throws Exception { - com.aliyun.dysmsapi20170525.Client client = this.createClient(); - AddSmsTemplateRequest addSmsTemplateRequest = new AddSmsTemplateRequest() - .setTemplateType(1) - .setTemplateName(smsTemplate.getTemplateName()) - .setTemplateContent(smsTemplate.getTemplateContent()) - .setRemark(smsTemplate.getRemark()); - - AddSmsTemplateResponse response = client.addSmsTemplate(addSmsTemplateRequest); - if (!("OK").equals(response.getBody().getCode())) { - throw new ServiceException(response.getBody().getMessage()); - } - return response.getBody().getTemplateCode(); - } - - @Override - public void deleteSmsTemplate(String templateCode) throws Exception { - com.aliyun.dysmsapi20170525.Client client = this.createClient(); - DeleteSmsTemplateRequest deleteSmsTemplateRequest = new DeleteSmsTemplateRequest() - .setTemplateCode(templateCode); - - DeleteSmsTemplateResponse response = client.deleteSmsTemplate(deleteSmsTemplateRequest); - if (!("OK").equals(response.getBody().getCode())) { - throw new ServiceException(response.getBody().getMessage()); - } - } + private void sendSmsCode(String signName, String mobile, Map param, String templateCode) { - /** - * 初始化账号Client - * - * @return Client 短信操作util - */ - public com.aliyun.dysmsapi20170525.Client createClient() { - try { - Setting setting = settingService.get(SettingEnum.SMS_SETTING.name()); - if (StrUtil.isBlank(setting.getSettingValue())) { - throw new ServiceException(ResultCode.ALI_SMS_SETTING_ERROR); - } - SmsSetting smsSetting = new Gson().fromJson(setting.getSettingValue(), SmsSetting.class); - - Config config = new Config(); - //您的AccessKey ID - config.accessKeyId = smsSetting.getAccessKeyId(); - //您的AccessKey Secret - config.accessKeySecret = smsSetting.getAccessSecret(); - //访问的域名 - config.endpoint = "dysmsapi.aliyuncs.com"; - return new com.aliyun.dysmsapi20170525.Client(config); - } catch (Exception e) { - log.error("短信初始化错误", e); - } - return null; } /** diff --git a/framework/src/main/java/cn/lili/modules/sms/AliSmsUtil.java b/framework/src/main/java/cn/lili/modules/sms/plugin/SmsPlugin.java similarity index 68% rename from framework/src/main/java/cn/lili/modules/sms/AliSmsUtil.java rename to framework/src/main/java/cn/lili/modules/sms/plugin/SmsPlugin.java index abfab733..dabf86cf 100644 --- a/framework/src/main/java/cn/lili/modules/sms/AliSmsUtil.java +++ b/framework/src/main/java/cn/lili/modules/sms/plugin/SmsPlugin.java @@ -1,16 +1,46 @@ -package cn.lili.modules.sms; +package cn.lili.modules.sms.plugin; import cn.lili.modules.sms.entity.dos.SmsSign; import cn.lili.modules.sms.entity.dos.SmsTemplate; +import cn.lili.modules.sms.entity.enums.SmsEnum; +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +import java.util.List; import java.util.Map; /** - * @author Chopper - * @version v4.1 - * @since 2021/2/1 6:05 下午 + * 短信插件接口 + * + * @author Bulbasaur + * @since 2023-02-16 */ -public interface AliSmsUtil { +public interface SmsPlugin { + + /** + * 插件名称 + */ + SmsEnum pluginName(); + + /** + * 短信发送 + * + * @param mobile 接收手机号 + * @param param 参数 + * @param templateCode 模版code + * @param signName 签名名称 + */ + void sendSmsCode(String signName, String mobile, Map param, String templateCode) throws TencentCloudSDKException; + + /** + * 短信批量发送 + * + * @param mobile 接收手机号 + * @param signName 签名 + * @param templateCode 模版code + */ + void sendBatchSms(String signName, List mobile, String templateCode); + + /** * 申请短信签名 * diff --git a/framework/src/main/java/cn/lili/modules/sms/plugin/SmsPluginFactory.java b/framework/src/main/java/cn/lili/modules/sms/plugin/SmsPluginFactory.java new file mode 100644 index 00000000..0ae7bf5d --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/sms/plugin/SmsPluginFactory.java @@ -0,0 +1,59 @@ +package cn.lili.modules.sms.plugin; + +import cn.hutool.json.JSONUtil; +import cn.lili.common.exception.ServiceException; +import cn.lili.modules.sms.entity.enums.SmsEnum; +import cn.lili.modules.sms.plugin.impl.AliSmsPlugin; +import cn.lili.modules.sms.plugin.impl.HuaweiSmsPlugin; +import cn.lili.modules.sms.plugin.impl.TencentSmsPlugin; +import cn.lili.modules.system.entity.dos.Setting; +import cn.lili.modules.system.entity.dto.SmsSetting; +import cn.lili.modules.system.entity.enums.SettingEnum; +import cn.lili.modules.system.service.SettingService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 短信服务抽象工厂 直接返回操作类 + * + * @author Bulbasaur + * @version v1.0 + * @since 2023-02-16 + */ +@Component +public class SmsPluginFactory { + + @Autowired + private SettingService settingService; + + + /** + * 获取oss client + * + * @return + */ + public SmsPlugin smsPlugin() { + + SmsSetting smsSetting = null; + try { + Setting setting = settingService.get(SettingEnum.SMS_SETTING.name()); + + smsSetting = JSONUtil.toBean(setting.getSettingValue(), SmsSetting.class); + + + switch (SmsEnum.valueOf(smsSetting.getType())) { + + case ALI: + return new AliSmsPlugin(smsSetting); + case TENCENT: + return new TencentSmsPlugin(smsSetting); + case HUAWEI: + return new HuaweiSmsPlugin(smsSetting); + default: + throw new ServiceException(); + } + } catch (Exception e) { + throw new ServiceException(); + } + } +} diff --git a/framework/src/main/java/cn/lili/modules/sms/plugin/impl/AliSmsPlugin.java b/framework/src/main/java/cn/lili/modules/sms/plugin/impl/AliSmsPlugin.java new file mode 100644 index 00000000..e8d7b1aa --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/sms/plugin/impl/AliSmsPlugin.java @@ -0,0 +1,265 @@ +package cn.lili.modules.sms.plugin.impl; + +import cn.hutool.json.JSONUtil; +import cn.lili.common.enums.ResultCode; +import cn.lili.common.exception.ServiceException; +import cn.lili.common.utils.Base64Utils; +import cn.lili.modules.sms.entity.dos.SmsSign; +import cn.lili.modules.sms.entity.dos.SmsTemplate; +import cn.lili.modules.sms.entity.enums.SmsEnum; +import cn.lili.modules.sms.plugin.SmsPlugin; +import cn.lili.modules.system.entity.dto.SmsSetting; +import com.aliyun.dysmsapi20170525.models.*; +import com.aliyun.teaopenapi.models.Config; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 阿里云短信插件 + * + * @author Bulbasaur + * @since 2023-02-16 + */ +@Slf4j +public class AliSmsPlugin implements SmsPlugin { + + private SmsSetting smsSetting; + + public AliSmsPlugin(SmsSetting smsSetting) { + this.smsSetting = smsSetting; + } + + @Override + public SmsEnum pluginName() { + return SmsEnum.ALI; + } + + @Override + public void sendSmsCode(String signName, String mobile, Map param, String templateCode) { + com.aliyun.dysmsapi20170525.Client client = this.createClient(); + SendSmsRequest sendSmsRequest = new SendSmsRequest() + .setSignName(signName) + .setPhoneNumbers(mobile) + .setTemplateCode(templateCode) + .setTemplateParam(JSONUtil.toJsonStr(param)); + try { + SendSmsResponse response = client.sendSms(sendSmsRequest); + if (!("OK").equals(response.getBody().getCode())) { + throw new ServiceException(response.getBody().getMessage()); + } + } catch (Exception e) { + log.error("发送短信错误", e); + } + } + + + @Override + public void sendBatchSms(String signName, List mobile, String templateCode) { + + com.aliyun.dysmsapi20170525.Client client = this.createClient(); + + List sign = new ArrayList(); + + sign.addAll(mobile); + sign.replaceAll(e -> signName); + + //手机号拆成多个小组进行发送 + List> mobileList = new ArrayList<>(); + + //签名名称多个小组 + List> signNameList = new ArrayList<>(); + + //循环分组 + for (int i = 0; i < (mobile.size() / 100 + (mobile.size() % 100 == 0 ? 0 : 1)); i++) { + int endPoint = Math.min((100 + (i * 100)), mobile.size()); + mobileList.add(mobile.subList((i * 100), endPoint)); + signNameList.add(sign.subList((i * 100), endPoint)); + } + +// //发送短信 + for (int i = 0; i < mobileList.size(); i++) { + SendBatchSmsRequest sendBatchSmsRequest = new SendBatchSmsRequest() + .setPhoneNumberJson(JSONUtil.toJsonStr(mobileList.get(i))) + .setSignNameJson(JSONUtil.toJsonStr(signNameList.get(i))) + .setTemplateCode(templateCode); + try { + client.sendBatchSms(sendBatchSmsRequest); + } catch (Exception e) { + log.error("批量发送短信错误", e); + } + } + + } + + @Override + public void addSmsSign(SmsSign smsSign) throws Exception { + //设置参数添加短信签名 + com.aliyun.dysmsapi20170525.Client client = this.createClient(); + //营业执照 + AddSmsSignRequest.AddSmsSignRequestSignFileList signFileList0 = new AddSmsSignRequest.AddSmsSignRequestSignFileList() + .setFileContents(Base64Utils.encode(smsSign.getBusinessLicense())) + .setFileSuffix(smsSign.getBusinessLicense().substring(smsSign.getBusinessLicense().lastIndexOf(".") + 1)); + //授权委托书 + AddSmsSignRequest.AddSmsSignRequestSignFileList signFileList1 = new AddSmsSignRequest.AddSmsSignRequestSignFileList() + .setFileContents(Base64Utils.encode(smsSign.getLicense())) + .setFileSuffix(smsSign.getLicense().substring(smsSign.getLicense().lastIndexOf(".")) + 1); + //添加短信签名 + AddSmsSignRequest addSmsSignRequest = new AddSmsSignRequest() + .setSignName(smsSign.getSignName()) + .setSignSource(smsSign.getSignSource()) + .setRemark(smsSign.getRemark()) + .setSignFileList(java.util.Arrays.asList( + signFileList0, + signFileList1 + )); + AddSmsSignResponse response = client.addSmsSign(addSmsSignRequest); + if (!("OK").equals(response.getBody().getCode())) { + throw new ServiceException(response.getBody().getMessage()); + } + } + + @Override + public void deleteSmsSign(String signName) throws Exception { + com.aliyun.dysmsapi20170525.Client client = this.createClient(); + DeleteSmsSignRequest deleteSmsSignRequest = new DeleteSmsSignRequest() + .setSignName(signName); + + DeleteSmsSignResponse response = client.deleteSmsSign(deleteSmsSignRequest); + if (!("OK").equals(response.getBody().getCode())) { + throw new ServiceException(response.getBody().getMessage()); + } + + } + + @Override + public Map querySmsSign(String signName) throws Exception { + //设置参数查看短信签名 + com.aliyun.dysmsapi20170525.Client client = this.createClient(); + QuerySmsSignRequest querySmsSignRequest = new QuerySmsSignRequest().setSignName(signName); + + QuerySmsSignResponse response = client.querySmsSign(querySmsSignRequest); + if (!("OK").equals(response.getBody().getCode())) { + throw new ServiceException(response.getBody().getMessage()); + } + Map map = new HashMap<>(2); + map.put("SignStatus", response.getBody().getSignStatus()); + map.put("Reason", response.getBody().getReason()); + return map; + } + + @Override + public void modifySmsSign(SmsSign smsSign) throws Exception { + //设置参数添加短信签名 + com.aliyun.dysmsapi20170525.Client client = this.createClient(); + + ModifySmsSignRequest.ModifySmsSignRequestSignFileList signFileList0 = new ModifySmsSignRequest.ModifySmsSignRequestSignFileList() + .setFileContents(Base64Utils.encode(smsSign.getBusinessLicense())) + .setFileSuffix(smsSign.getBusinessLicense().substring(smsSign.getBusinessLicense().lastIndexOf(".") + 1)); + ModifySmsSignRequest.ModifySmsSignRequestSignFileList signFileList1 = new ModifySmsSignRequest.ModifySmsSignRequestSignFileList() + .setFileContents(Base64Utils.encode(smsSign.getLicense())) + .setFileSuffix(smsSign.getLicense().substring(smsSign.getBusinessLicense().lastIndexOf(".") + 1)); + ModifySmsSignRequest modifySmsSign = new ModifySmsSignRequest() + .setSignName(smsSign.getSignName()) + .setSignSource(smsSign.getSignSource()) + .setRemark(smsSign.getRemark()) + .setSignFileList(java.util.Arrays.asList( + signFileList0, + signFileList1 + )); + ModifySmsSignResponse response = client.modifySmsSign(modifySmsSign); + if (!("OK").equals(response.getBody().getCode())) { + throw new ServiceException(response.getBody().getMessage()); + } + } + + @Override + public void modifySmsTemplate(SmsTemplate smsTemplate) throws Exception { + com.aliyun.dysmsapi20170525.Client client = this.createClient(); + ModifySmsTemplateRequest modifySmsTemplateRequest = new ModifySmsTemplateRequest() + .setTemplateType(smsTemplate.getTemplateType()) + .setTemplateName(smsTemplate.getTemplateName()) + .setTemplateContent(smsTemplate.getTemplateContent()) + .setRemark(smsTemplate.getRemark()) + .setTemplateCode(smsTemplate.getTemplateCode()); + + ModifySmsTemplateResponse response = client.modifySmsTemplate(modifySmsTemplateRequest); + if (!("OK").equals(response.getBody().getCode())) { + throw new ServiceException(response.getBody().getMessage()); + } + } + + @Override + public Map querySmsTemplate(String templateCode) throws Exception { + com.aliyun.dysmsapi20170525.Client client = this.createClient(); + QuerySmsTemplateRequest querySmsTemplateRequest = new QuerySmsTemplateRequest() + .setTemplateCode(templateCode); + QuerySmsTemplateResponse response = client.querySmsTemplate(querySmsTemplateRequest); + + if (!("OK").equals(response.getBody().getCode())) { + throw new ServiceException(response.getBody().getMessage()); + } + Map map = new HashMap<>(4); + map.put("TemplateStatus", response.getBody().getTemplateStatus()); + map.put("Reason", response.getBody().getReason()); + map.put("TemplateCode", response.getBody().getTemplateCode()); + return map; + } + + @Override + public String addSmsTemplate(SmsTemplate smsTemplate) throws Exception { + com.aliyun.dysmsapi20170525.Client client = this.createClient(); + AddSmsTemplateRequest addSmsTemplateRequest = new AddSmsTemplateRequest() + .setTemplateType(1) + .setTemplateName(smsTemplate.getTemplateName()) + .setTemplateContent(smsTemplate.getTemplateContent()) + .setRemark(smsTemplate.getRemark()); + + AddSmsTemplateResponse response = client.addSmsTemplate(addSmsTemplateRequest); + if (!("OK").equals(response.getBody().getCode())) { + throw new ServiceException(response.getBody().getMessage()); + } + return response.getBody().getTemplateCode(); + } + + @Override + public void deleteSmsTemplate(String templateCode) throws Exception { + com.aliyun.dysmsapi20170525.Client client = this.createClient(); + DeleteSmsTemplateRequest deleteSmsTemplateRequest = new DeleteSmsTemplateRequest() + .setTemplateCode(templateCode); + + DeleteSmsTemplateResponse response = client.deleteSmsTemplate(deleteSmsTemplateRequest); + if (!("OK").equals(response.getBody().getCode())) { + throw new ServiceException(response.getBody().getMessage()); + } + } + + + /** + * 初始化账号Client + * + * @return Client 短信操作 + */ + public com.aliyun.dysmsapi20170525.Client createClient() { + try { + if (smsSetting == null) { + throw new ServiceException(ResultCode.ALI_SMS_SETTING_ERROR); + } + Config config = new Config(); + //您的AccessKey ID + config.accessKeyId = smsSetting.getAccessKeyId(); + //您的AccessKey Secret + config.accessKeySecret = smsSetting.getAccessSecret(); + //访问的域名 + config.endpoint = "dysmsapi.aliyuncs.com"; + return new com.aliyun.dysmsapi20170525.Client(config); + } catch (Exception e) { + log.error("短信初始化错误", e); + } + return null; + } + +} diff --git a/framework/src/main/java/cn/lili/modules/sms/plugin/impl/HuaweiSmsPlugin.java b/framework/src/main/java/cn/lili/modules/sms/plugin/impl/HuaweiSmsPlugin.java new file mode 100644 index 00000000..fa6818c5 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/sms/plugin/impl/HuaweiSmsPlugin.java @@ -0,0 +1,323 @@ +package cn.lili.modules.sms.plugin.impl; + +import cn.lili.modules.sms.entity.dos.SmsSign; +import cn.lili.modules.sms.entity.dos.SmsTemplate; +import cn.lili.modules.sms.entity.enums.SmsEnum; +import cn.lili.modules.sms.plugin.SmsPlugin; +import cn.lili.modules.system.entity.dto.SmsSetting; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import javax.net.ssl.*; +import java.io.*; +import java.net.URL; +import java.net.URLEncoder; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * 腾讯云短信插件 + * + * @author Bulbasaur + * @since 2023-02-16 + */ +@Slf4j +public class HuaweiSmsPlugin implements SmsPlugin { + + private SmsSetting smsSetting; + + public HuaweiSmsPlugin(SmsSetting smsSetting) { + this.smsSetting = smsSetting; + } + + @Override + public SmsEnum pluginName() { + return SmsEnum.HUAWEI; + } + + //无需修改,用于格式化鉴权头域,给"X-WSSE"参数赋值 + private static final String WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\""; + //无需修改,用于格式化鉴权头域,给"Authorization"参数赋值 + private static final String AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\""; + + + @Override + public void sendSmsCode(String signName, String mobile, Map param, String templateCode) { + try { + this.sendSms(signName, mobile, "[" + param.values() + "]", templateCode); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + @Override + public void sendBatchSms(String signName, List mobile, String templateCode) { + try { + this.sendSms(signName, StringUtils.join(mobile, ","), null, templateCode); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void addSmsSign(SmsSign smsSign) throws Exception { + + } + + @Override + public void deleteSmsSign(String signName) throws Exception { + + } + + @Override + public Map querySmsSign(String signName) throws Exception { + return null; + } + + @Override + public void modifySmsSign(SmsSign smsSign) throws Exception { + + } + + @Override + public void modifySmsTemplate(SmsTemplate smsTemplate) throws Exception { + + } + + @Override + public Map querySmsTemplate(String templateCode) throws Exception { + return null; + } + + @Override + public String addSmsTemplate(SmsTemplate smsTemplate) throws Exception { + return null; + } + + @Override + public void deleteSmsTemplate(String templateCode) throws Exception { + + } + + + private void sendSms(String signName, String mobile, String param, String templateCode) throws Exception { + //必填,请参考"开发准备"获取如下数据,替换为实际值 + String url = "https://smsapi.cn-north-4.myhuaweicloud.com:443/sms/batchSendSms/v1"; //APP接入地址(在控制台"应用管理"页面获取)+接口访问URI + String appKey = smsSetting.getHuaweiAppKey(); //APP_Key + String appSecret = smsSetting.getHuaweiAppSecret(); //APP_Secret + String sender = smsSetting.getHuaweiSender(); //国内短信签名通道号或国际/港澳台短信通道号 + String templateId = templateCode; //模板ID + + //条件必填,国内短信关注,当templateId指定的模板类型为通用模板时生效且必填,必须是已审核通过的,与模板类型一致的签名名称 + //国际/港澳台短信不用关注该参数 + String signature = signName; //签名名称 + + //必填,全局号码格式(包含国家码),示例:+8615123456789,多个号码之间用英文逗号分隔 + String receiver = mobile; //短信接收人号码 + + //选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告 + String statusCallBack = ""; + + /** + * 选填,使用无变量模板时请赋空值 String templateParas = ""; + * 单变量模板示例:模板内容为"您的验证码是${1}"时,templateParas可填写为"[\"369751\"]" + * 双变量模板示例:模板内容为"您有${1}件快递请到${2}领取"时,templateParas可填写为"[\"3\",\"人民公园正门\"]" + * 模板中的每个变量都必须赋值,且取值不能为空 + * 查看更多模板和变量规范:产品介绍>模板和变量规范 + */ + String templateParas = param; //模板变量,此处以单变量验证码短信为例,请客户自行生成6位验证码,并定义为字符串类型,以杜绝首位0丢失的问题(例如:002569变成了2569)。 + + //请求Body,不携带签名名称时,signature请填null + String body = buildRequestBody(sender, receiver, templateId, templateParas, statusCallBack, signature); + if (null == body || body.isEmpty()) { + System.out.println("body is null."); + return; + } + + //请求Headers中的X-WSSE参数值 + String wsseHeader = buildWsseHeader(appKey, appSecret); + if (null == wsseHeader || wsseHeader.isEmpty()) { + System.out.println("wsse header is null."); + return; + } + + Writer out = null; + BufferedReader in = null; + StringBuffer result = new StringBuffer(); + HttpsURLConnection connection = null; + InputStream is = null; + + + HostnameVerifier hv = new HostnameVerifier() { + + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + trustAllHttpsCertificates(); + + try { + URL realUrl = new URL(url); + connection = (HttpsURLConnection) realUrl.openConnection(); + + connection.setHostnameVerifier(hv); + connection.setDoOutput(true); + connection.setDoInput(true); + connection.setUseCaches(true); + //请求方法 + connection.setRequestMethod("POST"); + //请求Headers参数 + connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + connection.setRequestProperty("Authorization", AUTH_HEADER_VALUE); + connection.setRequestProperty("X-WSSE", wsseHeader); + + connection.connect(); + out = new OutputStreamWriter(connection.getOutputStream()); + out.write(body); //发送请求Body参数 + out.flush(); + out.close(); + + int status = connection.getResponseCode(); + if (200 == status) { //200 + is = connection.getInputStream(); + } else { //400/401 + is = connection.getErrorStream(); + } + in = new BufferedReader(new InputStreamReader(is, "UTF-8")); + String line = ""; + while ((line = in.readLine()) != null) { + result.append(line); + } + System.out.println(result.toString()); //打印响应消息实体 + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (null != out) { + out.close(); + } + if (null != is) { + is.close(); + } + if (null != in) { + in.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + /** + * 构造请求Body体 + * + * @param sender + * @param receiver + * @param templateId + * @param templateParas + * @param statusCallBack + * @param signature | 签名名称,使用国内短信通用模板时填写 + * @return + */ + static String buildRequestBody(String sender, String receiver, String templateId, String templateParas, + String statusCallBack, String signature) { + if (null == sender || null == receiver || null == templateId || sender.isEmpty() || receiver.isEmpty() + || templateId.isEmpty()) { + System.out.println("buildRequestBody(): sender, receiver or templateId is null."); + return null; + } + Map map = new HashMap(); + + map.put("from", sender); + map.put("to", receiver); + map.put("templateId", templateId); + if (null != templateParas && !templateParas.isEmpty()) { + map.put("templateParas", templateParas); + } + if (null != statusCallBack && !statusCallBack.isEmpty()) { + map.put("statusCallback", statusCallBack); + } + if (null != signature && !signature.isEmpty()) { + map.put("signature", signature); + } + + StringBuilder sb = new StringBuilder(); + String temp = ""; + + for (String s : map.keySet()) { + try { + temp = URLEncoder.encode(map.get(s), "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + sb.append(s).append("=").append(temp).append("&"); + } + + return sb.deleteCharAt(sb.length() - 1).toString(); + } + + /** + * 构造X-WSSE参数值 + * + * @param appKey + * @param appSecret + * @return + */ + static String buildWsseHeader(String appKey, String appSecret) { + if (null == appKey || null == appSecret || appKey.isEmpty() || appSecret.isEmpty()) { + System.out.println("buildWsseHeader(): appKey or appSecret is null."); + return null; + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + String time = sdf.format(new Date()); //Created + String nonce = UUID.randomUUID().toString().replace("-", ""); //Nonce + + MessageDigest md; + byte[] passwordDigest = null; + + try { + md = MessageDigest.getInstance("SHA-256"); + md.update((nonce + time + appSecret).getBytes()); + passwordDigest = md.digest(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + + //如果JDK版本是1.8,请加载原生Base64类,并使用如下代码 + String passwordDigestBase64Str = Base64.getEncoder().encodeToString(passwordDigest); //PasswordDigest + //如果JDK版本低于1.8,请加载三方库提供Base64类,并使用如下代码 + //String passwordDigestBase64Str = Base64.encodeBase64String(passwordDigest); //PasswordDigest + //若passwordDigestBase64Str中包含换行符,请执行如下代码进行修正 + //passwordDigestBase64Str = passwordDigestBase64Str.replaceAll("[\\s*\t\n\r]", ""); + return String.format(WSSE_HEADER_FORMAT, appKey, passwordDigestBase64Str, nonce, time); + } + + /*** @throws Exception + */ + static void trustAllHttpsCertificates() throws Exception { + TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + return; + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + return; + } + + public X509Certificate[] getAcceptedIssuers() { + return null; + } + } + }; + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, trustAllCerts, null); + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + } +} diff --git a/framework/src/main/java/cn/lili/modules/sms/plugin/impl/TencentSmsPlugin.java b/framework/src/main/java/cn/lili/modules/sms/plugin/impl/TencentSmsPlugin.java new file mode 100644 index 00000000..dae2cba0 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/sms/plugin/impl/TencentSmsPlugin.java @@ -0,0 +1,254 @@ +package cn.lili.modules.sms.plugin.impl; + +import cn.hutool.core.convert.Convert; +import cn.lili.modules.sms.entity.dos.SmsSign; +import cn.lili.modules.sms.entity.dos.SmsTemplate; +import cn.lili.modules.sms.entity.enums.SmsEnum; +import cn.lili.modules.sms.plugin.SmsPlugin; +import cn.lili.modules.system.entity.dto.SmsSetting; +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +import com.tencentcloudapi.common.profile.HttpProfile; +import com.tencentcloudapi.sms.v20210111.SmsClient; +import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest; +import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; +import java.util.Map; + +/** + * 腾讯云短信插件 + * + * @author Bulbasaur + * @since 2023-02-16 + */ +@Slf4j +public class TencentSmsPlugin implements SmsPlugin { + + private SmsSetting smsSetting; + + public TencentSmsPlugin(SmsSetting smsSetting) { + this.smsSetting = smsSetting; + } + + @Override + public SmsEnum pluginName() { + return SmsEnum.TENCENT; + } + + + @Override + public void sendSmsCode(String signName, String mobile, Map param, String templateCode) { + try { + /* 实例化一个请求对象,根据调用的接口和实际情况,可以进一步设置请求参数 + * 你可以直接查询SDK源码确定接口有哪些属性可以设置 + * 属性可能是基本类型,也可能引用了另一个数据结构 + * 推荐使用IDE进行开发,可以方便的跳转查阅各个接口和数据结构的文档说明 */ + SendSmsRequest req = new SendSmsRequest(); + + /* 填充请求参数,这里request对象的成员变量即对应接口的入参 + * 你可以通过官网接口文档或跳转到request对象的定义处查看请求参数的定义 + * 基本类型的设置: + * 帮助链接: + * 短信控制台: https://console.cloud.tencent.com/smsv2 + * 腾讯云短信小助手: https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81 */ + + /* 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId,示例如1400006666 */ + // 应用 ID 可前往 [短信控制台](https://console.cloud.tencent.com/smsv2/app-manage) 查看 + req.setSmsSdkAppId(smsSetting.getTencentSdkAppId()); + + /* 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名 */ + // 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看 + req.setSignName(smsSetting.getTencentSignName()); + + /* 模板 ID: 必须填写已审核通过的模板 ID */ + // 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看 + req.setTemplateId(templateCode); + + /* 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,若无模板参数,则设置为空 */ + req.setTemplateParamSet(param.values().toArray(new String[0])); + + /* 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号] + * 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号 */ + String[] phoneNumberSet = {"+86" + mobile}; + req.setPhoneNumberSet(phoneNumberSet); + + /* 用户的 session 内容(无需要可忽略): 可以携带用户侧 ID 等上下文信息,server 会原样返回 */ + String sessionContext = ""; + req.setSessionContext(sessionContext); + + /* 短信码号扩展号(无需要可忽略): 默认未开通,如需开通请联系 [腾讯云短信小助手] */ + String extendCode = ""; + req.setExtendCode(extendCode); + + /* 国际/港澳台短信 SenderId(无需要可忽略): 国内短信填空,默认未开通,如需开通请联系 [腾讯云短信小助手] */ + String senderid = ""; + req.setSenderId(senderid); + + /* 通过 client 对象调用 SendSms 方法发起请求。注意请求方法名与请求对象是对应的 + * 返回的 res 是一个 SendSmsResponse 类的实例,与请求对象对应 */ + SendSmsResponse res = getClient().SendSms(req); + + // 输出json格式的字符串回包 + System.out.println(SendSmsResponse.toJsonString(res)); + + // 也可以取出单个值,你可以通过官网接口文档或跳转到response对象的定义处查看返回字段的定义 + // System.out.println(res.getRequestId()); + + /* 当出现以下错误码时,快速解决方案参考 + * [FailedOperation.SignatureIncorrectOrUnapproved](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Afailedoperation.signatureincorrectorunapproved-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F) + * [FailedOperation.TemplateIncorrectOrUnapproved](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Afailedoperation.templateincorrectorunapproved-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F) + * [UnauthorizedOperation.SmsSdkAppIdVerifyFail](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Aunauthorizedoperation.smssdkappidverifyfail-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F) + * [UnsupportedOperation.ContainDomesticAndInternationalPhoneNumber](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Aunsupportedoperation.containdomesticandinternationalphonenumber-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F) + * 更多错误,可咨询[腾讯云助手](https://tccc.qcloud.com/web/im/index.html#/chat?webAppId=8fa15978f85cb41f7e2ea36920cb3ae1&title=Sms) + */ + } catch (TencentCloudSDKException tencentCloudSDKException) { + tencentCloudSDKException.printStackTrace(); + } + + } + + @Override + public void sendBatchSms(String signName, List mobile, String templateCode) { + try { + /* 实例化一个请求对象,根据调用的接口和实际情况,可以进一步设置请求参数 + * 你可以直接查询SDK源码确定接口有哪些属性可以设置 + * 属性可能是基本类型,也可能引用了另一个数据结构 + * 推荐使用IDE进行开发,可以方便的跳转查阅各个接口和数据结构的文档说明 */ + SendSmsRequest req = new SendSmsRequest(); + + /* 填充请求参数,这里request对象的成员变量即对应接口的入参 + * 你可以通过官网接口文档或跳转到request对象的定义处查看请求参数的定义 + * 基本类型的设置: + * 帮助链接: + * 短信控制台: https://console.cloud.tencent.com/smsv2 + * 腾讯云短信小助手: https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81 */ + + /* 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId,示例如1400006666 */ + // 应用 ID 可前往 [短信控制台](https://console.cloud.tencent.com/smsv2/app-manage) 查看 + req.setSmsSdkAppId(smsSetting.getTencentSdkAppId()); + + /* 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名 */ + // 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看 + req.setSignName(smsSetting.getTencentSignName()); + + /* 模板 ID: 必须填写已审核通过的模板 ID */ + // 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看 + req.setTemplateId(templateCode); + + /* 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,若无模板参数,则设置为空 */ + req.setTemplateParamSet(null); + + /* 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号] + * 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号 */ + req.setPhoneNumberSet(Convert.toStrArray(mobile)); + + /* 用户的 session 内容(无需要可忽略): 可以携带用户侧 ID 等上下文信息,server 会原样返回 */ + String sessionContext = ""; + req.setSessionContext(sessionContext); + + /* 短信码号扩展号(无需要可忽略): 默认未开通,如需开通请联系 [腾讯云短信小助手] */ + String extendCode = ""; + req.setExtendCode(extendCode); + + /* 国际/港澳台短信 SenderId(无需要可忽略): 国内短信填空,默认未开通,如需开通请联系 [腾讯云短信小助手] */ + String senderid = ""; + req.setSenderId(senderid); + + /* 通过 client 对象调用 SendSms 方法发起请求。注意请求方法名与请求对象是对应的 + * 返回的 res 是一个 SendSmsResponse 类的实例,与请求对象对应 */ + SendSmsResponse res = getClient().SendSms(req); + + // 输出json格式的字符串回包 + System.out.println(SendSmsResponse.toJsonString(res)); + + // 也可以取出单个值,你可以通过官网接口文档或跳转到response对象的定义处查看返回字段的定义 + // System.out.println(res.getRequestId()); + + /* 当出现以下错误码时,快速解决方案参考 + * [FailedOperation.SignatureIncorrectOrUnapproved](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Afailedoperation.signatureincorrectorunapproved-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F) + * [FailedOperation.TemplateIncorrectOrUnapproved](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Afailedoperation.templateincorrectorunapproved-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F) + * [UnauthorizedOperation.SmsSdkAppIdVerifyFail](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Aunauthorizedoperation.smssdkappidverifyfail-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F) + * [UnsupportedOperation.ContainDomesticAndInternationalPhoneNumber](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Aunsupportedoperation.containdomesticandinternationalphonenumber-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F) + * 更多错误,可咨询[腾讯云助手](https://tccc.qcloud.com/web/im/index.html#/chat?webAppId=8fa15978f85cb41f7e2ea36920cb3ae1&title=Sms) + */ + } catch (TencentCloudSDKException tencentCloudSDKException) { + tencentCloudSDKException.printStackTrace(); + } + } + + @Override + public void addSmsSign(SmsSign smsSign) throws Exception { + + } + + @Override + public void deleteSmsSign(String signName) throws Exception { + + } + + @Override + public Map querySmsSign(String signName) throws Exception { + return null; + } + + @Override + public void modifySmsSign(SmsSign smsSign) throws Exception { + + } + + @Override + public void modifySmsTemplate(SmsTemplate smsTemplate) throws Exception { + + } + + @Override + public Map querySmsTemplate(String templateCode) throws Exception { + return null; + } + + @Override + public String addSmsTemplate(SmsTemplate smsTemplate) throws Exception { + return null; + } + + @Override + public void deleteSmsTemplate(String templateCode) throws Exception { + + } + + + /** + * 获取smsclient + * + * @return + */ + private SmsClient getClient() { + /* 必要步骤: + * 实例化一个认证对象,入参需要传入腾讯云账户密钥对secretId,secretKey。 + * 这里采用的是从环境变量读取的方式,需要在环境变量中先设置这两个值。 + * 你也可以直接在代码中写死密钥对,但是小心不要将代码复制、上传或者分享给他人, + * 以免泄露密钥对危及你的财产安全。 + * SecretId、SecretKey 查询: https://console.cloud.tencent.com/cam/capi */ + Credential cred = new Credential(smsSetting.getTencentSecretId(), smsSetting.getTencentSecretKey()); + + // 实例化一个http选项,可选,没有特殊需求可以跳过 + HttpProfile httpProfile = new HttpProfile(); + // 设置代理(无需要直接忽略) + // httpProfile.setProxyHost("真实代理ip"); + // httpProfile.setProxyPort(真实代理端口); + /* SDK默认使用POST方法。 + * 如果你一定要使用GET方法,可以在这里设置。GET方法无法处理一些较大的请求 */ + httpProfile.setReqMethod("POST"); + /* SDK有默认的超时时间,非必要请不要进行调整 + * 如有需要请在代码中查阅以获取最新的默认值 */ + httpProfile.setConnTimeout(60); + /* 指定接入地域域名,默认就近地域接入域名为 sms.tencentcloudapi.com ,也支持指定地域域名访问,例如广州地域的域名为 sms.ap-guangzhou.tencentcloudapi.com */ + httpProfile.setEndpoint("sms.tencentcloudapi.com"); + + /* 实例化要请求产品(以sms为例)的client对象 + * 第二个参数是地域信息,可以直接填写字符串ap-guangzhou,支持的地域列表参考 https://cloud.tencent.com/document/api/382/52071#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8 */ + return new SmsClient(cred, "ap-guangzhou"); + } +} diff --git a/framework/src/main/java/cn/lili/modules/sms/serviceimpl/SmsSignServiceImpl.java b/framework/src/main/java/cn/lili/modules/sms/serviceimpl/SmsSignServiceImpl.java index d55c8b98..6820b3fa 100644 --- a/framework/src/main/java/cn/lili/modules/sms/serviceimpl/SmsSignServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/sms/serviceimpl/SmsSignServiceImpl.java @@ -3,9 +3,9 @@ package cn.lili.modules.sms.serviceimpl; import cn.lili.common.enums.ResultCode; import cn.lili.common.exception.ServiceException; import cn.lili.common.vo.PageVO; -import cn.lili.modules.sms.AliSmsUtil; import cn.lili.modules.sms.entity.dos.SmsSign; import cn.lili.modules.sms.mapper.SmsSignMapper; +import cn.lili.modules.sms.plugin.SmsPluginFactory; import cn.lili.modules.sms.service.SmsSignService; import cn.lili.mybatis.util.PageUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; @@ -23,6 +23,7 @@ import java.util.Map; /** * 短信签名业务层实现 + * * @author Chopper * @since 2021/1/30 4:27 下午 */ @@ -30,7 +31,7 @@ import java.util.Map; @Service public class SmsSignServiceImpl extends ServiceImpl implements SmsSignService { @Autowired - private AliSmsUtil aliSmsUtil; + private SmsPluginFactory smsPluginFactory; @Override @Transactional(rollbackFor = Exception.class) @@ -40,11 +41,11 @@ public class SmsSignServiceImpl extends ServiceImpl impl if (this.getOne(new QueryWrapper().eq("sign_name", smsSign.getSignName())) != null) { throw new ServiceException(ResultCode.SMS_SIGN_EXIST_ERROR); } - aliSmsUtil.addSmsSign(smsSign); + smsPluginFactory.smsPlugin().addSmsSign(smsSign); smsSign.setSignStatus(0); this.save(smsSign); } catch (Exception e) { - log.error("添加短信签名错误",e); + log.error("添加短信签名错误", e); } } @@ -54,11 +55,11 @@ public class SmsSignServiceImpl extends ServiceImpl impl try { SmsSign smsSign = this.getById(id); if (smsSign != null) { - aliSmsUtil.deleteSmsSign(smsSign.getSignName()); + smsPluginFactory.smsPlugin().deleteSmsSign(smsSign.getSignName()); this.removeById(id); } } catch (Exception e) { - log.error("删除短信签名错误",e); + log.error("删除短信签名错误", e); } } @@ -72,13 +73,13 @@ public class SmsSignServiceImpl extends ServiceImpl impl List list = list(new LambdaQueryWrapper().ne(SmsSign::getSignStatus, 1)); //查询签名状态 for (SmsSign smsSign : list) { - map = aliSmsUtil.querySmsSign(smsSign.getSignName()); + map = smsPluginFactory.smsPlugin().querySmsSign(smsSign.getSignName()); smsSign.setSignStatus((Integer) map.get("SignStatus")); smsSign.setReason(map.get("Reason").toString()); this.updateById(smsSign); } } catch (Exception e) { - log.error("查询短信签名错误",e); + log.error("查询短信签名错误", e); } } @@ -86,10 +87,10 @@ public class SmsSignServiceImpl extends ServiceImpl impl @Transactional(rollbackFor = Exception.class) public void modifySmsSign(SmsSign smsSign) { try { - aliSmsUtil.modifySmsSign(smsSign); + smsPluginFactory.smsPlugin().modifySmsSign(smsSign); this.updateById(smsSign); } catch (Exception e) { - log.error("更新短信签名错误",e); + log.error("更新短信签名错误", e); } } diff --git a/framework/src/main/java/cn/lili/modules/sms/serviceimpl/SmsTemplateServiceImpl.java b/framework/src/main/java/cn/lili/modules/sms/serviceimpl/SmsTemplateServiceImpl.java index b23a4990..8f813b5a 100644 --- a/framework/src/main/java/cn/lili/modules/sms/serviceimpl/SmsTemplateServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/sms/serviceimpl/SmsTemplateServiceImpl.java @@ -1,9 +1,9 @@ package cn.lili.modules.sms.serviceimpl; import cn.lili.common.vo.PageVO; -import cn.lili.modules.sms.AliSmsUtil; import cn.lili.modules.sms.entity.dos.SmsTemplate; import cn.lili.modules.sms.mapper.SmsTemplateMapper; +import cn.lili.modules.sms.plugin.SmsPluginFactory; import cn.lili.modules.sms.service.SmsTemplateService; import cn.lili.mybatis.util.PageUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; @@ -19,25 +19,27 @@ import java.util.Map; /** * 短信模板业务层实现 + * * @author Chopper * @since 2021/1/30 4:27 下午 */ @Slf4j @Service public class SmsTemplateServiceImpl extends ServiceImpl implements SmsTemplateService { + @Autowired - private AliSmsUtil aliSmsUtil; + private SmsPluginFactory smsPluginFactory; @Override public void addSmsTemplate(SmsTemplate smsTemplate) { try { - smsTemplate.setTemplateCode(aliSmsUtil.addSmsTemplate(smsTemplate)); + smsTemplate.setTemplateCode(smsPluginFactory.smsPlugin().addSmsTemplate(smsTemplate)); smsTemplate.setTemplateStatus(0); smsTemplate.setTemplateType(1); this.save(smsTemplate); } catch (Exception e) { - log.error("添加短信模板错误",e); + log.error("添加短信模板错误", e); } } @@ -46,11 +48,11 @@ public class SmsTemplateServiceImpl extends ServiceImpl list = list(new LambdaQueryWrapper().eq(SmsTemplate::getTemplateStatus, 0)); //查询签名状态 for (SmsTemplate smsTemplate : list) { - map = aliSmsUtil.querySmsTemplate(smsTemplate.getTemplateCode()); + map = smsPluginFactory.smsPlugin().querySmsTemplate(smsTemplate.getTemplateCode()); smsTemplate.setTemplateStatus((Integer) map.get("TemplateStatus")); smsTemplate.setReason(map.get("Reason").toString()); smsTemplate.setTemplateCode(map.get("TemplateCode").toString()); this.updateById(smsTemplate); } } catch (Exception e) { - log.error("查询短信模板错误",e); + log.error("查询短信模板错误", e); } } @Override public void modifySmsTemplate(SmsTemplate smsTemplate) { try { - aliSmsUtil.modifySmsTemplate(smsTemplate); + smsPluginFactory.smsPlugin().modifySmsTemplate(smsTemplate); smsTemplate.setTemplateStatus(0); this.updateById(smsTemplate); } catch (Exception e) { - log.error("重新提交短信模板错误",e); + log.error("重新提交短信模板错误", e); } } diff --git a/framework/src/main/java/cn/lili/modules/system/entity/dto/KuaidiSetting.java b/framework/src/main/java/cn/lili/modules/system/entity/dto/LogisticsSetting.java similarity index 50% rename from framework/src/main/java/cn/lili/modules/system/entity/dto/KuaidiSetting.java rename to framework/src/main/java/cn/lili/modules/system/entity/dto/LogisticsSetting.java index 2348871e..8409f80d 100644 --- a/framework/src/main/java/cn/lili/modules/system/entity/dto/KuaidiSetting.java +++ b/framework/src/main/java/cn/lili/modules/system/entity/dto/LogisticsSetting.java @@ -11,23 +11,29 @@ import java.io.Serializable; * @since 2020-03-10 10:04 上午 */ @Data -public class KuaidiSetting implements Serializable { +public class LogisticsSetting implements Serializable { private static final long serialVersionUID = 3520379500723173689L; + + /** + * 快递查询类型 + */ + private String type; + /** * 企业id */ - private String ebusinessID; + private String kdniaoEbusinessID; /** * 密钥 */ - private String appKey; - /** - * api地址 - */ - private String reqURL; + private String kdniaoAppKey; /** - * 电子面单api地址 + * 快递100 授权码,请申请企业版获取 */ - private String sheetReqURL; + private String kuaidi100Customer; + /** + * 快递100 Key + */ + private String kuaidi100Key; } diff --git a/framework/src/main/java/cn/lili/modules/system/entity/dto/OssSetting.java b/framework/src/main/java/cn/lili/modules/system/entity/dto/OssSetting.java index 760c191c..95c225ba 100644 --- a/framework/src/main/java/cn/lili/modules/system/entity/dto/OssSetting.java +++ b/framework/src/main/java/cn/lili/modules/system/entity/dto/OssSetting.java @@ -24,25 +24,25 @@ public class OssSetting implements Serializable { private String type; /** - * 域名 + * 阿里云-域名 */ - private String endPoint = ""; + private String aliyunOSSEndPoint = ""; /** - * 储存空间 + * 阿里云-储存空间 */ - private String bucketName = ""; + private String aliyunOSSBucketName = ""; /** - * 存放路径路径 + * 阿里云-存放路径路径 */ - private String picLocation = ""; + private String aliyunOSSPicLocation = ""; /** - * 密钥id + * 阿里云-密钥id */ - private String accessKeyId = ""; + private String aliyunOSSAccessKeyId = ""; /** - * 密钥 + * 阿里云-密钥 */ - private String accessKeySecret = ""; + private String aliyunOSSAccessKeySecret = ""; /** @@ -71,6 +71,48 @@ public class OssSetting implements Serializable { private String m_bucketName; + /** + * 华为云-发起者的Access Key + * + * @return + */ + + String huaweicloudOBSAccessKey; + /** + * 华为云-密钥 + */ + String huaweicloudOBSSecretKey; + /** + * 华为云OBS-节点 + */ + String huaweicloudOBSEndPoint; + + /** + * 华为云OBS-桶 + */ + private String huaweicloudOBSBucketName = ""; + + /** + * 腾讯云 用户的 SecretId + */ + String tencentCOSSecretId; + /** + * 腾讯云 用户的 SecretKey + */ + String tencentCOSSecretKey; + /** + * 腾讯云 bucket 的地域 + */ + String tencentCOSRegion; + /** + * 腾讯云 bucket + */ + String tencentCOSBucket; + /** + * 腾讯云-域名 + */ + private String tencentCOSEndPoint = ""; + public String getType() { //默认给阿里云oss存储类型 if (StringUtils.isEmpty(type)) { diff --git a/framework/src/main/java/cn/lili/modules/system/entity/dto/SmsSetting.java b/framework/src/main/java/cn/lili/modules/system/entity/dto/SmsSetting.java index 683a0663..f72589ca 100644 --- a/framework/src/main/java/cn/lili/modules/system/entity/dto/SmsSetting.java +++ b/framework/src/main/java/cn/lili/modules/system/entity/dto/SmsSetting.java @@ -7,23 +7,60 @@ import java.io.Serializable; /** * 短信配置 * 这里在前台不做调整,方便客户直接把服务商的内容配置在我们平台 + * * @author Chopper * @since 2020/11/30 15:23 */ @Data public class SmsSetting implements Serializable { + + /** + * 类型 + */ + private String type; + /** - * 从上到下yi依次是 - * 节点地址 * key + */ + private String accessKeyId; + /** * 密钥 + */ + private String accessSecret; + /** * 签名 */ - private String regionId; - - private String accessKeyId; - - private String accessSecret; - private String signName; + + + /** + * 腾讯云 用户的 SecretId + */ + String tencentSecretId; + /** + * 腾讯云 用户的 SecretKey + */ + String tencentSecretKey; + /* 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId,示例如1400006666 */ + String tencentSdkAppId; + /* 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名 */ + String tencentSignName; + + /** + * 华为 APP_Key + */ + String huaweiAppKey; + /** + * 华为 APP_Secret + */ + String huaweiAppSecret; + + /** + * 国内短信签名通道号或国际/港澳台短信通道号 + */ + String huaweiSender; + /** + * 签名名称 + */ + String huaweiSignature; } diff --git a/framework/src/main/java/cn/lili/modules/system/entity/enums/SettingEnum.java b/framework/src/main/java/cn/lili/modules/system/entity/enums/SettingEnum.java index 00d7b6cf..b7fc730a 100644 --- a/framework/src/main/java/cn/lili/modules/system/entity/enums/SettingEnum.java +++ b/framework/src/main/java/cn/lili/modules/system/entity/enums/SettingEnum.java @@ -17,8 +17,8 @@ public enum SettingEnum { EMAIL_SETTING, //商品设置 GOODS_SETTING, - //快递鸟设置 - KUAIDI_SETTING, + //快递设置 + LOGISTICS_SETTING, //订单配置 ORDER_SETTING, //阿里OSS配置 @@ -45,6 +45,9 @@ public enum SettingEnum { ALIPAY_PAYMENT, //微信支付设置 WECHAT_PAYMENT, + //银联支付设置 + UNION_PAYMENT, + //热词设置 HOT_WORDS } diff --git a/framework/src/main/java/cn/lili/modules/system/service/LogisticsService.java b/framework/src/main/java/cn/lili/modules/system/service/LogisticsService.java index 5cdf8698..6e552da9 100644 --- a/framework/src/main/java/cn/lili/modules/system/service/LogisticsService.java +++ b/framework/src/main/java/cn/lili/modules/system/service/LogisticsService.java @@ -19,10 +19,15 @@ public interface LogisticsService extends IService { * * @param logisticsId 物流公司ID * @param logisticsNo 单号 - * @param customerName 手机号后四位 + * @param phone 手机号 * @return */ - Traces getLogistic(String logisticsId, String logisticsNo, String customerName); + Traces getLogisticTrack(String logisticsId, String logisticsNo, String phone); + + + Traces getLogisticMapTrack(String logisticsId, String logisticsNo, String phone, String from, String to); + + String labelOrder(String orderSn, String logisticsId); /** * 获取已开启的物流公司列表 diff --git a/framework/src/main/java/cn/lili/modules/system/serviceimpl/LogisticsServiceImpl.java b/framework/src/main/java/cn/lili/modules/system/serviceimpl/LogisticsServiceImpl.java index 6dd2cbac..d1121dbf 100644 --- a/framework/src/main/java/cn/lili/modules/system/serviceimpl/LogisticsServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/system/serviceimpl/LogisticsServiceImpl.java @@ -1,34 +1,33 @@ package cn.lili.modules.system.serviceimpl; -import cn.hutool.core.text.CharSequenceUtil; import cn.lili.common.enums.ResultCode; import cn.lili.common.enums.SwitchEnum; import cn.lili.common.exception.ServiceException; +import cn.lili.common.security.OperationalJudgment; +import cn.lili.modules.logistics.LogisticsPluginFactory; +import cn.lili.modules.logistics.entity.dto.LabelOrderDTO; +import cn.lili.modules.member.service.StoreLogisticsService; +import cn.lili.modules.order.order.entity.dos.Order; +import cn.lili.modules.order.order.entity.dos.OrderItem; +import cn.lili.modules.order.order.entity.enums.DeliverStatusEnum; +import cn.lili.modules.order.order.entity.enums.OrderStatusEnum; +import cn.lili.modules.order.order.service.OrderItemService; +import cn.lili.modules.order.order.service.OrderService; +import cn.lili.modules.store.entity.dos.StoreLogistics; +import cn.lili.modules.store.entity.dto.StoreDeliverGoodsAddressDTO; +import cn.lili.modules.store.service.StoreDetailService; import cn.lili.modules.system.entity.dos.Logistics; -import cn.lili.modules.system.entity.dos.Setting; -import cn.lili.modules.system.entity.dto.KuaidiSetting; -import cn.lili.modules.system.entity.enums.SettingEnum; import cn.lili.modules.system.entity.vo.Traces; import cn.lili.modules.system.mapper.LogisticsMapper; import cn.lili.modules.system.service.LogisticsService; -import cn.lili.modules.system.service.SettingService; -import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.google.gson.Gson; import groovy.util.logging.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.io.*; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.util.HashMap; import java.util.List; -import java.util.Map; /** * 物流公司业务层实现 @@ -40,19 +39,72 @@ import java.util.Map; @Service public class LogisticsServiceImpl extends ServiceImpl implements LogisticsService { @Autowired - private SettingService settingService; + private LogisticsPluginFactory logisticsPluginFactory; + @Autowired + private OrderService orderService; + @Autowired + private OrderItemService orderItemService; + @Autowired + private StoreLogisticsService storeLogisticsService; + @Autowired + private StoreDetailService storeDetailService; @Override - public Traces getLogistic(String logisticsId, String logisticsNo, String customerName) { + public Traces getLogisticTrack(String logisticsId, String logisticsNo, String phone) { try { - return getOrderTracesByJson(logisticsId, logisticsNo,customerName); + return logisticsPluginFactory.filePlugin().pollQuery(this.getById(logisticsId), logisticsNo, phone); } catch (Exception e) { - log.error("获取物流公司错误",e); + log.error("获取物流公司错误", e); } return null; } + @Override + public Traces getLogisticMapTrack(String logisticsId, String logisticsNo, String phone, String from, String to) { + try { + return logisticsPluginFactory.filePlugin().pollMapTrack(this.getById(logisticsId), logisticsNo, phone, from, to); + } catch (Exception e) { + log.error("获取物流公司错误", e); + + } + return null; + } + + @Override + public String labelOrder(String orderSn, String logisticsId) { + + //获取订单及子订单 + Order order = OperationalJudgment.judgment(orderService.getBySn(orderSn)); + if (order.getDeliverStatus().equals(DeliverStatusEnum.UNDELIVERED.name()) + && order.getOrderStatus().equals(OrderStatusEnum.UNDELIVERED.name())) { + + //订单货物 + List orderItems = orderItemService.getByOrderSn(orderSn); + //获取对应物流 + Logistics logistics = this.getById(logisticsId); + // 店铺-物流公司设置 + LambdaQueryWrapper lambdaQueryWrapper = Wrappers.lambdaQuery(); + lambdaQueryWrapper.eq(StoreLogistics::getLogisticsId, logisticsId); + lambdaQueryWrapper.eq(StoreLogistics::getStoreId, order.getStoreId()); + StoreLogistics storeLogistics = storeLogisticsService.getOne(lambdaQueryWrapper); + //获取店家信息 + StoreDeliverGoodsAddressDTO storeDeliverGoodsAddressDTO = storeDetailService.getStoreDeliverGoodsAddressDto(order.getStoreId()); + + LabelOrderDTO labelOrderDTO = new LabelOrderDTO(); + labelOrderDTO.setOrder(order); + labelOrderDTO.setOrderItems(orderItems); + labelOrderDTO.setLogistics(logistics); + labelOrderDTO.setStoreLogistics(storeLogistics); + labelOrderDTO.setStoreDeliverGoodsAddressDTO(storeDeliverGoodsAddressDTO); + //触发电子面单 + return logisticsPluginFactory.filePlugin().labelOrder(labelOrderDTO); + } else { + throw new ServiceException(ResultCode.ORDER_LABEL_ORDER_ERROR); + } + + } + @Override public List getOpenLogistics() { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); @@ -60,218 +112,4 @@ public class LogisticsServiceImpl extends ServiceImpl params = new HashMap<>(8); - params.put("RequestData", urlEncoder(requestData, "UTF-8")); - params.put("EBusinessID", EBusinessID); - params.put("RequestType", "1002"); - String dataSign = encrypt(requestData, AppKey, "UTF-8"); - params.put("DataSign", urlEncoder(dataSign, "UTF-8")); - params.put("DataType", "2"); - - String result = sendPost(ReqURL, params); - Map map = (Map) JSON.parse(result); - return new Traces(logistics.getName(), expNo, (List) map.get("Traces")); - } - return null; - } - - /** - * MD5加密 - * - * @param str 内容 - * @param charset 编码方式 - * @throws Exception - */ - @SuppressWarnings("unused") - private String MD5(String str, String charset) throws Exception { - MessageDigest md = MessageDigest.getInstance("MD5"); - md.update(str.getBytes(charset)); - byte[] result = md.digest(); - StringBuffer sb = new StringBuffer(32); - for (int i = 0; i < result.length; i++) { - int val = result[i] & 0xff; - if (val <= 0xf) { - sb.append("0"); - } - sb.append(Integer.toHexString(val)); - } - return sb.toString().toLowerCase(); - } - - /** - * base64编码 - * - * @param str 内容 - * @param charset 编码方式di - * @throws UnsupportedEncodingException - */ - private String base64(String str, String charset) throws UnsupportedEncodingException { - return base64Encode(str.getBytes(charset)); - } - - @SuppressWarnings("unused") - private String urlEncoder(String str, String charset) throws UnsupportedEncodingException { - return URLEncoder.encode(str, charset); - } - - /** - * 电商Sign签名生成 - * - * @param content 内容 - * @param keyValue Appkey - * @param charset 编码方式 - * @return DataSign签名 - * @throws UnsupportedEncodingException ,Exception - */ - @SuppressWarnings("unused") - private String encrypt(String content, String keyValue, String charset) throws Exception { - if (keyValue != null) { - return base64(MD5(content + keyValue, charset), charset); - } - return base64(MD5(content, charset), charset); - } - - /** - * 向指定 URL 发送POST方法的请求 - * - * @param url 发送请求的 URL - * @param params 请求的参数集合 - * @return 远程资源的响应结果 - */ - @SuppressWarnings("unused") - private String sendPost(String url, Map params) { - OutputStreamWriter out = null; - BufferedReader in = null; - StringBuilder result = new StringBuilder(); - try { - URL realUrl = new URL(url); - HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection(); - //发送POST请求必须设置如下两行 - conn.setDoOutput(true); - conn.setDoInput(true); - //POST方法 - conn.setRequestMethod("POST"); - //设置通用的请求属性 - conn.setRequestProperty("accept", "*/*"); - conn.setRequestProperty("connection", "Keep-Alive"); - conn.setRequestProperty("user-agent", - "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - conn.connect(); - //获取URLConnection对象对应的输出流 - out = new OutputStreamWriter(conn.getOutputStream(), StandardCharsets.UTF_8); - //发送请求参数 - if (params != null) { - StringBuilder param = new StringBuilder(); - for (Map.Entry entry : params.entrySet()) { - if (param.length() > 0) { - param.append("&"); - } - param.append(entry.getKey()); - param.append("="); - param.append(entry.getValue()); - } - out.write(param.toString()); - } - //flush输出流的缓冲 - out.flush(); - //定义BufferedReader输入流来读取URL的响应 - in = new BufferedReader( - new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8)); - String line; - while ((line = in.readLine()) != null) { - result.append(line); - } - } catch (Exception e) { - log.error("向指定 URL 发送POST方法的请求错误",e); - } - //使用finally块来关闭输出流、输入流 - finally { - try { - if (out != null) { - out.close(); - } - if (in != null) { - in.close(); - } - } catch (IOException ex) { - ex.printStackTrace(); - } - } - return result.toString(); - } - - - private static final char[] BASE64_ENCODE_CHARS = new char[]{ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', '+', '/'}; - - public static String base64Encode(byte[] data) { - StringBuffer sb = new StringBuffer(); - int len = data.length; - int i = 0; - int b1, b2, b3; - while (i < len) { - b1 = data[i++] & 0xff; - if (i == len) { - sb.append(BASE64_ENCODE_CHARS[b1 >>> 2]); - sb.append(BASE64_ENCODE_CHARS[(b1 & 0x3) << 4]); - sb.append("=="); - break; - } - b2 = data[i++] & 0xff; - if (i == len) { - sb.append(BASE64_ENCODE_CHARS[b1 >>> 2]); - sb.append(BASE64_ENCODE_CHARS[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]); - sb.append(BASE64_ENCODE_CHARS[(b2 & 0x0f) << 2]); - sb.append("="); - break; - } - b3 = data[i++] & 0xff; - sb.append(BASE64_ENCODE_CHARS[b1 >>> 2]); - sb.append(BASE64_ENCODE_CHARS[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]); - sb.append(BASE64_ENCODE_CHARS[((b2 & 0x0f) << 2) | ((b3 & 0xc0) >>> 6)]); - sb.append(BASE64_ENCODE_CHARS[b3 & 0x3f]); - } - return sb.toString(); - } - } diff --git a/manager-api/src/main/java/cn/lili/controller/setting/SettingManagerController.java b/manager-api/src/main/java/cn/lili/controller/setting/SettingManagerController.java index bf85cf9b..7c6b8133 100644 --- a/manager-api/src/main/java/cn/lili/controller/setting/SettingManagerController.java +++ b/manager-api/src/main/java/cn/lili/controller/setting/SettingManagerController.java @@ -1,6 +1,7 @@ package cn.lili.controller.setting; import cn.hutool.json.JSONUtil; +import cn.lili.cache.Cache; import cn.lili.common.aop.annotation.DemoSite; import cn.lili.common.enums.ResultCode; import cn.lili.common.enums.ResultUtil; @@ -36,6 +37,11 @@ import java.util.Collections; public class SettingManagerController { @Autowired private SettingService settingService; + /** + * 缓存 + */ + @Autowired + private Cache cache; @DemoSite @@ -79,7 +85,6 @@ public class SettingManagerController { } - /** * 对配置进行过滤 * @@ -111,6 +116,7 @@ public class SettingManagerController { */ private ResultMessage createSetting(String key) { SettingEnum settingEnum = SettingEnum.valueOf(key); + cache.remove(key); Setting setting = settingService.get(key); switch (settingEnum) { case BASE_SETTING: @@ -133,10 +139,10 @@ public class SettingManagerController { return setting == null ? ResultUtil.data(new GoodsSetting()) : ResultUtil.data(JSONUtil.toBean(setting.getSettingValue(), GoodsSetting.class)); - case KUAIDI_SETTING: + case LOGISTICS_SETTING: return setting == null ? - ResultUtil.data(new KuaidiSetting()) : - ResultUtil.data(JSONUtil.toBean(setting.getSettingValue(), KuaidiSetting.class)); + ResultUtil.data(new LogisticsSetting()) : + ResultUtil.data(JSONUtil.toBean(setting.getSettingValue(), LogisticsSetting.class)); case ORDER_SETTING: return setting == null ? ResultUtil.data(new OrderSetting()) : diff --git a/pom.xml b/pom.xml index fb8c22ca..1d30464c 100644 --- a/pom.xml +++ b/pom.xml @@ -61,6 +61,10 @@ 2.3.1 20211018.2 8.0.3 + 3.21.8 + 5.6.97 + 3.1.693 + 1.0.11 diff --git a/seller-api/src/main/java/cn/lili/controller/order/OrderStoreController.java b/seller-api/src/main/java/cn/lili/controller/order/OrderStoreController.java index 3bbdd2c0..f8fb7c2c 100644 --- a/seller-api/src/main/java/cn/lili/controller/order/OrderStoreController.java +++ b/seller-api/src/main/java/cn/lili/controller/order/OrderStoreController.java @@ -7,7 +7,6 @@ import cn.lili.common.enums.ResultUtil; import cn.lili.common.security.OperationalJudgment; import cn.lili.common.security.context.UserContext; import cn.lili.common.vo.ResultMessage; -import cn.lili.modules.kdBrid.service.KdNiaoService; import cn.lili.modules.member.entity.dto.MemberAddressDTO; import cn.lili.modules.member.service.StoreLogisticsService; import cn.lili.modules.order.order.entity.dto.OrderExportDTO; @@ -16,6 +15,7 @@ import cn.lili.modules.order.order.entity.vo.OrderDetailVO; import cn.lili.modules.order.order.entity.vo.OrderSimpleVO; import cn.lili.modules.order.order.service.OrderPriceService; import cn.lili.modules.order.order.service.OrderService; +import cn.lili.modules.system.service.LogisticsService; import com.baomidou.mybatisplus.core.metadata.IPage; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; @@ -63,10 +63,10 @@ public class OrderStoreController { private StoreLogisticsService storeLogisticsService; /** - * 快递鸟电子面单 + * 快递 */ @Autowired - private KdNiaoService kdNiaoService; + private LogisticsService logisticsService; @ApiOperation(value = "查询订单列表") @@ -200,7 +200,7 @@ public class OrderStoreController { @ApiImplicitParam(name = "logisticsId", value = "物流公司", required = true, dataType = "String", paramType = "query") }) public ResultMessage createElectronicsFaceSheet(@NotNull(message = "参数非法") @PathVariable String orderSn, - @NotNull(message = "请选择物流公司") String logisticsId) throws Exception{ - return ResultUtil.data(kdNiaoService.createElectronicsFaceSheet(orderSn,logisticsId)); + @NotNull(message = "请选择物流公司") String logisticsId) throws Exception { + return ResultUtil.data(logisticsService.labelOrder(orderSn, logisticsId)); } } \ No newline at end of file