Merge pull request #80

pg
This commit is contained in:
misworga831 2023-03-09 16:45:27 +08:00 committed by GitHub
commit f7ba021799
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
100 changed files with 4345 additions and 1021 deletions

View File

@ -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;

View File

@ -165,3 +165,11 @@ PS手机验证码为 111111
##### 交流 qq 2群 875294241已满
##### 交流 qq 3群 263785057已满
##### 交流 qq 4群 674617534
### 附录
有人有自己的学习视频、学习记录文档、希望宣传关联开源项目等均可以私聊仓库所有者。
类似:
清晨敲代码同学的分析: https://blog.csdn.net/vaevaevae233/category_12103567.html

View File

@ -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 = "开票")

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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() + "的商品不存在,更新商品失败!");

View 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>

View 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

View 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
View 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

View File

@ -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>

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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))
//签名算法和密钥

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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.");

View File

@ -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() + "/";
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}

View File

@ -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();
}
}
}

View File

@ -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();

View File

@ -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();
/**
* 获取商家聊天列表

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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();
}
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -74,6 +74,14 @@ public interface MemberService extends IService<Member> {
*/
Token usernameStoreLogin(String username, String password);
/**
* 商家登录用户名密码登录
*
* @param mobilePhone 用户名
* @return token
*/
Token mobilePhoneStoreLogin(String mobilePhone);
/**
* 注册手机号验证码登录
*

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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*");
}
}

View File

@ -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

View File

@ -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);
/**
* 订单核验
*

View File

@ -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

View File

@ -16,6 +16,11 @@ public enum PaymentMethodEnum {
* 支付宝
*/
ALIPAY("aliPayPlugin", "支付宝"),
/**
* 银联-云闪付
*/
UNIONPAY("unionPayPlugin", "银联-云闪付"),
/**
* 余额支付
*/

View File

@ -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);
}
/**
* 获取收银台参数
*

View File

@ -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);
}
/**
* 支付回调地址
*

View File

@ -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);
}
}
/**
* 验证支付结果
*

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();
}
}
/**
* 验证结果执行支付回调
*

View File

@ -555,6 +555,11 @@ public enum WechatApiEnum {
* 连锁品牌-删除分账接收方
*/
BRAND_PROFIT_SHARING_RECEIVERS_delete("/v3/brand/profitsharing/receivers/delete"),
/**
* 发起商家转账
*/
TRANSFER_BATCHES("/v3/transfer/batches"),
;
/**

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
/**
* 短信批量发送

View File

@ -0,0 +1,15 @@
package cn.lili.modules.sms.entity.enums;
/**
* 短信通道枚举
*
* @author Bulbasaur
* @since 2023-02-16
*/
public enum SmsEnum {
/**
* 短信渠道
*/
ALI, HUAWEI, TENCENT;
}

View File

@ -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

View File

@ -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);
/**
* 申请短信签名
*

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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());
}
}

View File

@ -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() {
/* 必要步骤
* 实例化一个认证对象入参需要传入腾讯云账户密钥对secretIdsecretKey
* 这里采用的是从环境变量读取的方式需要在环境变量中先设置这两个值
* 你也可以直接在代码中写死密钥对但是小心不要将代码复制上传或者分享给他人
* 以免泄露密钥对危及你的财产安全
* SecretIdSecretKey 查询: 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");
}
}

View File

@ -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);

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)) {

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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);
}
/**

View File

@ -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;
}

View File

@ -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) {

View File

@ -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

View File

@ -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");

View File

@ -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();
}

View File

@ -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")

View File

@ -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));
}
}

View File

@ -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()) :

View File

@ -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>

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}