调整系统定时任务;添加分布式锁;修改配置文件
This commit is contained in:
parent
a94b58dfed
commit
358196d8cf
@ -4,7 +4,7 @@ cpop:
|
|||||||
profile: E:/Cpop/uploadPath
|
profile: E:/Cpop/uploadPath
|
||||||
jwt:
|
jwt:
|
||||||
#白名单
|
#白名单
|
||||||
whiteList: /login,/miniLogin,/getCaptcha,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources
|
whiteList: /login,/miniLogin,/wxPay/callback/notify/**,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources
|
||||||
gateway:
|
gateway:
|
||||||
rsa-keypair:
|
rsa-keypair:
|
||||||
# 公钥文件
|
# 公钥文件
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
# 项目相关配置
|
# 项目相关配置
|
||||||
cpop:
|
cpop:
|
||||||
# 文件路径 示例( Windows配置W:/WorkSpace/java/uploadPath,Linux配置 /home/baseFramework/uploadPath)
|
# 文件路径 示例( Windows配置W:/WorkSpace/java/uploadPath,Linux配置 /home/baseFramework/uploadPath)
|
||||||
#profile: /root/jambox-union/jambox-oam/uploadPath/upload
|
profile: /root/cpop-union/cpop-mall/upload
|
||||||
profile: E:/Cpop/uploadPath
|
|
||||||
jwt:
|
jwt:
|
||||||
#白名单
|
#白名单
|
||||||
whiteList: /login,/miniLogin,/wxPay/callback/notify/**,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources,/wxOpen/receiveTicket,/wxOpen/*/callback,/wxOpen/bindOpenAccount/*,/wxCp/portal/*
|
whiteList: /login,/miniLogin,/wxPay/callback/notify/**,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources,/wxOpen/receiveTicket,/wxOpen/*/callback,/wxOpen/bindOpenAccount/*,/wxCp/portal/*
|
||||||
@ -10,9 +9,9 @@ cpop:
|
|||||||
gateway:
|
gateway:
|
||||||
rsa-keypair:
|
rsa-keypair:
|
||||||
# 公钥文件
|
# 公钥文件
|
||||||
publicKeyFile: E:\Cpop\Cpop-Union\Cpop-Core\src\main\resources\static\keyPair\publicKey
|
publicKeyFile: /root/cpop-union/cpop-mall/script/secretKey/publicKey
|
||||||
# 公钥文件
|
# 公钥文件
|
||||||
privateKeyFile: E:\Cpop\Cpop-Union\Cpop-Core\src\main\resources\static\keyPair\privateKey
|
privateKeyFile: /root/cpop-union/cpop-mall/script/secretKey/privateKey
|
||||||
|
|
||||||
# DataSource Config
|
# DataSource Config
|
||||||
spring:
|
spring:
|
||||||
@ -80,11 +79,18 @@ knife4j:
|
|||||||
terms-of-service-url: https://api.jamboxsys.com
|
terms-of-service-url: https://api.jamboxsys.com
|
||||||
group:
|
group:
|
||||||
#商城
|
#商城
|
||||||
Mall:
|
Mall-Backstage:
|
||||||
group-name: Mall
|
#后台
|
||||||
|
group-name: Mall-Backstage
|
||||||
api-rule: package
|
api-rule: package
|
||||||
api-rule-resources:
|
api-rule-resources:
|
||||||
- com.cpop.mall
|
- com.cpop.mall.business.controller.backstage
|
||||||
|
Mall-Mini:
|
||||||
|
#后台
|
||||||
|
group-name: Mall-Mini
|
||||||
|
api-rule: package
|
||||||
|
api-rule-resources:
|
||||||
|
- com.cpop.mall.business.controller.mini
|
||||||
#系统
|
#系统
|
||||||
System:
|
System:
|
||||||
group-name: System
|
group-name: System
|
||||||
@ -100,6 +106,6 @@ logging:
|
|||||||
wx:
|
wx:
|
||||||
pay:
|
pay:
|
||||||
#通知地址
|
#通知地址
|
||||||
notifyUrl: https://frp-oak.top:11899/Cpop-Mall/wxPay/callback/notify/order
|
notifyUrl: https://test.cpopsz.com/onlineShop/Cpop-Mall/wxPay/callback/notify/order
|
||||||
#支付成功
|
#支付成功
|
||||||
notifyRefund: https://frp-oak.top:11899/Cpop-Mall/wxPay/callback/notify/refund
|
notifyRefund: https://test.cpopsz.com/onlineShop/Cpop-Mall/wxPay/callback/notify/refund
|
||||||
@ -31,7 +31,7 @@ spring:
|
|||||||
max-file-size: 1024MB
|
max-file-size: 1024MB
|
||||||
max-request-size: 300MB
|
max-request-size: 300MB
|
||||||
profiles:
|
profiles:
|
||||||
active: prod,mall,system
|
active: test,mall,system
|
||||||
datasource:
|
datasource:
|
||||||
type: com.zaxxer.hikari.HikariDataSource
|
type: com.zaxxer.hikari.HikariDataSource
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
|
|||||||
@ -69,10 +69,17 @@ public class ProductBo implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* 商品图地址
|
* 商品图地址
|
||||||
*/
|
*/
|
||||||
//@NotBlank(message = "商品图地址不能为空")
|
@NotBlank(message = "商品图地址不能为空")
|
||||||
@ApiModelProperty(value = "商品图地址",required = true)
|
@ApiModelProperty(value = "商品图地址",required = true)
|
||||||
private String picUrl;
|
private String picUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品详情图地址
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "商品图地址不能为空")
|
||||||
|
@ApiModelProperty(value = "商品详情图地址",required = true)
|
||||||
|
private String picDetailUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 购买限制(0:会员限制;1:新客限定;2:用户限购)
|
* 购买限制(0:会员限制;1:新客限定;2:用户限购)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -37,6 +37,7 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static com.cpop.core.base.table.table.SysUserTableDef.SYS_USER;
|
import static com.cpop.core.base.table.table.SysUserTableDef.SYS_USER;
|
||||||
@ -124,68 +125,77 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
|||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public Object placeOrder(PlaceOrderBo bo) {
|
public Object placeOrder(PlaceOrderBo bo) {
|
||||||
//检查库存
|
RedisService redisService = SpringUtils.getBean(RedisService.class);
|
||||||
Map<String, Integer> recordNumIsEnough = recordNumIsEnough(bo.getPlaceOrderDetailList());
|
//获取当前下单用户信息
|
||||||
try {
|
JSONObject loginStaffInfo = SecurityUtils.getInstance().getLoginUserInfo();
|
||||||
Order order = BeanUtils.mapToClass(bo, Order.class);
|
//分布式锁进行幂等处理
|
||||||
List<OrderDetail> orderDetails = BeanUtils.mapToList(bo.getPlaceOrderDetailList(), OrderDetail.class);
|
Lock userIdLock = redisService.distributedLock(MallRedisConstant.IDEMPOTENT_LOCK_USER_PAY + loginStaffInfo.getString("userId"));
|
||||||
//规格记录ids
|
if (userIdLock.tryLock()) {
|
||||||
Set<String> recordIds = orderDetails.stream().map(OrderDetail::getProductRecordId).collect(Collectors.toSet());
|
//检查库存
|
||||||
//获取涉及到的商品
|
Map<String, Integer> recordNumIsEnough = recordNumIsEnough(bo.getPlaceOrderDetailList());
|
||||||
ProductService productService = SpringUtils.getBean(ProductService.class);
|
try {
|
||||||
List<Product> productList = productService.queryChain()
|
Order order = BeanUtils.mapToClass(bo, Order.class);
|
||||||
.select(PRODUCT.ID, PRODUCT.PRODUCT_NAME, PRODUCT.DESCRIPTION)
|
List<OrderDetail> orderDetails = BeanUtils.mapToList(bo.getPlaceOrderDetailList(), OrderDetail.class);
|
||||||
.from(PRODUCT)
|
//规格记录ids
|
||||||
.leftJoin(PRODUCT_RECORD).on(PRODUCT_RECORD.PRODUCT_ID.eq(PRODUCT.ID))
|
Set<String> recordIds = orderDetails.stream().map(OrderDetail::getProductRecordId).collect(Collectors.toSet());
|
||||||
.where(PRODUCT_RECORD.ID.in(recordIds))
|
//获取涉及到的商品
|
||||||
.list();
|
ProductService productService = SpringUtils.getBean(ProductService.class);
|
||||||
//获取当前下单用户信息
|
List<Product> productList = productService.queryChain()
|
||||||
JSONObject loginStaffInfo = SecurityUtils.getInstance().getLoginUserInfo();
|
.select(PRODUCT.ID, PRODUCT.PRODUCT_NAME, PRODUCT.DESCRIPTION)
|
||||||
//设置待付款
|
.from(PRODUCT)
|
||||||
order.setOrderStatus(0)
|
.leftJoin(PRODUCT_RECORD).on(PRODUCT_RECORD.PRODUCT_ID.eq(PRODUCT.ID))
|
||||||
.setPreviousStatus(0)
|
.where(PRODUCT_RECORD.ID.in(recordIds))
|
||||||
//获取当前用户所属品牌
|
.list();
|
||||||
.setBrandId(loginStaffInfo.getString("brandId"))
|
//设置待付款
|
||||||
.setProductNames(productList.stream().map(Product::getProductName).collect(Collectors.joining(",")))
|
order.setOrderStatus(0)
|
||||||
.setPayUserId(loginStaffInfo.getString("userId"));
|
.setPreviousStatus(0)
|
||||||
if (StringUtils.isBlank(bo.getPayUserName())) {
|
//获取当前用户所属品牌
|
||||||
order.setPayUserName(loginStaffInfo.getString("nickName"));
|
.setBrandId(loginStaffInfo.getString("brandId"))
|
||||||
|
.setProductNames(productList.stream().map(Product::getProductName).collect(Collectors.joining(",")))
|
||||||
|
.setPayUserId(loginStaffInfo.getString("userId"));
|
||||||
|
if (StringUtils.isBlank(bo.getPayUserName())) {
|
||||||
|
order.setPayUserName(loginStaffInfo.getString("nickName"));
|
||||||
|
}
|
||||||
|
this.save(order);
|
||||||
|
//保存订单详情
|
||||||
|
orderDetails.forEach(item -> {
|
||||||
|
item.setOrderId(order.getId());
|
||||||
|
});
|
||||||
|
SpringUtils.getBean(OrderDetailService.class).saveBatch(orderDetails);
|
||||||
|
//微信支付
|
||||||
|
if (bo.getPayType() == 0) {
|
||||||
|
WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
|
||||||
|
//需要分账
|
||||||
|
orderRequest.setProfitSharing("Y")
|
||||||
|
.setSpbillCreateIp(IpUtils.getHostIp())
|
||||||
|
.setSubOpenid(loginStaffInfo.getString("openId"))
|
||||||
|
//商品描述
|
||||||
|
.setBody(productList.stream().map(Product::getDescription).collect(Collectors.joining(",")))
|
||||||
|
//商品详情
|
||||||
|
.setDetail(JSONObject.toJSONString(BeanUtils.mapToList(bo.getPlaceOrderDetailList(), WxPayGoodsDetailDto.class)))
|
||||||
|
.setOutTradeNo(order.getId())
|
||||||
|
//元转分
|
||||||
|
.setTotalFee(bo.getTotalAmount().scaleByPowerOfTen(2).intValue())
|
||||||
|
.setTradeType("JSAPI");
|
||||||
|
//微信支付统一下单
|
||||||
|
WxPayService wxPayService = wxPayHandler.getWxPayService();
|
||||||
|
return wxPayService.createOrder(orderRequest);
|
||||||
|
} else {
|
||||||
|
return pointPay(recordNumIsEnough, order.getId());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
//回滚库存
|
||||||
|
recordNumIsEnough.forEach((key, value) -> {
|
||||||
|
redisService.longIncrement(MallRedisConstant.STOCK_RECORD_NUM + key, value.longValue());
|
||||||
|
});
|
||||||
|
throw new ServiceException(e.getMessage());
|
||||||
|
}finally {
|
||||||
|
//释放锁
|
||||||
|
userIdLock.unlock();
|
||||||
}
|
}
|
||||||
this.save(order);
|
}else {
|
||||||
//保存订单详情
|
//获取锁失败,直接返回空
|
||||||
orderDetails.forEach(item -> {
|
return null;
|
||||||
item.setOrderId(order.getId());
|
|
||||||
});
|
|
||||||
SpringUtils.getBean(OrderDetailService.class).saveBatch(orderDetails);
|
|
||||||
//微信支付
|
|
||||||
if (bo.getPayType() == 0) {
|
|
||||||
WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
|
|
||||||
//需要分账
|
|
||||||
orderRequest.setProfitSharing("Y")
|
|
||||||
.setSpbillCreateIp(IpUtils.getHostIp())
|
|
||||||
.setSubOpenid(loginStaffInfo.getString("openId"))
|
|
||||||
//商品描述
|
|
||||||
.setBody(productList.stream().map(Product::getDescription).collect(Collectors.joining(",")))
|
|
||||||
//商品详情
|
|
||||||
.setDetail(JSONObject.toJSONString(BeanUtils.mapToList(bo.getPlaceOrderDetailList(), WxPayGoodsDetailDto.class)))
|
|
||||||
.setOutTradeNo(order.getId())
|
|
||||||
//元转分
|
|
||||||
.setTotalFee(bo.getTotalAmount().scaleByPowerOfTen(2).intValue())
|
|
||||||
.setTradeType("JSAPI");
|
|
||||||
//微信支付统一下单
|
|
||||||
WxPayService wxPayService = wxPayHandler.getWxPayService();
|
|
||||||
return wxPayService.createOrder(orderRequest);
|
|
||||||
} else {
|
|
||||||
//TODO:积分支付直接扣库存
|
|
||||||
return pointPay(recordNumIsEnough, order.getId());
|
|
||||||
}
|
|
||||||
} catch (Exception e){
|
|
||||||
//回滚库存
|
|
||||||
RedisService redisService = SpringUtils.getBean(RedisService.class);
|
|
||||||
recordNumIsEnough.forEach((key, value) -> {
|
|
||||||
redisService.longIncrement(MallRedisConstant.STOCK_RECORD_NUM + key, value.longValue());
|
|
||||||
});
|
|
||||||
throw new ServiceException(e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,8 +215,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
|||||||
productRecordService.updateBatch(productRecords);
|
productRecordService.updateBatch(productRecords);
|
||||||
//TODO:通知到云?
|
//TODO:通知到云?
|
||||||
//修改订单状态
|
//修改订单状态
|
||||||
return this.updateChain()
|
return this.updateChain().set(ORDER.ORDER_STATUS, 3).where(ORDER.ID.eq(orderId)).update();
|
||||||
.set(ORDER.ORDER_STATUS, 3).where(ORDER.ID.eq(orderId)).update();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
package com.cpop.mall.business.service.impl;
|
package com.cpop.mall.business.service.impl;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.cpop.common.constant.Constants;
|
||||||
import com.cpop.common.utils.StringUtils;
|
import com.cpop.common.utils.StringUtils;
|
||||||
import com.cpop.common.utils.bean.BeanUtils;
|
import com.cpop.common.utils.bean.BeanUtils;
|
||||||
import com.cpop.core.base.entity.PageDomain;
|
import com.cpop.core.base.entity.PageDomain;
|
||||||
import com.cpop.core.base.enums.SourceType;
|
import com.cpop.core.base.enums.SourceType;
|
||||||
|
import com.cpop.core.base.enums.UserType;
|
||||||
import com.cpop.core.utils.SecurityUtils;
|
import com.cpop.core.utils.SecurityUtils;
|
||||||
import com.cpop.core.utils.SpringUtils;
|
import com.cpop.core.utils.SpringUtils;
|
||||||
import com.cpop.core.utils.sql.SqlUtils;
|
import com.cpop.core.utils.sql.SqlUtils;
|
||||||
import com.cpop.jambox.business.entity.BrandExtend;
|
import com.cpop.jambox.business.entity.BrandExtend;
|
||||||
import com.cpop.jambox.business.service.BrandExtendService;
|
import com.cpop.jambox.business.service.BrandExtendService;
|
||||||
|
import com.cpop.jambox.business.vo.CardTemplateListVo;
|
||||||
import com.cpop.mall.business.bo.ProductBo;
|
import com.cpop.mall.business.bo.ProductBo;
|
||||||
import com.cpop.mall.business.bo.ProductPageBo;
|
import com.cpop.mall.business.bo.ProductPageBo;
|
||||||
import com.cpop.mall.business.bo.ProductRecordBo;
|
import com.cpop.mall.business.bo.ProductRecordBo;
|
||||||
|
|||||||
@ -28,14 +28,14 @@ public class ProductRecordSyncStockTask {
|
|||||||
*/
|
*/
|
||||||
@Scheduled(cron="0 5 1 * * ?")
|
@Scheduled(cron="0 5 1 * * ?")
|
||||||
public void syncMysqlStockToRedis(){
|
public void syncMysqlStockToRedis(){
|
||||||
log.info("===============================开始<-库存信息同步->开始===============================");
|
log.info("===============================开始<--库存信息同步-->开始===============================");
|
||||||
//获取所有库存
|
//获取所有库存
|
||||||
List<ProductRecord> productRecords = SpringUtils.getBean(ProductRecordService.class).list();
|
List<ProductRecord> productRecords = SpringUtils.getBean(ProductRecordService.class).list();
|
||||||
RedisService redisService = SpringUtils.getBean(RedisService.class);
|
RedisService redisService = SpringUtils.getBean(RedisService.class);
|
||||||
productRecords.forEach(item->{
|
productRecords.forEach(item->{
|
||||||
redisService.setCacheObject(MallRedisConstant.STOCK_RECORD_NUM + item.getProductId(), item.getRecordNum());
|
redisService.setCacheObject(MallRedisConstant.STOCK_RECORD_NUM + item.getId(), item.getRecordNum());
|
||||||
log.info("商品记录id为:{};商品库存为:{}", item.getProductId(), item.getRecordNum());
|
log.info("商品记录id为:{};商品库存为:{}", item.getProductId(), item.getRecordNum());
|
||||||
});
|
});
|
||||||
log.info("===============================结束<-库存信息结束->结束===============================");
|
log.info("===============================结束<--库存信息结束-->结束===============================");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,5 +5,13 @@ package com.cpop.mall.framework.constant;
|
|||||||
*/
|
*/
|
||||||
public interface MallRedisConstant {
|
public interface MallRedisConstant {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* redis库存
|
||||||
|
*/
|
||||||
String STOCK_RECORD_NUM = "mall:stock:recordNum:";
|
String STOCK_RECORD_NUM = "mall:stock:recordNum:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户支付幂等键
|
||||||
|
*/
|
||||||
|
String IDEMPOTENT_LOCK_USER_PAY = "mall:idempotentLock:userPay:";
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user