commit
f7ba021799
@ -80,3 +80,11 @@ ALTER TABLE li_store ADD `self_pick_flag` bit(1) DEFAULT NULL;
|
||||
历史足迹增加店铺Id
|
||||
*/
|
||||
ALTER TABLE li_foot_print ADD `store_id` varchar(255) DEFAULT NULL COMMENT '店铺ID';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
订单增加自提信息
|
||||
*/
|
||||
ALTER TABLE li_member_withdraw_apply ADD `real_name` varchar(255) DEFAULT NULL;
|
||||
ALTER TABLE li_member_withdraw_apply ADD `connect_number` varchar(255) DEFAULT NULL;
|
||||
|
@ -165,3 +165,11 @@ PS:手机验证码为 ‘111111’
|
||||
##### 交流 qq 2群 875294241(已满)
|
||||
##### 交流 qq 3群 263785057(已满)
|
||||
##### 交流 qq 4群 674617534
|
||||
|
||||
|
||||
### 附录
|
||||
有人有自己的学习视频、学习记录文档、希望宣传关联开源项目等均可以私聊仓库所有者。
|
||||
|
||||
类似:
|
||||
|
||||
清晨敲代码同学的分析: https://blog.csdn.net/vaevaevae233/category_12103567.html
|
@ -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 = "开票")
|
||||
|
@ -10,6 +10,7 @@ import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@ -26,6 +27,7 @@ import javax.validation.constraints.Min;
|
||||
@RestController
|
||||
@Api(tags = "买家端,预存款充值记录接口")
|
||||
@RequestMapping("/buyer/trade/recharge")
|
||||
@Validated
|
||||
public class RechargeTradeBuyerController {
|
||||
|
||||
@Autowired
|
||||
@ -37,7 +39,10 @@ public class RechargeTradeBuyerController {
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "price", value = "充值金额", required = true, dataType = "double", paramType = "query")
|
||||
})
|
||||
public ResultMessage<Recharge> create(@Max(value = 10000, message = "充值金额单次最多允许充值10000元") @Min(value = 1, message = "充值金额单次最少充值金额为1元") Double price) {
|
||||
public ResultMessage<Recharge> create(
|
||||
@Max(value = 10000, message = "充值金额单次最多允许充值10000元")
|
||||
@Min(value = 1, message = "充值金额单次最少充值金额为1元")
|
||||
Double price) {
|
||||
Recharge recharge = this.rechargeService.recharge(price);
|
||||
return ResultUtil.data(recharge);
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import io.swagger.annotations.ApiImplicitParams;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.constraints.Max;
|
||||
@ -36,6 +37,7 @@ import javax.validation.constraints.Pattern;
|
||||
@RestController
|
||||
@Api(tags = "买家端,会员余额接口")
|
||||
@RequestMapping("/buyer/wallet/wallet")
|
||||
@Validated
|
||||
public class MemberWalletBuyerController {
|
||||
|
||||
/**
|
||||
@ -127,7 +129,10 @@ public class MemberWalletBuyerController {
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "price", value = "提现金额", required = true, dataType = "double", paramType = "query")
|
||||
})
|
||||
public ResultMessage<Boolean> withdrawal(@Max(value = 9999, message = "充值金额单次最多允许提现9999元") @Min(value = 1, message = "充值金额单次最少提现金额为1元") Double price) {
|
||||
public ResultMessage<Boolean> withdrawal(
|
||||
@Max(value = 9999, message = "提现金额单次最多允许提现9999元")
|
||||
@Min(value = 1, message = "提现金额单次最少提现金额为1元")
|
||||
Double price) {
|
||||
return ResultUtil.data(memberWalletService.applyWithdrawal(price));
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.lili.common.aop.annotation.RetryOperation;
|
||||
import cn.lili.common.exception.RetryException;
|
||||
import cn.lili.common.vo.PageVO;
|
||||
import cn.lili.event.GoodsCommentCompleteEvent;
|
||||
import cn.lili.modules.distribution.entity.dos.DistributionGoods;
|
||||
import cn.lili.modules.distribution.entity.dto.DistributionGoodsSearchParams;
|
||||
@ -33,6 +34,8 @@ import cn.lili.modules.promotion.service.PromotionService;
|
||||
import cn.lili.modules.search.entity.dos.EsGoodsIndex;
|
||||
import cn.lili.modules.search.service.EsGoodsIndexService;
|
||||
import cn.lili.rocketmq.tags.GoodsTagsEnum;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||
@ -54,6 +57,8 @@ import java.util.stream.Collectors;
|
||||
@RocketMQMessageListener(topic = "${lili.data.rocketmq.goods-topic}", consumerGroup = "${lili.data.rocketmq.goods-group}")
|
||||
public class GoodsMessageListener implements RocketMQListener<MessageExt> {
|
||||
|
||||
private static final int BATCH_SIZE = 10;
|
||||
|
||||
/**
|
||||
* ES商品
|
||||
*/
|
||||
@ -175,10 +180,8 @@ public class GoodsMessageListener implements RocketMQListener<MessageExt> {
|
||||
try {
|
||||
String updateIndexFieldsJsonStr = new String(messageExt.getBody());
|
||||
JSONObject updateIndexFields = JSONUtil.parseObj(updateIndexFieldsJsonStr);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> queryFields = updateIndexFields.get("queryFields", Map.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> updateFields = updateIndexFields.get("updateFields", Map.class);
|
||||
@SuppressWarnings("unchecked") Map<String, Object> queryFields = updateIndexFields.get("queryFields", Map.class);
|
||||
@SuppressWarnings("unchecked") Map<String, Object> updateFields = updateIndexFields.get("updateFields", Map.class);
|
||||
goodsIndexService.updateIndex(queryFields, updateFields);
|
||||
} catch (Exception e) {
|
||||
log.error("更新商品索引事件执行异常,商品信息: " + new String(messageExt.getBody()), e);
|
||||
@ -238,10 +241,7 @@ public class GoodsMessageListener implements RocketMQListener<MessageExt> {
|
||||
try {
|
||||
goodsCommentCompleteEvent.goodsComment(memberEvaluation);
|
||||
} catch (Exception e) {
|
||||
log.error("评价{},在{}业务中,状态修改事件执行异常",
|
||||
new String(messageExt.getBody()),
|
||||
goodsCommentCompleteEvent.getClass().getName(),
|
||||
e);
|
||||
log.error("评价{},在{}业务中,状态修改事件执行异常", new String(messageExt.getBody()), goodsCommentCompleteEvent.getClass().getName(), e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -260,26 +260,42 @@ public class GoodsMessageListener implements RocketMQListener<MessageExt> {
|
||||
log.info("更新商品索引促销信息: {}", promotionsJsonStr);
|
||||
JSONObject jsonObject = JSONUtil.parseObj(promotionsJsonStr);
|
||||
// 转换为详细的促销信息(注:促销信息必须继承自 BasePromotions,且必须保证派生类存在与sdk包下)
|
||||
BasePromotions promotions = (BasePromotions) jsonObject.get("promotions",
|
||||
ClassLoaderUtil.loadClass(jsonObject.get("promotionsType").toString()));
|
||||
BasePromotions promotions = (BasePromotions) jsonObject.get("promotions", ClassLoaderUtil.loadClass(jsonObject.get("promotionsType").toString()));
|
||||
// 获取促销唯一key,由 促销类型 + 促销id 组成
|
||||
String esPromotionKey = jsonObject.get("esPromotionKey").toString();
|
||||
if (PromotionsScopeTypeEnum.PORTION_GOODS.name().equals(promotions.getScopeType())) {
|
||||
for (int i = 0; ; i++) {
|
||||
PromotionGoodsSearchParams searchParams = new PromotionGoodsSearchParams();
|
||||
searchParams.setPromotionId(promotions.getId());
|
||||
List<PromotionGoods> promotionGoodsList = this.promotionGoodsService.listFindAll(searchParams);
|
||||
List<String> skuIds = promotionGoodsList.stream().map(PromotionGoods::getSkuId).collect(Collectors.toList());
|
||||
PageVO pageVO = new PageVO();
|
||||
pageVO.setPageNumber(i);
|
||||
pageVO.setPageSize(BATCH_SIZE);
|
||||
Page<PromotionGoods> promotionGoodsPage = this.promotionGoodsService.pageFindAll(searchParams, pageVO);
|
||||
if (promotionGoodsPage == null || promotionGoodsPage.getRecords().isEmpty()) {
|
||||
break;
|
||||
}
|
||||
List<String> skuIds = promotionGoodsPage.getRecords().stream().map(PromotionGoods::getSkuId).collect(Collectors.toList());
|
||||
// 更新商品索引促销信息(删除原索引中相关的促销信息,更新索引中促销信息)
|
||||
this.goodsIndexService.deleteEsGoodsPromotionByPromotionKey(skuIds, esPromotionKey);
|
||||
this.goodsIndexService.updateEsGoodsIndexByList(promotionGoodsList, promotions, esPromotionKey);
|
||||
this.goodsIndexService.updateEsGoodsIndexByList(promotionGoodsPage.getRecords(), promotions, esPromotionKey);
|
||||
}
|
||||
|
||||
} else if (PromotionsScopeTypeEnum.PORTION_GOODS_CATEGORY.name().equals(promotions.getScopeType())) {
|
||||
for (int i = 0; ; i++) {
|
||||
GoodsSearchParams searchParams = new GoodsSearchParams();
|
||||
searchParams.setCategoryPath(promotions.getScopeId());
|
||||
List<GoodsSku> goodsSkuByList = this.goodsSkuService.getGoodsSkuByList(searchParams);
|
||||
List<String> skuIds = goodsSkuByList.stream().map(GoodsSku::getId).collect(Collectors.toList());
|
||||
searchParams.setPageNumber(i);
|
||||
searchParams.setPageSize(BATCH_SIZE);
|
||||
IPage<GoodsSku> goodsSkuByPage = this.goodsSkuService.getGoodsSkuByPage(searchParams);
|
||||
if (goodsSkuByPage == null || goodsSkuByPage.getRecords().isEmpty()) {
|
||||
break;
|
||||
}
|
||||
List<String> skuIds = goodsSkuByPage.getRecords().stream().map(GoodsSku::getId).collect(Collectors.toList());
|
||||
// 更新商品索引促销信息(删除原索引中相关的促销信息,更新索引中促销信息)
|
||||
this.goodsIndexService.deleteEsGoodsPromotionByPromotionKey(skuIds, esPromotionKey);
|
||||
this.goodsIndexService.updateEsGoodsIndexPromotions(skuIds, promotions, esPromotionKey);
|
||||
}
|
||||
|
||||
} else if (PromotionsScopeTypeEnum.ALL.name().equals(promotions.getScopeType())) {
|
||||
this.goodsIndexService.updateEsGoodsIndexAllByList(promotions, esPromotionKey);
|
||||
}
|
||||
@ -321,20 +337,23 @@ public class GoodsMessageListener implements RocketMQListener<MessageExt> {
|
||||
* @param goods 商品消息
|
||||
*/
|
||||
private void updateGoodsIndex(Goods goods) {
|
||||
for (int i = 1; ; i++) {
|
||||
//如果商品通过审核&&并且已上架
|
||||
GoodsSearchParams searchParams = new GoodsSearchParams();
|
||||
searchParams.setGoodsId(goods.getId());
|
||||
List<GoodsSku> goodsSkuList = this.goodsSkuService.getGoodsSkuByList(searchParams);
|
||||
log.info("goods:{}", goods);
|
||||
log.info("goodsSkuList:{}", goodsSkuList);
|
||||
if (goods.getAuthFlag().equals(GoodsAuthEnum.PASS.name())
|
||||
&& goods.getMarketEnable().equals(GoodsStatusEnum.UPPER.name())
|
||||
&& Boolean.FALSE.equals(goods.getDeleteFlag())) {
|
||||
this.generatorGoodsIndex(goods, goodsSkuList);
|
||||
searchParams.setPageNumber(i);
|
||||
searchParams.setPageSize(BATCH_SIZE);
|
||||
IPage<GoodsSku> goodsSkuByPage = this.goodsSkuService.getGoodsSkuByPage(searchParams);
|
||||
if (goodsSkuByPage == null || goodsSkuByPage.getRecords().isEmpty()) {
|
||||
break;
|
||||
}
|
||||
log.info("goods:{}", goods);
|
||||
log.info("goodsSkuList:{}", goodsSkuByPage.getRecords());
|
||||
if (goods.getAuthFlag().equals(GoodsAuthEnum.PASS.name()) && goods.getMarketEnable().equals(GoodsStatusEnum.UPPER.name()) && Boolean.FALSE.equals(goods.getDeleteFlag())) {
|
||||
this.generatorGoodsIndex(goods, goodsSkuByPage.getRecords());
|
||||
} else {
|
||||
//如果商品状态值不支持es搜索,那么将商品信息做下架处理
|
||||
else {
|
||||
for (GoodsSku goodsSku : goodsSkuList) {
|
||||
for (GoodsSku goodsSku : goodsSkuByPage.getRecords()) {
|
||||
EsGoodsIndex esGoodsOld = goodsIndexService.findById(goodsSku.getId());
|
||||
if (esGoodsOld != null) {
|
||||
goodsIndexService.deleteIndexById(goodsSku.getId());
|
||||
@ -343,6 +362,8 @@ public class GoodsMessageListener implements RocketMQListener<MessageExt> {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成商品索引
|
||||
*
|
||||
@ -462,9 +483,7 @@ public class GoodsMessageListener implements RocketMQListener<MessageExt> {
|
||||
goodsSku.setBuyCount(buyCount);
|
||||
goodsSkuService.update(goodsSku);
|
||||
|
||||
this.goodsIndexService.updateIndex(
|
||||
MapUtil.builder(new HashMap<String, Object>()).put("id", goodsCompleteMessage.getSkuId()).build(),
|
||||
MapUtil.builder(new HashMap<String, Object>()).put("buyCount", buyCount).build());
|
||||
this.goodsIndexService.updateIndex(MapUtil.builder(new HashMap<String, Object>()).put("id", goodsCompleteMessage.getSkuId()).build(), MapUtil.builder(new HashMap<String, Object>()).put("buyCount", buyCount).build());
|
||||
|
||||
} else {
|
||||
log.error("商品SkuId为[" + goodsCompleteMessage.getGoodsId() + "的商品不存在,更新商品失败!");
|
||||
|
50
docs/diagram/OrderComplaintBuyerController.uml
Normal file
50
docs/diagram/OrderComplaintBuyerController.uml
Normal file
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Diagram>
|
||||
<ID>JAVA</ID>
|
||||
<OriginalElement>cn.lili.controller.order.OrderComplaintBuyerController</OriginalElement>
|
||||
<nodes>
|
||||
<node x="-377.0" y="-206.0">cn.lili.modules.order.order.service.OrderComplaintCommunicationService</node>
|
||||
<node x="-927.5" y="123.5">cn.lili.controller.order.OrderComplaintStoreController</node>
|
||||
<node x="-378.0" y="607.0">cn.lili.modules.order.order.service.OrderComplaintService</node>
|
||||
<node x="311.5" y="111.0">cn.lili.controller.order.OrderComplaintBuyerController</node>
|
||||
<node x="-308.0" y="123.5">cn.lili.controller.order.OrderComplaintManagerController</node>
|
||||
</nodes>
|
||||
<notes />
|
||||
<edges>
|
||||
<edge source="cn.lili.controller.order.OrderComplaintStoreController" target="cn.lili.modules.order.order.service.OrderComplaintCommunicationService" relationship="TO_ONE">
|
||||
<point x="278.0" y="-84.5" />
|
||||
<point x="-330.0" y="38.5" />
|
||||
</edge>
|
||||
<edge source="cn.lili.controller.order.OrderComplaintStoreController" target="cn.lili.modules.order.order.service.OrderComplaintService" relationship="TO_ONE">
|
||||
<point x="262.0" y="84.5" />
|
||||
<point x="-300.0" y="-119.0" />
|
||||
</edge>
|
||||
<edge source="cn.lili.controller.order.OrderComplaintBuyerController" target="cn.lili.modules.order.order.service.OrderComplaintCommunicationService" relationship="TO_ONE">
|
||||
<point x="-286.0" y="-73.0" />
|
||||
<point x="345.0" y="38.5" />
|
||||
</edge>
|
||||
<edge source="cn.lili.controller.order.OrderComplaintBuyerController" target="cn.lili.modules.order.order.service.OrderComplaintService" relationship="TO_ONE">
|
||||
<point x="0.0" y="73.0" />
|
||||
<point x="606.5" y="726.0" />
|
||||
<point x="307.5" y="0.0" />
|
||||
</edge>
|
||||
<edge source="cn.lili.controller.order.OrderComplaintManagerController" target="cn.lili.modules.order.order.service.OrderComplaintCommunicationService" relationship="TO_ONE">
|
||||
<point x="-11.5" y="-84.5" />
|
||||
<point x="0.0" y="38.5" />
|
||||
</edge>
|
||||
<edge source="cn.lili.controller.order.OrderComplaintManagerController" target="cn.lili.modules.order.order.service.OrderComplaintService" relationship="TO_ONE">
|
||||
<point x="-57.5" y="84.5" />
|
||||
<point x="0.0" y="-119.0" />
|
||||
</edge>
|
||||
</edges>
|
||||
<settings layout="Hierarchic" zoom="1.0" showDependencies="true" x="-13.0" y="319.65625" />
|
||||
<SelectedNodes />
|
||||
<Categories>
|
||||
<Category>Inner Classes</Category>
|
||||
<Category>Methods</Category>
|
||||
<Category>Properties</Category>
|
||||
</Categories>
|
||||
<SCOPE>All</SCOPE>
|
||||
<VISIBILITY>private</VISIBILITY>
|
||||
</Diagram>
|
||||
|
20
docs/uml/AfterSaleRefundGodos.puml
Normal file
20
docs/uml/AfterSaleRefundGodos.puml
Normal file
@ -0,0 +1,20 @@
|
||||
@startuml
|
||||
'https://plantuml.com/sequence-diagram
|
||||
|
||||
actor user
|
||||
actor seller
|
||||
actor manager
|
||||
|
||||
user --> 平台: 申请售后
|
||||
seller -> 平台: 审核售后申请
|
||||
activate 平台
|
||||
平台 -> 平台: 更新售后状态
|
||||
return 售后审核响应
|
||||
|
||||
user -> 平台: 填写物流信息
|
||||
seller->平台: 确认收货
|
||||
activate 平台
|
||||
平台 -> 平台: 自动退款
|
||||
return 售后审核响应
|
||||
平台 -> user: 售后结束
|
||||
@enduml
|
16
docs/uml/AfterSaleRefundMoney.puml
Normal file
16
docs/uml/AfterSaleRefundMoney.puml
Normal file
@ -0,0 +1,16 @@
|
||||
@startuml
|
||||
'https://plantuml.com/sequence-diagram
|
||||
|
||||
actor user
|
||||
actor seller
|
||||
actor manager
|
||||
|
||||
user --> 平台: 申请售后
|
||||
seller -> 平台: 审核售后申请
|
||||
activate 平台
|
||||
平台 -> 平台: 通过审核,自动退款
|
||||
manager --> 平台: 审核阶段可介入操作
|
||||
return 售后审核响应
|
||||
|
||||
user -> 平台: 查询售后结果
|
||||
@enduml
|
21
docs/uml/Complaint.puml
Normal file
21
docs/uml/Complaint.puml
Normal file
@ -0,0 +1,21 @@
|
||||
@startuml
|
||||
'https://plantuml.com/sequence-diagram
|
||||
|
||||
actor user
|
||||
actor seller
|
||||
actor manager
|
||||
|
||||
activate 平台
|
||||
user -> 平台: 输入原因,发起投诉
|
||||
user --> 平台: 多次输出对话
|
||||
seller --> 平台: 多次输出对话
|
||||
manager --> 平台: 多次输出对话
|
||||
manager -> 平台: 根据各方意见,仲裁投诉结果
|
||||
activate 平台
|
||||
平台->平台: 仲裁结果,更新状态
|
||||
|
||||
平台 -> seller: 根据平台仲裁结果进行处理
|
||||
平台 -> user: 根据平台仲裁结果进行处理
|
||||
deactivate 平台
|
||||
|
||||
@enduml
|
@ -437,8 +437,33 @@
|
||||
<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>
|
||||
<dependency>
|
||||
<groupId>com.qiyuesuo.sdk</groupId>
|
||||
<artifactId>SDK</artifactId>
|
||||
<version>2.1.7</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/src/main/resources/maven-repository/SF-CSIM-EXPRESS-SDK-V2.1.7.jar</systemPath>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
@ -202,6 +202,8 @@ public enum ResultCode {
|
||||
ORDER_ITEM_NOT_EXIST(31014, "当前订单项不存在!"),
|
||||
POINT_NOT_ENOUGH(31015, "当前会员积分不足购买当前积分商品!"),
|
||||
|
||||
ORDER_LABEL_ORDER_ERROR(31016, "订单不能打印电子面单"),
|
||||
|
||||
|
||||
/**
|
||||
* 支付
|
||||
@ -219,7 +221,7 @@ public enum ResultCode {
|
||||
PAY_POINT_ENOUGH(32010, "积分不足,不能兑换"),
|
||||
PAY_NOT_EXIST_ORDER(32011, "支付订单不存在"),
|
||||
CAN_NOT_RECHARGE_WALLET(32012, "不能使用余额进行充值"),
|
||||
|
||||
RECHARGE_PRICE_ERROR(32013, "充值金额错误"),
|
||||
|
||||
/**
|
||||
* 售后
|
||||
@ -257,7 +259,7 @@ public enum ResultCode {
|
||||
WALLET_REMARK_ERROR(34004, "请填写审核备注!"),
|
||||
WALLET_EXIT_ERROR(34000, "钱包已存在,无法重复创建"),
|
||||
WALLET_APPLY_ERROR(34005, "提现申请异常!"),
|
||||
|
||||
WALLET_WITHDRAWAL_AMOUNT_ERROR(34006, "申请提现金额异常!"),
|
||||
/**
|
||||
* 评价
|
||||
*/
|
||||
@ -411,8 +413,10 @@ public enum ResultCode {
|
||||
STORE_NOT_OPEN(50004, "该会员未开通店铺"),
|
||||
STORE_NOT_LOGIN_ERROR(50005, "未登录店铺"),
|
||||
STORE_CLOSE_ERROR(50006, "店铺关闭,请联系管理员"),
|
||||
STORE_DELIVER_GOODS_ADDRESS(50007,"请填写商家发货地址"),
|
||||
FREIGHT_TEMPLATE_NOT_EXIST(50010, "当前模版不存在"),
|
||||
STORE_STATUS_ERROR(50011, "店铺状态异常,无法申请"),
|
||||
STORE_DELIVER_ADDRESS_EXIST(50012,"请填写发货地址"),
|
||||
|
||||
/**
|
||||
* 结算单
|
||||
@ -489,6 +493,12 @@ public enum ResultCode {
|
||||
WECHAT_ERROR(80307, "微信接口异常"),
|
||||
APP_VERSION_EXIST(80307, "APP版本已存在"),
|
||||
|
||||
/**
|
||||
* IM
|
||||
*/
|
||||
IM_MESSAGE_ADD_ERROR(80400,"IM消息发送错误"),
|
||||
IM_MESSAGE_EDIT_ERROR(80400,"IM消息更新错误"),
|
||||
|
||||
/**
|
||||
* 其他
|
||||
*/
|
||||
@ -500,6 +510,7 @@ public enum ResultCode {
|
||||
PURCHASE_ORDER_DEADLINE_ERROR(90004, "供求单,已超过报名截止时间"),
|
||||
INDEX_BUILDING(90005, "索引正在生成");
|
||||
|
||||
|
||||
private final Integer code;
|
||||
private final String message;
|
||||
|
||||
|
@ -2,6 +2,7 @@ package cn.lili.common.security;
|
||||
|
||||
import cn.lili.common.security.enums.UserEnums;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@ -13,6 +14,7 @@ import java.io.Serializable;
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class AuthUser implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 582441893336003319L;
|
||||
@ -84,22 +86,5 @@ public class AuthUser implements Serializable {
|
||||
this.nickName = nickName;
|
||||
}
|
||||
|
||||
public AuthUser(String username, String id, String face, UserEnums manager, String nickName, Boolean isSuper) {
|
||||
this.username = username;
|
||||
this.id = id;
|
||||
this.face = face;
|
||||
this.role = manager;
|
||||
this.isSuper = isSuper;
|
||||
this.nickName = nickName;
|
||||
}
|
||||
|
||||
public AuthUser(String username, String id, UserEnums manager, String nickName, Boolean isSuper, String clerkId, String face) {
|
||||
this.username = username;
|
||||
this.id = id;
|
||||
this.role = manager;
|
||||
this.isSuper = isSuper;
|
||||
this.nickName = nickName;
|
||||
this.clerkId = clerkId;
|
||||
this.face = face;
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,10 @@ import cn.lili.cache.Cache;
|
||||
import cn.lili.cache.CachePrefix;
|
||||
import cn.lili.common.enums.ResultCode;
|
||||
import cn.lili.common.exception.ServiceException;
|
||||
import cn.lili.common.properties.JWTTokenProperties;
|
||||
import cn.lili.common.security.AuthUser;
|
||||
import cn.lili.common.security.enums.SecurityEnum;
|
||||
import cn.lili.common.security.enums.UserEnums;
|
||||
import cn.lili.common.properties.JWTTokenProperties;
|
||||
import com.google.gson.Gson;
|
||||
import io.jsonwebtoken.*;
|
||||
import io.jsonwebtoken.security.SignatureException;
|
||||
@ -34,24 +34,21 @@ public class TokenUtil {
|
||||
/**
|
||||
* 构建token
|
||||
*
|
||||
* @param username 主体
|
||||
* @param claim 私有声明
|
||||
* @param longTerm 长时间特殊token 如:移动端,微信小程序等
|
||||
* @param userEnums 用户枚举
|
||||
* @param authUser 私有声明
|
||||
* @return TOKEN
|
||||
*/
|
||||
public Token createToken(String username, Object claim, boolean longTerm, UserEnums userEnums) {
|
||||
public Token createToken(AuthUser authUser) {
|
||||
Token token = new Token();
|
||||
//访问token
|
||||
String accessToken = createToken(username, claim, tokenProperties.getTokenExpireTime());
|
||||
String accessToken = createToken(authUser, tokenProperties.getTokenExpireTime());
|
||||
|
||||
cache.put(CachePrefix.ACCESS_TOKEN.getPrefix(userEnums) + accessToken, 1,
|
||||
cache.put(CachePrefix.ACCESS_TOKEN.getPrefix(authUser.getRole()) + accessToken, 1,
|
||||
tokenProperties.getTokenExpireTime(), TimeUnit.MINUTES);
|
||||
//刷新token生成策略:如果是长时间有效的token(用于app),则默认15天有效期刷新token。如果是普通用户登录,则刷新token为普通token2倍数
|
||||
Long expireTime = longTerm ? 15 * 24 * 60L : tokenProperties.getTokenExpireTime() * 2;
|
||||
String refreshToken = createToken(username, claim, expireTime);
|
||||
Long expireTime = authUser.getLongTerm() ? 15 * 24 * 60L : tokenProperties.getTokenExpireTime() * 2;
|
||||
String refreshToken = createToken(authUser, expireTime);
|
||||
|
||||
cache.put(CachePrefix.REFRESH_TOKEN.getPrefix(userEnums) + refreshToken, 1, expireTime, TimeUnit.MINUTES);
|
||||
cache.put(CachePrefix.REFRESH_TOKEN.getPrefix(authUser.getRole()) + refreshToken, 1, expireTime, TimeUnit.MINUTES);
|
||||
|
||||
token.setAccessToken(accessToken);
|
||||
token.setRefreshToken(refreshToken);
|
||||
@ -62,17 +59,17 @@ public class TokenUtil {
|
||||
* 刷新token
|
||||
*
|
||||
* @param oldRefreshToken 刷新token
|
||||
* @param userEnums 用户枚举
|
||||
* @return token
|
||||
*/
|
||||
public Token refreshToken(String oldRefreshToken, UserEnums userEnums) {
|
||||
public Token refreshToken(String oldRefreshToken) {
|
||||
|
||||
Claims claims;
|
||||
try {
|
||||
claims = Jwts.parser()
|
||||
.setSigningKey(SecretKeyUtil.generalKeyByDecoders())
|
||||
.parseClaimsJws(oldRefreshToken).getBody();
|
||||
} catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | SignatureException | IllegalArgumentException e) {
|
||||
} catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | SignatureException |
|
||||
IllegalArgumentException e) {
|
||||
//token 过期 认证失败等
|
||||
throw new ServiceException(ResultCode.USER_AUTH_EXPIRED);
|
||||
}
|
||||
@ -80,7 +77,7 @@ public class TokenUtil {
|
||||
//获取存储在claims中的用户信息
|
||||
String json = claims.get(SecurityEnum.USER_CONTEXT.getValue()).toString();
|
||||
AuthUser authUser = new Gson().fromJson(json, AuthUser.class);
|
||||
|
||||
UserEnums userEnums = authUser.getRole();
|
||||
|
||||
String username = authUser.getUsername();
|
||||
//获取是否长期有效的token
|
||||
@ -91,17 +88,18 @@ public class TokenUtil {
|
||||
if (cache.hasKey(CachePrefix.REFRESH_TOKEN.getPrefix(userEnums) + oldRefreshToken)) {
|
||||
Token token = new Token();
|
||||
//访问token
|
||||
String accessToken = createToken(username, authUser, tokenProperties.getTokenExpireTime());
|
||||
String accessToken = createToken(authUser, tokenProperties.getTokenExpireTime());
|
||||
cache.put(CachePrefix.ACCESS_TOKEN.getPrefix(userEnums) + accessToken, 1, tokenProperties.getTokenExpireTime(), TimeUnit.MINUTES);
|
||||
|
||||
//如果是信任登录设备,则刷新token长度继续延长
|
||||
Long expirationTime = tokenProperties.getTokenExpireTime() * 2;
|
||||
if (longTerm) {
|
||||
expirationTime = 60 * 24 * 15L;
|
||||
authUser.setLongTerm(true);
|
||||
}
|
||||
|
||||
//刷新token生成策略:如果是长时间有效的token(用于app),则默认15天有效期刷新token。如果是普通用户登录,则刷新token为普通token2倍数
|
||||
String refreshToken = createToken(username, authUser, expirationTime);
|
||||
String refreshToken = createToken(authUser, expirationTime);
|
||||
|
||||
cache.put(CachePrefix.REFRESH_TOKEN.getPrefix(userEnums) + refreshToken, 1, expirationTime, TimeUnit.MINUTES);
|
||||
token.setAccessToken(accessToken);
|
||||
@ -117,18 +115,17 @@ public class TokenUtil {
|
||||
/**
|
||||
* 生成token
|
||||
*
|
||||
* @param username 主体
|
||||
* @param claim 私有神明内容
|
||||
* @param authUser jwt主体对象
|
||||
* @param expirationTime 过期时间(分钟)
|
||||
* @return token字符串
|
||||
*/
|
||||
private String createToken(String username, Object claim, Long expirationTime) {
|
||||
private String createToken(AuthUser authUser, Long expirationTime) {
|
||||
//JWT 生成
|
||||
return Jwts.builder()
|
||||
//jwt 私有声明
|
||||
.claim(SecurityEnum.USER_CONTEXT.getValue(), new Gson().toJson(claim))
|
||||
.claim(SecurityEnum.USER_CONTEXT.getValue(), new Gson().toJson(authUser))
|
||||
//JWT的主体
|
||||
.setSubject(username)
|
||||
.setSubject(authUser.getUsername())
|
||||
//失效时间 当前时间+过期分钟
|
||||
.setExpiration(new Date(System.currentTimeMillis() + expirationTime * 60 * 1000))
|
||||
//签名算法和密钥
|
||||
|
@ -34,6 +34,8 @@ public class Distribution extends BaseEntity {
|
||||
this.memberName = memberName;
|
||||
distributionOrderCount=0;
|
||||
this.distributionStatus = DistributionStatusEnum.APPLY.name();
|
||||
commissionFrozen=0D;
|
||||
canRebate=0D;
|
||||
BeanUtil.copyProperties(distributionApplyDTO, this);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -427,6 +427,7 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
|
||||
LambdaUpdateWrapper<Goods> lambdaUpdateWrapper = Wrappers.lambdaUpdate();
|
||||
lambdaUpdateWrapper.set(Goods::getTemplateId, templateId);
|
||||
lambdaUpdateWrapper.in(Goods::getId, goodsIds);
|
||||
cache.multiDel(goodsIds);
|
||||
return this.update(lambdaUpdateWrapper);
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,8 @@ package cn.lili.modules.im.entity.dos;
|
||||
|
||||
|
||||
import cn.lili.common.utils.SnowFlake;
|
||||
import cn.lili.modules.member.entity.dos.Member;
|
||||
import cn.lili.modules.store.entity.dos.Store;
|
||||
import cn.lili.mybatis.BaseTenantEntity;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
@ -99,4 +101,71 @@ public class ImTalk extends BaseTenantEntity {
|
||||
this.name1 = name1;
|
||||
this.name2 = name2;
|
||||
}
|
||||
|
||||
public ImTalk(Member member1,Member member2){
|
||||
if(Long.parseLong(member1.getId()) > Long.parseLong(member2.getId())){
|
||||
this.userId1 = member2.getId();
|
||||
this.userId2 = member1.getId();
|
||||
this.top1 = false;
|
||||
this.top2 = false;
|
||||
this.disable1 = false;
|
||||
this.disable2 = false;
|
||||
this.storeFlag1 = false;
|
||||
this.storeFlag2 = false;
|
||||
this.setId(SnowFlake.getIdStr());
|
||||
this.lastTalkTime = new Date();
|
||||
this.face1 = member2.getFace();
|
||||
this.face2 = member1.getFace();
|
||||
this.name1 = member2.getNickName();
|
||||
this.name2 = member1.getNickName();
|
||||
}else{
|
||||
this.userId1 = member1.getId();
|
||||
this.userId2 = member2.getId();
|
||||
this.top1 = false;
|
||||
this.top2 = false;
|
||||
this.disable1 = false;
|
||||
this.disable2 = false;
|
||||
this.storeFlag1 = false;
|
||||
this.storeFlag2 = false;
|
||||
this.setId(SnowFlake.getIdStr());
|
||||
this.lastTalkTime = new Date();
|
||||
this.face1 = member1.getFace();
|
||||
this.face2 = member2.getFace();
|
||||
this.name1 = member1.getNickName();
|
||||
this.name2 = member2.getNickName();
|
||||
}
|
||||
}
|
||||
public ImTalk(Member member, Store store){
|
||||
if(Long.parseLong(member.getId()) > Long.parseLong(store.getId())){
|
||||
this.userId1 = store.getId();
|
||||
this.userId2 = member.getId();
|
||||
this.top1 = false;
|
||||
this.top2 = false;
|
||||
this.disable1 = false;
|
||||
this.disable2 = false;
|
||||
this.storeFlag1 = true;
|
||||
this.storeFlag2 = false;
|
||||
this.setId(SnowFlake.getIdStr());
|
||||
this.lastTalkTime = new Date();
|
||||
this.face1 = store.getStoreLogo();
|
||||
this.face2 = member.getFace();
|
||||
this.name1 = store.getStoreName();
|
||||
this.name2 = member.getNickName();
|
||||
}else{
|
||||
this.userId1 = member.getId();
|
||||
this.userId2 = store.getId();
|
||||
this.top1 = false;
|
||||
this.top2 = false;
|
||||
this.disable1 = false;
|
||||
this.disable2 = false;
|
||||
this.storeFlag1 = false;
|
||||
this.storeFlag2 = true;
|
||||
this.setId(SnowFlake.getIdStr());
|
||||
this.lastTalkTime = new Date();
|
||||
this.face1 = member.getFace();
|
||||
this.face2 = store.getStoreLogo();
|
||||
this.name1 = member.getNickName();
|
||||
this.name2 = store.getStoreName();
|
||||
}
|
||||
}
|
||||
}
|
@ -16,29 +16,32 @@ public interface ImMessageService extends IService<ImMessage> {
|
||||
/**
|
||||
* 阅读消息
|
||||
*
|
||||
* @param talkId
|
||||
* @param accessToken
|
||||
* @param talkId 对话Id
|
||||
* @param accessToken 验证token
|
||||
*/
|
||||
void read(String talkId, String accessToken);
|
||||
|
||||
/**
|
||||
* 未读消息列表
|
||||
*
|
||||
* @param accessToken
|
||||
* @param accessToken 验证token
|
||||
* @return 未读消息列表
|
||||
*/
|
||||
List<ImMessage> unReadMessages(String accessToken);
|
||||
|
||||
/**
|
||||
* 历史消息
|
||||
*
|
||||
* @param accessToken
|
||||
* @param to
|
||||
* @param accessToken 验证token
|
||||
* @param to 接收人
|
||||
*
|
||||
* @return 历史消息列表
|
||||
*/
|
||||
List<ImMessage> historyMessage(String accessToken, String to);
|
||||
|
||||
/**
|
||||
* 是否有新消息
|
||||
* @param accessToken
|
||||
* @param accessToken 验证token
|
||||
* @return
|
||||
*/
|
||||
Boolean hasNewMessage(String accessToken);
|
||||
@ -52,7 +55,7 @@ public interface ImMessageService extends IService<ImMessage> {
|
||||
|
||||
/**
|
||||
* 获取所有未读消息
|
||||
* @return
|
||||
* @return 未读数量
|
||||
*/
|
||||
Long unreadMessageCount();
|
||||
|
||||
|
@ -17,10 +17,9 @@ public interface ImTalkService extends IService<ImTalk> {
|
||||
* 获取与某人的聊天框
|
||||
*
|
||||
* @param userId1
|
||||
* @param userId2
|
||||
* @return
|
||||
*/
|
||||
ImTalk getTalkByUser(String userId1, String userId2);
|
||||
ImTalk getTalkByUser(String userId1);
|
||||
|
||||
/**
|
||||
* 置顶消息
|
||||
@ -41,7 +40,7 @@ public interface ImTalkService extends IService<ImTalk> {
|
||||
* 获取用户聊天列表
|
||||
* @return
|
||||
*/
|
||||
List<ImTalkVO> getUserTalkList(String userName);
|
||||
List<ImTalkVO> getUserTalkList();
|
||||
|
||||
/**
|
||||
* 获取商家聊天列表
|
||||
|
@ -4,6 +4,7 @@ import cn.lili.common.enums.ResultCode;
|
||||
import cn.lili.common.exception.ServiceException;
|
||||
import cn.lili.common.security.AuthUser;
|
||||
import cn.lili.common.security.context.UserContext;
|
||||
import cn.lili.common.security.enums.UserEnums;
|
||||
import cn.lili.modules.im.entity.dos.ImMessage;
|
||||
import cn.lili.modules.im.entity.dto.MessageQueryParams;
|
||||
import cn.lili.modules.im.mapper.ImMessageMapper;
|
||||
@ -18,9 +19,9 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Im消息 业务实现
|
||||
@ -130,9 +131,18 @@ public class ImMessageServiceImpl extends ServiceImpl<ImMessageMapper, ImMessage
|
||||
* @param messageList 消息列表
|
||||
*/
|
||||
private void readMessage(List<ImMessage> messageList) {
|
||||
if (messageList.size() > 0) {
|
||||
if (!messageList.isEmpty()) {
|
||||
//判断用户类型
|
||||
AuthUser authUser = Objects.requireNonNull(UserContext.getCurrentUser());
|
||||
String toUserId = "";
|
||||
if(UserEnums.MEMBER.equals(authUser.getRole())){
|
||||
toUserId = authUser.getId();
|
||||
}else if(UserEnums.STORE.equals(authUser.getRole())){
|
||||
toUserId = authUser.getStoreId();
|
||||
}
|
||||
//发送给自己的未读信息进行已读操作
|
||||
for (ImMessage imMessage : messageList) {
|
||||
if(Boolean.FALSE.equals(imMessage.getIsRead())){
|
||||
if(Boolean.FALSE.equals(imMessage.getIsRead()) && imMessage.getToUser().equals(toUserId)){
|
||||
imMessage.setIsRead(true);
|
||||
}
|
||||
}
|
||||
|
@ -21,9 +21,9 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.stringtemplate.v4.ST;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -45,47 +45,44 @@ public class ImTalkServiceImpl extends ServiceImpl<ImTalkMapper, ImTalk> impleme
|
||||
@Autowired
|
||||
private ImMessageService imMessageService;
|
||||
|
||||
@Override
|
||||
public ImTalk getTalkByUser(String userId1, String userId2) {
|
||||
public ImTalk getTalkByUser(String userId) {
|
||||
LambdaQueryWrapper<ImTalk> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(ImTalk::getUserId2, userId2);
|
||||
queryWrapper.eq(ImTalk::getUserId1, userId1);
|
||||
AuthUser currentUser = Objects.requireNonNull(UserContext.getCurrentUser());
|
||||
//登录用户的Id
|
||||
String selfId = "";
|
||||
//查看当前用户角色对Id进行赋值
|
||||
if(UserEnums.STORE.equals(currentUser.getRole())){
|
||||
selfId = currentUser.getStoreId();
|
||||
}else if(UserEnums.MEMBER.equals(currentUser.getRole())){
|
||||
selfId = currentUser.getId();
|
||||
}
|
||||
//小数在前保证永远是同一个对话
|
||||
String finalSelfId = selfId;
|
||||
queryWrapper.and(wq-> wq.eq(ImTalk::getUserId2, userId).eq(ImTalk::getUserId1, finalSelfId).or().eq(ImTalk::getUserId2, finalSelfId).eq(ImTalk::getUserId1, userId));
|
||||
ImTalk imTalk = this.getOne(queryWrapper);
|
||||
AuthUser currentUser = UserContext.getCurrentUser();
|
||||
//如果没有聊天,则创建聊天
|
||||
if (imTalk == null) {
|
||||
// 没有登录的这个账户信息
|
||||
if (currentUser == null) {
|
||||
return null;
|
||||
}
|
||||
//当自己为店铺时
|
||||
if(UserEnums.STORE.equals(currentUser.getRole())){
|
||||
Store selfStore = storeService.getById(userId1);
|
||||
Store selfStore = storeService.getById(selfId);
|
||||
//没有这个用户信息
|
||||
Member other = memberService.getById(userId2);
|
||||
Member other = memberService.getById(userId);
|
||||
if(other == null){
|
||||
return null;
|
||||
}
|
||||
//自己为店铺其他人必定为用户
|
||||
imTalk = new ImTalk(userId1, userId2, selfStore.getStoreLogo(), other.getFace(), selfStore.getStoreName(), other.getNickName());
|
||||
imTalk.setStoreFlag1(true);
|
||||
imTalk = new ImTalk(other,selfStore);
|
||||
}else if(UserEnums.MEMBER.equals(currentUser.getRole())){
|
||||
//没有这个店铺信息
|
||||
Member self = memberService.getById(userId1);
|
||||
Member otherMember = memberService.getById(userId2);
|
||||
Store otherStore = storeService.getById(userId2);
|
||||
Member self = memberService.getById(selfId);
|
||||
Member otherMember = memberService.getById(userId);
|
||||
Store otherStore = storeService.getById(userId);
|
||||
if(otherStore != null){
|
||||
imTalk = new ImTalk(userId1, userId2, self.getFace(), otherStore.getStoreLogo(), self.getNickName(), otherStore.getStoreName());
|
||||
imTalk.setStoreFlag2(true);
|
||||
imTalk = new ImTalk(self, otherStore);
|
||||
}else if (otherMember != null){
|
||||
imTalk = new ImTalk(userId1, userId2, self.getFace(), otherMember.getFace(), self.getNickName(), otherMember.getNickName());
|
||||
}else{
|
||||
return null;
|
||||
imTalk = new ImTalk(self, otherMember);
|
||||
}
|
||||
}
|
||||
this.save(imTalk);
|
||||
} else {
|
||||
imTalk = check(imTalk);
|
||||
}
|
||||
return imTalk;
|
||||
}
|
||||
@ -93,7 +90,7 @@ public class ImTalkServiceImpl extends ServiceImpl<ImTalkMapper, ImTalk> impleme
|
||||
/**
|
||||
* 发起聊天后,如果聊天不可见为true,则需要修正
|
||||
*
|
||||
* @param imTalk
|
||||
* @param imTalk 对话信息
|
||||
*/
|
||||
private ImTalk check(ImTalk imTalk) {
|
||||
if (imTalk.getDisable1() || imTalk.getDisable2()) {
|
||||
@ -131,23 +128,16 @@ public class ImTalkServiceImpl extends ServiceImpl<ImTalkMapper, ImTalk> impleme
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ImTalkVO> getUserTalkList(String userName) {
|
||||
public List<ImTalkVO> getUserTalkList() {
|
||||
AuthUser authUser = UserContext.getCurrentUser();
|
||||
if(authUser == null){
|
||||
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||
}
|
||||
LambdaQueryWrapper<ImTalk> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.and(wq->{
|
||||
wq.like(ImTalk::getName1, userName).or().like(ImTalk::getName2,userName);
|
||||
});
|
||||
queryWrapper.and(wq->{
|
||||
wq.like(ImTalk::getUserId1, authUser.getId()).or().like(ImTalk::getUserId2,authUser.getId());
|
||||
});
|
||||
queryWrapper.and(wq-> wq.eq(ImTalk::getUserId1, authUser.getId()).or().eq(ImTalk::getUserId2,authUser.getId()));
|
||||
queryWrapper.orderByDesc(ImTalk::getLastTalkTime);
|
||||
List<ImTalk> imTalks = this.list(queryWrapper);
|
||||
List<ImTalkVO> imTalkVOList = imTalks.stream().map(imTalk -> {
|
||||
return new ImTalkVO(imTalk, authUser.getId());
|
||||
}).collect(Collectors.toList());
|
||||
List<ImTalkVO> imTalkVOList = imTalks.stream().map(imTalk -> new ImTalkVO(imTalk, authUser.getId())).collect(Collectors.toList());
|
||||
getUnread(imTalkVOList);
|
||||
return imTalkVOList;
|
||||
}
|
||||
@ -160,7 +150,7 @@ public class ImTalkServiceImpl extends ServiceImpl<ImTalkMapper, ImTalk> impleme
|
||||
}
|
||||
LambdaQueryWrapper<ImTalk> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.and(wq->{
|
||||
wq.like(ImTalk::getUserId1, authUser.getStoreId()).or().like(ImTalk::getUserId2,authUser.getStoreId());
|
||||
wq.eq(ImTalk::getUserId1, authUser.getStoreId()).or().eq(ImTalk::getUserId2,authUser.getStoreId());
|
||||
});
|
||||
queryWrapper.orderByDesc(ImTalk::getLastTalkTime);
|
||||
List<ImTalk> imTalks = this.list(queryWrapper);
|
||||
@ -174,12 +164,12 @@ public class ImTalkServiceImpl extends ServiceImpl<ImTalkMapper, ImTalk> impleme
|
||||
|
||||
/**
|
||||
* 获取未读消息数量
|
||||
* @param imTalkVOList
|
||||
* @param imTalkVOList 消息列表
|
||||
*/
|
||||
private void getUnread(List<ImTalkVO> imTalkVOList){
|
||||
if(imTalkVOList.size() > 0){
|
||||
if(!imTalkVOList.isEmpty()){
|
||||
for (ImTalkVO imTalkVO : imTalkVOList) {
|
||||
long count = imMessageService.count(new LambdaQueryWrapper<ImMessage>().eq(ImMessage::getFromUser, imTalkVO.getUserId()).eq(ImMessage::getIsRead, false));
|
||||
long count = imMessageService.count(new LambdaQueryWrapper<ImMessage>().eq(ImMessage::getFromUser, imTalkVO.getUserId()).eq(ImMessage::getTalkId,imTalkVO.getId()).eq(ImMessage::getIsRead, false));
|
||||
imTalkVO.setUnread(count);
|
||||
}
|
||||
}
|
||||
|
@ -23,20 +23,23 @@ public class SeatTokenGenerate extends AbstractTokenGenerate<Seat> {
|
||||
|
||||
@Override
|
||||
public Token createToken(Seat seat, Boolean longTerm) {
|
||||
AuthUser authUser = new AuthUser(
|
||||
seat.getUsername(),
|
||||
seat.getId(),
|
||||
seat.getNickName(),
|
||||
seat.getFace(),
|
||||
UserEnums.SEAT);
|
||||
authUser.setTenantId(seat.getTenantId());
|
||||
AuthUser authUser = AuthUser.builder()
|
||||
.username(seat.getUsername())
|
||||
.id(seat.getId())
|
||||
.nickName(seat.getNickName())
|
||||
.face(seat.getFace())
|
||||
.role(UserEnums.SEAT)
|
||||
.longTerm(longTerm)
|
||||
.tenantId(seat.getTenantId())
|
||||
.build();
|
||||
|
||||
//登陆成功生成token
|
||||
return tokenUtil.createToken(seat.getUsername(), authUser, longTerm, UserEnums.SEAT);
|
||||
return tokenUtil.createToken(authUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token refreshToken(String refreshToken) {
|
||||
return tokenUtil.refreshToken(refreshToken, UserEnums.SEAT);
|
||||
return tokenUtil.refreshToken(refreshToken);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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,58 @@
|
||||
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.order.order.entity.vo.OrderDetailVO;
|
||||
import cn.lili.modules.system.entity.dos.Logistics;
|
||||
import cn.lili.modules.system.entity.vo.Traces;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 物流插件接口
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
Map labelOrder(LabelOrderDTO labelOrderDTO);
|
||||
|
||||
String createOrder(OrderDetailVO orderDetailVO);
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
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.logistics.plugin.shunfeng.ShunfengPlugin;
|
||||
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);
|
||||
case SHUNFENG:
|
||||
return new ShunfengPlugin(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,SHUNFENG;
|
||||
}
|
@ -1,35 +1,23 @@
|
||||
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.order.order.entity.vo.OrderDetailVO;
|
||||
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,103 +30,109 @@ 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 Map<String,Object> labelOrder(LabelOrderDTO labelOrderDTO) {
|
||||
try {
|
||||
Map<String,Object> resultMap = new HashMap();
|
||||
//订单
|
||||
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() + "'," + //客户密码
|
||||
@ -184,16 +178,21 @@ public class KdNiaoServiceImpl implements KdNiaoService {
|
||||
|
||||
//组织系统级参数
|
||||
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);
|
||||
String result = sendPost(reqURL, params);
|
||||
if (CharSequenceUtil.isEmpty(result) || CharSequenceUtil.isBlank(result)) {
|
||||
throw new ServiceException(ResultCode.LOGISTICS_CHECK_SETTING);
|
||||
}
|
||||
@ -201,20 +200,25 @@ public class KdNiaoServiceImpl implements KdNiaoService {
|
||||
JSONObject obj = JSONObject.parseObject(result);
|
||||
log.info("电子面单响应:{}", result);
|
||||
if (!"100".equals(obj.getString("ResultCode"))) {
|
||||
return obj.getString("Reason");
|
||||
resultMap.put("Reason",obj.getString("Reason"));
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
JSONObject orderJson = JSONObject.parseObject(obj.getString("Order"));
|
||||
|
||||
//电子面单模板
|
||||
printTemplate = obj.getString("PrintTemplate");
|
||||
|
||||
//进行发货
|
||||
orderService.delivery(orderSn, orderJson.getString("LogisticCode"), logisticsId);
|
||||
resultMap.put("printTemplate",obj.getString("PrintTemplate"));
|
||||
return resultMap;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return printTemplate;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createOrder(OrderDetailVO orderDetailVO) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* MD5加密
|
||||
*
|
||||
@ -323,7 +327,7 @@ public class KdNiaoServiceImpl implements KdNiaoService {
|
||||
result.append(line);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("向指定 URL 发送POST方法的请求错误", e);
|
||||
}
|
||||
//使用finally块来关闭输出流、输入流
|
||||
finally {
|
||||
@ -381,5 +385,4 @@ public class KdNiaoServiceImpl implements KdNiaoService {
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,191 @@
|
||||
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.order.order.entity.vo.OrderDetailVO;
|
||||
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 Map<String,Object> 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createOrder(OrderDetailVO orderDetailVO) {
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,242 @@
|
||||
package cn.lili.modules.logistics.plugin.shunfeng;
|
||||
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.lili.common.enums.ResultCode;
|
||||
import cn.lili.common.exception.ServiceException;
|
||||
import cn.lili.common.utils.SpringContextUtil;
|
||||
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.vo.OrderDetailVO;
|
||||
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.dto.LogisticsSetting;
|
||||
import cn.lili.modules.system.entity.vo.Traces;
|
||||
import com.sf.csim.express.service.CallExpressServiceTools;
|
||||
import com.sf.csim.express.service.HttpClientUtil;
|
||||
import com.sf.csim.express.service.IServiceCodeStandard;
|
||||
import com.sf.csim.express.service.code.ExpressServiceCodeEnum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 顺丰插件
|
||||
* @author admin
|
||||
*/
|
||||
@Slf4j
|
||||
public class ShunfengPlugin implements LogisticsPlugin {
|
||||
|
||||
/**
|
||||
* ExpressServiceCodeEnum 对应速运类-快递APIs
|
||||
* POSTServiceCodeEnum 对应速运类-驿站APIs
|
||||
* YJTServiceCodeEnum 对应解决方案-医寄通APIs
|
||||
* EPSServiceCodeEnum 对应解决方案-快递管家APIs
|
||||
* 详情见code目录下枚举类,客户可自行修改引用的该类
|
||||
**/
|
||||
private LogisticsSetting logisticsSetting;
|
||||
|
||||
public ShunfengPlugin(){}
|
||||
|
||||
public ShunfengPlugin(LogisticsSetting logisticsSetting) {
|
||||
this.logisticsSetting = logisticsSetting;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogisticsEnum pluginName() {
|
||||
return LogisticsEnum.SHUNFENG;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文档地址:https://open.sf-express.com/Api/ApiDetails?level3=393&interName=%E4%B8%8B%E8%AE%A2%E5%8D%95%E6%8E%A5%E5%8F%A3-EXP_RECE_CREATE_ORDER
|
||||
*
|
||||
* @param orderDetailVO
|
||||
*/
|
||||
public String createOrder(OrderDetailVO orderDetailVO) {
|
||||
StoreDetailService storeService = SpringContextUtil.getBean(StoreDetailService.class);
|
||||
StoreDeliverGoodsAddressDTO storeDeliverGoodsAddressDTO = storeService.getStoreDeliverGoodsAddressDto(orderDetailVO.getOrder().getStoreId());
|
||||
if(storeDeliverGoodsAddressDTO == null){
|
||||
throw new ServiceException(ResultCode.STORE_DELIVER_ADDRESS_EXIST);
|
||||
}
|
||||
try {
|
||||
Order order = orderDetailVO.getOrder();
|
||||
Map<String, Object> msgDataMap = new HashMap<String, Object>();
|
||||
msgDataMap.put("language", "zh-CN");
|
||||
msgDataMap.put("orderId", order.getSn());
|
||||
//托寄物信息
|
||||
List<Map<String, Object>> cargoDetails = new ArrayList<>();
|
||||
for (OrderItem orderItem : orderDetailVO.getOrderItems()) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("name", orderItem.getGoodsName());
|
||||
cargoDetails.add(map);
|
||||
}
|
||||
msgDataMap.put("cargoDetails", cargoDetails);
|
||||
|
||||
//收寄双方信息
|
||||
List<Map<String, Object>> contactInfoList = new ArrayList<>();
|
||||
Map<String, Object> storeContactInfoMap = new HashMap<>();
|
||||
storeContactInfoMap.put("contactType", 1);
|
||||
storeContactInfoMap.put("contact", storeDeliverGoodsAddressDTO.getSalesConsignorName());
|
||||
storeContactInfoMap.put("mobile", storeDeliverGoodsAddressDTO.getSalesConsignorMobile());
|
||||
//国家或地区2位代码 参照附录
|
||||
storeContactInfoMap.put("country", "CN");
|
||||
//详细地址,若有四级行政区划,如镇/街道等信息可拼接至此字段,格式样例:镇/街道+详细地址。若province/city 字段的值不传,此字段必须包含省市信息,避免影响原寄地代码识别,如:广东省深圳市福田区新洲十一街万基商务大厦10楼;此字段地址必须详细,否则会影响目的地中转识别;
|
||||
storeContactInfoMap.put("address", storeDeliverGoodsAddressDTO.getSalesConsignorAddressPath() + storeDeliverGoodsAddressDTO.getSalesConsignorDetail());
|
||||
contactInfoList.add(storeContactInfoMap);
|
||||
|
||||
Map<String, Object> memberContactInfoMap = new HashMap<>();
|
||||
memberContactInfoMap.put("contactType", 2);
|
||||
memberContactInfoMap.put("contact", order.getConsigneeName());
|
||||
memberContactInfoMap.put("mobile", order.getConsigneeMobile());
|
||||
//国家或地区2位代码 参照附录
|
||||
memberContactInfoMap.put("country", "CN");
|
||||
//详细地址,若有四级行政区划,如镇/街道等信息可拼接至此字段,格式样例:镇/街道+详细地址。若province/city 字段的值不传,此字段必须包含省市信息,避免影响原寄地代码识别,如:广东省深圳市福田区新洲十一街万基商务大厦10楼;此字段地址必须详细,否则会影响目的地中转识别;
|
||||
memberContactInfoMap.put("address", order.getConsigneeAddressPath() + order.getConsigneeDetail());
|
||||
contactInfoList.add(memberContactInfoMap);
|
||||
msgDataMap.put("contactInfoList", contactInfoList);
|
||||
|
||||
msgDataMap.put("expressTypeId", 1);
|
||||
msgDataMap.put("isReturnRoutelabel", 1);
|
||||
|
||||
|
||||
String result = sendPost(ExpressServiceCodeEnum.EXP_RECE_CREATE_ORDER, msgDataMap);
|
||||
JSONObject resultData = JSONUtil.parseObj(result).getJSONObject("apiResultData");
|
||||
if(Boolean.TRUE.toString().equals(resultData.get("success").toString())){
|
||||
return resultData.getJSONObject("msgData").getJSONArray("waybillNoInfoList").getJSONObject(0).get("waybillNo").toString();
|
||||
}
|
||||
throw new ServiceException(resultData.get("errorMsg").toString());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文档地址:https://open.sf-express.com/Api/ApiDetails?apiServiceCode=EXP_RECE_SEARCH_ROUTES&category=1&apiClassify=1&interName=%E8%B7%AF%E7%94%B1%E6%9F%A5%E8%AF%A2%E6%8E%A5%E5%8F%A3-EXP_RECE_SEARCH_ROUTES
|
||||
*
|
||||
* @param logistics 物流公司
|
||||
* @param expNo
|
||||
* @param phone
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Traces pollQuery(Logistics logistics, String expNo, String phone) {
|
||||
try {
|
||||
Map<String, Object> msgDataMap = new HashMap<String, Object>();
|
||||
msgDataMap.put("language", "zh-CN");
|
||||
/**
|
||||
* 查询号类别:
|
||||
* 1:根据顺丰运单号查询,trackingNumber将被当作顺丰运单号处理
|
||||
* 2:根据客户订单号查询,trackingNumber将被当作客户订单号处理
|
||||
*/
|
||||
msgDataMap.put("trackingType", 1);
|
||||
List<String> trackingNumber = new ArrayList<>();
|
||||
trackingNumber.add(expNo);
|
||||
msgDataMap.put("trackingNumber", trackingNumber);
|
||||
JSONObject result = JSONUtil.parseObj(sendPost(ExpressServiceCodeEnum.EXP_RECE_SEARCH_ROUTES, msgDataMap));
|
||||
JSONObject resultData = result.getJSONObject("apiResultData");
|
||||
if(Boolean.TRUE.toString().equals(resultData.get("success").toString())){
|
||||
JSONArray routesJson = resultData.getJSONObject("msgData").getJSONArray("routeResps").getJSONObject(0).getJSONArray("routes");
|
||||
List<Map> routes = routesJson.toList(Map.class);
|
||||
return new Traces(logistics.getName(),expNo,routes);
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Traces pollMapTrack(Logistics logistics, String expNo, String phone, String from, String to) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文档地址:http://open.sf-express.com/Api/ApiDetails?level3=317&interName=%E4%BA%91%E6%89%93%E5%8D%B0%E9%9D%A2%E5%8D%952.0%E6%8E%A5%E5%8F%A3-COM_RECE_CLOUD_PRINT_WAYBILLS
|
||||
*
|
||||
* @param labelOrderDTO 电子面单DTO
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Map<String,Object> labelOrder(LabelOrderDTO labelOrderDTO) {
|
||||
try {
|
||||
Map<String, Object> msgDataMap = new HashMap<>();
|
||||
//模板编码
|
||||
//关联云打印接口后,点击查看,可在接口详情页获取模板编码,类似:fm_76130_standard_{partnerId}
|
||||
msgDataMap.put("templateCode", logisticsSetting.getTemplateCode());
|
||||
//业务数据
|
||||
Map<String, Object> documents = new HashMap<>();
|
||||
documents.put("masterWaybillNo", labelOrderDTO.getOrder().getLogisticsNo());
|
||||
msgDataMap.put("documents",documents);
|
||||
msgDataMap.put("sync",true);
|
||||
/**
|
||||
* 版本号,传固定值:2.0
|
||||
*/
|
||||
msgDataMap.put("version", "2.0");
|
||||
JSONObject result = JSONUtil.parseObj(sendPost(ExpressServiceCodeEnum.COM_RECE_CLOUD_PRINT_WAYBILLS, msgDataMap));
|
||||
JSONObject resultData = result.getJSONObject("apiResultData");
|
||||
if(Boolean.TRUE.toString().equals(resultData.get("success").toString())){
|
||||
return resultData.getJSONObject("obj").getJSONArray("files").toList(Map.class).get(0);
|
||||
}
|
||||
throw new ServiceException(resultData.getJSONArray("errorMessage").get(0).toString());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文档地址:https://open.sf-express.com/Api/ApiDetails?level3=409&interName=%E9%A2%84%E8%AE%A1%E6%B4%BE%E9%80%81%E6%97%B6%E9%97%B4%E6%8E%A5%E5%8F%A3-EXP_RECE_SEARCH_PROMITM
|
||||
*
|
||||
* @param searchNo
|
||||
* @param checkNos
|
||||
*/
|
||||
public String searchPromitm(String searchNo, String checkNos) {
|
||||
try {
|
||||
Map<String, Object> msgDataMap = new HashMap<String, Object>();
|
||||
//顺丰运单号
|
||||
msgDataMap.put("searchNo", searchNo);
|
||||
//校验类型 1,电话号码校验 2,月结卡号校验
|
||||
msgDataMap.put("checkType", 1);
|
||||
//校验值 当校验类型为1时传电话号码 当校验类型为2时传月结卡号
|
||||
List<String> mobileList= new ArrayList<>();
|
||||
mobileList.add(checkNos);
|
||||
msgDataMap.put("checkNos", mobileList);
|
||||
JSONObject result = JSONUtil.parseObj(sendPost(ExpressServiceCodeEnum.EXP_RECE_SEARCH_PROMITM, msgDataMap));
|
||||
JSONObject resultData = result.getJSONObject("apiResultData");
|
||||
if(Boolean.TRUE.toString().equals(resultData.get("success").toString())){
|
||||
return resultData.getJSONObject("msgData").get("promiseTm").toString();
|
||||
}
|
||||
throw new ServiceException(resultData.get("errorMsg").toString());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String sendPost(IServiceCodeStandard standardService, Map<String, Object> msgDataMap) throws UnsupportedEncodingException {
|
||||
CallExpressServiceTools tools = CallExpressServiceTools.getInstance();
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
String timeStamp = String.valueOf(System.currentTimeMillis());
|
||||
// 顾客编码
|
||||
params.put("partnerID", logisticsSetting.getClientCode());
|
||||
params.put("requestID", UUID.randomUUID().toString().replace("-", ""));
|
||||
// 接口服务码
|
||||
params.put("serviceCode", standardService.getCode());
|
||||
params.put("timestamp", timeStamp);
|
||||
params.put("msgData", JSONUtil.toJsonStr(msgDataMap));
|
||||
|
||||
params.put("msgDigest", tools.getMsgDigest(params.get("msgData"), timeStamp, logisticsSetting.getCheckWord()));
|
||||
String result = HttpClientUtil.post(logisticsSetting.getCallUrl(), params);
|
||||
|
||||
log.info("===调用地址 ===" + logisticsSetting.getCallUrl());
|
||||
log.info("===顾客编码 ===" + logisticsSetting.getClientCode());
|
||||
log.info("===返回结果:" + result);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -74,6 +74,14 @@ public interface MemberService extends IService<Member> {
|
||||
*/
|
||||
Token usernameStoreLogin(String username, String password);
|
||||
|
||||
/**
|
||||
* 商家登录:用户名、密码登录
|
||||
*
|
||||
* @param mobilePhone 用户名
|
||||
* @return token
|
||||
*/
|
||||
Token mobilePhoneStoreLogin(String mobilePhone);
|
||||
|
||||
/**
|
||||
* 注册:手机号、验证码登录
|
||||
*
|
||||
|
@ -198,6 +198,22 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
|
||||
throw new ServiceException(ResultCode.USER_PASSWORD_ERROR);
|
||||
}
|
||||
//对店铺状态的判定处理
|
||||
return checkMemberStore(member);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token mobilePhoneStoreLogin(String mobilePhone) {
|
||||
Member member = this.findMember(mobilePhone);
|
||||
//如果手机号不存在则自动注册用户
|
||||
if (member == null) {
|
||||
throw new ServiceException(ResultCode.USER_NOT_EXIST);
|
||||
}
|
||||
loginBindUser(member);
|
||||
//对店铺状态的判定处理
|
||||
return checkMemberStore(member);
|
||||
}
|
||||
|
||||
private Token checkMemberStore(Member member) {
|
||||
if (Boolean.TRUE.equals(member.getHaveStore())) {
|
||||
Store store = storeService.getById(member.getStoreId());
|
||||
if (!store.getStoreDisable().equals(StoreStatusEnum.OPEN.name())) {
|
||||
@ -206,7 +222,6 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
|
||||
} else {
|
||||
throw new ServiceException(ResultCode.USER_NOT_EXIST);
|
||||
}
|
||||
|
||||
return storeTokenGenerate.createToken(member, false);
|
||||
}
|
||||
|
||||
|
@ -57,14 +57,21 @@ public class MemberTokenGenerate extends AbstractTokenGenerate<Member> {
|
||||
String destination = rocketmqCustomProperties.getMemberTopic() + ":" + MemberTagsEnum.MEMBER_LOGIN.name();
|
||||
rocketMQTemplate.asyncSend(destination, member, RocketmqSendCallbackBuilder.commonCallback());
|
||||
|
||||
AuthUser authUser = new AuthUser(member.getUsername(), member.getId(), member.getNickName(), member.getFace(), UserEnums.MEMBER);
|
||||
AuthUser authUser = AuthUser.builder()
|
||||
.username(member.getUsername())
|
||||
.face(member.getFace())
|
||||
.id(member.getId())
|
||||
.role(UserEnums.MEMBER)
|
||||
.nickName(member.getNickName())
|
||||
.longTerm(longTerm)
|
||||
.build();
|
||||
//登陆成功生成token
|
||||
return tokenUtil.createToken(member.getUsername(), authUser, longTerm, UserEnums.MEMBER);
|
||||
return tokenUtil.createToken(authUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token refreshToken(String refreshToken) {
|
||||
return tokenUtil.refreshToken(refreshToken, UserEnums.MEMBER);
|
||||
return tokenUtil.refreshToken(refreshToken);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,16 +11,16 @@ import cn.lili.common.security.enums.UserEnums;
|
||||
import cn.lili.common.security.token.Token;
|
||||
import cn.lili.common.security.token.TokenUtil;
|
||||
import cn.lili.common.security.token.base.AbstractTokenGenerate;
|
||||
import cn.lili.modules.member.entity.dos.Clerk;
|
||||
import cn.lili.modules.member.entity.dos.Member;
|
||||
import cn.lili.modules.member.entity.vo.StoreUserMenuVO;
|
||||
import cn.lili.modules.member.service.ClerkService;
|
||||
import cn.lili.modules.member.service.StoreMenuRoleService;
|
||||
import cn.lili.modules.store.entity.dos.Store;
|
||||
import cn.lili.modules.store.service.StoreService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.lili.modules.member.entity.dos.Clerk;
|
||||
import cn.lili.modules.member.entity.vo.StoreUserMenuVO;
|
||||
import cn.lili.modules.member.service.ClerkService;
|
||||
import cn.lili.modules.member.service.StoreMenuRoleService;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -69,16 +69,25 @@ public class StoreTokenGenerate extends AbstractTokenGenerate<Member> {
|
||||
if (store == null) {
|
||||
throw new ServiceException(ResultCode.STORE_NOT_OPEN);
|
||||
}
|
||||
AuthUser authUser = new AuthUser(member.getUsername(), member.getId(), UserEnums.STORE, member.getNickName(), clerk.getIsSuper(), clerk.getId(),store.getStoreLogo());
|
||||
|
||||
authUser.setStoreId(store.getId());
|
||||
authUser.setStoreName(store.getStoreName());
|
||||
return tokenUtil.createToken(member.getUsername(), authUser, longTerm, UserEnums.STORE);
|
||||
//构建对象
|
||||
AuthUser authUser = AuthUser.builder()
|
||||
.username(member.getUsername())
|
||||
.id(member.getId())
|
||||
.role(UserEnums.STORE)
|
||||
.nickName(member.getNickName())
|
||||
.isSuper(clerk.getIsSuper())
|
||||
.clerkId(clerk.getId())
|
||||
.face(store.getStoreLogo())
|
||||
.storeId(store.getId())
|
||||
.storeName(store.getStoreName())
|
||||
.longTerm(longTerm)
|
||||
.build();
|
||||
return tokenUtil.createToken(authUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token refreshToken(String refreshToken) {
|
||||
return tokenUtil.refreshToken(refreshToken, UserEnums.STORE);
|
||||
return tokenUtil.refreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,7 +154,6 @@ public class StoreTokenGenerate extends AbstractTokenGenerate<Member> {
|
||||
superPermissions.add("/store/passport/login*");
|
||||
|
||||
|
||||
|
||||
//店铺设置
|
||||
queryPermissions.add("/store/settings/storeSettings*");
|
||||
//文章接口
|
||||
@ -154,6 +162,5 @@ public class StoreTokenGenerate extends AbstractTokenGenerate<Member> {
|
||||
queryPermissions.add("/store/statistics/index*");
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 查询导出订单列表
|
||||
*
|
||||
@ -166,6 +165,14 @@ public interface OrderService extends IService<Order> {
|
||||
*/
|
||||
Order delivery(String orderSn, String invoiceNumber, String logisticsId);
|
||||
|
||||
/**
|
||||
* 订单发货
|
||||
*
|
||||
* @param orderSn 订单编号
|
||||
* @return 订单
|
||||
*/
|
||||
Order shunFengDelivery(String orderSn);
|
||||
|
||||
/**
|
||||
* 获取物流踪迹
|
||||
*
|
||||
@ -174,6 +181,14 @@ public interface OrderService extends IService<Order> {
|
||||
*/
|
||||
Traces getTraces(String orderSn);
|
||||
|
||||
/**
|
||||
* 获取地图版 物流踪迹
|
||||
*
|
||||
* @param orderSn 订单编号
|
||||
* @return 物流踪迹
|
||||
*/
|
||||
Traces getMapTraces(String orderSn);
|
||||
|
||||
/**
|
||||
* 订单核验
|
||||
*
|
||||
|
@ -16,10 +16,11 @@ 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.logistics.entity.enums.LogisticsEnum;
|
||||
import cn.lili.modules.member.entity.dto.MemberAddressDTO;
|
||||
import cn.lili.modules.member.service.StoreLogisticsService;
|
||||
import cn.lili.modules.order.cart.entity.dto.TradeDTO;
|
||||
import cn.lili.modules.order.cart.entity.enums.DeliveryMethodEnum;
|
||||
import cn.lili.modules.order.order.aop.OrderLogPoint;
|
||||
@ -41,8 +42,11 @@ 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.dto.LogisticsSetting;
|
||||
import cn.lili.modules.system.entity.vo.Traces;
|
||||
import cn.lili.modules.system.service.LogisticsService;
|
||||
import cn.lili.mybatis.util.PageUtil;
|
||||
@ -149,6 +153,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) {
|
||||
@ -164,6 +171,8 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
||||
List<OrderVO> orderVOS = new ArrayList<>();
|
||||
//循环购物车
|
||||
tradeDTO.getCartList().forEach(item -> {
|
||||
//当前购物车订单子项
|
||||
List<OrderItem> currentOrderItems = new ArrayList<>();
|
||||
Order order = new Order(item, tradeDTO);
|
||||
//构建orderVO对象
|
||||
OrderVO orderVO = new OrderVO();
|
||||
@ -174,10 +183,13 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
||||
//记录日志
|
||||
orderLogs.add(new OrderLog(item.getSn(), UserContext.getCurrentUser().getId(), UserContext.getCurrentUser().getRole().getRole(), UserContext.getCurrentUser().getUsername(), message));
|
||||
item.getCheckedSkuList().forEach(
|
||||
sku -> orderItems.add(new OrderItem(sku, item, tradeDTO))
|
||||
sku -> {
|
||||
orderItems.add(new OrderItem(sku, item, tradeDTO));
|
||||
currentOrderItems.add(new OrderItem(sku, item, tradeDTO));
|
||||
}
|
||||
);
|
||||
//写入子订单信息
|
||||
orderVO.setOrderItems(orderItems);
|
||||
orderVO.setOrderItems(currentOrderItems);
|
||||
//orderVO 记录
|
||||
orderVOS.add(orderVO);
|
||||
});
|
||||
@ -451,13 +463,33 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
||||
return order;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Order shunFengDelivery(String orderSn) {
|
||||
OrderDetailVO orderDetailVO = this.queryDetail(orderSn);
|
||||
String logisticsNo = logisticsService.sfCreateOrder(orderDetailVO);
|
||||
Logistics logistics = logisticsService.getOne(new LambdaQueryWrapper<Logistics>().eq(Logistics::getCode,"SF"));
|
||||
return delivery(orderSn,logisticsNo,logistics.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Traces getTraces(String orderSn) {
|
||||
//获取订单信息
|
||||
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
|
||||
|
@ -16,6 +16,11 @@ public enum PaymentMethodEnum {
|
||||
* 支付宝
|
||||
*/
|
||||
ALIPAY("aliPayPlugin", "支付宝"),
|
||||
|
||||
/**
|
||||
* 银联-云闪付
|
||||
*/
|
||||
UNIONPAY("unionPayPlugin", "银联-云闪付"),
|
||||
/**
|
||||
* 余额支付
|
||||
*/
|
||||
|
@ -18,6 +18,7 @@ import cn.lili.modules.system.entity.dto.payment.PaymentSupportSetting;
|
||||
import cn.lili.modules.system.entity.dto.payment.dto.PaymentSupportItem;
|
||||
import cn.lili.modules.system.entity.enums.SettingEnum;
|
||||
import cn.lili.modules.system.service.SettingService;
|
||||
import cn.lili.modules.wallet.entity.dos.MemberWithdrawApply;
|
||||
import cn.lili.modules.wallet.service.MemberWalletService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -142,6 +143,15 @@ public class CashierSupport {
|
||||
payment.notify(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户提现
|
||||
* @param paymentMethodEnum 支付渠道
|
||||
* @param memberWithdrawApply 用户提现申请
|
||||
*/
|
||||
public void transfer(PaymentMethodEnum paymentMethodEnum, MemberWithdrawApply memberWithdrawApply){
|
||||
Payment payment = (Payment) SpringContextUtil.getBean(paymentMethodEnum.getPlugin());
|
||||
payment.transfer(memberWithdrawApply);
|
||||
}
|
||||
/**
|
||||
* 获取收银台参数
|
||||
*
|
||||
|
@ -6,6 +6,7 @@ import cn.lili.common.vo.ResultMessage;
|
||||
import cn.lili.modules.payment.entity.RefundLog;
|
||||
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
|
||||
import cn.lili.modules.payment.kit.dto.PayParam;
|
||||
import cn.lili.modules.wallet.entity.dos.MemberWithdrawApply;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@ -110,6 +111,13 @@ public interface Payment {
|
||||
throw new ServiceException(ResultCode.PAY_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提现
|
||||
*/
|
||||
default void transfer(MemberWithdrawApply memberWithdrawApply) {
|
||||
throw new ServiceException(ResultCode.PAY_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付回调地址
|
||||
*
|
||||
|
@ -26,11 +26,13 @@ import cn.lili.modules.system.entity.dos.Setting;
|
||||
import cn.lili.modules.system.entity.dto.payment.AlipayPaymentSetting;
|
||||
import cn.lili.modules.system.entity.enums.SettingEnum;
|
||||
import cn.lili.modules.system.service.SettingService;
|
||||
import cn.lili.modules.wallet.entity.dos.MemberWithdrawApply;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.domain.*;
|
||||
import com.alipay.api.internal.util.AlipaySignature;
|
||||
import com.alipay.api.response.AlipayTradeCancelResponse;
|
||||
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
|
||||
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
|
||||
import com.alipay.api.response.AlipayTradeRefundResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -229,6 +231,43 @@ public class AliPayPlugin implements Payment {
|
||||
log.info("支付异步通知:");
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付宝提现
|
||||
* 文档地址:https://opendocs.alipay.com/open/02byuo?scene=ca56bca529e64125a2786703c6192d41&ref=api
|
||||
*
|
||||
* @param memberWithdrawApply 会员提现申请
|
||||
*/
|
||||
@Override
|
||||
public void transfer(MemberWithdrawApply memberWithdrawApply) {
|
||||
AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
|
||||
model.setOutBizNo(SnowFlake.createStr("T"));
|
||||
model.setRemark("用户提现");
|
||||
model.setBusinessParams("{\"payer_show_name_use_alias\":\"true\"}");
|
||||
model.setBizScene("DIRECT_TRANSFER");
|
||||
Participant payeeInfo = new Participant();
|
||||
payeeInfo.setIdentity(memberWithdrawApply.getConnectNumber());
|
||||
payeeInfo.setIdentityType("ALIPAY_LOGON_ID");
|
||||
payeeInfo.setName(memberWithdrawApply.getRealName());
|
||||
model.setPayeeInfo(payeeInfo);
|
||||
|
||||
model.setTransAmount(memberWithdrawApply.getApplyMoney().toString());
|
||||
model.setProductCode("TRANS_ACCOUNT_NO_PWD");
|
||||
model.setOrderTitle("用户提现");
|
||||
//交互退款
|
||||
try {
|
||||
AlipayFundTransUniTransferResponse alipayFundTransUniTransferResponse = AliPayApi.uniTransferToResponse(model,null);
|
||||
log.error("支付宝退款,参数:{},支付宝响应:{}", JSONUtil.toJsonStr(model), JSONUtil.toJsonStr(alipayFundTransUniTransferResponse));
|
||||
if (alipayFundTransUniTransferResponse.isSuccess()) {
|
||||
|
||||
} else {
|
||||
log.error(alipayFundTransUniTransferResponse.getSubMsg());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("用户提现异常:", e);
|
||||
throw new ServiceException(ResultCode.PAY_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证支付结果
|
||||
*
|
||||
|
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
*
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
*
|
||||
* <p>IJPay 交流群: 723992875</p>
|
||||
*
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
|
||||
*
|
||||
* <p>云闪付接口</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package cn.lili.modules.payment.kit.plugin.unionpay;
|
||||
|
||||
import cn.lili.modules.payment.kit.core.kit.HttpKit;
|
||||
import cn.lili.modules.payment.kit.core.kit.WxPayKit;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class UnionPayApi {
|
||||
public static String authUrl = "https://qr.95516.com/qrcGtwWeb-web/api/userAuth?version=1.0.0&redirectUrl=%s";
|
||||
|
||||
public static String execution(String url, Map<String, String> params) {
|
||||
return HttpKit.getDelegate().post(url, WxPayKit.toXml(params));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户授权 API
|
||||
*
|
||||
* @param url 回调地址,可以自定义参数 https://pay.javen.com/callback?sdk=ijpay
|
||||
* @return 银联重定向 Url
|
||||
*/
|
||||
public static String buildAuthUrl(String url) {
|
||||
return String.format(authUrl, url);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
|
||||
package cn.lili.modules.payment.kit.plugin.unionpay;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付等常用的支付方式以及各种常用的接口。</p>
|
||||
*
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
*
|
||||
* <p>IJPay 交流群: 723992875</p>
|
||||
*
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
|
||||
*
|
||||
* <p>云闪付常用配置</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class UnionPayApiConfig implements Serializable {
|
||||
private static final long serialVersionUID = -9025648880068727445L;
|
||||
|
||||
/**
|
||||
* 商户平台分配的账号
|
||||
*/
|
||||
private String mchId;
|
||||
/**
|
||||
* 连锁商户号
|
||||
*/
|
||||
private String groupMchId;
|
||||
/**
|
||||
* 授权交易机构代码
|
||||
*/
|
||||
private String agentMchId;
|
||||
/**
|
||||
* 商户平台分配的密钥
|
||||
*/
|
||||
private String apiKey;
|
||||
/**
|
||||
* 商户平台网关
|
||||
*/
|
||||
private String serverUrl;
|
||||
/**
|
||||
* 应用域名,回调中会使用此参数
|
||||
*/
|
||||
private String domain;
|
||||
/**
|
||||
* 其他附加参数
|
||||
*/
|
||||
private Object exParams;
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
|
||||
package cn.lili.modules.payment.kit.plugin.unionpay;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付等常用的支付方式以及各种常用的接口。</p>
|
||||
*
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
*
|
||||
* <p>IJPay 交流群: 723992875</p>
|
||||
*
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
|
||||
*
|
||||
* <p>云闪付常用配置 Kit</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public class UnionPayApiConfigKit {
|
||||
private static final ThreadLocal<String> TL = new ThreadLocal<String>();
|
||||
|
||||
private static final Map<String, UnionPayApiConfig> CFG_MAP = new ConcurrentHashMap<String, UnionPayApiConfig>();
|
||||
private static final String DEFAULT_CFG_KEY = "_default_key_";
|
||||
|
||||
/**
|
||||
* 添加云闪付配置,每个 mchId 只需添加一次,相同 mchId 将被覆盖
|
||||
*
|
||||
* @param UnionPayApiConfig 云闪付配置
|
||||
* @return {@link UnionPayApiConfig} 云闪付配置
|
||||
*/
|
||||
public static UnionPayApiConfig putApiConfig(UnionPayApiConfig UnionPayApiConfig) {
|
||||
if (CFG_MAP.size() == 0) {
|
||||
CFG_MAP.put(DEFAULT_CFG_KEY, UnionPayApiConfig);
|
||||
}
|
||||
return CFG_MAP.put(UnionPayApiConfig.getMchId(), UnionPayApiConfig);
|
||||
}
|
||||
|
||||
public static UnionPayApiConfig setThreadLocalApiConfig(UnionPayApiConfig UnionPayApiConfig) {
|
||||
if (StrUtil.isNotEmpty(UnionPayApiConfig.getMchId())) {
|
||||
setThreadLocalMchId(UnionPayApiConfig.getMchId());
|
||||
}
|
||||
return putApiConfig(UnionPayApiConfig);
|
||||
}
|
||||
|
||||
public static UnionPayApiConfig removeApiConfig(UnionPayApiConfig UnionPayApiConfig) {
|
||||
return removeApiConfig(UnionPayApiConfig.getMchId());
|
||||
}
|
||||
|
||||
public static UnionPayApiConfig removeApiConfig(String mchId) {
|
||||
return CFG_MAP.remove(mchId);
|
||||
}
|
||||
|
||||
public static void setThreadLocalMchId(String mchId) {
|
||||
if (StrUtil.isEmpty(mchId)) {
|
||||
mchId = CFG_MAP.get(DEFAULT_CFG_KEY).getMchId();
|
||||
}
|
||||
TL.set(mchId);
|
||||
}
|
||||
|
||||
public static void removeThreadLocalMchId() {
|
||||
TL.remove();
|
||||
}
|
||||
|
||||
public static String getMchId() {
|
||||
String appId = TL.get();
|
||||
if (StrUtil.isEmpty(appId)) {
|
||||
appId = CFG_MAP.get(DEFAULT_CFG_KEY).getMchId();
|
||||
}
|
||||
return appId;
|
||||
}
|
||||
|
||||
public static UnionPayApiConfig getApiConfig() {
|
||||
String appId = getMchId();
|
||||
return getApiConfig(appId);
|
||||
}
|
||||
|
||||
public static UnionPayApiConfig getApiConfig(String appId) {
|
||||
UnionPayApiConfig cfg = CFG_MAP.get(appId);
|
||||
if (cfg == null) {
|
||||
throw new IllegalStateException("需事先调用 UnionPayApiConfigKit.putApiConfig(UnionPayApiConfig) 将 mchId 对应的 UnionPayApiConfig 对象存入,才可以使用 UnionPayApiConfigKit.getUnionPayApiConfig() 的系列方法");
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
}
|
@ -0,0 +1,247 @@
|
||||
package cn.lili.modules.payment.kit.plugin.unionpay;
|
||||
|
||||
import cn.hutool.core.net.URLEncoder;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.lili.common.enums.ResultCode;
|
||||
import cn.lili.common.exception.ServiceException;
|
||||
import cn.lili.common.utils.SnowFlake;
|
||||
import cn.lili.common.vo.ResultMessage;
|
||||
import cn.lili.modules.payment.kit.CashierSupport;
|
||||
import cn.lili.modules.payment.kit.Payment;
|
||||
import cn.lili.modules.payment.kit.core.enums.SignType;
|
||||
import cn.lili.modules.payment.kit.core.kit.HttpKit;
|
||||
import cn.lili.modules.payment.kit.core.kit.IpKit;
|
||||
import cn.lili.modules.payment.kit.core.kit.WxPayKit;
|
||||
import cn.lili.modules.payment.kit.dto.PayParam;
|
||||
import cn.lili.modules.payment.kit.params.dto.CashierParam;
|
||||
import cn.lili.modules.payment.kit.plugin.unionpay.enums.ServiceEnum;
|
||||
import cn.lili.modules.payment.kit.plugin.unionpay.model.UnifiedOrderModel;
|
||||
import cn.lili.modules.payment.service.PaymentService;
|
||||
import cn.lili.modules.system.entity.dos.Setting;
|
||||
import cn.lili.modules.system.entity.dto.payment.UnionPaymentSetting;
|
||||
import cn.lili.modules.system.entity.enums.SettingEnum;
|
||||
import cn.lili.modules.system.service.SettingService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 银联云闪付 支付
|
||||
*
|
||||
* @author Bulbasaur
|
||||
* @since 2023/02/14 17:44
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class UnionPayPlugin implements Payment {
|
||||
|
||||
|
||||
/**
|
||||
* 收银台
|
||||
*/
|
||||
@Autowired
|
||||
private CashierSupport cashierSupport;
|
||||
/**
|
||||
* 支付日志
|
||||
*/
|
||||
@Autowired
|
||||
private PaymentService paymentService;
|
||||
/**
|
||||
* 配置
|
||||
*/
|
||||
@Autowired
|
||||
private SettingService settingService;
|
||||
|
||||
@Override
|
||||
public ResultMessage<Object> nativePay(HttpServletRequest request, PayParam payParam) {
|
||||
try {
|
||||
CashierParam cashierParam = cashierSupport.cashierParam(payParam);
|
||||
UnionPaymentSetting unionPaymentSetting = this.unionPaymentSetting();
|
||||
String notifyUrl = unionPaymentSetting.getUnionPayDomain().concat("/unionPay/payNotify");
|
||||
//用户ip
|
||||
String ip = IpKit.getRealIp(request);
|
||||
//第三方付款订单
|
||||
String outOrderNo = SnowFlake.getIdStr();
|
||||
String attach = URLEncoder.createDefault().encode(JSONUtil.toJsonStr(payParam), StandardCharsets.UTF_8);
|
||||
Map<String, String> params = UnifiedOrderModel.builder()
|
||||
.service(ServiceEnum.NATIVE.toString())
|
||||
.mch_id(unionPaymentSetting.getUnionPayMachId())
|
||||
.out_trade_no(outOrderNo)
|
||||
.body(cashierParam.getDetail())
|
||||
.attach(attach)
|
||||
.total_fee("0")
|
||||
.mch_create_ip(ip)
|
||||
.notify_url(notifyUrl)
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.build().createSign(unionPaymentSetting.getUnionPayKey(), SignType.MD5);
|
||||
|
||||
String xmlResult = UnionPayApi.execution(unionPaymentSetting.getUnionPayServerUrl(), params);
|
||||
log.info("xmlResult:" + xmlResult);
|
||||
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
|
||||
log.info(result.toString());
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultMessage<Object> appPay(HttpServletRequest request, PayParam payParam) {
|
||||
try {
|
||||
|
||||
CashierParam cashierParam = cashierSupport.cashierParam(payParam);
|
||||
UnionPaymentSetting unionPaymentSetting = this.unionPaymentSetting();
|
||||
String notifyUrl = unionPaymentSetting.getUnionPayDomain().concat("/unionPay/payNotify");
|
||||
String attach = URLEncoder.createDefault().encode(JSONUtil.toJsonStr(payParam), StandardCharsets.UTF_8);
|
||||
|
||||
//用户ip
|
||||
String ip = IpKit.getRealIp(request);
|
||||
Map<String, String> params = UnifiedOrderModel.builder()
|
||||
.service(ServiceEnum.WEI_XIN_APP_PAY.toString())
|
||||
.mch_id(unionPaymentSetting.getUnionPayMachId())
|
||||
.appid(unionPaymentSetting.getUnionPayAppId())
|
||||
.out_trade_no(WxPayKit.generateStr())
|
||||
.body(cashierParam.getDetail())
|
||||
.attach(attach)
|
||||
.total_fee("0")
|
||||
.mch_create_ip(ip)
|
||||
.notify_url(notifyUrl)
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.build()
|
||||
.createSign(unionPaymentSetting.getUnionPayKey(), SignType.MD5);
|
||||
|
||||
System.out.println(params);
|
||||
|
||||
String xmlResult = UnionPayApi.execution(unionPaymentSetting.getUnionPayServerUrl(), params);
|
||||
log.info("xmlResult:" + xmlResult);
|
||||
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
|
||||
if (!WxPayKit.verifyNotify(result, unionPaymentSetting.getUnionPayKey(), SignType.MD5)) {
|
||||
log.error("签名异常");
|
||||
}
|
||||
String status = result.get("status");
|
||||
String resultCode = result.get("result_code");
|
||||
if (!"0".equals(status) && !"0".equals(resultCode)) {
|
||||
log.error(result.get("err_msg"));
|
||||
return null;
|
||||
}
|
||||
log.error(result.get("pay_info"));
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultMessage<Object> jsApiPay(HttpServletRequest request, PayParam payParam) {
|
||||
String buyerLogonId="";
|
||||
String buyerId="";
|
||||
CashierParam cashierParam = cashierSupport.cashierParam(payParam);
|
||||
UnionPaymentSetting unionPaymentSetting = this.unionPaymentSetting();
|
||||
String attach = URLEncoder.createDefault().encode(JSONUtil.toJsonStr(payParam), StandardCharsets.UTF_8);
|
||||
//用户ip
|
||||
String ip = IpKit.getRealIp(request);
|
||||
try {
|
||||
if (StrUtil.isEmpty(buyerLogonId) && StrUtil.isEmpty(buyerId)) {
|
||||
log.error("buyer_logon_id buyer_id 不能同时为空");
|
||||
return null;
|
||||
}
|
||||
|
||||
String notifyUrl = unionPaymentSetting.getUnionPayDomain().concat("/unionPay/payNotify");
|
||||
|
||||
|
||||
Map<String, String> params = UnifiedOrderModel.builder()
|
||||
.service(ServiceEnum.ALI_PAY_JS_PAY.toString())
|
||||
.mch_id(unionPaymentSetting.getUnionPayMachId())
|
||||
.out_trade_no(WxPayKit.generateStr())
|
||||
.body(cashierParam.getDetail())
|
||||
.attach(attach)
|
||||
.total_fee("0")
|
||||
.mch_create_ip(ip)
|
||||
.notify_url(notifyUrl)
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.buyer_id(buyerId)
|
||||
.buyer_logon_id(buyerLogonId)
|
||||
.build()
|
||||
.createSign(unionPaymentSetting.getUnionPayKey(), SignType.MD5);
|
||||
|
||||
System.out.println(params);
|
||||
|
||||
String xmlResult = UnionPayApi.execution(unionPaymentSetting.getUnionPayServerUrl(), params);
|
||||
log.info("xmlResult:" + xmlResult);
|
||||
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
|
||||
log.info(result.toString());
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void callBack(HttpServletRequest request) {
|
||||
try {
|
||||
verifyNotify(request);
|
||||
} catch (Exception e) {
|
||||
log.error("支付异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(HttpServletRequest request) {
|
||||
try {
|
||||
verifyNotify(request);
|
||||
} catch (Exception e) {
|
||||
log.error("支付异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyNotify(HttpServletRequest request) throws Exception {
|
||||
String xmlMsg = HttpKit.readData(request);
|
||||
log.info("支付通知=" + xmlMsg);
|
||||
Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
|
||||
|
||||
String status = params.get("status");
|
||||
String returnCode = params.get("result_code");
|
||||
|
||||
log.info(status + " " + returnCode);
|
||||
|
||||
if ("0".equals(status) && "0".equals(returnCode)) {
|
||||
UnionPaymentSetting unionPaymentSetting = this.unionPaymentSetting();
|
||||
// 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态
|
||||
// 注意此处签名方式需与统一下单的签名类型一致
|
||||
if (WxPayKit.verifyNotify(params, unionPaymentSetting.getUnionPayKey(), SignType.MD5)) {
|
||||
log.info("支付成功....");
|
||||
// 更新订单信息
|
||||
// 发送通知等
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* 获取微信支付配置
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private UnionPaymentSetting unionPaymentSetting() {
|
||||
try {
|
||||
Setting systemSetting = settingService.get(SettingEnum.UNIONPAY_PAYMENT.name());
|
||||
UnionPaymentSetting unionPaymentSetting = JSONUtil.toBean(systemSetting.getSettingValue(), UnionPaymentSetting.class);
|
||||
return unionPaymentSetting;
|
||||
} catch (Exception e) {
|
||||
log.error("微信支付暂不支持", e);
|
||||
throw new ServiceException(ResultCode.PAY_NOT_SUPPORT);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package cn.lili.modules.payment.kit.plugin.unionpay.enums;
|
||||
|
||||
/**
|
||||
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
*
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
*
|
||||
* <p>IJPay 交流群: 723992875</p>
|
||||
*
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
|
||||
*
|
||||
* <p>云闪付接口类型枚举</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public enum ServiceEnum {
|
||||
/**
|
||||
* 刷卡支付
|
||||
*/
|
||||
MICRO_PAY("unified.trade.micropay"),
|
||||
/**
|
||||
* 扫码支付
|
||||
*/
|
||||
NATIVE("unified.trade.native"),
|
||||
/**
|
||||
* 微信公众号、小程序支付统一下单
|
||||
*/
|
||||
WEI_XIN_JS_PAY("pay.weixin.jspay"),
|
||||
/**
|
||||
* 微信 App 支付
|
||||
*/
|
||||
WEI_XIN_APP_PAY("pay.weixin.raw.app"),
|
||||
/**
|
||||
* 查询订单
|
||||
*/
|
||||
QUERY("unified.trade.query"),
|
||||
/**
|
||||
* 申请退款
|
||||
*/
|
||||
REFUND("unified.trade.refund"),
|
||||
/**
|
||||
* 退款查询
|
||||
*/
|
||||
REFUND_QUERY("unified.trade.refundquery"),
|
||||
/**
|
||||
* 关闭订单
|
||||
*/
|
||||
CLOSE("unified.trade.close"),
|
||||
/**
|
||||
* 撤销订单
|
||||
*/
|
||||
MICRO_PAY_REVERSE("unified.micropay.reverse"),
|
||||
/**
|
||||
* 授权码查询 openid
|
||||
*/
|
||||
AUTH_CODE_TO_OPENID("unified.tools.authcodetoopenid"),
|
||||
/**
|
||||
* 银联 JS 支付获取 userId
|
||||
*/
|
||||
UNION_PAY_USER_ID("pay.unionpay.userid"),
|
||||
/**
|
||||
* 银联 JS 支付下单
|
||||
*/
|
||||
UNION_JS_PAY("pay.unionpay.jspay"),
|
||||
/**
|
||||
* 支付宝服务窗口支付
|
||||
*/
|
||||
ALI_PAY_JS_PAY("pay.alipay.jspay"),
|
||||
/**
|
||||
* 下载单个商户时的对账单
|
||||
*/
|
||||
BILL_MERCHANT("pay.bill.merchant"),
|
||||
/**
|
||||
* 下载连锁商户下所有门店的对账单
|
||||
*/
|
||||
BILL_BIG_MERCHANT("pay.bill.bigMerchant"),
|
||||
/**
|
||||
* 下载某内部机构/外包服务机构下所有商户的对账单
|
||||
*/
|
||||
BILL_AGENT("pay.bill.agent");
|
||||
|
||||
/**
|
||||
* 接口类型
|
||||
*/
|
||||
private final String service;
|
||||
|
||||
ServiceEnum(String domain) {
|
||||
this.service = domain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return service;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
*
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
*
|
||||
* <p>IJPay 交流群: 723992875</p>
|
||||
*
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
|
||||
*
|
||||
* <p>云闪付-商户进件</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package cn.lili.modules.payment.kit.plugin.unionpay.model;
|
||||
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class ApplyModel extends BaseModel{
|
||||
/**
|
||||
* 合作伙伴 ID 即机构号
|
||||
*/
|
||||
private String partner;
|
||||
/**
|
||||
* 服务名称
|
||||
*/
|
||||
private String serviceName;
|
||||
/**
|
||||
* 支持 MD5 和RSA,默认为MD5
|
||||
*/
|
||||
private String signType;
|
||||
/**
|
||||
* 字符集,默认为UTF-8
|
||||
*/
|
||||
private String charset;
|
||||
/**
|
||||
* 请求数据
|
||||
*/
|
||||
private String data;
|
||||
/**
|
||||
* 数据类型
|
||||
*/
|
||||
private String dataType;
|
||||
/**
|
||||
* 数据签名
|
||||
*/
|
||||
private String dataSign;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
*
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
*
|
||||
* <p>IJPay 交流群: 723992875</p>
|
||||
*
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
|
||||
*
|
||||
* <p>云闪付-授权码查询 openId</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package cn.lili.modules.payment.kit.plugin.unionpay.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class AuthCodeToOpenIdModel extends BaseModel{
|
||||
private String service;
|
||||
private String version;
|
||||
private String charset;
|
||||
private String sign_type;
|
||||
private String mch_id;
|
||||
private String sub_appid;
|
||||
private String auth_code;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_agentno;
|
||||
private String groupno;
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/**
|
||||
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
*
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
*
|
||||
* <p>IJPay 交流群: 723992875</p>
|
||||
*
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
|
||||
*
|
||||
* <p>Model 公用方法</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package cn.lili.modules.payment.kit.plugin.unionpay.model;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.lili.modules.payment.kit.core.enums.SignType;
|
||||
import cn.lili.modules.payment.kit.core.kit.WxPayKit;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class BaseModel {
|
||||
|
||||
/**
|
||||
* 将建构的 builder 转为 Map
|
||||
*
|
||||
* @return 转化后的 Map
|
||||
*/
|
||||
public Map<String, String> toMap() {
|
||||
String[] fieldNames = getFiledNames(this);
|
||||
HashMap<String, String> map = new HashMap<String, String>(fieldNames.length);
|
||||
for (String name : fieldNames) {
|
||||
String value = (String) getFieldValueByName(name, this);
|
||||
if (StrUtil.isNotEmpty(value)) {
|
||||
map.put(name, value);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建签名 Map
|
||||
*
|
||||
* @param partnerKey API KEY
|
||||
* @param signType {@link SignType} 签名类型
|
||||
* @return 构建签名后的 Map
|
||||
*/
|
||||
public Map<String, String> createSign(String partnerKey, SignType signType) {
|
||||
return createSign(partnerKey, signType, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建签名 Map
|
||||
*
|
||||
* @param partnerKey API KEY
|
||||
* @param signType {@link SignType} 签名类型
|
||||
* @param haveSignType 签名是否包含 sign_type 字段
|
||||
* @return 构建签名后的 Map
|
||||
*/
|
||||
public Map<String, String> createSign(String partnerKey, SignType signType, boolean haveSignType) {
|
||||
return WxPayKit.buildSign(toMap(), partnerKey, signType, haveSignType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取属性名数组
|
||||
*
|
||||
* @param obj 对象
|
||||
* @return 返回对象属性名数组
|
||||
*/
|
||||
public String[] getFiledNames(Object obj) {
|
||||
Field[] fields = obj.getClass().getDeclaredFields();
|
||||
String[] fieldNames = new String[fields.length];
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
fieldNames[i] = fields[i].getName();
|
||||
}
|
||||
return fieldNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据属性名获取属性值
|
||||
*
|
||||
* @param fieldName 属性名称
|
||||
* @param obj 对象
|
||||
* @return 返回对应属性的值
|
||||
*/
|
||||
public Object getFieldValueByName(String fieldName, Object obj) {
|
||||
try {
|
||||
String firstLetter = fieldName.substring(0, 1).toUpperCase();
|
||||
String getter = new StringBuffer().append("get")
|
||||
.append(firstLetter)
|
||||
.append(fieldName.substring(1))
|
||||
.toString();
|
||||
Method method = obj.getClass().getMethod(getter);
|
||||
return method.invoke(obj);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
*
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
*
|
||||
* <p>IJPay 交流群: 723992875</p>
|
||||
*
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
|
||||
*
|
||||
* <p>云闪付-下单对账单</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package cn.lili.modules.payment.kit.plugin.unionpay.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class BillDownloadModel extends BaseModel{
|
||||
private String service;
|
||||
private String version;
|
||||
private String charset;
|
||||
private String bill_date;
|
||||
private String bill_type;
|
||||
private String sign_type;
|
||||
private String mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
*
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
*
|
||||
* <p>IJPay 交流群: 723992875</p>
|
||||
*
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
|
||||
*
|
||||
* <p>云闪付-关闭订单</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package cn.lili.modules.payment.kit.plugin.unionpay.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class CloseOrderModel extends BaseModel{
|
||||
private String service;
|
||||
private String version;
|
||||
private String charset;
|
||||
private String sign_type;
|
||||
private String mch_id;
|
||||
private String out_trade_no;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_agentno;
|
||||
private String groupno;
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
*
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
*
|
||||
* <p>IJPay 交流群: 723992875</p>
|
||||
*
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
|
||||
*
|
||||
* <p>云闪付-付款码支付</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package cn.lili.modules.payment.kit.plugin.unionpay.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class MicroPayModel extends BaseModel {
|
||||
private String service;
|
||||
private String version;
|
||||
private String charset;
|
||||
private String sign_type;
|
||||
private String mch_id;
|
||||
private String out_trade_no;
|
||||
private String device_info;
|
||||
private String body;
|
||||
private String goods_detail;
|
||||
private String sub_appid;
|
||||
private String attach;
|
||||
private String need_receipt;
|
||||
private String total_fee;
|
||||
private String mch_create_ip;
|
||||
private String auth_code;
|
||||
private String time_start;
|
||||
private String time_expire;
|
||||
private String op_user_id;
|
||||
private String op_shop_id;
|
||||
private String op_device_id;
|
||||
private String goods_tag;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_agentno;
|
||||
private String groupno;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
*
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
*
|
||||
* <p>IJPay 交流群: 723992875</p>
|
||||
*
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
|
||||
*
|
||||
* <p>云闪付-订单查询</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package cn.lili.modules.payment.kit.plugin.unionpay.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class OrderQueryModel extends BaseModel {
|
||||
private String service;
|
||||
private String version;
|
||||
private String charset;
|
||||
private String sign_type;
|
||||
private String mch_id;
|
||||
private String out_trade_no;
|
||||
private String transaction_id;
|
||||
private String sign_agentno;
|
||||
private String groupno;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
*
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
*
|
||||
* <p>IJPay 交流群: 723992875</p>
|
||||
*
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
|
||||
*
|
||||
* <p>云闪付-退款</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package cn.lili.modules.payment.kit.plugin.unionpay.model;
|
||||
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class RefundModel extends BaseModel{
|
||||
private String service;
|
||||
private String version;
|
||||
private String charset;
|
||||
private String sign_type;
|
||||
private String mch_id;
|
||||
private String out_trade_no;
|
||||
private String transaction_id;
|
||||
private String out_refund_no;
|
||||
private String total_fee;
|
||||
private String refund_fee;
|
||||
private String op_user_id;
|
||||
private String refund_channel;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_agentno;
|
||||
private String groupno;
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
*
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
*
|
||||
* <p>IJPay 交流群: 723992875</p>
|
||||
*
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
|
||||
*
|
||||
* <p>云闪付-查询退款</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package cn.lili.modules.payment.kit.plugin.unionpay.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class RefundQueryModel extends BaseModel{
|
||||
private String service;
|
||||
private String version;
|
||||
private String charset;
|
||||
private String sign_type;
|
||||
private String mch_id;
|
||||
private String out_trade_no;
|
||||
private String transaction_id;
|
||||
private String out_refund_no;
|
||||
private String refund_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_agentno;
|
||||
private String groupno;
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
*
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
*
|
||||
* <p>IJPay 交流群: 723992875</p>
|
||||
*
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
|
||||
*
|
||||
* <p>云闪付-撤销订单</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package cn.lili.modules.payment.kit.plugin.unionpay.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class ReverseModel extends BaseModel{
|
||||
private String service;
|
||||
private String version;
|
||||
private String charset;
|
||||
private String sign_type;
|
||||
private String mch_id;
|
||||
private String out_trade_no;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_agentno;
|
||||
private String groupno;
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
*
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
*
|
||||
* <p>IJPay 交流群: 723992875</p>
|
||||
*
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
|
||||
*
|
||||
* <p>云闪付-统一下单</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package cn.lili.modules.payment.kit.plugin.unionpay.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class UnifiedOrderModel extends BaseModel {
|
||||
private String service;
|
||||
private String version;
|
||||
private String charset;
|
||||
private String sign_type;
|
||||
private String mch_id;
|
||||
private String appid;
|
||||
private String is_raw;
|
||||
private String is_minipg;
|
||||
private String out_trade_no;
|
||||
private String device_info;
|
||||
private String op_shop_id;
|
||||
private String body;
|
||||
private String sub_openid;
|
||||
private String user_id;
|
||||
private String attach;
|
||||
private String sub_appid;
|
||||
private String total_fee;
|
||||
private String need_receipt;
|
||||
private String customer_ip;
|
||||
private String mch_create_ip;
|
||||
private String notify_url;
|
||||
private String time_start;
|
||||
private String time_expire;
|
||||
private String qr_code_timeout_express;
|
||||
private String op_user_id;
|
||||
private String goods_tag;
|
||||
private String product_id;
|
||||
private String nonce_str;
|
||||
private String buyer_logon_id;
|
||||
private String buyer_id;
|
||||
private String limit_credit_pay;
|
||||
private String sign;
|
||||
private String sign_agentno;
|
||||
private String groupno;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
*
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
*
|
||||
* <p>IJPay 交流群: 723992875</p>
|
||||
*
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
|
||||
*
|
||||
* <p>云闪付-银联 JS 支付获取 userId</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package cn.lili.modules.payment.kit.plugin.unionpay.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class UnionPayUserIdModel extends BaseModel{
|
||||
private String service;
|
||||
private String version;
|
||||
private String charset;
|
||||
private String sign_type;
|
||||
private String mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String user_auth_code;
|
||||
private String app_up_identifier;
|
||||
private String sign_agentno;
|
||||
private String groupno;
|
||||
}
|
@ -42,6 +42,7 @@ import cn.lili.modules.system.entity.dos.Setting;
|
||||
import cn.lili.modules.system.entity.dto.payment.WechatPaymentSetting;
|
||||
import cn.lili.modules.system.entity.enums.SettingEnum;
|
||||
import cn.lili.modules.system.service.SettingService;
|
||||
import cn.lili.modules.wallet.entity.dos.MemberWithdrawApply;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -52,6 +53,8 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@ -465,6 +468,63 @@ public class WechatPlugin implements Payment {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信提现
|
||||
* 文档地址:https://pay.weixin.qq.com/docs/merchant/apis/batch-transfer-to-balance/transfer-batch/initiate-batch-transfer.html
|
||||
*
|
||||
* @param memberWithdrawApply 会员提现申请
|
||||
*/
|
||||
@Override
|
||||
public void transfer(MemberWithdrawApply memberWithdrawApply) {
|
||||
|
||||
try {
|
||||
WechatPaymentSetting setting = wechatPaymentSetting();
|
||||
Connect connect = connectService.queryConnect(
|
||||
ConnectQueryDTO.builder().userId(UserContext.getCurrentUser().getId())
|
||||
.unionType(ConnectEnum.WECHAT_OPEN_ID.name()).build()
|
||||
);
|
||||
//根据自身情况设置AppId,此处我存放的是服务号的APPID,下方的openID需要对应此处的APPID配置
|
||||
TransferModel transferModel = new TransferModel()
|
||||
.setAppid(setting.getServiceAppId())
|
||||
.setOut_batch_no(SnowFlake.createStr("T"))
|
||||
.setBatch_name("用户提现")
|
||||
.setBatch_remark("用户提现")
|
||||
.setTotal_amount(CurrencyUtil.fen(memberWithdrawApply.getApplyMoney()))
|
||||
.setTotal_num(1)
|
||||
.setTransfer_scene_id("1000");
|
||||
List<TransferDetailInput> transferDetailListList = new ArrayList<>();
|
||||
{
|
||||
TransferDetailInput transferDetailInput = new TransferDetailInput();
|
||||
transferDetailInput.setOut_detail_no(SnowFlake.createStr("TD"));
|
||||
transferDetailInput.setTransfer_amount(CurrencyUtil.fen(memberWithdrawApply.getApplyMoney()));
|
||||
transferDetailInput.setTransfer_remark("用户提现");
|
||||
transferDetailInput.setOpenid(connect.getUnionId());
|
||||
// transferDetailInput.setUserName(
|
||||
// "757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45");
|
||||
// transferDetailInput.setUserIdCard(
|
||||
// "8609cb22e1774a50a930e414cc71eca06121bcd266335cda230d24a7886a8d9f");
|
||||
transferDetailListList.add(transferDetailInput);
|
||||
}
|
||||
transferModel.setTransfer_detail_list(transferDetailListList);
|
||||
|
||||
PaymentHttpResponse response = WechatApi.v3(
|
||||
RequestMethodEnums.POST,
|
||||
WechatDomain.CHINA.toString(),
|
||||
WechatApiEnum.TRANSFER_BATCHES.toString(),
|
||||
setting.getMchId(),
|
||||
setting.getSerialNumber(),
|
||||
null,
|
||||
setting.getApiclient_key(),
|
||||
JSONUtil.toJsonStr(transferModel)
|
||||
);
|
||||
log.info("微信提现响应 {}", response);
|
||||
//根据自身业务进行接下来的任务处理
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证结果,执行支付回调
|
||||
*
|
||||
|
@ -555,6 +555,11 @@ public enum WechatApiEnum {
|
||||
* 连锁品牌-删除分账接收方
|
||||
*/
|
||||
BRAND_PROFIT_SHARING_RECEIVERS_delete("/v3/brand/profitsharing/receivers/delete"),
|
||||
|
||||
/**
|
||||
* 发起商家转账
|
||||
*/
|
||||
TRANSFER_BATCHES("/v3/transfer/batches"),
|
||||
;
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,29 @@
|
||||
package cn.lili.modules.payment.kit.plugin.wechat.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 转账的明细
|
||||
*
|
||||
* @author Bulbasaur
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class TransferDetailInput {
|
||||
//商户系统内部区分转账批次单下不同转账明细单的唯一标识,要求此参数只能由数字、大小写字母组成
|
||||
private String out_detail_no;
|
||||
//转账金额单位为“分”
|
||||
private Integer transfer_amount;
|
||||
//单条转账备注(微信用户会收到该备注),UTF8编码,最多允许32个字符
|
||||
private String transfer_remark;
|
||||
//商户appid下,某用户的openid
|
||||
private String openid;
|
||||
|
||||
//收款方真实姓名。支持标准RSA算法和国密算法,公钥由微信侧提供
|
||||
//明细转账金额<0.3元时,不允许填写收款用户姓名
|
||||
//明细转账金额 >= 2,000元时,该笔明细必须填写收款用户姓名
|
||||
//同一批次转账明细中的姓名字段传入规则需保持一致,也即全部填写、或全部不填写
|
||||
//若商户传入收款用户姓名,微信支付会校验用户openID与姓名是否一致,并提供电子回单
|
||||
//private String user_name;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package cn.lili.modules.payment.kit.plugin.wechat.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 提现
|
||||
* @author Bulbasaur
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class TransferModel {
|
||||
//申请商户号的appid或商户号绑定的appid(企业号corpid即为此appid)
|
||||
private String appid;
|
||||
//商户系统内部的商家批次单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
|
||||
private String out_batch_no;
|
||||
//该笔批量转账的名称
|
||||
private String batch_name;
|
||||
//转账说明,UTF8编码,最多允许32个字符
|
||||
private String batch_remark;
|
||||
//转账金额单位为“分”。转账总金额必须与批次内所有明细转账金额之和保持一致,否则无法发起转账操作
|
||||
private Integer total_amount;
|
||||
//一个转账批次单最多发起一千笔转账。转账总笔数必须与批次内所有明细之和保持一致,否则无法发起转账操作
|
||||
private Integer total_num;
|
||||
//发起批量转账的明细列表,最多一千笔
|
||||
private List<TransferDetailInput> transfer_detail_list;
|
||||
//必填,指定该笔转账使用的转账场景ID
|
||||
private String transfer_scene_id;
|
||||
}
|
@ -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,22 @@ 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.sms.plugin.SmsPluginFactory;
|
||||
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 +37,7 @@ import java.util.Map;
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class SmsUtilAliImplService implements SmsUtil, AliSmsUtil {
|
||||
public class SmsUtilAliImplService implements SmsUtil {
|
||||
|
||||
@Autowired
|
||||
private Cache cache;
|
||||
@ -52,6 +45,8 @@ public class SmsUtilAliImplService implements SmsUtil, AliSmsUtil {
|
||||
private SettingService settingService;
|
||||
@Autowired
|
||||
private MemberService memberService;
|
||||
@Autowired
|
||||
private SmsPluginFactory smsPluginFactory;
|
||||
|
||||
@Autowired
|
||||
private SmsTemplateProperties smsTemplateProperties;
|
||||
@ -126,7 +121,7 @@ public class SmsUtilAliImplService implements SmsUtil, AliSmsUtil {
|
||||
} else {
|
||||
log.info("接收手机:{},验证码:{}", mobile, code);
|
||||
//发送短信
|
||||
this.sendSmsCode(smsSetting.getSignName(), mobile, params, templateCode);
|
||||
smsPluginFactory.smsPlugin().sendSmsCode(smsSetting.getSignName(), mobile, params, templateCode);
|
||||
}
|
||||
//缓存中写入要验证的信息
|
||||
cache.put(cacheKey(verificationEnums, mobile, uuid), code, 300L);
|
||||
@ -145,233 +140,11 @@ 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));
|
||||
smsPluginFactory.smsPlugin().sendBatchSms(signName, mobile, templateCode);
|
||||
}
|
||||
|
||||
// //发送短信
|
||||
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 短信操作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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成缓存key
|
||||
|
@ -1,16 +1,45 @@
|
||||
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 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);
|
||||
|
||||
/**
|
||||
* 短信批量发送
|
||||
*
|
||||
* @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,7 +41,7 @@ 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) {
|
||||
@ -54,7 +55,7 @@ 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) {
|
||||
@ -72,7 +73,7 @@ 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);
|
||||
@ -86,7 +87,7 @@ 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);
|
||||
|
@ -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,20 +19,22 @@ 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);
|
||||
@ -46,7 +48,7 @@ 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) {
|
||||
@ -63,7 +65,7 @@ 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());
|
||||
@ -77,7 +79,7 @@ public class SmsTemplateServiceImpl extends ServiceImpl<SmsTemplateMapper, SmsTe
|
||||
@Override
|
||||
public void modifySmsTemplate(SmsTemplate smsTemplate) {
|
||||
try {
|
||||
aliSmsUtil.modifySmsTemplate(smsTemplate);
|
||||
smsPluginFactory.smsPlugin().modifySmsTemplate(smsTemplate);
|
||||
smsTemplate.setTemplateStatus(0);
|
||||
this.updateById(smsTemplate);
|
||||
} catch (Exception e) {
|
||||
|
@ -1,33 +0,0 @@
|
||||
package cn.lili.modules.system.entity.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 快递设置
|
||||
*
|
||||
* @author Chopper
|
||||
* @since 2020-03-10 10:04 上午
|
||||
*/
|
||||
@Data
|
||||
public class KuaidiSetting implements Serializable {
|
||||
private static final long serialVersionUID = 3520379500723173689L;
|
||||
/**
|
||||
* 企业id
|
||||
*/
|
||||
private String ebusinessID;
|
||||
/**
|
||||
* 密钥
|
||||
*/
|
||||
private String appKey;
|
||||
/**
|
||||
* api地址
|
||||
*/
|
||||
private String reqURL;
|
||||
|
||||
/**
|
||||
* 电子面单api地址
|
||||
*/
|
||||
private String sheetReqURL;
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package cn.lili.modules.system.entity.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import cn.lili.modules.logistics.entity.enums.LogisticsEnum;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 快递设置
|
||||
*
|
||||
* @author Chopper
|
||||
* @since 2020-03-10 10:04 上午
|
||||
*/
|
||||
@Data
|
||||
public class LogisticsSetting implements Serializable {
|
||||
private static final long serialVersionUID = 3520379500723173689L;
|
||||
|
||||
/**
|
||||
* 快递查询类型
|
||||
* @see LogisticsEnum
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 企业id
|
||||
*/
|
||||
private String kdniaoEbusinessID;
|
||||
/**
|
||||
* 密钥
|
||||
*/
|
||||
private String kdniaoAppKey;
|
||||
|
||||
/**
|
||||
* 快递100 授权码,请申请企业版获取
|
||||
*/
|
||||
private String kuaidi100Customer;
|
||||
/**
|
||||
* 快递100 Key
|
||||
*/
|
||||
private String kuaidi100Key;
|
||||
|
||||
/**
|
||||
* 顺丰顾客编码
|
||||
*/
|
||||
String clientCode;
|
||||
|
||||
/**
|
||||
* 顺丰校验码
|
||||
*/
|
||||
String checkWord;
|
||||
|
||||
/**
|
||||
* 顺丰请求地址
|
||||
*/
|
||||
String callUrl;
|
||||
|
||||
/**
|
||||
* 顺丰打印模板
|
||||
*/
|
||||
String templateCode;
|
||||
|
||||
/**
|
||||
* 顺丰月结号
|
||||
*/
|
||||
String monthlyCardNo;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
package cn.lili.modules.system.entity.dto.payment;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
/**
|
||||
* 银联-云闪付支付设置
|
||||
*
|
||||
* @author Bulbasaur
|
||||
* @since 2023-02-17
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class UnionPaymentSetting {
|
||||
|
||||
/**
|
||||
* 商户号
|
||||
*/
|
||||
private String unionPayMachId;
|
||||
/**
|
||||
* 密钥
|
||||
*/
|
||||
private String unionPayKey;
|
||||
/**
|
||||
* 请求地址
|
||||
*/
|
||||
private String unionPayServerUrl;
|
||||
/**
|
||||
* 交易请求地址
|
||||
*/
|
||||
private String unionPayDomain;
|
||||
/**
|
||||
* 应用ID
|
||||
*/
|
||||
private String unionPayAppId;
|
||||
}
|
@ -17,8 +17,8 @@ public enum SettingEnum {
|
||||
EMAIL_SETTING,
|
||||
//商品设置
|
||||
GOODS_SETTING,
|
||||
//快递鸟设置
|
||||
KUAIDI_SETTING,
|
||||
//快递设置
|
||||
LOGISTICS_SETTING,
|
||||
//订单配置
|
||||
ORDER_SETTING,
|
||||
//阿里OSS配置
|
||||
@ -45,6 +45,8 @@ public enum SettingEnum {
|
||||
ALIPAY_PAYMENT,
|
||||
//微信支付设置
|
||||
WECHAT_PAYMENT,
|
||||
//银联支付设置
|
||||
UNIONPAY_PAYMENT,
|
||||
//热词设置
|
||||
HOT_WORDS
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
package cn.lili.modules.system.service;
|
||||
|
||||
import cn.lili.modules.order.order.entity.vo.OrderDetailVO;
|
||||
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.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 物流公司业务层
|
||||
@ -19,10 +22,36 @@ 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);
|
||||
|
||||
/**
|
||||
* 获取物流信息
|
||||
* @param logisticsId
|
||||
* @param logisticsNo
|
||||
* @param phone
|
||||
* @param from
|
||||
* @param to
|
||||
* @return
|
||||
*/
|
||||
Traces getLogisticMapTrack(String logisticsId, String logisticsNo, String phone, String from, String to);
|
||||
|
||||
/**
|
||||
* 打印电子面单
|
||||
* @param orderSn 订单编号
|
||||
* @param logisticsId 物流Id
|
||||
* @return
|
||||
*/
|
||||
Map labelOrder(String orderSn, String logisticsId);
|
||||
|
||||
/**
|
||||
* 顺丰平台下单
|
||||
* @param orderDetailVO 订单信息
|
||||
* @return 顺丰单号
|
||||
*/
|
||||
String sfCreateOrder(OrderDetailVO orderDetailVO);
|
||||
|
||||
/**
|
||||
* 获取已开启的物流公司列表
|
||||
@ -30,4 +59,10 @@ public interface LogisticsService extends IService<Logistics> {
|
||||
* @return 物流公司列表
|
||||
*/
|
||||
List<Logistics> getOpenLogistics();
|
||||
|
||||
/**
|
||||
* 获取物流设置
|
||||
* @return
|
||||
*/
|
||||
LogisticsSetting getLogisticsSetting();
|
||||
}
|
@ -1,32 +1,40 @@
|
||||
package cn.lili.modules.system.serviceimpl;
|
||||
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
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.common.utils.BeanUtil;
|
||||
import cn.lili.modules.logistics.LogisticsPluginFactory;
|
||||
import cn.lili.modules.logistics.entity.dto.LabelOrderDTO;
|
||||
import cn.lili.modules.logistics.entity.enums.LogisticsEnum;
|
||||
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.entity.vo.OrderDetailVO;
|
||||
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.dto.LogisticsSetting;
|
||||
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;
|
||||
|
||||
@ -39,13 +47,24 @@ import java.util.Map;
|
||||
@Slf4j
|
||||
@Service
|
||||
public class LogisticsServiceImpl extends ServiceImpl<LogisticsMapper, Logistics> implements LogisticsService {
|
||||
@Autowired
|
||||
private LogisticsPluginFactory logisticsPluginFactory;
|
||||
@Autowired
|
||||
private OrderService orderService;
|
||||
@Autowired
|
||||
private OrderItemService orderItemService;
|
||||
@Autowired
|
||||
private StoreLogisticsService storeLogisticsService;
|
||||
@Autowired
|
||||
private StoreDetailService storeDetailService;
|
||||
|
||||
@Autowired
|
||||
private SettingService settingService;
|
||||
|
||||
@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);
|
||||
|
||||
@ -53,6 +72,63 @@ public class LogisticsServiceImpl extends ServiceImpl<LogisticsMapper, Logistics
|
||||
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 Map labelOrder(String orderSn, String logisticsId) {
|
||||
//获取设置
|
||||
LogisticsSetting logisticsSetting = this.getLogisticsSetting();
|
||||
//获取订单及子订单
|
||||
Order order = OperationalJudgment.judgment(orderService.getBySn(orderSn));
|
||||
if ((LogisticsEnum.SHUNFENG.name().equals(logisticsSetting.getType()) && order.getDeliverStatus().equals(DeliverStatusEnum.DELIVERED.name()) && order.getOrderStatus().equals(OrderStatusEnum.DELIVERED.name()))
|
||||
|| (order.getDeliverStatus().equals(DeliverStatusEnum.UNDELIVERED.name()) && order.getOrderStatus().equals(OrderStatusEnum.UNDELIVERED.name()))) {
|
||||
//订单货物
|
||||
List<OrderItem> orderItems = orderItemService.getByOrderSn(orderSn);
|
||||
//获取对应物流
|
||||
Logistics logistics;
|
||||
|
||||
if(LogisticsEnum.SHUNFENG.name().equals(logisticsSetting.getType())){
|
||||
logistics = this.getOne(new LambdaQueryWrapper<Logistics>().eq(Logistics::getCode,"SF"));
|
||||
}else{
|
||||
logistics = this.getById(logisticsId);
|
||||
}
|
||||
// 店铺-物流公司设置
|
||||
LambdaQueryWrapper<StoreLogistics> lambdaQueryWrapper = Wrappers.lambdaQuery();
|
||||
lambdaQueryWrapper.eq(StoreLogistics::getLogisticsId, logistics.getId());
|
||||
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 String sfCreateOrder(OrderDetailVO orderDetailVO) {
|
||||
return logisticsPluginFactory.filePlugin().createOrder(orderDetailVO);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Logistics> getOpenLogistics() {
|
||||
LambdaQueryWrapper<Logistics> queryWrapper = new LambdaQueryWrapper<>();
|
||||
@ -60,218 +136,10 @@ 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();
|
||||
@Override
|
||||
public LogisticsSetting getLogisticsSetting() {
|
||||
Setting setting = settingService.get(SettingEnum.LOGISTICS_SETTING.name());
|
||||
return JSONUtil.toBean(setting.getSettingValue(), LogisticsSetting.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -40,18 +40,26 @@ public class ManagerTokenGenerate extends AbstractTokenGenerate<AdminUser> {
|
||||
|
||||
@Override
|
||||
public Token createToken(AdminUser adminUser, Boolean longTerm) {
|
||||
AuthUser authUser = new AuthUser(adminUser.getUsername(), adminUser.getId(), adminUser.getAvatar(), UserEnums.MANAGER, adminUser.getNickName(), adminUser.getIsSuper());
|
||||
AuthUser authUser = AuthUser.builder()
|
||||
.username(adminUser.getUsername())
|
||||
.id(adminUser.getId())
|
||||
.face(adminUser.getAvatar())
|
||||
.role(UserEnums.MANAGER)
|
||||
.nickName(adminUser.getNickName())
|
||||
.isSuper(adminUser.getIsSuper())
|
||||
.longTerm(longTerm)
|
||||
.build();
|
||||
|
||||
List<UserMenuVO> userMenuVOList = roleMenuService.findAllMenu(authUser.getId());
|
||||
//缓存权限列表
|
||||
cache.put(CachePrefix.PERMISSION_LIST.getPrefix(UserEnums.MANAGER) + authUser.getId(), this.permissionList(userMenuVOList));
|
||||
|
||||
return tokenUtil.createToken(adminUser.getUsername(), authUser, longTerm, UserEnums.MANAGER);
|
||||
return tokenUtil.createToken(authUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token refreshToken(String refreshToken) {
|
||||
return tokenUtil.refreshToken(refreshToken, UserEnums.MANAGER);
|
||||
return tokenUtil.refreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,4 +56,9 @@ public class MemberWithdrawApply extends BaseEntity {
|
||||
@ApiModelProperty(value = "sn")
|
||||
private String sn;
|
||||
|
||||
@ApiModelProperty(value = "真实姓名")
|
||||
private String realName;
|
||||
@ApiModelProperty(value = "第三方平台账号")
|
||||
private String connectNumber;
|
||||
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ import cn.lili.common.utils.SnowFlake;
|
||||
import cn.lili.common.utils.StringUtils;
|
||||
import cn.lili.modules.member.entity.dos.Member;
|
||||
import cn.lili.modules.member.service.MemberService;
|
||||
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
|
||||
import cn.lili.modules.payment.kit.CashierSupport;
|
||||
import cn.lili.modules.system.entity.dos.Setting;
|
||||
import cn.lili.modules.system.entity.dto.WithdrawalSetting;
|
||||
import cn.lili.modules.system.entity.enums.SettingEnum;
|
||||
@ -77,6 +79,8 @@ public class MemberWalletServiceImpl extends ServiceImpl<MemberWalletMapper, Mem
|
||||
*/
|
||||
@Autowired
|
||||
private MemberWithdrawApplyService memberWithdrawApplyService;
|
||||
@Autowired
|
||||
private CashierSupport cashierSupport;
|
||||
|
||||
@Override
|
||||
public MemberWalletVO getMemberWallet(String memberId) {
|
||||
@ -253,6 +257,11 @@ public class MemberWalletServiceImpl extends ServiceImpl<MemberWalletMapper, Mem
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean applyWithdrawal(Double price) {
|
||||
|
||||
if (price == null || price <= 0 || price > 1000000) {
|
||||
throw new ServiceException(ResultCode.WALLET_WITHDRAWAL_AMOUNT_ERROR);
|
||||
}
|
||||
|
||||
MemberWithdrawalMessage memberWithdrawalMessage = new MemberWithdrawalMessage();
|
||||
AuthUser authUser = UserContext.getCurrentUser();
|
||||
//构建审核参数
|
||||
@ -302,7 +311,8 @@ public class MemberWalletServiceImpl extends ServiceImpl<MemberWalletMapper, Mem
|
||||
memberWithdrawApply.setInspectTime(new Date());
|
||||
//保存或者修改零钱提现
|
||||
this.memberWithdrawApplyService.saveOrUpdate(memberWithdrawApply);
|
||||
//TODO 调用自动提现接口
|
||||
//TODO 做成配置项目
|
||||
cashierSupport.transfer(PaymentMethodEnum.WECHAT, memberWithdrawApply);
|
||||
boolean result = true;
|
||||
//如果微信提现失败 则抛出异常 回滚数据
|
||||
if (!result) {
|
||||
|
@ -42,6 +42,11 @@ public class RechargeServiceImpl extends ServiceImpl<RechargeMapper, Recharge> i
|
||||
|
||||
@Override
|
||||
public Recharge recharge(Double price) {
|
||||
|
||||
if (price == null || price <= 0 || price > 1000000) {
|
||||
throw new ServiceException(ResultCode.RECHARGE_PRICE_ERROR);
|
||||
}
|
||||
|
||||
//获取当前登录的会员
|
||||
AuthUser authUser = UserContext.getCurrentUser();
|
||||
//构建sn
|
||||
|
@ -7,7 +7,6 @@ import cn.lili.common.enums.ClientTypeEnum;
|
||||
import cn.lili.common.enums.ResultCode;
|
||||
import cn.lili.common.exception.ServiceException;
|
||||
import cn.lili.common.utils.DateUtil;
|
||||
import cn.lili.common.utils.HttpUtils;
|
||||
import cn.lili.common.utils.StringUtils;
|
||||
import cn.lili.modules.connect.entity.Connect;
|
||||
import cn.lili.modules.connect.entity.enums.ConnectEnum;
|
||||
@ -111,7 +110,7 @@ public class WechatMessageUtil {
|
||||
map.put("data", postParams);
|
||||
|
||||
log.info("参数内容:" + JSONUtil.toJsonStr(map));
|
||||
String content = HttpUtils.doPostWithJson(url, map);
|
||||
String content = HttpUtil.post(url, JSONUtil.toJsonStr(map));
|
||||
JSONObject json = new JSONObject(content);
|
||||
log.info("微信消息发送结果:" + content);
|
||||
String errorMessage = json.getStr("errmsg");
|
||||
|
Binary file not shown.
@ -2,6 +2,7 @@ package cn.lili.controller.im;
|
||||
|
||||
import cn.lili.common.enums.ResultCode;
|
||||
import cn.lili.common.enums.ResultUtil;
|
||||
import cn.lili.common.exception.ServiceException;
|
||||
import cn.lili.common.vo.ResultMessage;
|
||||
import cn.lili.modules.im.entity.dos.ImMessage;
|
||||
import cn.lili.modules.im.entity.dto.MessageQueryParams;
|
||||
@ -32,39 +33,39 @@ public class ImMessageController {
|
||||
@ApiOperation(value = "查看Im消息详情")
|
||||
public ResultMessage<ImMessage> get(@PathVariable String id) {
|
||||
ImMessage imMessage = imMessageService.getById(id);
|
||||
return new ResultUtil<ImMessage>().setData(imMessage);
|
||||
return ResultUtil.data(imMessage);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@ApiOperation(value = "分页获取Im消息")
|
||||
public ResultMessage<List<ImMessage>> historyMessage(MessageQueryParams messageQueryParams) {
|
||||
List<ImMessage> data = imMessageService.getList(messageQueryParams);
|
||||
return new ResultUtil<List<ImMessage>>().setData(data);
|
||||
return ResultUtil.data(data);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@ApiOperation(value = "新增Im消息")
|
||||
public ResultMessage<ImMessage> save(ImMessage imMessage) {
|
||||
if (imMessageService.save(imMessage)) {
|
||||
return new ResultUtil<ImMessage>().setData(imMessage);
|
||||
return ResultUtil.data(imMessage);
|
||||
}
|
||||
return new ResultUtil<ImMessage>().setErrorMsg(ResultCode.ERROR);
|
||||
throw new ServiceException(ResultCode.IM_MESSAGE_ADD_ERROR);
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
@ApiOperation(value = "更新Im消息")
|
||||
public ResultMessage<ImMessage> update(@PathVariable String id, ImMessage imMessage) {
|
||||
if (imMessageService.updateById(imMessage)) {
|
||||
return new ResultUtil<ImMessage>().setData(imMessage);
|
||||
return ResultUtil.data(imMessage);
|
||||
}
|
||||
return new ResultUtil<ImMessage>().setErrorMsg(ResultCode.ERROR);
|
||||
throw new ServiceException(ResultCode.IM_MESSAGE_EDIT_ERROR);
|
||||
}
|
||||
|
||||
@DeleteMapping(value = "/{ids}")
|
||||
@ApiOperation(value = "删除Im消息")
|
||||
public ResultMessage<Object> delAllByIds(@PathVariable List ids) {
|
||||
imMessageService.removeByIds(ids);
|
||||
return ResultUtil.success(ResultCode.SUCCESS);
|
||||
return ResultUtil.success();
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,16 +2,11 @@ package cn.lili.controller.im;
|
||||
|
||||
import cn.lili.common.enums.ResultCode;
|
||||
import cn.lili.common.enums.ResultUtil;
|
||||
import cn.lili.common.security.AuthUser;
|
||||
import cn.lili.common.security.context.UserContext;
|
||||
import cn.lili.common.vo.ResultMessage;
|
||||
import cn.lili.modules.im.entity.dos.ImTalk;
|
||||
import cn.lili.modules.im.entity.vo.ImTalkVO;
|
||||
import cn.lili.modules.im.service.ImTalkService;
|
||||
import cn.lili.modules.store.service.StoreService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -19,7 +14,6 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
/**
|
||||
@ -34,43 +28,38 @@ public class ImTalkController {
|
||||
|
||||
private final ImTalkService imTalkService;
|
||||
|
||||
@Autowired
|
||||
private StoreService storeService;
|
||||
|
||||
@GetMapping(value = "/{id}")
|
||||
@ApiOperation(value = "查看聊天详情")
|
||||
public ResultMessage<ImTalk> get(@PathVariable String id) {
|
||||
|
||||
ImTalk imTalk = imTalkService.getById(id);
|
||||
return new ResultUtil<ImTalk>().setData(imTalk);
|
||||
return ResultUtil.data(imTalk);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/user/{uid}")
|
||||
@ApiOperation(value = "查看与某人聊天详情")
|
||||
public ResultMessage<ImTalk> getUser(@PathVariable String uid) {
|
||||
AuthUser authUser = UserContext.getCurrentUser();
|
||||
return ResultUtil.data(imTalkService.getTalkByUser(authUser.getId(), uid));
|
||||
//通过长度判断,保证每次都是同一个聊天
|
||||
return ResultUtil.data(imTalkService.getTalkByUser(uid));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/by/user/{userId}")
|
||||
@ApiOperation(value = "查看与某人聊天详情")
|
||||
public ResultMessage<ImTalkVO> getByUser(@PathVariable String userId) {
|
||||
AuthUser authUser = UserContext.getCurrentUser();
|
||||
return ResultUtil.data(new ImTalkVO(imTalkService.getTalkByUser(authUser.getId(), userId), authUser.getId()));
|
||||
return ResultUtil.data(new ImTalkVO(imTalkService.getTalkByUser(userId),userId));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/top")
|
||||
@ApiOperation(value = "查看与某人聊天详情")
|
||||
public ResultMessage top(String id, Boolean top) {
|
||||
public ResultMessage<Object> top(String id, Boolean top) {
|
||||
imTalkService.top(id, top);
|
||||
return ResultUtil.success();
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@ApiOperation(value = "分页获取聊天")
|
||||
@ApiImplicitParam(name = "userName", value = "用户名称", paramType = "query", dataType = "String")
|
||||
public ResultMessage<List<ImTalkVO>> getUserTalkList(String userName) {
|
||||
return ResultUtil.data(imTalkService.getUserTalkList(userName));
|
||||
@ApiOperation(value = "分页获取用户聊天")
|
||||
public ResultMessage<List<ImTalkVO>> getUserTalkList() {
|
||||
return ResultUtil.data(imTalkService.getUserTalkList());
|
||||
}
|
||||
|
||||
@GetMapping("/store/list")
|
||||
|
@ -1,80 +0,0 @@
|
||||
package cn.lili.controller.im;
|
||||
|
||||
|
||||
import cn.lili.common.enums.ResultUtil;
|
||||
import cn.lili.common.security.AuthUser;
|
||||
import cn.lili.common.security.context.UserContext;
|
||||
import cn.lili.common.vo.ResultMessage;
|
||||
import cn.lili.modules.member.entity.dos.Member;
|
||||
import cn.lili.modules.member.entity.dto.FootPrintQueryParams;
|
||||
import cn.lili.modules.member.service.FootprintService;
|
||||
import cn.lili.modules.member.service.MemberService;
|
||||
import cn.lili.modules.search.entity.dos.EsGoodsIndex;
|
||||
import cn.lili.modules.store.entity.dos.Store;
|
||||
import cn.lili.modules.store.service.StoreService;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
||||
/**
|
||||
* @author Chopper
|
||||
*/
|
||||
@RestController
|
||||
@Api(tags = "Im消息接口")
|
||||
@RequestMapping("/im/user")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||
public class ImUserController {
|
||||
|
||||
private final MemberService memberService;
|
||||
|
||||
@Autowired
|
||||
private StoreService storeService;
|
||||
|
||||
@Autowired
|
||||
private FootprintService footprintService;
|
||||
|
||||
@GetMapping
|
||||
@ApiOperation(value = "获取用户信息")
|
||||
public ResultMessage<Member> getImUser() {
|
||||
AuthUser authUser = UserContext.getCurrentUser();
|
||||
return ResultUtil.data(memberService.getById(authUser.getId()));
|
||||
}
|
||||
|
||||
@GetMapping("/store")
|
||||
@ApiOperation(value = "获取店铺信息")
|
||||
public ResultMessage<Store> getStoreUser() {
|
||||
AuthUser authUser = UserContext.getCurrentUser();
|
||||
return ResultUtil.data(storeService.getById(authUser.getStoreId()));
|
||||
}
|
||||
|
||||
@GetMapping("/{memberId}")
|
||||
@ApiImplicitParam(name = "memberId", value = "店铺Id", required = true, dataType = "String", paramType = "path")
|
||||
@ApiOperation(value = "获取用户信息")
|
||||
public ResultMessage<Member> getImUserDetail(@PathVariable String memberId) {
|
||||
return ResultUtil.data(memberService.getById(memberId));
|
||||
}
|
||||
|
||||
@GetMapping("/store/{storeId}")
|
||||
@ApiImplicitParam(name = "storeId", value = "店铺Id", required = true, dataType = "String", paramType = "path")
|
||||
@ApiOperation(value = "获取店铺信息")
|
||||
public ResultMessage<Store> getStoreUserDetail(@PathVariable String storeId) {
|
||||
return ResultUtil.data(storeService.getById(storeId));
|
||||
}
|
||||
|
||||
@GetMapping("/history")
|
||||
@ApiOperation(value = "获取会员的历史足迹")
|
||||
public ResultMessage<IPage<EsGoodsIndex>> getMemberHistory(FootPrintQueryParams params) {
|
||||
return ResultUtil.data(footprintService.footPrintPage(params));
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
@ -12,6 +13,7 @@ import cn.lili.modules.system.entity.dto.connect.QQConnectSetting;
|
||||
import cn.lili.modules.system.entity.dto.connect.WechatConnectSetting;
|
||||
import cn.lili.modules.system.entity.dto.payment.AlipayPaymentSetting;
|
||||
import cn.lili.modules.system.entity.dto.payment.PaymentSupportSetting;
|
||||
import cn.lili.modules.system.entity.dto.payment.UnionPaymentSetting;
|
||||
import cn.lili.modules.system.entity.dto.payment.WechatPaymentSetting;
|
||||
import cn.lili.modules.system.entity.dto.payment.dto.PaymentSupportForm;
|
||||
import cn.lili.modules.system.entity.enums.SettingEnum;
|
||||
@ -36,6 +38,11 @@ import java.util.Collections;
|
||||
public class SettingManagerController {
|
||||
@Autowired
|
||||
private SettingService settingService;
|
||||
/**
|
||||
* 缓存
|
||||
*/
|
||||
@Autowired
|
||||
private Cache<String> cache;
|
||||
|
||||
|
||||
@DemoSite
|
||||
@ -79,7 +86,6 @@ public class SettingManagerController {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 对配置进行过滤
|
||||
*
|
||||
@ -111,6 +117,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 +140,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()) :
|
||||
@ -165,6 +172,10 @@ public class SettingManagerController {
|
||||
return setting == null ?
|
||||
ResultUtil.data(new AlipayPaymentSetting()) :
|
||||
ResultUtil.data(JSONUtil.toBean(setting.getSettingValue(), AlipayPaymentSetting.class));
|
||||
case UNIONPAY_PAYMENT:
|
||||
return setting == null ?
|
||||
ResultUtil.data(new UnionPaymentSetting()) :
|
||||
ResultUtil.data(JSONUtil.toBean(setting.getSettingValue(), UnionPaymentSetting.class));
|
||||
case WECHAT_CONNECT:
|
||||
return setting == null ?
|
||||
ResultUtil.data(new WechatConnectSetting()) :
|
||||
|
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 = "查询订单列表")
|
||||
@ -120,6 +120,14 @@ public class OrderStoreController {
|
||||
return ResultUtil.data(orderService.delivery(orderSn, logisticsNo, logisticsId));
|
||||
}
|
||||
|
||||
@PreventDuplicateSubmissions
|
||||
@ApiOperation(value = "订单顺丰发货")
|
||||
@ApiImplicitParam(name = "orderSn", value = "订单sn", required = true, dataType = "String", paramType = "path")
|
||||
@PostMapping(value = "/{orderSn}/shunfeng/delivery")
|
||||
public ResultMessage<Object> shunFengDelivery(@NotNull(message = "参数非法") @PathVariable String orderSn) {
|
||||
return ResultUtil.data(orderService.shunFengDelivery(orderSn));
|
||||
}
|
||||
|
||||
@PreventDuplicateSubmissions
|
||||
@ApiOperation(value = "取消订单")
|
||||
@ApiImplicitParams({
|
||||
@ -200,7 +208,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) {
|
||||
return ResultUtil.data(logisticsService.labelOrder(orderSn, logisticsId));
|
||||
}
|
||||
}
|
@ -1,13 +1,21 @@
|
||||
package cn.lili.controller.other;
|
||||
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.lili.common.enums.ResultCode;
|
||||
import cn.lili.common.enums.ResultUtil;
|
||||
import cn.lili.common.exception.ServiceException;
|
||||
import cn.lili.common.security.context.UserContext;
|
||||
import cn.lili.common.vo.ResultMessage;
|
||||
import cn.lili.modules.member.service.StoreLogisticsService;
|
||||
import cn.lili.modules.store.entity.dos.StoreLogistics;
|
||||
import cn.lili.modules.store.entity.dto.StoreLogisticsCustomerDTO;
|
||||
import cn.lili.modules.system.entity.dos.Setting;
|
||||
import cn.lili.modules.system.entity.dto.ImSetting;
|
||||
import cn.lili.modules.system.entity.dto.LogisticsSetting;
|
||||
import cn.lili.modules.system.entity.enums.SettingEnum;
|
||||
import cn.lili.modules.system.entity.vo.StoreLogisticsVO;
|
||||
import cn.lili.modules.system.service.SettingService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
@ -36,6 +44,9 @@ public class LogisticsStoreController {
|
||||
@Autowired
|
||||
private StoreLogisticsService storeLogisticsService;
|
||||
|
||||
@Autowired
|
||||
private SettingService settingService;
|
||||
|
||||
@ApiOperation(value = "获取商家物流公司列表,如果已选择则checked有值")
|
||||
@GetMapping
|
||||
public ResultMessage<List<StoreLogisticsVO>> get() {
|
||||
@ -99,4 +110,18 @@ public class LogisticsStoreController {
|
||||
return ResultUtil.data(storeLogisticsService.getStoreLogisticsInfo(logisticsId));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取IM接口前缀")
|
||||
@GetMapping("/setting")
|
||||
public ResultMessage<String> getUrl() {
|
||||
String logisticsType;
|
||||
try {
|
||||
Setting logisticsSettingVal = settingService.get(SettingEnum.LOGISTICS_SETTING.name());
|
||||
LogisticsSetting logisticsSetting = JSONUtil.toBean(logisticsSettingVal.getSettingValue(), LogisticsSetting.class);
|
||||
logisticsType = logisticsSetting.getType();
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException(ResultCode.ORDER_LOGISTICS_ERROR);
|
||||
}
|
||||
return ResultUtil.data(logisticsType);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import cn.lili.common.security.enums.UserEnums;
|
||||
import cn.lili.common.vo.ResultMessage;
|
||||
import cn.lili.modules.member.entity.dos.Member;
|
||||
import cn.lili.modules.member.service.MemberService;
|
||||
import cn.lili.modules.sms.SmsUtil;
|
||||
import cn.lili.modules.verification.entity.enums.VerificationEnums;
|
||||
import cn.lili.modules.verification.service.VerificationService;
|
||||
import io.swagger.annotations.Api;
|
||||
@ -41,6 +42,9 @@ public class StorePassportController {
|
||||
@Autowired
|
||||
private MemberService memberService;
|
||||
|
||||
@Autowired
|
||||
private SmsUtil smsUtil;
|
||||
|
||||
@Autowired
|
||||
private VerificationService verificationService;
|
||||
|
||||
@ -59,6 +63,22 @@ public class StorePassportController {
|
||||
}
|
||||
}
|
||||
|
||||
@ApiOperation(value = "短信登录接口")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "mobile", value = "手机号", required = true, paramType = "query"),
|
||||
@ApiImplicitParam(name = "code", value = "验证码", required = true, paramType = "query")
|
||||
})
|
||||
@PostMapping("/smsLogin")
|
||||
public ResultMessage<Object> smsLogin(@NotNull(message = "手机号为空") @RequestParam String mobile,
|
||||
@NotNull(message = "验证码为空") @RequestParam String code,
|
||||
@RequestHeader String uuid) {
|
||||
if (smsUtil.verifyCode(mobile, VerificationEnums.LOGIN, uuid, code)) {
|
||||
return ResultUtil.data(memberService.mobilePhoneStoreLogin(mobile));
|
||||
} else {
|
||||
throw new ServiceException(ResultCode.VERIFICATION_SMS_CHECKED_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@ApiOperation(value = "注销接口")
|
||||
@PostMapping("/logout")
|
||||
public ResultMessage<Object> logout() {
|
||||
@ -66,6 +86,33 @@ public class StorePassportController {
|
||||
return ResultUtil.success();
|
||||
}
|
||||
|
||||
@ApiOperation(value = "通过短信重置密码")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "mobile", value = "手机号", required = true, paramType = "query"),
|
||||
@ApiImplicitParam(name = "password", value = "是否保存登录", required = true, paramType = "query")
|
||||
})
|
||||
@PostMapping("/resetByMobile")
|
||||
public ResultMessage<Member> resetByMobile(@NotNull(message = "手机号为空") @RequestParam String mobile,
|
||||
@NotNull(message = "验证码为空") @RequestParam String code,
|
||||
@RequestHeader String uuid) {
|
||||
//校验短信验证码是否正确
|
||||
if (smsUtil.verifyCode(mobile, VerificationEnums.FIND_USER, uuid, code)) {
|
||||
//校验是否通过手机号可获取会员,存在则将会员信息存入缓存,有效时间3分钟
|
||||
memberService.findByMobile(uuid, mobile);
|
||||
return ResultUtil.success();
|
||||
} else {
|
||||
throw new ServiceException(ResultCode.VERIFICATION_SMS_CHECKED_ERROR);
|
||||
}
|
||||
}
|
||||
@ApiOperation(value = "修改密码")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "password", value = "密码", required = true, paramType = "query")
|
||||
})
|
||||
@PostMapping("/resetPassword")
|
||||
public ResultMessage<Object> resetByMobile(@NotNull(message = "密码为空") @RequestParam String password, @RequestHeader String uuid) {
|
||||
return ResultUtil.data(memberService.resetByMobile(uuid, password));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "修改密码")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "password", value = "旧密码", required = true, paramType = "query"),
|
||||
@ -86,7 +133,4 @@ public class StorePassportController {
|
||||
public ResultMessage<Object> refreshToken(@NotNull(message = "刷新token不能为空") @PathVariable String refreshToken) {
|
||||
return ResultUtil.data(this.memberService.refreshStoreToken(refreshToken));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user