存储新增:腾讯云、华为云
短信新增:腾讯云、华为云 物流新增:快递100 物流查询方式新增:快递查询地图轨迹
This commit is contained in:
parent
f92756c103
commit
98907b33aa
@ -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<Object> getMapTraces(@NotBlank(message = "订单编号不能为空") @PathVariable String orderSn) {
|
||||
OperationalJudgment.judgment(orderService.getBySn(orderSn));
|
||||
return ResultUtil.data(orderService.getMapTraces(orderSn));
|
||||
}
|
||||
|
||||
|
||||
@PreventDuplicateSubmissions
|
||||
@ApiOperation(value = "开票")
|
||||
|
@ -437,8 +437,26 @@
|
||||
<artifactId>minio</artifactId>
|
||||
<version>${minio.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.huaweicloud</groupId>
|
||||
<artifactId>esdk-obs-java</artifactId>
|
||||
<version>${huaweicloud.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.qcloud</groupId>
|
||||
<artifactId>cos_api</artifactId>
|
||||
<version>${cos.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.tencentcloudapi</groupId>
|
||||
<artifactId>tencentcloud-sdk-java</artifactId>
|
||||
<version>${tencentcloud.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.kuaidi100-api</groupId>
|
||||
<artifactId>sdk</artifactId>
|
||||
<version>${kuaidi100-api.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
@ -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, "订单不能打印电子面单"),
|
||||
|
||||
|
||||
/**
|
||||
* 支付
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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.");
|
||||
|
@ -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<String> 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() + "/";
|
||||
}
|
||||
}
|
@ -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<String> keys) {
|
||||
COSClient cosClient = getCOSClient();
|
||||
|
||||
try {
|
||||
List<DeleteObjectsRequest.KeyVersion> 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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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<OrderItem> orderItems;
|
||||
//物流公司
|
||||
Logistics logistics;
|
||||
//店铺物流公司配置
|
||||
StoreLogistics storeLogistics;
|
||||
//店铺发件地址
|
||||
StoreDeliverGoodsAddressDTO storeDeliverGoodsAddressDTO;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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<OrderItem> orderItems = orderItemService.getByOrderSn(orderSn);
|
||||
|
||||
Setting setting = settingService.get(SettingEnum.KUAIDI_SETTING.name());
|
||||
if (CharSequenceUtil.isBlank(setting.getSettingValue())) {
|
||||
throw new ServiceException(ResultCode.LOGISTICS_NOT_SETTING);
|
||||
public LogisticsEnum pluginName() {
|
||||
return LogisticsEnum.KDNIAO;
|
||||
}
|
||||
KuaidiSetting kuaidiSetting = new Gson().fromJson(setting.getSettingValue(), KuaidiSetting.class);
|
||||
|
||||
//ID
|
||||
String EBusinessID = kuaidiSetting.getEbusinessID();
|
||||
@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<String, String> 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");
|
||||
|
||||
//KEY
|
||||
String AppKey = kuaidiSetting.getAppKey();
|
||||
String result = sendPost(reqURL, params);
|
||||
Map map = (Map) JSON.parse(result);
|
||||
return new Traces(logistics.getName(), expNo, (List<Map>) map.get("Traces"));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//请求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<String, String> params = new HashMap<String, String>();
|
||||
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<OrderItem> orderItems = labelOrderDTO.getOrderItems();
|
||||
//获取对应物流
|
||||
Logistics logistics = logisticsService.getById(logisticsId);
|
||||
|
||||
//物流为空,抛出异常
|
||||
if (logistics == null) {
|
||||
throw new ServiceException(ResultCode.ORDER_LOGISTICS_ERROR);
|
||||
}
|
||||
|
||||
//获取店家的物流信息
|
||||
LambdaQueryWrapper<StoreLogistics> 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,44 +168,48 @@ public class KdNiaoServiceImpl implements KdNiaoService {
|
||||
"},";
|
||||
}
|
||||
resultDate = resultDate + "]," +
|
||||
"'Quantity': "+orderItems.size()+"," + //包裹数
|
||||
"'IsReturnPrintTemplate':1,"+ //生成电子面单模板
|
||||
"'Remark': '" + order.getRemark() + "'"+//商家备注
|
||||
"'Quantity': " + orderItems.size() + "," + //包裹数
|
||||
"'IsReturnPrintTemplate':1," + //生成电子面单模板
|
||||
"'Remark': '" + order.getRemark() + "'" +//商家备注
|
||||
"}";
|
||||
|
||||
|
||||
//组织系统级参数
|
||||
Map<String, String> 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");
|
||||
return obj.getString("PrintTemplate");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//进行发货
|
||||
orderService.delivery(orderSn, orderJson.getString("LogisticCode"), logisticsId);
|
||||
}
|
||||
return printTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
@ -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<Map> traces = new ArrayList<>();
|
||||
for (QueryTrackData queryTrackData : queryTrackResp.getData()) {
|
||||
Map map = new HashMap<String, String>();
|
||||
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<OrderItem> 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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -269,8 +269,7 @@ public class AfterSaleServiceImpl extends ServiceImpl<AfterSaleMapper, AfterSale
|
||||
|
||||
//根据售后单号获取售后单
|
||||
AfterSale afterSale = OperationalJudgment.judgment(this.getBySn(afterSaleSn));
|
||||
String str=storeDetailService.getStoreDetail(afterSale.getStoreId()).getSalesConsigneeMobile();
|
||||
return logisticsService.getLogistic(afterSale.getMLogisticsCode(), afterSale.getMLogisticsNo(), str.substring(str.length()-4));
|
||||
return logisticsService.getLogisticTrack(afterSale.getMLogisticsCode(), afterSale.getMLogisticsNo(), storeDetailService.getStoreDetail(afterSale.getStoreId()).getSalesConsigneeMobile());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -91,7 +91,6 @@ public interface OrderService extends IService<Order> {
|
||||
List<Order> queryListByPromotion(String pintuanId);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 查询导出订单列表
|
||||
*
|
||||
@ -174,6 +173,14 @@ public interface OrderService extends IService<Order> {
|
||||
*/
|
||||
Traces getTraces(String orderSn);
|
||||
|
||||
/**
|
||||
* 获取地图版 物流踪迹
|
||||
*
|
||||
* @param orderSn 订单编号
|
||||
* @return 物流踪迹
|
||||
*/
|
||||
Traces getMapTraces(String orderSn);
|
||||
|
||||
/**
|
||||
* 订单核验
|
||||
*
|
||||
|
@ -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<OrderMapper, Order> 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<OrderMapper, Order> 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<OrderMapper, Order> 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<OrderMapper, Order> implements
|
||||
public Order take(String verificationCode) {
|
||||
String storeId = OperationalJudgment.judgment(UserContext.getCurrentUser()).getStoreId();
|
||||
Order order = this.getOne(new LambdaQueryWrapper<Order>().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<OrderMapper, Order> implements
|
||||
public Order getOrderByVerificationCode(String verificationCode) {
|
||||
String storeId = Objects.requireNonNull(UserContext.getCurrentUser()).getStoreId();
|
||||
return this.getOne(new LambdaQueryWrapper<Order>()
|
||||
.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<OrderMapper, Order> 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;
|
||||
}
|
||||
//修改订单
|
||||
|
@ -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<String, String> param, String templateCode);
|
||||
|
||||
/**
|
||||
* 短信批量发送
|
||||
|
@ -0,0 +1,15 @@
|
||||
package cn.lili.modules.sms.entity.enums;
|
||||
|
||||
/**
|
||||
* 短信通道枚举
|
||||
*
|
||||
* @author Bulbasaur
|
||||
* @since 2023-02-16
|
||||
*/
|
||||
public enum SmsEnum {
|
||||
|
||||
/**
|
||||
* 短信渠道
|
||||
*/
|
||||
ALI, HUAWEI, TENCENT;
|
||||
}
|
@ -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<String, String> 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<String> mobile, String templateCode) {
|
||||
|
||||
com.aliyun.dysmsapi20170525.Client client = this.createClient();
|
||||
|
||||
List<String> sign = new ArrayList<String>();
|
||||
|
||||
sign.addAll(mobile);
|
||||
sign.replaceAll(e -> signName);
|
||||
|
||||
//手机号拆成多个小组进行发送
|
||||
List<List<String>> mobileList = new ArrayList<>();
|
||||
|
||||
//签名名称多个小组
|
||||
List<List<String>> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
private void sendSmsCode(String signName, String mobile, Map<String, String> param, String templateCode) {
|
||||
|
||||
|
||||
@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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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 短信操作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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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<String, String> param, String templateCode) throws TencentCloudSDKException;
|
||||
|
||||
/**
|
||||
* 短信批量发送
|
||||
*
|
||||
* @param mobile 接收手机号
|
||||
* @param signName 签名
|
||||
* @param templateCode 模版code
|
||||
*/
|
||||
void sendBatchSms(String signName, List<String> mobile, String templateCode);
|
||||
|
||||
|
||||
/**
|
||||
* 申请短信签名
|
||||
*
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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<String, String> 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<String> mobile, String templateCode) {
|
||||
|
||||
com.aliyun.dysmsapi20170525.Client client = this.createClient();
|
||||
|
||||
List<String> sign = new ArrayList<String>();
|
||||
|
||||
sign.addAll(mobile);
|
||||
sign.replaceAll(e -> signName);
|
||||
|
||||
//手机号拆成多个小组进行发送
|
||||
List<List<String>> mobileList = new ArrayList<>();
|
||||
|
||||
//签名名称多个小组
|
||||
List<List<String>> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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;
|
||||
}
|
||||
|
||||
}
|
@ -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<String, String> param, String templateCode) {
|
||||
try {
|
||||
this.sendSms(signName, mobile, "[" + param.values() + "]", templateCode);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendBatchSms(String signName, List<String> 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<String, Object> 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<String, Object> 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<String, String> map = new HashMap<String, String>();
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
@ -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<String, String> 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<String> 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<String, Object> 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<String, Object> 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");
|
||||
}
|
||||
}
|
@ -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<SmsSignMapper, SmsSign> implements SmsSignService {
|
||||
@Autowired
|
||||
private AliSmsUtil aliSmsUtil;
|
||||
private SmsPluginFactory smsPluginFactory;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@ -40,11 +41,11 @@ public class SmsSignServiceImpl extends ServiceImpl<SmsSignMapper, SmsSign> impl
|
||||
if (this.getOne(new QueryWrapper<SmsSign>().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<SmsSignMapper, SmsSign> 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<SmsSignMapper, SmsSign> impl
|
||||
List<SmsSign> list = list(new LambdaQueryWrapper<SmsSign>().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<SmsSignMapper, SmsSign> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<SmsTemplateMapper, SmsTemplate> 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<SmsTemplateMapper, SmsTe
|
||||
try {
|
||||
SmsTemplate smsTemplate = this.getById(id);
|
||||
if (smsTemplate.getTemplateCode() != null) {
|
||||
aliSmsUtil.deleteSmsTemplate(smsTemplate.getTemplateCode());
|
||||
smsPluginFactory.smsPlugin().deleteSmsTemplate(smsTemplate.getTemplateCode());
|
||||
}
|
||||
this.removeById(id);
|
||||
} catch (Exception e) {
|
||||
log.error("删除短信模板错误",e);
|
||||
log.error("删除短信模板错误", e);
|
||||
}
|
||||
|
||||
}
|
||||
@ -63,25 +65,25 @@ public class SmsTemplateServiceImpl extends ServiceImpl<SmsTemplateMapper, SmsTe
|
||||
List<SmsTemplate> list = list(new LambdaQueryWrapper<SmsTemplate>().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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -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)) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -19,10 +19,15 @@ public interface LogisticsService extends IService<Logistics> {
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 获取已开启的物流公司列表
|
||||
|
@ -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<LogisticsMapper, Logistics> 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<OrderItem> orderItems = orderItemService.getByOrderSn(orderSn);
|
||||
//获取对应物流
|
||||
Logistics logistics = this.getById(logisticsId);
|
||||
// 店铺-物流公司设置
|
||||
LambdaQueryWrapper<StoreLogistics> 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<Logistics> getOpenLogistics() {
|
||||
LambdaQueryWrapper<Logistics> queryWrapper = new LambdaQueryWrapper<>();
|
||||
@ -60,218 +112,4 @@ public class LogisticsServiceImpl extends ServiceImpl<LogisticsMapper, Logistics
|
||||
return this.list(queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取物流信息
|
||||
*
|
||||
* @param logisticsId 物流公司ID
|
||||
* @param expNo 物流单号
|
||||
* @param customerName 手机号后四位
|
||||
* @return 物流信息
|
||||
* @throws Exception
|
||||
*/
|
||||
private Traces getOrderTracesByJson(String logisticsId, String expNo, String customerName) throws Exception {
|
||||
Setting setting = settingService.get(SettingEnum.KUAIDI_SETTING.name());
|
||||
if (CharSequenceUtil.isBlank(setting.getSettingValue())) {
|
||||
throw new ServiceException(ResultCode.LOGISTICS_NOT_SETTING);
|
||||
}
|
||||
KuaidiSetting kuaidiSetting = new Gson().fromJson(setting.getSettingValue(), KuaidiSetting.class);
|
||||
|
||||
//ID
|
||||
String EBusinessID = kuaidiSetting.getEbusinessID();
|
||||
|
||||
//KEY
|
||||
String AppKey = kuaidiSetting.getAppKey();
|
||||
|
||||
//请求url
|
||||
String ReqURL = kuaidiSetting.getReqURL();
|
||||
|
||||
Logistics logistics = this.getById(logisticsId);
|
||||
|
||||
if (logistics != null) {
|
||||
String requestData = "{'OrderCode':'','ShipperCode':'" + logistics.getCode() +
|
||||
"','LogisticCode':'" + expNo + "'" +
|
||||
",'CustomerName':'" + customerName + "'"+
|
||||
"}";
|
||||
Map<String, String> 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>) 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<String, String> 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<String, String> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<String> 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()) :
|
||||
|
4
pom.xml
4
pom.xml
@ -61,6 +61,10 @@
|
||||
<spring-boot-admin>2.3.1</spring-boot-admin>
|
||||
<owasp-java-html-sanitizer>20211018.2</owasp-java-html-sanitizer>
|
||||
<minio.version>8.0.3</minio.version>
|
||||
<huaweicloud.version>3.21.8</huaweicloud.version>
|
||||
<cos.version>5.6.97</cos.version>
|
||||
<tencentcloud.version>3.1.693</tencentcloud.version>
|
||||
<kuaidi100-api.version>1.0.11</kuaidi100-api.version>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
|
@ -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<Object> 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));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user