mirror of
https://gitee.com/youlaitech/youlai-mall.git
synced 2024-12-22 12:48:59 +08:00
refactor: 订单流程优化和项目重构
This commit is contained in:
parent
78817eaafd
commit
00c35f20fd
@ -1,5 +1,6 @@
|
||||
package com.youlai.mall.oms.config;
|
||||
|
||||
import com.youlai.common.factory.NamedThreadFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@ -10,12 +11,15 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 线程池配置
|
||||
*
|
||||
* @author haoxr
|
||||
* @date 2022/2/13
|
||||
*/
|
||||
@Configuration
|
||||
public class ThreadPoolConfig {
|
||||
|
||||
@Bean
|
||||
public ThreadPoolExecutor threadPoolExecutor() {
|
||||
return new ThreadPoolExecutor(50,500,30, TimeUnit.SECONDS,new ArrayBlockingQueue<>(10000));
|
||||
}
|
||||
@Bean
|
||||
public ThreadPoolExecutor threadPoolExecutor() {
|
||||
return new ThreadPoolExecutor(50, 500, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10000), new NamedThreadFactory("订单线程"));
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,6 @@ import com.youlai.mall.oms.pojo.entity.OmsOrderItem;
|
||||
import com.youlai.mall.oms.pojo.query.OrderPageQuery;
|
||||
import com.youlai.mall.oms.service.IOrderItemService;
|
||||
import com.youlai.mall.oms.service.IOrderService;
|
||||
import com.youlai.mall.ums.api.MemberFeignClient;
|
||||
import com.youlai.mall.ums.pojo.dto.MemberDTO;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
@ -31,14 +29,13 @@ import java.util.Optional;
|
||||
* @date 2020-12-30 22:31:10
|
||||
*/
|
||||
@Api(tags = "「系统端」订单管理")
|
||||
@RestController("adminOrderController")
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/orders")
|
||||
@RequiredArgsConstructor
|
||||
public class OrderController {
|
||||
public class OmsOrderController {
|
||||
|
||||
private final IOrderService orderService;
|
||||
private final IOrderItemService orderItemService;
|
||||
private final MemberFeignClient memberFeignClient;
|
||||
|
||||
@ApiOperation("订单列表")
|
||||
@GetMapping
|
||||
@ -62,10 +59,7 @@ public class OrderController {
|
||||
);
|
||||
orderItems = Optional.ofNullable(orderItems).orElse(new ArrayList<>());
|
||||
|
||||
// 会员明细
|
||||
Result<MemberDTO> result = memberFeignClient.getUserById(order.getMemberId());
|
||||
MemberDTO member = result.getData();
|
||||
orderDTO.setOrder(order).setOrderItems(orderItems).setMember(member);
|
||||
orderDTO.setOrder(order).setOrderItems(orderItems);
|
||||
return Result.success(orderDTO);
|
||||
}
|
||||
|
@ -2,14 +2,13 @@ package com.youlai.mall.oms.controller.app;
|
||||
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import com.youlai.common.result.Result;
|
||||
import com.youlai.common.web.util.JwtUtils;
|
||||
import com.youlai.common.web.util.MemberUtils;
|
||||
import com.youlai.mall.oms.pojo.dto.CartItemDTO;
|
||||
import com.youlai.mall.oms.service.ICartService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Collections;
|
||||
@ -24,18 +23,17 @@ import java.util.List;
|
||||
@Api(tags = "「移动端」购物车管理")
|
||||
@RestController
|
||||
@RequestMapping("/app-api/v1/carts")
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor
|
||||
public class CartController {
|
||||
|
||||
private ICartService cartService;
|
||||
private final ICartService cartService;
|
||||
|
||||
@ApiOperation(value = "查询购物车")
|
||||
@GetMapping
|
||||
@ApiOperationSupport(order = 1)
|
||||
public <T> Result<T> getCart() {
|
||||
try {
|
||||
Long memberId = JwtUtils.getUserId();
|
||||
Long memberId = MemberUtils.getMemberId();
|
||||
List<CartItemDTO> result = cartService.listCartItemByMemberId(memberId);
|
||||
return Result.success((T) result);
|
||||
} catch (Exception e) {
|
||||
|
@ -4,11 +4,11 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.youlai.common.result.Result;
|
||||
import com.youlai.common.web.util.JwtUtils;
|
||||
import com.youlai.common.web.util.MemberUtils;
|
||||
import com.youlai.mall.oms.enums.PayTypeEnum;
|
||||
import com.youlai.mall.oms.pojo.dto.OrderConfirmDTO;
|
||||
import com.youlai.mall.oms.pojo.form.OrderSubmitForm;
|
||||
import com.youlai.mall.oms.pojo.entity.OmsOrder;
|
||||
import com.youlai.mall.oms.pojo.form.OrderSubmitForm;
|
||||
import com.youlai.mall.oms.pojo.query.OrderPageQuery;
|
||||
import com.youlai.mall.oms.pojo.vo.OrderConfirmVO;
|
||||
import com.youlai.mall.oms.pojo.vo.OrderSubmitVO;
|
||||
@ -18,12 +18,10 @@ import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
|
||||
/**
|
||||
* @author huawei
|
||||
* @email huawei_code@163.com
|
||||
@ -32,20 +30,19 @@ import javax.validation.Valid;
|
||||
@Api(tags = "「移动端」订单管理")
|
||||
@RestController
|
||||
@RequestMapping("/app-api/v1/orders")
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class OrderController {
|
||||
|
||||
final IOrderService orderService;
|
||||
|
||||
@ApiOperation("订单列表")
|
||||
@ApiOperation("分页列表")
|
||||
@GetMapping
|
||||
public Result listOrdersWithPage(OrderPageQuery queryParams) {
|
||||
IPage<OmsOrder> result = orderService.page(
|
||||
new Page<>(queryParams.getPageNum(), queryParams.getPageSize()),
|
||||
new LambdaQueryWrapper<OmsOrder>()
|
||||
.eq(OmsOrder::getStatus, queryParams.getStatus())
|
||||
.eq(OmsOrder::getMemberId, JwtUtils.getUserId())
|
||||
.eq(queryParams.getStatus() != null, OmsOrder::getStatus, queryParams.getStatus())
|
||||
.eq(OmsOrder::getMemberId, MemberUtils.getMemberId())
|
||||
);
|
||||
return Result.success(result.getRecords(), result.getTotal());
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package com.youlai.mall.oms.pojo.dto;
|
||||
|
||||
import com.youlai.mall.oms.pojo.entity.OmsOrder;
|
||||
import com.youlai.mall.oms.pojo.entity.OmsOrderItem;
|
||||
import com.youlai.mall.ums.pojo.dto.MemberDTO;
|
||||
import com.youlai.mall.ums.dto.MemberDTO;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
@ -7,7 +7,7 @@ import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 订单商品信息表
|
||||
* 订单明细表
|
||||
*
|
||||
* @author huawei
|
||||
* @email huawei_code@163.com
|
||||
@ -24,10 +24,12 @@ public class OmsOrderItem extends BaseEntity {
|
||||
* 订单ID
|
||||
*/
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 商品sku id
|
||||
* 商品ID
|
||||
*/
|
||||
private Long skuId;
|
||||
|
||||
/**
|
||||
* 商品sku编号
|
||||
*/
|
||||
@ -58,7 +60,6 @@ public class OmsOrderItem extends BaseEntity {
|
||||
*/
|
||||
private Long totalAmount;
|
||||
|
||||
|
||||
/**
|
||||
* 逻辑删除(0:正常;1:已删除)
|
||||
*/
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.youlai.mall.oms.pojo.form;
|
||||
|
||||
import com.youlai.mall.oms.pojo.dto.OrderItemDTO;
|
||||
import com.youlai.mall.ums.pojo.entity.UmsAddress;
|
||||
import com.youlai.mall.ums.dto.MemberAddressDTO;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.Size;
|
||||
@ -53,6 +53,6 @@ public class OrderSubmitForm {
|
||||
/**
|
||||
* 收获地址
|
||||
*/
|
||||
private UmsAddress deliveryAddress;
|
||||
private MemberAddressDTO deliveryAddress;
|
||||
|
||||
}
|
||||
|
@ -2,19 +2,25 @@ package com.youlai.mall.oms.pojo.vo;
|
||||
|
||||
import com.youlai.common.base.BaseVO;
|
||||
import com.youlai.mall.oms.pojo.dto.OrderItemDTO;
|
||||
import com.youlai.mall.ums.pojo.entity.UmsAddress;
|
||||
import com.youlai.mall.ums.dto.MemberAddressDTO;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@ApiModel("订单确认视图层对象")
|
||||
@Data
|
||||
public class OrderConfirmVO {
|
||||
|
||||
@ApiModelProperty("订单token")
|
||||
private String orderToken;
|
||||
|
||||
@ApiModelProperty("订单明细")
|
||||
private List<OrderItemDTO> orderItems;
|
||||
|
||||
private List<UmsAddress> addresses;
|
||||
@ApiModelProperty("会员收获地址列表")
|
||||
private List<MemberAddressDTO> addresses;
|
||||
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import cn.hutool.core.lang.Assert;
|
||||
import com.youlai.common.result.ResultCode;
|
||||
import com.youlai.common.web.exception.BizException;
|
||||
import com.youlai.common.web.util.JwtUtils;
|
||||
import com.youlai.common.web.util.MemberUtils;
|
||||
import com.youlai.mall.oms.constant.OmsConstants;
|
||||
import com.youlai.mall.oms.pojo.dto.CartItemDTO;
|
||||
import com.youlai.mall.oms.service.ICartService;
|
||||
@ -52,7 +53,7 @@ public class CartServiceImpl implements ICartService {
|
||||
*/
|
||||
@Override
|
||||
public boolean deleteCart() {
|
||||
String key = OmsConstants.CART_PREFIX + JwtUtils.getUserId();
|
||||
String key = OmsConstants.CART_PREFIX + MemberUtils.getMemberId();
|
||||
redisTemplate.delete(key);
|
||||
return true;
|
||||
}
|
||||
@ -64,7 +65,7 @@ public class CartServiceImpl implements ICartService {
|
||||
public boolean addCartItem(Long skuId) {
|
||||
Long memberId;
|
||||
try {
|
||||
memberId = JwtUtils.getUserId();
|
||||
memberId = MemberUtils.getMemberId();
|
||||
} catch (Exception e) {
|
||||
throw new BizException(ResultCode.TOKEN_INVALID_OR_EXPIRED);
|
||||
}
|
||||
@ -104,7 +105,7 @@ public class CartServiceImpl implements ICartService {
|
||||
public boolean updateCartItem(CartItemDTO cartItem) {
|
||||
Long memberId;
|
||||
try {
|
||||
memberId = JwtUtils.getUserId();
|
||||
memberId = MemberUtils.getMemberId();
|
||||
} catch (Exception e) {
|
||||
throw new BizException(ResultCode.TOKEN_INVALID_OR_EXPIRED);
|
||||
}
|
||||
@ -130,7 +131,7 @@ public class CartServiceImpl implements ICartService {
|
||||
public boolean removeCartItem(Long skuId) {
|
||||
Long memberId;
|
||||
try {
|
||||
memberId = JwtUtils.getUserId();
|
||||
memberId = MemberUtils.getMemberId();
|
||||
} catch (Exception e) {
|
||||
throw new BizException(ResultCode.TOKEN_INVALID_OR_EXPIRED);
|
||||
}
|
||||
@ -148,7 +149,7 @@ public class CartServiceImpl implements ICartService {
|
||||
public boolean checkAll(boolean checked) {
|
||||
Long memberId;
|
||||
try {
|
||||
memberId = JwtUtils.getUserId();
|
||||
memberId = MemberUtils.getMemberId();
|
||||
} catch (Exception e) {
|
||||
throw new BizException(ResultCode.TOKEN_INVALID_OR_EXPIRED);
|
||||
}
|
||||
@ -171,7 +172,7 @@ public class CartServiceImpl implements ICartService {
|
||||
public boolean removeCheckedItem() {
|
||||
Long memberId;
|
||||
try {
|
||||
memberId = JwtUtils.getUserId();
|
||||
memberId = MemberUtils.getMemberId();
|
||||
} catch (Exception e) {
|
||||
throw new BizException(ResultCode.TOKEN_INVALID_OR_EXPIRED);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.youlai.mall.oms.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.youlai.common.web.util.JwtUtils;
|
||||
import com.youlai.common.web.util.MemberUtils;
|
||||
import com.youlai.mall.oms.mapper.OrderLogMapper;
|
||||
import com.youlai.mall.oms.pojo.entity.OmsOrderLog;
|
||||
import com.youlai.mall.oms.service.IOrderLogService;
|
||||
@ -24,8 +24,8 @@ public class OrderLogServiceImpl extends ServiceImpl<OrderLogMapper, OmsOrderLog
|
||||
|
||||
@Override
|
||||
public void addOrderLogs(Long orderId, Integer orderStatus, String detail) {
|
||||
Long userId = JwtUtils.getUserId();
|
||||
addOrderLogs(orderId, orderStatus, userId.toString(), detail);
|
||||
Long memberId = MemberUtils.getMemberId();
|
||||
addOrderLogs(orderId, orderStatus, memberId.toString(), detail);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ import com.youlai.common.enums.BusinessTypeEnum;
|
||||
import com.youlai.common.redis.BusinessNoGenerator;
|
||||
import com.youlai.common.result.Result;
|
||||
import com.youlai.common.web.exception.BizException;
|
||||
import com.youlai.common.web.util.JwtUtils;
|
||||
import com.youlai.common.web.util.MemberUtils;
|
||||
import com.youlai.mall.oms.config.WxPayProperties;
|
||||
import com.youlai.mall.oms.enums.OrderStatusEnum;
|
||||
import com.youlai.mall.oms.enums.OrderTypeEnum;
|
||||
@ -48,8 +48,7 @@ import com.youlai.mall.pms.pojo.dto.SkuInfoDTO;
|
||||
import com.youlai.mall.pms.pojo.dto.app.LockStockDTO;
|
||||
import com.youlai.mall.ums.api.MemberAddressFeignClient;
|
||||
import com.youlai.mall.ums.api.MemberFeignClient;
|
||||
import com.youlai.mall.ums.pojo.entity.UmsAddress;
|
||||
import com.youlai.mall.ums.pojo.entity.UmsMember;
|
||||
import com.youlai.mall.ums.dto.MemberAddressDTO;
|
||||
import io.seata.spring.annotation.GlobalTransactional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -72,6 +71,12 @@ import java.util.stream.Collectors;
|
||||
|
||||
import static com.youlai.mall.oms.constant.OmsConstants.*;
|
||||
|
||||
/**
|
||||
* 订单业务实现类
|
||||
*
|
||||
* @author haoxr
|
||||
* @date 2022/2/12
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@Service
|
||||
@ -111,41 +116,19 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
|
||||
public OrderConfirmVO confirm(OrderConfirmDTO orderConfirmDTO) {
|
||||
log.info("订单确认:{}", orderConfirmDTO);
|
||||
OrderConfirmVO orderConfirmVO = new OrderConfirmVO();
|
||||
Long memberId = JwtUtils.getUserId();
|
||||
|
||||
// 获取购买商品信息
|
||||
// 获取订单的商品信息
|
||||
CompletableFuture<Void> orderItemsCompletableFuture = CompletableFuture.runAsync(() -> {
|
||||
List<OrderItemDTO> orderItems = new ArrayList<>();
|
||||
Long skuId = orderConfirmDTO.getSkuId();
|
||||
if (skuId != null) { // 直接购买
|
||||
Result<SkuInfoDTO> getSkuInfoResult = skuFeignClient.getSkuInfo(orderConfirmDTO.getSkuId());
|
||||
Assert.isTrue(Result.isSuccess(getSkuInfoResult), "获取商品信息失败");
|
||||
SkuInfoDTO skuInfoDTO = getSkuInfoResult.getData();
|
||||
OrderItemDTO orderItemDTO = new OrderItemDTO();
|
||||
BeanUtil.copyProperties(skuInfoDTO, orderItemDTO);
|
||||
orderItems.add(orderItemDTO);
|
||||
} else { // 购物车结算
|
||||
List<CartItemDTO> cartItems = cartService.listCartItemByMemberId(memberId);
|
||||
List<OrderItemDTO> items = cartItems.stream()
|
||||
.filter(CartItemDTO::getChecked)
|
||||
.map(cartItem -> {
|
||||
OrderItemDTO orderItemDTO = new OrderItemDTO();
|
||||
BeanUtil.copyProperties(cartItem, orderItemDTO);
|
||||
return orderItemDTO;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
orderItems.addAll(items);
|
||||
}
|
||||
List<OrderItemDTO> orderItems = this.getOrderItems(orderConfirmDTO.getSkuId());
|
||||
orderConfirmVO.setOrderItems(orderItems);
|
||||
}, threadPoolExecutor);
|
||||
|
||||
// 获取会员地址列表
|
||||
// 获取会员收获地址
|
||||
CompletableFuture<Void> addressesCompletableFuture = CompletableFuture.runAsync(() -> {
|
||||
List<UmsAddress> addresses = addressFeignService.list(memberId).getData();
|
||||
List<MemberAddressDTO> addresses = addressFeignService.listCurrMemberAddresses().getData();
|
||||
orderConfirmVO.setAddresses(addresses);
|
||||
}, threadPoolExecutor);
|
||||
|
||||
// 生成唯一标识,防止订单重复提交
|
||||
// 生成唯一 token,防止订单重复提交
|
||||
CompletableFuture<Void> orderTokenCompletableFuture = CompletableFuture.runAsync(() -> {
|
||||
String orderToken = businessNoGenerator.generate(BusinessTypeEnum.ORDER);
|
||||
orderConfirmVO.setOrderToken(orderToken);
|
||||
@ -164,7 +147,8 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
|
||||
@GlobalTransactional
|
||||
public OrderSubmitVO submit(OrderSubmitForm orderSubmitForm) {
|
||||
log.info("订单提交数据:{}", JSONUtil.toJsonStr(orderSubmitForm));
|
||||
// 订单校验
|
||||
|
||||
// 订单基础信息校验
|
||||
List<OrderItemDTO> orderItems = orderSubmitForm.getOrderItems();
|
||||
Assert.isTrue(CollectionUtil.isNotEmpty(orderItems), "订单没有商品");
|
||||
|
||||
@ -176,24 +160,18 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
|
||||
|
||||
// 订单验价
|
||||
Long orderTotalAmount = orderSubmitForm.getTotalAmount();
|
||||
boolean checkResult = checkOrderPrice(orderTotalAmount, orderItems);
|
||||
boolean checkResult = this.checkOrderPrice(orderTotalAmount, orderItems);
|
||||
Assert.isTrue(checkResult, "当前页面已过期,请重新刷新页面再提交");
|
||||
|
||||
// 锁定库存
|
||||
List<LockStockDTO> skuLockList = orderItems.stream()
|
||||
.map(item -> LockStockDTO.builder().skuId(item.getSkuId())
|
||||
.count(item.getCount())
|
||||
.orderToken(orderToken)
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
Result lockResult = skuFeignClient.lockStock(skuLockList);
|
||||
Assert.isTrue(Result.isSuccess(lockResult), "锁定商品库存失败:{}", lockResult.getMsg());
|
||||
// 锁定商品库存
|
||||
this.lockStock(orderToken, orderItems);
|
||||
|
||||
|
||||
// 创建订单
|
||||
OmsOrder order = new OmsOrder().setOrderSn(orderToken) // 把orderToken赋值给订单编号
|
||||
.setStatus(OrderStatusEnum.PENDING_PAYMENT.getCode())
|
||||
.setSourceType(OrderTypeEnum.APP.getCode())
|
||||
.setMemberId(JwtUtils.getUserId())
|
||||
.setMemberId(MemberUtils.getMemberId())
|
||||
.setRemark(orderSubmitForm.getRemark())
|
||||
.setPayAmount(orderSubmitForm.getPayAmount())
|
||||
.setTotalQuantity(orderItems.stream().map(OrderItemDTO::getCount).reduce(0, Integer::sum))
|
||||
@ -224,6 +202,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
|
||||
return submitVO;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 订单支付
|
||||
*
|
||||
@ -280,11 +259,12 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 余额支付
|
||||
*
|
||||
* @param order
|
||||
* @return
|
||||
*/
|
||||
private Boolean balancePay(OmsOrder order) {
|
||||
// 扣减余额
|
||||
Long payAmount = order.getPayAmount();
|
||||
@ -304,13 +284,9 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
|
||||
private WxPayUnifiedOrderV3Result.JsapiResult wxJsapiPay(String appId, OmsOrder order) {
|
||||
Long userId = JwtUtils.getUserId();
|
||||
Result<UmsMember> userInfoResult = memberFeignClient.getUserEntityById(userId);
|
||||
if (!Result.isSuccess(userInfoResult)) {
|
||||
throw new BizException("用户查询失败");
|
||||
}
|
||||
UmsMember userInfo = userInfoResult.getData();
|
||||
Long memberId = MemberUtils.getMemberId();
|
||||
Long payAmount = order.getPayAmount();
|
||||
// 如果已经有outTradeNo了就先进行关单
|
||||
if (PayTypeEnum.WEIXIN_JSAPI.getCode().equals(order.getPayType()) && StrUtil.isNotBlank(order.getOutTradeNo())) {
|
||||
@ -322,7 +298,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
|
||||
}
|
||||
}
|
||||
// 用户id前补零保证五位,对超出五位的保留后五位
|
||||
String userIdFilledZero = String.format("%05d", userId);
|
||||
String userIdFilledZero = String.format("%05d", memberId);
|
||||
String fiveDigitsUserId = userIdFilledZero.substring(userIdFilledZero.length() - 5);
|
||||
// 在前面加上wxo(weixin order)等前缀是为了人工可以快速分辨订单号是下单还是退款、来自哪家支付机构等
|
||||
// 将时间戳+3位随机数+五位id组成商户订单号,规则参考自<a href="https://tech.meituan.com/2016/11/18/dianping-order-db-sharding.html">大众点评</a>
|
||||
@ -333,12 +309,14 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
|
||||
order.setOutTradeNo(outTradeNo);
|
||||
this.updateById(order);
|
||||
|
||||
String memberOpenId = memberFeignClient.getMemberOpenId(memberId).getData();
|
||||
|
||||
WxPayUnifiedOrderV3Request wxRequest = new WxPayUnifiedOrderV3Request()
|
||||
.setOutTradeNo(outTradeNo)
|
||||
.setAppid(appId)
|
||||
.setNotifyUrl(wxPayProperties.getPayNotifyUrl())
|
||||
.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(Math.toIntExact(payAmount)))
|
||||
.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(userInfo.getOpenid()))
|
||||
.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(memberOpenId))
|
||||
.setDescription("赅买-订单编号" + order.getOrderSn());
|
||||
WxPayUnifiedOrderV3Result.JsapiResult jsapiResult;
|
||||
try {
|
||||
@ -465,11 +443,11 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单验价
|
||||
* 订单验价,进入结算页面的订单总价和当前所有商品的总价是否一致
|
||||
*
|
||||
* @param orderTotalAmount 订单总金额
|
||||
* @param orderItems 订单商品明细
|
||||
* @return
|
||||
* @param orderItems 订单商品明细
|
||||
* @return true:订单总价和商品总价一致;false:订单总价和商品总价不一致。
|
||||
*/
|
||||
private boolean checkOrderPrice(Long orderTotalAmount, List<OrderItemDTO> orderItems) {
|
||||
CheckPriceDTO checkPriceDTO = new CheckPriceDTO();
|
||||
@ -490,4 +468,54 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订单的商品明细
|
||||
*
|
||||
* @param skuId 直接购买会有值
|
||||
* @return
|
||||
*/
|
||||
private List<OrderItemDTO> getOrderItems(Long skuId) {
|
||||
List<OrderItemDTO> orderItems;
|
||||
if (skuId != null) { // 直接购买
|
||||
orderItems = new ArrayList<>();
|
||||
SkuInfoDTO skuInfoDTO = skuFeignClient.getSkuInfo(skuId).getData();
|
||||
OrderItemDTO orderItemDTO = new OrderItemDTO();
|
||||
BeanUtil.copyProperties(skuInfoDTO, orderItemDTO);
|
||||
|
||||
orderItemDTO.setCount(1); // 直接购买商品的数量为1
|
||||
orderItems.add(orderItemDTO);
|
||||
} else { // 购物车结算
|
||||
Long memberId = MemberUtils.getMemberId();
|
||||
List<CartItemDTO> cartItems = cartService.listCartItemByMemberId(memberId);
|
||||
orderItems = cartItems.stream()
|
||||
.filter(CartItemDTO::getChecked)
|
||||
.map(cartItem -> {
|
||||
OrderItemDTO orderItemDTO = new OrderItemDTO();
|
||||
BeanUtil.copyProperties(cartItem, orderItemDTO);
|
||||
return orderItemDTO;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
return orderItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* 锁定商品库存
|
||||
*
|
||||
* @param orderToken
|
||||
* @param orderItems
|
||||
*/
|
||||
private void lockStock(String orderToken, List<OrderItemDTO> orderItems) {
|
||||
LockStockDTO lockStockDTO = new LockStockDTO();
|
||||
lockStockDTO.setOrderToken(orderToken);
|
||||
|
||||
List<LockStockDTO.LockedSku> lockedSkuList = orderItems.stream()
|
||||
.map(orderItem -> new LockStockDTO.LockedSku()
|
||||
.setSkuId(orderItem.getSkuId())
|
||||
.setCount(orderItem.getCount())
|
||||
).collect(Collectors.toList());
|
||||
|
||||
lockStockDTO.setLockedSkuList(lockedSkuList);
|
||||
skuFeignClient.lockStock(lockStockDTO);
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,11 @@
|
||||
package com.youlai.mall.oms.controller;
|
||||
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
|
||||
@SpringBootTest
|
||||
@Slf4j
|
||||
public class RabbitMQTest {
|
||||
@ -16,7 +14,7 @@ public class RabbitMQTest {
|
||||
private RabbitTemplate rabbitTemplate;
|
||||
|
||||
@Test
|
||||
public void createOrderTest() {
|
||||
public void createOrderTest() {
|
||||
rabbitTemplate.convertAndSend("order.exchange", "order.create", "4acd475a-c6aa-4d9a-a3a5-40da7472cbee");
|
||||
}
|
||||
}
|
||||
|
@ -19,31 +19,29 @@ public interface SkuFeignClient {
|
||||
Result<SkuInfoDTO> getSkuInfo(@PathVariable Long skuId);
|
||||
|
||||
/**
|
||||
* 锁定库存
|
||||
* 锁定商品库存
|
||||
*/
|
||||
@PutMapping("/app-api/v1/sku/_lock")
|
||||
Result lockStock(@RequestBody List<LockStockDTO> list);
|
||||
Result lockStock(@RequestBody LockStockDTO lockStockDTO);
|
||||
|
||||
/**
|
||||
* 解锁库存
|
||||
* 解锁商品库存
|
||||
*/
|
||||
@PutMapping("/app-api/v1/sku/_unlock")
|
||||
Result<Boolean> unlockStock(@RequestParam String orderToken);
|
||||
|
||||
Result unlockStock(@RequestParam String orderToken);
|
||||
|
||||
/**
|
||||
* 扣减库存
|
||||
* 扣减商品库存
|
||||
*/
|
||||
@PutMapping("/app-api/v1/sku/_deduct")
|
||||
Result deductStock(@RequestParam String orderToken);
|
||||
|
||||
|
||||
/**
|
||||
* 商品验价
|
||||
* 订单商品验价
|
||||
*
|
||||
* @param checkPriceDTO
|
||||
* @return
|
||||
*/
|
||||
@PutMapping("/app-api/v1/sku/price/_check")
|
||||
@PostMapping("/app-api/v1/sku/price/_check")
|
||||
Result<Boolean> checkPrice(@RequestBody CheckPriceDTO checkPriceDTO);
|
||||
}
|
||||
|
@ -1,27 +1,44 @@
|
||||
package com.youlai.mall.pms.pojo.dto.app;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description 锁定库存
|
||||
* 锁定库存传输层实体
|
||||
*
|
||||
* @author haoxr
|
||||
* @createTime 2021-03-07 15:14
|
||||
* @date 2021-03-07 15:14
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LockStockDTO {
|
||||
|
||||
private Long skuId;
|
||||
|
||||
private Integer count;
|
||||
public class LockStockDTO {
|
||||
|
||||
/**
|
||||
* 订单token
|
||||
*/
|
||||
private String orderToken;
|
||||
|
||||
private Boolean locked;
|
||||
/**
|
||||
* 锁定商品列表
|
||||
*/
|
||||
private List<LockedSku> lockedSkuList;
|
||||
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
public static class LockedSku {
|
||||
|
||||
/**
|
||||
* 商品ID
|
||||
*/
|
||||
private Long skuId;
|
||||
|
||||
/**
|
||||
* 商品数量
|
||||
*/
|
||||
private Integer count;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ public class PmsSku extends BaseEntity {
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 商品ID
|
||||
* SPU ID
|
||||
*/
|
||||
private Long spuId;
|
||||
|
||||
@ -38,7 +38,7 @@ public class PmsSku extends BaseEntity {
|
||||
private String specIds;
|
||||
|
||||
/**
|
||||
* 商品价格
|
||||
* 商品价格(单位:分)
|
||||
*/
|
||||
private Long price;
|
||||
|
||||
|
@ -8,7 +8,7 @@ package com.youlai.mall.pms.common.constant;
|
||||
*/
|
||||
public interface PmsConstants {
|
||||
|
||||
String LOCKED_STOCK_PREFIX = "stock:locked:";
|
||||
String LOCKED_STOCK_PREFIX = "pms:locked_stock:";
|
||||
|
||||
String LOCK_SKU_PREFIX = "lock:sku:";
|
||||
|
||||
|
@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/sku")
|
||||
@RequiredArgsConstructor
|
||||
public class StockController {
|
||||
public class OmsSkuController {
|
||||
|
||||
private final IPmsSkuService skuService;
|
||||
|
@ -17,7 +17,7 @@ import java.util.List;
|
||||
* 商品库存单元控制器 (Stock Keeping Unit)
|
||||
*/
|
||||
@Api(tags = "「移动端」商品库存")
|
||||
@RestController("appSkuController")
|
||||
@RestController
|
||||
@RequestMapping("/app-api/v1/sku")
|
||||
@RequiredArgsConstructor
|
||||
public class SkuController {
|
||||
@ -25,9 +25,9 @@ public class SkuController {
|
||||
private final IPmsSkuService skuService;
|
||||
|
||||
@ApiOperation(value = "获取商品库存信息")
|
||||
@GetMapping("/{skuId}")
|
||||
@GetMapping("/{skuId}/info")
|
||||
public Result<SkuInfoDTO> getSkuInfo(
|
||||
@ApiParam("商品库存单元ID") @PathVariable Long skuId
|
||||
@ApiParam("SKU ID") @PathVariable Long skuId
|
||||
) {
|
||||
SkuInfoDTO skuInfo = skuService.getSkuInfo(skuId);
|
||||
return Result.success(skuInfo);
|
||||
@ -44,8 +44,9 @@ public class SkuController {
|
||||
|
||||
@ApiOperation(value = "锁定库存")
|
||||
@PutMapping("/_lock")
|
||||
public Result lockStock(@RequestBody List<LockStockDTO> list) {
|
||||
return skuService.lockStock(list);
|
||||
public Result lockStock(@RequestBody LockStockDTO lockStockDTO) {
|
||||
boolean lockResult = skuService.lockStock(lockStockDTO);
|
||||
return Result.success(lockResult);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "解锁库存")
|
||||
@ -66,6 +67,6 @@ public class SkuController {
|
||||
@PostMapping("/price/_check")
|
||||
public Result<Boolean> checkPrice(@RequestBody CheckPriceDTO checkPriceDTO) {
|
||||
boolean result = skuService.checkPrice(checkPriceDTO);
|
||||
return Result.judge(result);
|
||||
return Result.success(result);
|
||||
}
|
||||
}
|
||||
|
@ -35,14 +35,9 @@ public interface IPmsSkuService extends IService<PmsSku> {
|
||||
|
||||
|
||||
/**
|
||||
* 锁定库存
|
||||
* 锁定商品库存
|
||||
*/
|
||||
Result lockStock(List<LockStockDTO> list);
|
||||
|
||||
/**
|
||||
* 锁定库存
|
||||
*/
|
||||
// Boolean lockStockTcc(List<LockStockDTO> list);
|
||||
boolean lockStock(LockStockDTO lockStockDTO);
|
||||
|
||||
/**
|
||||
* 解锁库存
|
||||
|
@ -1,12 +1,11 @@
|
||||
package com.youlai.mall.pms.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.youlai.common.result.Result;
|
||||
import com.youlai.common.web.exception.BizException;
|
||||
import com.youlai.mall.pms.common.constant.PmsConstants;
|
||||
import com.youlai.mall.pms.mapper.PmsSkuMapper;
|
||||
@ -22,6 +21,7 @@ import org.redisson.api.RedissonClient;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@ -56,73 +56,50 @@ public class PmsSkuServiceImpl extends ServiceImpl<PmsSkuMapper, PmsSku> impleme
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建订单时锁定库存
|
||||
* 锁定库存 - 订单提交
|
||||
*/
|
||||
@Override
|
||||
public Result lockStock(List<LockStockDTO> skuLockList) {
|
||||
log.info("=======================创建订单,开始锁定商品库存=======================");
|
||||
log.info("锁定商品信息:{}", skuLockList.toString());
|
||||
if (CollectionUtil.isEmpty(skuLockList)) {
|
||||
return Result.failed("锁定的商品列表为空");
|
||||
}
|
||||
//prepareSkuLockList(null, skuLockList);
|
||||
@Transactional
|
||||
public boolean lockStock(LockStockDTO lockStockDTO) {
|
||||
log.info("锁定商品库存:{}", JSONUtil.toJsonStr(lockStockDTO));
|
||||
|
||||
List<LockStockDTO.LockedSku> lockedSkuList = lockStockDTO.getLockedSkuList();
|
||||
Assert.isTrue(CollectionUtil.isNotEmpty(lockedSkuList), "锁定的商品为空");
|
||||
|
||||
// 锁定商品
|
||||
skuLockList.forEach(item -> {
|
||||
RLock lock = redissonClient.getLock(PmsConstants.LOCK_SKU_PREFIX + item.getSkuId()); // 获取商品的分布式锁
|
||||
lockedSkuList.forEach(lockedSku -> {
|
||||
RLock lock = redissonClient.getLock(PmsConstants.LOCK_SKU_PREFIX + lockedSku.getSkuId()); // 获取商品的分布式锁
|
||||
lock.lock();
|
||||
boolean result = this.update(new LambdaUpdateWrapper<PmsSku>()
|
||||
.setSql("locked_stock = locked_stock + " + item.getCount())
|
||||
.eq(PmsSku::getId, item.getSkuId())
|
||||
.apply("stock - locked_stock >= {0}", item.getCount())
|
||||
boolean lockResult = this.update(new LambdaUpdateWrapper<PmsSku>()
|
||||
.setSql("locked_stock_num = locked_stock_num + " + lockedSku.getCount())
|
||||
.eq(PmsSku::getId, lockedSku.getSkuId())
|
||||
.apply("stock_num - locked_stock_num >= {0}", lockedSku.getCount())
|
||||
);
|
||||
if (result) {
|
||||
item.setLocked(true);
|
||||
if (lockResult) {
|
||||
lock.unlock();
|
||||
} else {
|
||||
item.setLocked(false);
|
||||
throw new BizException("锁定商品" + lockedSku.getSkuId() + "失败");
|
||||
}
|
||||
lock.unlock();
|
||||
});
|
||||
|
||||
// 锁定失败的商品集合
|
||||
List<LockStockDTO> unlockSkuList = skuLockList.stream().filter(item -> !item.getLocked()).collect(Collectors.toList());
|
||||
if (CollectionUtil.isNotEmpty(unlockSkuList)) {
|
||||
// 恢复已被锁定的库存
|
||||
List<LockStockDTO> lockSkuList = skuLockList.stream().filter(LockStockDTO::getLocked).collect(Collectors.toList());
|
||||
lockSkuList.forEach(item ->
|
||||
this.update(new LambdaUpdateWrapper<PmsSku>()
|
||||
.eq(PmsSku::getId, item.getSkuId())
|
||||
.setSql("locked_stock = locked_stock - " + item.getCount()))
|
||||
);
|
||||
// 提示订单哪些商品库存不足
|
||||
String ids = unlockSkuList.stream().map(sku -> sku.getSkuId().toString()).collect(Collectors.joining(","));
|
||||
return Result.failed("商品" + ids + "库存不足");
|
||||
}
|
||||
|
||||
// 将锁定的商品保存至Redis中
|
||||
String orderToken = skuLockList.get(0).getOrderToken();
|
||||
redisTemplate.opsForValue().set(PmsConstants.LOCKED_STOCK_PREFIX + orderToken, JSONUtil.toJsonStr(skuLockList));
|
||||
return Result.success();
|
||||
// 将锁定商品库存信息保存至Redis
|
||||
String orderToken = lockStockDTO.getOrderToken();
|
||||
redisTemplate.opsForValue().set(PmsConstants.LOCKED_STOCK_PREFIX + orderToken, JSONUtil.toJsonStr(lockedSkuList));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 订单超时关单解锁库存
|
||||
* 释放库存 - 订单超时未支付
|
||||
*/
|
||||
@Override
|
||||
public boolean unlockStock(String orderToken) {
|
||||
log.info("=======================订单超时未支付系统自动关单释放库存=======================");
|
||||
String json = redisTemplate.opsForValue().get(PmsConstants.LOCKED_STOCK_PREFIX + orderToken);
|
||||
log.info("释放库存信息:{}", json);
|
||||
if (StrUtil.isBlank(json)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
List<LockStockDTO> skuLockList = JSONUtil.toList(json, LockStockDTO.class);
|
||||
|
||||
skuLockList.forEach(item ->
|
||||
log.info("释放库存,orderToken:{}", orderToken);
|
||||
String lockedSkuJsonStr = redisTemplate.opsForValue().get(PmsConstants.LOCKED_STOCK_PREFIX + orderToken);
|
||||
List<LockStockDTO.LockedSku> lockedSkuList = JSONUtil.toList(lockedSkuJsonStr, LockStockDTO.LockedSku.class);
|
||||
lockedSkuList.forEach(item ->
|
||||
this.update(new LambdaUpdateWrapper<PmsSku>()
|
||||
.eq(PmsSku::getId, item.getSkuId())
|
||||
.setSql("locked_stock = locked_stock - " + item.getCount()))
|
||||
.setSql("locked_stock_num = locked_stock_num - " + item.getCount()))
|
||||
);
|
||||
|
||||
// 删除redis中锁定的库存
|
||||
@ -131,24 +108,19 @@ public class PmsSkuServiceImpl extends ServiceImpl<PmsSkuMapper, PmsSku> impleme
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付成功时扣减库存
|
||||
* 扣减库存 - 支付成功
|
||||
*/
|
||||
@Override
|
||||
public boolean deductStock(String orderToken) {
|
||||
log.info("=======================支付成功扣减订单中商品库存=======================");
|
||||
String json = redisTemplate.opsForValue().get(PmsConstants.LOCKED_STOCK_PREFIX + orderToken);
|
||||
log.info("订单商品信息:{}", json);
|
||||
if (StrUtil.isBlank(json)) {
|
||||
return true;
|
||||
}
|
||||
log.info("扣减库存,orderToken:{}",orderToken);
|
||||
String lockedSkuJsonStr = redisTemplate.opsForValue().get(PmsConstants.LOCKED_STOCK_PREFIX + orderToken);
|
||||
List<LockStockDTO.LockedSku> lockedSkuList = JSONUtil.toList(lockedSkuJsonStr, LockStockDTO.LockedSku.class);
|
||||
|
||||
List<LockStockDTO> skuLockList = JSONUtil.toList(json, LockStockDTO.class);
|
||||
|
||||
skuLockList.forEach(item -> {
|
||||
lockedSkuList.forEach(item -> {
|
||||
boolean result = this.update(new LambdaUpdateWrapper<PmsSku>()
|
||||
.eq(PmsSku::getId, item.getSkuId())
|
||||
.setSql("stock = stock - " + item.getCount()) // 扣减库存
|
||||
.setSql("locked_stock = locked_stock - " + item.getCount())
|
||||
.setSql("stock_num = stock_num - " + item.getCount())
|
||||
.setSql("locked_stock_num = locked_stock_num - " + item.getCount())
|
||||
);
|
||||
if (!result) {
|
||||
throw new BizException("扣减库存失败,商品" + item.getSkuId() + "库存不足");
|
||||
|
@ -9,7 +9,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.youlai.common.web.util.JwtUtils;
|
||||
import com.youlai.common.web.util.MemberUtils;
|
||||
import com.youlai.mall.pms.common.constant.PmsConstants;
|
||||
import com.youlai.mall.pms.common.enums.AttributeTypeEnum;
|
||||
import com.youlai.mall.pms.mapper.PmsSpuMapper;
|
||||
@ -146,7 +146,7 @@ public class PmsSpuServiceImpl extends ServiceImpl<PmsSpuMapper, PmsSpu> impleme
|
||||
}
|
||||
|
||||
// 添加用户浏览历史记录
|
||||
Long loginUserId = JwtUtils.getUserId();
|
||||
Long loginUserId = MemberUtils.getMemberId();
|
||||
if (loginUserId != null) {
|
||||
ProductHistoryVO vo = new ProductHistoryVO();
|
||||
vo.setId(goodsInfo.getId());
|
||||
|
@ -1,25 +0,0 @@
|
||||
package com.youlai.mall.pms.tcc.idempotent;
|
||||
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.Table;
|
||||
/**
|
||||
* @Author DaniR
|
||||
* @Description TCC幂等工具类
|
||||
* @Date 2021/7/15 20:38
|
||||
**/
|
||||
public class IdempotentUtil {
|
||||
|
||||
private static Table<Class<?>,String,Long> map= HashBasedTable.create();
|
||||
|
||||
public static void addMarker(Class<?> clazz,String xid,Long marker){
|
||||
map.put(clazz,xid,marker);
|
||||
}
|
||||
|
||||
public static Long getMarker(Class<?> clazz,String xid){
|
||||
return map.get(clazz,xid);
|
||||
}
|
||||
|
||||
public static void removeMarker(Class<?> clazz,String xid){
|
||||
map.remove(clazz,xid);
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package com.youlai.mall.pms.tcc.service;
|
||||
|
||||
import com.youlai.mall.pms.pojo.dto.app.LockStockDTO;
|
||||
import io.seata.rm.tcc.api.BusinessActionContext;
|
||||
import io.seata.rm.tcc.api.BusinessActionContextParameter;
|
||||
import io.seata.rm.tcc.api.LocalTCC;
|
||||
import io.seata.rm.tcc.api.TwoPhaseBusinessAction;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@LocalTCC
|
||||
public interface SeataTccSkuService {
|
||||
|
||||
@TwoPhaseBusinessAction(name = "prepareSkuLockList", commitMethod = "commitSkuLockList", rollbackMethod = "rollbackSkuLockList")
|
||||
boolean prepareSkuLockList(BusinessActionContext businessActionContext,
|
||||
@BusinessActionContextParameter(paramName = "skuLockList") List<LockStockDTO> skuLockList);
|
||||
|
||||
boolean commitSkuLockList(BusinessActionContext businessActionContext);
|
||||
|
||||
boolean rollbackSkuLockList(BusinessActionContext businessActionContext);
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
package com.youlai.mall.pms.tcc.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.youlai.common.web.exception.BizException;
|
||||
import com.youlai.mall.pms.common.constant.PmsConstants;
|
||||
import com.youlai.mall.pms.pojo.dto.app.LockStockDTO;
|
||||
import com.youlai.mall.pms.pojo.entity.PmsSku;
|
||||
import com.youlai.mall.pms.service.IPmsSkuService;
|
||||
import com.youlai.mall.pms.tcc.idempotent.IdempotentUtil;
|
||||
import com.youlai.mall.pms.tcc.service.SeataTccSkuService;
|
||||
import io.seata.rm.tcc.api.BusinessActionContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SeataTccSkuServiceImpl implements SeataTccSkuService {
|
||||
|
||||
@Autowired
|
||||
private IPmsSkuService iPmsSkuService;
|
||||
|
||||
@Autowired
|
||||
private RedissonClient redissonClient;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean prepareSkuLockList(BusinessActionContext businessActionContext, List<LockStockDTO> skuLockList) {
|
||||
|
||||
if (Objects.nonNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) {
|
||||
return true;
|
||||
}
|
||||
if (CollectionUtil.isEmpty(skuLockList)) {
|
||||
throw new BizException("锁定的商品列表为空");
|
||||
}
|
||||
// 锁定商品
|
||||
skuLockList.forEach(item -> {
|
||||
RLock lock = redissonClient.getLock(PmsConstants.LOCK_SKU_PREFIX + item.getSkuId()); // 获取商品的分布式锁
|
||||
lock.lock();
|
||||
boolean result = iPmsSkuService.update(new LambdaUpdateWrapper<PmsSku>()
|
||||
.setSql("locked_stock = locked_stock + " + item.getCount())
|
||||
.eq(PmsSku::getId, item.getSkuId())
|
||||
.apply("stock - locked_stock >= {0}", item.getCount())
|
||||
);
|
||||
item.setLocked(result);
|
||||
lock.unlock();
|
||||
});
|
||||
// 锁定失败的商品集合
|
||||
List<LockStockDTO> unlockSkuList = skuLockList.stream().filter(item -> !item.getLocked()).collect(Collectors.toList());
|
||||
if (CollectionUtil.isNotEmpty(unlockSkuList)) {
|
||||
// 恢复已被锁定的库存
|
||||
List<LockStockDTO> lockSkuList = skuLockList.stream().filter(LockStockDTO::getLocked).collect(Collectors.toList());
|
||||
lockSkuList.forEach(item ->
|
||||
iPmsSkuService.update(new LambdaUpdateWrapper<PmsSku>()
|
||||
.eq(PmsSku::getId, item.getSkuId())
|
||||
.setSql("locked_stock = locked_stock - " + item.getCount()))
|
||||
);
|
||||
// 提示订单哪些商品库存不足
|
||||
List<Long> ids = unlockSkuList.stream().map(LockStockDTO::getSkuId).collect(Collectors.toList());
|
||||
throw new BizException("商品" + ids + "库存不足");
|
||||
}
|
||||
IdempotentUtil.addMarker(getClass(), businessActionContext.getXid(), System.currentTimeMillis());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public boolean commitSkuLockList(BusinessActionContext businessActionContext) {
|
||||
if (Objects.isNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) {
|
||||
return true;
|
||||
}
|
||||
IdempotentUtil.removeMarker(getClass(), businessActionContext.getXid());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public boolean rollbackSkuLockList(BusinessActionContext businessActionContext) {
|
||||
|
||||
if (Objects.isNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) {
|
||||
return true;
|
||||
}
|
||||
JSONArray jsonObjectList = (JSONArray) businessActionContext.getActionContext("skuLockList");
|
||||
|
||||
List<LockStockDTO> skuLockList = JSONUtil.toList(jsonObjectList,LockStockDTO.class);
|
||||
skuLockList.forEach(item ->
|
||||
iPmsSkuService.update(new LambdaUpdateWrapper<PmsSku>()
|
||||
.eq(PmsSku::getId, item.getSkuId())
|
||||
.setSql("locked_stock = locked_stock - " + item.getCount()))
|
||||
);
|
||||
IdempotentUtil.removeMarker(getClass(), businessActionContext.getXid());
|
||||
return true;
|
||||
}
|
||||
}
|
@ -20,9 +20,9 @@
|
||||
<!-- 获取商品库存单元信息 -->
|
||||
<select id="getSkuInfo" resultType="com.youlai.mall.pms.pojo.dto.SkuInfoDTO">
|
||||
select
|
||||
t1.id,
|
||||
t1.id skuId,
|
||||
t1.sku_sn,
|
||||
t1.name,
|
||||
t1.name skuName,
|
||||
t1.pic_url,
|
||||
t1.price,
|
||||
t1.stock_num,
|
||||
|
@ -6,12 +6,13 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.youlai.common.base.BasePageQuery;
|
||||
import com.youlai.common.result.Result;
|
||||
import com.youlai.common.web.util.JwtUtils;
|
||||
import com.youlai.common.web.util.MemberUtils;
|
||||
import com.youlai.mall.sms.pojo.domain.SmsCouponRecord;
|
||||
import com.youlai.mall.sms.service.ICouponRecordService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@ -24,26 +25,25 @@ import org.springframework.web.bind.annotation.*;
|
||||
@Api(tags = "「系统端」优惠券领券记录")
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/coupon_record")
|
||||
@RequiredArgsConstructor
|
||||
public class CouponRecordController {
|
||||
|
||||
@Autowired
|
||||
private ICouponRecordService couponRecordService;
|
||||
private final ICouponRecordService couponRecordService;
|
||||
|
||||
@ApiOperation(value = "分页获取会员领券记录")
|
||||
@GetMapping("/page")
|
||||
public Result page(BasePageQuery pageQuery) {
|
||||
Long userId = JwtUtils.getUserId();
|
||||
LambdaQueryWrapper<SmsCouponRecord> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(SmsCouponRecord::getUserId, userId).orderByDesc(SmsCouponRecord::getGmtCreate);
|
||||
Page<SmsCouponRecord> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
|
||||
IPage<SmsCouponRecord> result = couponRecordService.page(page, queryWrapper);
|
||||
IPage<SmsCouponRecord> result = couponRecordService.page(page, new LambdaQueryWrapper<SmsCouponRecord>()
|
||||
.eq(SmsCouponRecord::getUserId, MemberUtils.getMemberId())
|
||||
.orderByDesc(SmsCouponRecord::getGmtCreate));
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取优惠券记录详情")
|
||||
@GetMapping("/{id}/detail")
|
||||
public Result detail(@ApiParam(value = "优惠券记录ID") @PathVariable("id") String id) {
|
||||
Long userId = JwtUtils.getUserId();
|
||||
Long userId = MemberUtils.getMemberId();
|
||||
QueryWrapper<SmsCouponRecord> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("user_id", userId).eq("id", id);
|
||||
SmsCouponRecord result = couponRecordService.getOne(queryWrapper);
|
||||
@ -53,7 +53,6 @@ public class CouponRecordController {
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用户领券功能
|
||||
* 1、查询优惠券是否真实存在
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.youlai.mall.sms.controller.app;
|
||||
|
||||
import com.youlai.common.result.Result;
|
||||
import com.youlai.common.web.util.MemberUtils;
|
||||
import com.youlai.mall.sms.util.BeanMapperUtils;
|
||||
import com.youlai.common.web.util.JwtUtils;
|
||||
import com.youlai.mall.sms.pojo.domain.SmsCoupon;
|
||||
@ -40,7 +41,7 @@ public class AppCouponController {
|
||||
@ApiOperation("查看可领取优惠券模板列表")
|
||||
@GetMapping("/template")
|
||||
public Result<List<CouponTemplateVO>> findAvailableTemplate() {
|
||||
List<CouponTemplateVO> availableTemplate = couponService.findAvailableTemplate(JwtUtils.getUserId());
|
||||
List<CouponTemplateVO> availableTemplate = couponService.findAvailableTemplate(MemberUtils.getMemberId());
|
||||
return Result.success(availableTemplate);
|
||||
}
|
||||
|
||||
@ -48,7 +49,7 @@ public class AppCouponController {
|
||||
@GetMapping("/receive")
|
||||
public Result receive(@ApiParam(value = "优惠券模板ID")
|
||||
@RequestParam("templateId") String templateId) {
|
||||
couponService.receive(JwtUtils.getUserId(), templateId);
|
||||
couponService.receive(MemberUtils.getMemberId(), templateId);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@ -56,7 +57,7 @@ public class AppCouponController {
|
||||
@GetMapping("/list")
|
||||
public Result<List<SmsCouponVO>> list(@ApiParam(value = "优惠券模板ID", defaultValue = "1")
|
||||
@RequestParam(value = "state", required = false) Integer state) {
|
||||
List<SmsCoupon> coupons = couponService.findCouponsByState(JwtUtils.getUserId(), state);
|
||||
List<SmsCoupon> coupons = couponService.findCouponsByState(MemberUtils.getMemberId(), state);
|
||||
return Result.success(BeanMapperUtils.mapList(coupons, SmsCouponVO.class));
|
||||
}
|
||||
|
||||
|
@ -4,11 +4,13 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.youlai.common.web.exception.BizException;
|
||||
import com.youlai.common.web.util.JwtUtils;
|
||||
import com.youlai.common.web.util.MemberUtils;
|
||||
import com.youlai.mall.sms.mapper.SmsCouponRecordMapper;
|
||||
import com.youlai.mall.sms.pojo.domain.SmsCoupon;
|
||||
import com.youlai.mall.sms.pojo.domain.SmsCouponRecord;
|
||||
import com.youlai.mall.sms.service.ICouponRecordService;
|
||||
import com.youlai.mall.sms.service.ISmsCouponService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
@ -28,31 +30,27 @@ import static com.youlai.mall.sms.pojo.constant.AppConstants.COUPON_LOCK;
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class CouponRecordServiceImpl extends ServiceImpl<SmsCouponRecordMapper, SmsCouponRecord> implements ICouponRecordService {
|
||||
|
||||
@Autowired
|
||||
private ISmsCouponService couponService;
|
||||
|
||||
@Autowired
|
||||
private RedissonClient redissonClient;
|
||||
private final ISmsCouponService couponService;
|
||||
private final RedissonClient redissonClient;
|
||||
|
||||
@Override
|
||||
public void add(String couponId) {
|
||||
Long userId = JwtUtils.getUserId();
|
||||
Long memberId = MemberUtils.getMemberId();
|
||||
RLock lock = redissonClient.getLock(COUPON_LOCK + couponId);
|
||||
lock.lock();
|
||||
|
||||
try {
|
||||
SmsCoupon coupon = couponService.getById(couponId);
|
||||
this.couponCheck(coupon, userId);
|
||||
this.couponCheck(coupon, memberId);
|
||||
// 封装优惠券领取记录对象
|
||||
SmsCouponRecord couponRecord = new SmsCouponRecord();
|
||||
BeanUtils.copyProperties(coupon, couponRecord);
|
||||
couponRecord.setStartTime(new Date());
|
||||
// couponRecord.setEndTime(DateUtil.offsetDay(new Date(), coupon.getValidDays()));
|
||||
// couponRecord.setUseState(CouponStateEnum.NEW.name());
|
||||
couponRecord.setUserId(JwtUtils.getUserId());
|
||||
couponRecord.setUserName(JwtUtils.getUsername());
|
||||
couponRecord.setUserId(memberId);
|
||||
couponRecord.setUserName(MemberUtils.getUsername());
|
||||
couponRecord.setCouponId(coupon.getId());
|
||||
couponRecord.setId(null);
|
||||
|
||||
@ -63,7 +61,7 @@ public class CouponRecordServiceImpl extends ServiceImpl<SmsCouponRecordMapper,
|
||||
//库存扣减成功才保存
|
||||
this.save(couponRecord);
|
||||
} else {
|
||||
log.warn("发放优惠券失败,coupon={},loginUser={}", coupon, userId);
|
||||
log.warn("发放优惠券失败,coupon={},loginUser={}", coupon, memberId);
|
||||
throw new BizException("发放优惠券失败");
|
||||
}
|
||||
} finally {
|
||||
|
@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.youlai.common.web.exception.BizException;
|
||||
import com.youlai.common.web.util.MemberUtils;
|
||||
import com.youlai.mall.sms.util.BeanMapperUtils;
|
||||
import com.youlai.common.web.util.JwtUtils;
|
||||
import com.youlai.mall.sms.mapper.SmsCouponMapper;
|
||||
@ -195,8 +196,8 @@ public class SmsCouponServiceImpl extends ServiceImpl<SmsCouponMapper, SmsCoupon
|
||||
SmsCoupon coupon = new SmsCoupon();
|
||||
coupon.setTemplateId(template.getId());
|
||||
coupon.setCouponCode(couponCode);
|
||||
coupon.setUserId(JwtUtils.getUserId());
|
||||
coupon.setUserName(JwtUtils.getUsername());
|
||||
coupon.setUserId(MemberUtils.getMemberId());
|
||||
coupon.setUserName(MemberUtils.getUsername());
|
||||
coupon.setState(CouponStateEnum.USABLE);
|
||||
CouponTemplateRule.Expiration expiration = template.getRule().getExpiration();
|
||||
if (expiration.getPeriod() == 1) {
|
||||
|
@ -1,32 +1,28 @@
|
||||
package com.youlai.mall.ums.api;
|
||||
|
||||
import com.youlai.common.result.Result;
|
||||
import com.youlai.mall.ums.pojo.entity.UmsAddress;
|
||||
import com.youlai.mall.ums.dto.MemberAddressDTO;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(name = "mall-ums",contextId = "address")
|
||||
/**
|
||||
* 会员地址 Feign 客户端
|
||||
*
|
||||
* @author haoxr
|
||||
* @date 2022/2/12
|
||||
*/
|
||||
@FeignClient(name = "mall-ums", contextId = "address")
|
||||
public interface MemberAddressFeignClient {
|
||||
|
||||
/**
|
||||
* 获取地址详情
|
||||
*/
|
||||
@GetMapping("/app-api/v1/addresses/{id}")
|
||||
Result<UmsAddress> getById(@PathVariable("id") Long id);
|
||||
|
||||
|
||||
/**
|
||||
* 获取会员地址列表
|
||||
* 获取当前会员地址列表
|
||||
*
|
||||
* @param memberId
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/app-api/v1/addresses")
|
||||
Result<List<UmsAddress>> list(@RequestParam Long memberId);
|
||||
Result<List<MemberAddressDTO>> listCurrMemberAddresses();
|
||||
|
||||
}
|
||||
|
||||
|
@ -2,33 +2,30 @@ package com.youlai.mall.ums.api;
|
||||
|
||||
import com.youlai.common.result.Result;
|
||||
import com.youlai.mall.pms.pojo.vo.ProductHistoryVO;
|
||||
import com.youlai.mall.ums.pojo.dto.MemberAuthDTO;
|
||||
import com.youlai.mall.ums.pojo.dto.MemberDTO;
|
||||
import com.youlai.mall.ums.pojo.entity.UmsMember;
|
||||
import com.youlai.mall.ums.dto.MemberAuthInfoDTO;
|
||||
import com.youlai.mall.ums.dto.MemberDTO;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@FeignClient(name = "mall-ums", contextId = "member")
|
||||
public interface MemberFeignClient {
|
||||
|
||||
/**
|
||||
* 新增会员
|
||||
*
|
||||
* @param member
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/app-api/v1/members")
|
||||
Result<Long> add(@RequestBody UmsMember member);
|
||||
|
||||
@PutMapping("/app-api/v1/members/{id}")
|
||||
<T> Result<T> update(@PathVariable Long id, @RequestBody UmsMember member);
|
||||
Result<Long> addMember(@RequestBody MemberDTO member);
|
||||
|
||||
/**
|
||||
* 获取会员信息
|
||||
* 获取会员的 openid
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/app-api/v1/members/{id}")
|
||||
Result<MemberDTO> getUserById(@PathVariable Long id);
|
||||
|
||||
/**
|
||||
* 获取会员信息
|
||||
*/
|
||||
@GetMapping("/app-api/v1/members/detail/{id}")
|
||||
Result<UmsMember> getUserEntityById(@PathVariable Long id);
|
||||
|
||||
@PostMapping("/app-api/v1/members/{memberId}/openid")
|
||||
Result<String> getMemberOpenId(@PathVariable Long memberId);
|
||||
|
||||
/**
|
||||
* 扣减会员余额
|
||||
@ -50,8 +47,7 @@ public interface MemberFeignClient {
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/app-api/v1/members/openid/{openid}")
|
||||
Result<MemberAuthDTO> loadUserByOpenId(@PathVariable String openid);
|
||||
|
||||
Result<MemberAuthInfoDTO> loadUserByOpenId(@PathVariable String openid);
|
||||
|
||||
/**
|
||||
* 根据手机号获取会员认证信息
|
||||
@ -60,8 +56,7 @@ public interface MemberFeignClient {
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/app-api/v1/members/mobile/{mobile}")
|
||||
Result<MemberAuthDTO> loadUserByMobile(@PathVariable String mobile);
|
||||
|
||||
Result<MemberAuthInfoDTO> loadUserByMobile(@PathVariable String mobile);
|
||||
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,47 @@
|
||||
package com.youlai.mall.ums.dto;
|
||||
|
||||
import com.youlai.common.constraint.CheckCityValid;
|
||||
import com.youlai.common.constraint.CityType;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Positive;
|
||||
|
||||
/**
|
||||
* 会员地址传输层对象
|
||||
*
|
||||
* @author <a href="mailto:xianrui0365@163.com">haoxr</a>
|
||||
* @date 2022/2/12 15:57
|
||||
*/
|
||||
@Data
|
||||
public class MemberAddressDTO {
|
||||
|
||||
@NotNull(message = "{id.positive}")
|
||||
@Positive(message = "{id.positive}")
|
||||
private Long memberId;
|
||||
|
||||
private String consigneeName;
|
||||
|
||||
@Pattern(regexp = "^1(3\\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\\d|9[0-35-9])\\d{8}$", message = "{phone.valid}")
|
||||
private String consigneeMobile;
|
||||
|
||||
@CheckCityValid(CityType.PROVINCE)
|
||||
private String province;
|
||||
|
||||
@CheckCityValid(CityType.CITY)
|
||||
private String city;
|
||||
|
||||
@CheckCityValid(CityType.AREA)
|
||||
private String area;
|
||||
|
||||
@Length(min = 1, max = 100, message = "{text.length.min},{text.length.max}")
|
||||
private String detailAddress;
|
||||
|
||||
private Integer defaulted;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,30 @@
|
||||
package com.youlai.mall.ums.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 会员认证传输层对象
|
||||
*
|
||||
* @author haoxr
|
||||
* @date 2022/2/12
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class MemberAuthInfoDTO {
|
||||
|
||||
/**
|
||||
* 会员ID
|
||||
*/
|
||||
private Long memberId;
|
||||
|
||||
/**
|
||||
* 会员名(openId、mobile)
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 状态(1:正常;0:禁用)
|
||||
*/
|
||||
private Integer status;
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.youlai.mall.ums.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
|
||||
/**
|
||||
* 会员传输层对象
|
||||
*
|
||||
* @author haoxr
|
||||
* @date 2022/2/12
|
||||
*/
|
||||
@Data
|
||||
public class MemberDTO {
|
||||
|
||||
private Integer gender;
|
||||
|
||||
private String nickName;
|
||||
|
||||
private String mobile;
|
||||
|
||||
private LocalDate birthday;
|
||||
|
||||
private String avatarUrl;
|
||||
|
||||
private String openid;
|
||||
|
||||
private String sessionKey;
|
||||
|
||||
private String city;
|
||||
|
||||
private String country;
|
||||
|
||||
private String language;
|
||||
|
||||
private String province;
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.youlai.mall.ums.pojo.dto;
|
||||
package com.youlai.mall.ums.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
@ -1,4 +1,4 @@
|
||||
package com.youlai.mall.ums.pojo.dto;
|
||||
package com.youlai.mall.ums.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
@ -1,13 +0,0 @@
|
||||
package com.youlai.mall.ums.pojo.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class MemberAuthDTO {
|
||||
|
||||
private Long userId;
|
||||
private String username;
|
||||
private Integer status;
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package com.youlai.mall.ums.pojo.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class MemberDTO {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String nickName;
|
||||
|
||||
private String avatarUrl;
|
||||
|
||||
private String mobile;
|
||||
|
||||
private Long balance;
|
||||
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package com.youlai.mall.ums.pojo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.youlai.common.base.BaseEntity;
|
||||
import com.youlai.common.constraint.CheckCityValid;
|
||||
import com.youlai.common.constraint.CityType;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class UmsAddress extends BaseEntity {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
// @NotNull(message = "{id.positive}")
|
||||
// @Positive(message = "{id.positive}")
|
||||
private Long memberId;
|
||||
|
||||
@Length(min = 2, max = 8, message = "{text.length.min},{text.length.max}")
|
||||
private String name;
|
||||
|
||||
@Pattern(regexp = "^1(3\\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\\d|9[0-35-9])\\d{8}$", message = "{phone.valid}")
|
||||
private String mobile;
|
||||
|
||||
@CheckCityValid(CityType.PROVINCE)
|
||||
private String province;
|
||||
|
||||
@CheckCityValid(CityType.CITY)
|
||||
private String city;
|
||||
|
||||
@CheckCityValid(CityType.AREA)
|
||||
private String area;
|
||||
|
||||
@Length(min = 1, max = 100, message = "{text.length.min},{text.length.max}")
|
||||
private String address;
|
||||
|
||||
@Pattern(regexp = "^[0-9]{6}$", message = "{zipcode.valid}")
|
||||
private String zipCode;
|
||||
|
||||
private Integer defaulted;
|
||||
}
|
@ -13,6 +13,7 @@ import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@ -21,9 +22,9 @@ import java.util.List;
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/members")
|
||||
@RequiredArgsConstructor
|
||||
public class MemberController {
|
||||
public class UmsMemberController {
|
||||
|
||||
private final IUmsMemberService iUmsMemberService;
|
||||
private final IUmsMemberService memberService;
|
||||
|
||||
@ApiOperation(value = "会员分页列表")
|
||||
@GetMapping
|
||||
@ -32,7 +33,7 @@ public class MemberController {
|
||||
@ApiParam("每页数量") Long pageSize,
|
||||
@ApiParam("会员昵称") String nickName
|
||||
) {
|
||||
IPage<UmsMember> result = iUmsMemberService.list(new Page<>(pageNum, pageSize), nickName);
|
||||
IPage<UmsMember> result = memberService.list(new Page<>(pageNum, pageSize), nickName);
|
||||
return Result.success(result.getRecords(), result.getTotal());
|
||||
}
|
||||
|
||||
@ -42,7 +43,7 @@ public class MemberController {
|
||||
public Result<UmsMember> getMemberDetail(
|
||||
@ApiParam("会员ID") @PathVariable Long id
|
||||
) {
|
||||
UmsMember user = iUmsMemberService.getById(id);
|
||||
UmsMember user = memberService.getById(id);
|
||||
return Result.success(user);
|
||||
}
|
||||
|
||||
@ -52,7 +53,7 @@ public class MemberController {
|
||||
@ApiParam("会员ID") @PathVariable Long id,
|
||||
@RequestBody UmsMember member
|
||||
) {
|
||||
boolean status = iUmsMemberService.updateById(member);
|
||||
boolean status = memberService.updateById(member);
|
||||
return Result.judge(status);
|
||||
}
|
||||
|
||||
@ -62,7 +63,7 @@ public class MemberController {
|
||||
@ApiParam("会员ID") @PathVariable Long id,
|
||||
@RequestBody UmsMember member
|
||||
) {
|
||||
boolean status = iUmsMemberService.update(new LambdaUpdateWrapper<UmsMember>()
|
||||
boolean status = memberService.update(new LambdaUpdateWrapper<UmsMember>()
|
||||
.eq(UmsMember::getId, id)
|
||||
.set(member.getStatus() != null, UmsMember::getStatus, member.getStatus())
|
||||
);
|
||||
@ -74,7 +75,7 @@ public class MemberController {
|
||||
public <T> Result<T> delete(
|
||||
@ApiParam("会员ID,多个以英文逗号(,)拼接") @PathVariable String ids
|
||||
) {
|
||||
boolean status = iUmsMemberService.update(new LambdaUpdateWrapper<UmsMember>()
|
||||
boolean status = memberService.update(new LambdaUpdateWrapper<UmsMember>()
|
||||
.in(UmsMember::getId, Arrays.asList(ids.split(",")))
|
||||
.set(UmsMember::getDeleted, GlobalConstants.STATUS_YES));
|
||||
return Result.judge(status);
|
@ -2,7 +2,8 @@ package com.youlai.mall.ums.controller.app;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.youlai.common.result.Result;
|
||||
import com.youlai.common.web.util.JwtUtils;
|
||||
import com.youlai.common.web.util.MemberUtils;
|
||||
import com.youlai.mall.ums.dto.MemberAddressDTO;
|
||||
import com.youlai.mall.ums.pojo.entity.UmsAddress;
|
||||
import com.youlai.mall.ums.service.IUmsAddressService;
|
||||
import io.swagger.annotations.Api;
|
||||
@ -21,22 +22,21 @@ import java.util.List;
|
||||
@RequiredArgsConstructor
|
||||
public class AddressController {
|
||||
|
||||
private final IUmsAddressService iUmsAddressService;
|
||||
private final IUmsAddressService addressService;
|
||||
|
||||
@ApiOperation(value = "获取会员地址列表")
|
||||
@ApiOperation(value = "获取当前会员地址列表")
|
||||
@GetMapping
|
||||
public Result<List<UmsAddress>> listAddresses() {
|
||||
List<UmsAddress> addressList = iUmsAddressService.list(new LambdaQueryWrapper<UmsAddress>()
|
||||
.eq(UmsAddress::getMemberId, JwtUtils.getUserId())
|
||||
.orderByDesc(UmsAddress::getDefaulted));
|
||||
public Result<List<MemberAddressDTO>> listCurrentMemberAddresses() {
|
||||
List<MemberAddressDTO> addressList = addressService.listCurrentMemberAddresses();
|
||||
return Result.success(addressList);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取地址详情")
|
||||
@GetMapping("/{addressId}")
|
||||
public Result<UmsAddress> getAddressDetail(
|
||||
@ApiParam("会员地址ID") @PathVariable Long addressId
|
||||
@ApiParam("地址ID") @PathVariable Long addressId
|
||||
) {
|
||||
UmsAddress umsAddress = iUmsAddressService.getById(addressId);
|
||||
UmsAddress umsAddress = addressService.getById(addressId);
|
||||
return Result.success(umsAddress);
|
||||
}
|
||||
|
||||
@ -45,18 +45,17 @@ public class AddressController {
|
||||
public Result addAddress(
|
||||
@RequestBody @Validated UmsAddress address
|
||||
) {
|
||||
boolean result = iUmsAddressService.addAddress(address);
|
||||
boolean result = addressService.addAddress(address);
|
||||
return Result.judge(result);
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation(value = "修改地址")
|
||||
@PutMapping("/{addressId}")
|
||||
public Result updateAddress(
|
||||
@ApiParam(value = "地址ID") @PathVariable Long addressId,
|
||||
@RequestBody @Validated UmsAddress address
|
||||
) {
|
||||
boolean result = iUmsAddressService.updateAddress(address);
|
||||
boolean result = addressService.updateAddress(address);
|
||||
return Result.judge(result);
|
||||
}
|
||||
|
||||
@ -65,7 +64,7 @@ public class AddressController {
|
||||
public Result deleteAddress(
|
||||
@ApiParam("地址ID,过个以英文逗号(,)分割") @PathVariable String ids
|
||||
) {
|
||||
boolean status = iUmsAddressService.removeByIds(Arrays.asList(ids.split(",")));
|
||||
boolean status = addressService.removeByIds(Arrays.asList(ids.split(",")));
|
||||
return Result.judge(status);
|
||||
}
|
||||
|
||||
|
@ -1,19 +1,18 @@
|
||||
package com.youlai.mall.ums.controller.app;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.youlai.common.result.Result;
|
||||
import com.youlai.common.result.ResultCode;
|
||||
import com.youlai.common.web.util.JwtUtils;
|
||||
import com.youlai.common.web.util.MemberUtils;
|
||||
import com.youlai.mall.pms.pojo.vo.ProductHistoryVO;
|
||||
import com.youlai.mall.ums.pojo.dto.MemberAuthDTO;
|
||||
import com.youlai.mall.ums.dto.MemberAuthInfoDTO;
|
||||
import com.youlai.mall.ums.dto.MemberDTO;
|
||||
import com.youlai.mall.ums.pojo.entity.UmsMember;
|
||||
import com.youlai.mall.ums.pojo.dto.MemberDTO;
|
||||
import com.youlai.mall.ums.pojo.vo.MemberVO;
|
||||
import com.youlai.mall.ums.service.IUmsMemberService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@ -21,90 +20,46 @@ import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
@Api(tags = "「移动端」会员管理")
|
||||
@RestController
|
||||
@RequestMapping("/app-api/v1/members")
|
||||
@RestController("appMemberController")
|
||||
@RequiredArgsConstructor
|
||||
public class MemberController {
|
||||
|
||||
private final IUmsMemberService iUmsMemberService;
|
||||
private final IUmsMemberService memberService;
|
||||
|
||||
@ApiOperation(value = "获取会员信息")
|
||||
@ApiImplicitParam(name = "id", value = "会员ID", required = true, paramType = "path", dataType = "Long")
|
||||
@GetMapping("/{id}")
|
||||
public Result<MemberDTO> getById(@PathVariable Long id) {
|
||||
MemberDTO memberDTO = new MemberDTO();
|
||||
UmsMember user = iUmsMemberService.getOne(
|
||||
new LambdaQueryWrapper<UmsMember>()
|
||||
.select(UmsMember::getId, UmsMember::getNickName, UmsMember::getMobile, UmsMember::getBalance)
|
||||
.eq(UmsMember::getId, id)
|
||||
);
|
||||
if (user != null) {
|
||||
BeanUtil.copyProperties(user, memberDTO);
|
||||
}
|
||||
return Result.success(memberDTO);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取会员实体信息")
|
||||
@ApiImplicitParam(name = "id", value = "会员ID", required = true, paramType = "path", dataType = "Long")
|
||||
@GetMapping("/detail/{id}")
|
||||
public Result<UmsMember> getMemberEntityById(
|
||||
@PathVariable Long id
|
||||
@ApiOperation(value = "根据会员的openid")
|
||||
@GetMapping("/{memberId}/openid")
|
||||
public Result<String> getMemberById(
|
||||
@ApiParam("会员ID") @PathVariable Long memberId
|
||||
) {
|
||||
UmsMember user = iUmsMemberService.getById(id);
|
||||
if (user == null) {
|
||||
return Result.failed(ResultCode.USER_NOT_EXIST);
|
||||
}
|
||||
return Result.success(user);
|
||||
UmsMember member = memberService.getOne(
|
||||
new LambdaQueryWrapper<UmsMember>()
|
||||
.eq(UmsMember::getId,memberId)
|
||||
.select(UmsMember::getOpenid)
|
||||
);
|
||||
String openid = member.getOpenid();
|
||||
return Result.success(openid);
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation(value = "新增会员")
|
||||
@ApiImplicitParam(name = "member", value = "实体JSON对象", required = true, paramType = "body", dataType = "UmsMember")
|
||||
@PostMapping
|
||||
public Result<Long> add(@RequestBody UmsMember member) {
|
||||
boolean status = iUmsMemberService.save(member);
|
||||
if (status) {
|
||||
return Result.success(member.getId());
|
||||
} else {
|
||||
return Result.failed();
|
||||
}
|
||||
}
|
||||
|
||||
@ApiOperation(value = "修改会员")
|
||||
@PutMapping("/{id}")
|
||||
public <T> Result<T> add(@PathVariable Long id, @RequestBody UmsMember user) {
|
||||
boolean status = iUmsMemberService.updateById(user);
|
||||
return Result.judge(status);
|
||||
public Result<Long> addMember(@RequestBody MemberDTO member) {
|
||||
Long memberId = memberService.addMember(member);
|
||||
return Result.success(memberId);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取登录会员信息")
|
||||
@GetMapping("/me")
|
||||
public Result<MemberDTO> getMemberInfo() {
|
||||
Long userId = JwtUtils.getUserId();
|
||||
UmsMember member = iUmsMemberService.getById(userId);
|
||||
if (member == null) {
|
||||
return Result.failed(ResultCode.USER_NOT_EXIST);
|
||||
}
|
||||
MemberDTO memberDTO = new MemberDTO();
|
||||
BeanUtil.copyProperties(member, memberDTO);
|
||||
return Result.success(memberDTO);
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation(value = "修改会员积分")
|
||||
@PutMapping("/{id}/points")
|
||||
public <T> Result<T> updatePoint(@PathVariable Long id, @RequestParam Integer num) {
|
||||
UmsMember user = iUmsMemberService.getById(id);
|
||||
user.setPoint(user.getPoint() + num);
|
||||
boolean result = iUmsMemberService.updateById(user);
|
||||
return Result.judge(result);
|
||||
public Result<MemberVO> getCurrentMemberInfo() {
|
||||
MemberVO memberVO = memberService.getCurrentMemberInfo();
|
||||
return Result.success(memberVO);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "扣减会员余额")
|
||||
@PutMapping("/current/balances/_deduct")
|
||||
public <T> Result<T> deductBalance(@RequestParam Long balances) {
|
||||
Long userId = JwtUtils.getUserId();
|
||||
boolean result = iUmsMemberService.update(new LambdaUpdateWrapper<UmsMember>()
|
||||
Long userId = MemberUtils.getMemberId();
|
||||
boolean result = memberService.update(new LambdaUpdateWrapper<UmsMember>()
|
||||
.setSql("balance = balance - " + balances)
|
||||
.eq(UmsMember::getId, userId)
|
||||
);
|
||||
@ -114,8 +69,8 @@ public class MemberController {
|
||||
@ApiOperation(value = "添加浏览历史")
|
||||
@PostMapping("/view/history")
|
||||
public <T> Result<T> addProductViewHistory(@RequestBody ProductHistoryVO product) {
|
||||
Long userId = JwtUtils.getUserId();
|
||||
iUmsMemberService.addProductViewHistory(product, userId);
|
||||
Long memberId = MemberUtils.getMemberId();
|
||||
memberService.addProductViewHistory(product, memberId);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@ -123,42 +78,35 @@ public class MemberController {
|
||||
@GetMapping("/view/history")
|
||||
public Result<Set<ProductHistoryVO>> getProductViewHistory() {
|
||||
try {
|
||||
Long userId = JwtUtils.getUserId();
|
||||
Set<ProductHistoryVO> historyList = iUmsMemberService.getProductViewHistory(userId);
|
||||
Long memberId = MemberUtils.getMemberId();
|
||||
Set<ProductHistoryVO> historyList = memberService.getProductViewHistory(memberId);
|
||||
return Result.success(historyList);
|
||||
} catch (Exception e) {
|
||||
return Result.success(Collections.emptySet());
|
||||
}
|
||||
}
|
||||
|
||||
@ApiOperation(value = "根据openid获取会员认证信息")
|
||||
@ApiImplicitParam(name = "openid", value = "微信身份唯一标识", required = true, paramType = "path", dataType = "String")
|
||||
@ApiOperation(value = "根据 openid 获取会员认证信息")
|
||||
@GetMapping("/openid/{openid}")
|
||||
public Result<MemberAuthDTO> getByOpenid(@PathVariable String openid) {
|
||||
UmsMember member = iUmsMemberService.getOne(new LambdaQueryWrapper<UmsMember>()
|
||||
.eq(UmsMember::getOpenid, openid)
|
||||
.select(UmsMember::getId, UmsMember::getOpenid, UmsMember::getStatus)
|
||||
);
|
||||
if (member == null) {
|
||||
return Result.failed(ResultCode.USER_NOT_EXIST);
|
||||
}
|
||||
MemberAuthDTO memberAuth = new MemberAuthDTO(member.getId(), member.getOpenid(), member.getStatus());
|
||||
return Result.success(memberAuth);
|
||||
public Result<MemberAuthInfoDTO> getByOpenid(
|
||||
@ApiParam("微信身份标识") @PathVariable String openid
|
||||
) {
|
||||
MemberAuthInfoDTO memberAuthInfo = memberService.getByOpenid(openid);
|
||||
return Result.success(memberAuthInfo);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "根据手机号获取会员认证信息")
|
||||
@ApiImplicitParam(name = "mobile", value = "会员手机号码", required = true, paramType = "path", dataType = "String")
|
||||
/**
|
||||
* 根据手机号获取会员认证信息
|
||||
*
|
||||
* @param mobile
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/mobile/{mobile}")
|
||||
public Result<MemberAuthDTO> getByMobile(@PathVariable String mobile) {
|
||||
UmsMember member = iUmsMemberService.getOne(new LambdaQueryWrapper<UmsMember>()
|
||||
.eq(UmsMember::getMobile, mobile)
|
||||
.select(UmsMember::getId, UmsMember::getMobile, UmsMember::getStatus)
|
||||
);
|
||||
if (member == null) {
|
||||
return Result.failed(ResultCode.USER_NOT_EXIST);
|
||||
}
|
||||
MemberAuthDTO memberAuth = new MemberAuthDTO(member.getId(), member.getMobile(), member.getStatus());
|
||||
return Result.success(memberAuth);
|
||||
public Result<MemberAuthInfoDTO> getByMobile(
|
||||
@ApiParam("手机号码") @PathVariable String mobile
|
||||
) {
|
||||
MemberAuthInfoDTO memberAuthInfo = memberService.getByMobile(mobile);
|
||||
return Result.success(memberAuthInfo);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import java.util.List;
|
||||
|
||||
|
||||
@Mapper
|
||||
public interface UmsUserMapper extends BaseMapper<UmsMember> {
|
||||
public interface UmsMemberMapper extends BaseMapper<UmsMember> {
|
||||
|
||||
@Select("<script>" +
|
||||
" SELECT * from ums_member " +
|
@ -0,0 +1,63 @@
|
||||
package com.youlai.mall.ums.pojo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.youlai.common.base.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:xianrui0365@163.com">haoxr</a>
|
||||
* @date 2022/2/12 16:12
|
||||
*/
|
||||
@Data
|
||||
public class UmsAddress extends BaseEntity {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 会员ID
|
||||
*/
|
||||
private Long memberId;
|
||||
|
||||
/**
|
||||
* 收货人姓名
|
||||
*/
|
||||
private String consigneeName;
|
||||
|
||||
/**
|
||||
* 收货人联系方式
|
||||
*/
|
||||
private String consigneeMobile;
|
||||
|
||||
/**
|
||||
* 省
|
||||
*/
|
||||
private String province;
|
||||
|
||||
/**
|
||||
* 市
|
||||
*/
|
||||
private String city;
|
||||
|
||||
/**
|
||||
* 区
|
||||
*/
|
||||
private String area;
|
||||
|
||||
/**
|
||||
* 详细地址
|
||||
*/
|
||||
private String detailAddress;
|
||||
|
||||
/**
|
||||
* 邮编
|
||||
*/
|
||||
private String zipCode;
|
||||
|
||||
/**
|
||||
* 是否默认地址(1:是;0:否)
|
||||
*/
|
||||
private Integer defaulted;
|
||||
|
||||
}
|
@ -1,17 +1,19 @@
|
||||
package com.youlai.mall.ums.pojo.entity;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.youlai.common.base.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:xianrui0365@163.com">haoxr</a>
|
||||
* @date 2022/2/12 16:15
|
||||
*/
|
||||
@Data
|
||||
public class UmsMember extends BaseEntity {
|
||||
|
||||
@ -32,18 +34,6 @@ public class UmsMember extends BaseEntity {
|
||||
|
||||
private String sessionKey;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private Integer point;
|
||||
|
||||
@TableLogic(delval = "1",value = "0")
|
||||
private Integer deleted;
|
||||
|
||||
@TableField(exist = false)
|
||||
private List<UmsAddress> addressList;
|
||||
|
||||
private Long balance;
|
||||
|
||||
private String city;
|
||||
|
||||
private String country;
|
||||
@ -52,4 +42,16 @@ public class UmsMember extends BaseEntity {
|
||||
|
||||
private String province;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private Long balance;
|
||||
|
||||
@TableLogic(delval = "1", value = "0")
|
||||
private Integer deleted;
|
||||
|
||||
@TableField(exist = false)
|
||||
private List<UmsAddress> addressList;
|
||||
|
||||
private Integer point;
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.youlai.mall.ums.pojo.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 会员视图层对象
|
||||
*
|
||||
* @author <a href="mailto:xianrui0365@163.com">haoxr</a>
|
||||
* @date 2022/2/12 21:13
|
||||
*/
|
||||
@ApiModel("会员视图层对象")
|
||||
@Data
|
||||
public class MemberVO {
|
||||
|
||||
@ApiModelProperty("会员ID")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty("会员昵称")
|
||||
private String nickName;
|
||||
|
||||
@ApiModelProperty("会员头像地址")
|
||||
private String avatarUrl;
|
||||
|
||||
@ApiModelProperty("会员手机号")
|
||||
private String mobile;
|
||||
|
||||
@ApiModelProperty("会员余额(单位:分)")
|
||||
private Long balance;
|
||||
|
||||
}
|
@ -2,8 +2,17 @@ package com.youlai.mall.ums.service;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.youlai.mall.ums.dto.MemberAddressDTO;
|
||||
import com.youlai.mall.ums.pojo.entity.UmsAddress;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 会员地址业务接口
|
||||
*
|
||||
* @author haoxr
|
||||
* @date 2022/2/12
|
||||
*/
|
||||
public interface IUmsAddressService extends IService<UmsAddress> {
|
||||
|
||||
/**
|
||||
@ -22,5 +31,10 @@ public interface IUmsAddressService extends IService<UmsAddress> {
|
||||
*/
|
||||
boolean updateAddress(UmsAddress address);
|
||||
|
||||
|
||||
/**
|
||||
* 获取当前登录会员的地址列表
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<MemberAddressDTO> listCurrentMemberAddresses();
|
||||
}
|
||||
|
@ -5,10 +5,19 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.youlai.mall.pms.pojo.vo.ProductHistoryVO;
|
||||
import com.youlai.mall.ums.dto.MemberAuthInfoDTO;
|
||||
import com.youlai.mall.ums.dto.MemberDTO;
|
||||
import com.youlai.mall.ums.pojo.entity.UmsMember;
|
||||
import com.youlai.mall.ums.pojo.vo.MemberVO;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 会员业务接口
|
||||
*
|
||||
* @author haoxr
|
||||
* @date 2022/2/12
|
||||
*/
|
||||
public interface IUmsMemberService extends IService<UmsMember> {
|
||||
|
||||
IPage<UmsMember> list(Page<UmsMember> page, String nickname);
|
||||
@ -16,4 +25,35 @@ public interface IUmsMemberService extends IService<UmsMember> {
|
||||
void addProductViewHistory(ProductHistoryVO product, Long userId);
|
||||
|
||||
Set<ProductHistoryVO> getProductViewHistory(Long userId);
|
||||
|
||||
/**
|
||||
* 根据 openid 获取会员认证信息
|
||||
*
|
||||
* @param openid
|
||||
* @return
|
||||
*/
|
||||
MemberAuthInfoDTO getByOpenid(String openid);
|
||||
|
||||
/**
|
||||
* 根据手机号获取会员认证信息
|
||||
*
|
||||
* @param mobile
|
||||
* @return
|
||||
*/
|
||||
MemberAuthInfoDTO getByMobile(String mobile);
|
||||
|
||||
/**
|
||||
* 新增会员
|
||||
*
|
||||
* @param member
|
||||
* @return
|
||||
*/
|
||||
Long addMember(MemberDTO member);
|
||||
|
||||
/**
|
||||
* 获取登录会员信息
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
MemberVO getCurrentMemberInfo();
|
||||
}
|
||||
|
@ -1,18 +1,32 @@
|
||||
package com.youlai.mall.ums.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.youlai.common.constant.GlobalConstants;
|
||||
import com.youlai.common.web.util.JwtUtils;
|
||||
import com.youlai.common.web.util.MemberUtils;
|
||||
import com.youlai.mall.ums.dto.MemberAddressDTO;
|
||||
import com.youlai.mall.ums.mapper.UmsAddressMapper;
|
||||
import com.youlai.mall.ums.pojo.entity.UmsAddress;
|
||||
import com.youlai.mall.ums.service.IUmsAddressService;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 会员地址业务实现类
|
||||
*
|
||||
* @author haoxr
|
||||
* @date 2022/2/12
|
||||
*/
|
||||
@Service
|
||||
public class UmsAddressServiceImpl extends ServiceImpl<UmsAddressMapper, UmsAddress> implements IUmsAddressService {
|
||||
|
||||
|
||||
/**
|
||||
* 添加地址
|
||||
*
|
||||
@ -21,7 +35,7 @@ public class UmsAddressServiceImpl extends ServiceImpl<UmsAddressMapper, UmsAddr
|
||||
*/
|
||||
@Override
|
||||
public boolean addAddress(UmsAddress address) {
|
||||
Long memberId = JwtUtils.getUserId();
|
||||
Long memberId = MemberUtils.getMemberId();
|
||||
address.setMemberId(memberId);
|
||||
if (GlobalConstants.STATUS_YES.equals(address.getDefaulted())) { // 修改其他默认地址为非默认
|
||||
this.update(new LambdaUpdateWrapper<UmsAddress>()
|
||||
@ -33,7 +47,6 @@ public class UmsAddressServiceImpl extends ServiceImpl<UmsAddressMapper, UmsAddr
|
||||
return this.save(address);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 修改地址
|
||||
*
|
||||
@ -42,11 +55,11 @@ public class UmsAddressServiceImpl extends ServiceImpl<UmsAddressMapper, UmsAddr
|
||||
*/
|
||||
@Override
|
||||
public boolean updateAddress(UmsAddress address) {
|
||||
Long loginUserId = JwtUtils.getUserId();
|
||||
Long memberId = MemberUtils.getMemberId();
|
||||
// 修改其他默认地址为非默认
|
||||
if (GlobalConstants.STATUS_YES.equals(address.getDefaulted())) {
|
||||
this.update(new LambdaUpdateWrapper<UmsAddress>()
|
||||
.eq(UmsAddress::getMemberId, loginUserId)
|
||||
.eq(UmsAddress::getMemberId, memberId)
|
||||
.eq(UmsAddress::getDefaulted, 1)
|
||||
.set(UmsAddress::getDefaulted, 0)
|
||||
);
|
||||
@ -54,4 +67,24 @@ public class UmsAddressServiceImpl extends ServiceImpl<UmsAddressMapper, UmsAddr
|
||||
return this.updateById(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录会员的地址列表
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public List<MemberAddressDTO> listCurrentMemberAddresses() {
|
||||
Long memberId = MemberUtils.getMemberId();
|
||||
List<UmsAddress> umsAddressList = this.list(new LambdaQueryWrapper<UmsAddress>()
|
||||
.eq(UmsAddress::getMemberId, memberId)
|
||||
.orderByDesc(UmsAddress::getDefaulted) // 默认地址排在首位
|
||||
);
|
||||
List<MemberAddressDTO> memberAddressList = Optional.ofNullable(umsAddressList).orElse(new ArrayList<>()).stream()
|
||||
.map(umsAddress -> {
|
||||
MemberAddressDTO memberAddressDTO = new MemberAddressDTO();
|
||||
BeanUtil.copyProperties(umsAddress, memberAddressDTO);
|
||||
return memberAddressDTO;
|
||||
}).collect(Collectors.toList());
|
||||
return memberAddressList;
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,20 @@
|
||||
package com.youlai.mall.ums.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.youlai.common.constant.GlobalConstants;
|
||||
import com.youlai.common.web.util.MemberUtils;
|
||||
import com.youlai.mall.pms.pojo.vo.ProductHistoryVO;
|
||||
import com.youlai.mall.ums.constant.UmsConstants;
|
||||
import com.youlai.mall.ums.dto.MemberAuthInfoDTO;
|
||||
import com.youlai.mall.ums.dto.MemberDTO;
|
||||
import com.youlai.mall.ums.mapper.UmsMemberMapper;
|
||||
import com.youlai.mall.ums.pojo.entity.UmsMember;
|
||||
import com.youlai.mall.ums.mapper.UmsUserMapper;
|
||||
import com.youlai.mall.ums.pojo.vo.MemberVO;
|
||||
import com.youlai.mall.ums.service.IUmsMemberService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
@ -15,9 +23,15 @@ import org.springframework.stereotype.Service;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 会员业务实现类
|
||||
*
|
||||
* @author haoxr
|
||||
* @date 2022/2/12
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class UmsMemberServiceImpl extends ServiceImpl<UmsUserMapper, UmsMember> implements IUmsMemberService {
|
||||
public class UmsMemberServiceImpl extends ServiceImpl<UmsMemberMapper, UmsMember> implements IUmsMemberService {
|
||||
|
||||
private final RedisTemplate redisTemplate;
|
||||
|
||||
@ -44,4 +58,91 @@ public class UmsMemberServiceImpl extends ServiceImpl<UmsUserMapper, UmsMember>
|
||||
public Set<ProductHistoryVO> getProductViewHistory(Long userId) {
|
||||
return redisTemplate.opsForZSet().reverseRange(UmsConstants.USER_PRODUCT_HISTORY + userId, 0, 9);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 openid 获取会员认证信息
|
||||
*
|
||||
* @param openid
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public MemberAuthInfoDTO getByOpenid(String openid) {
|
||||
UmsMember member = this.getOne(new LambdaQueryWrapper<UmsMember>()
|
||||
.eq(UmsMember::getOpenid, openid)
|
||||
.select(UmsMember::getId,
|
||||
UmsMember::getOpenid,
|
||||
UmsMember::getStatus
|
||||
)
|
||||
);
|
||||
Assert.isTrue(member != null, "会员不存在");
|
||||
|
||||
MemberAuthInfoDTO memberAuth = new MemberAuthInfoDTO()
|
||||
.setMemberId(member.getId())
|
||||
.setUsername(member.getOpenid())
|
||||
.setStatus(member.getStatus());
|
||||
return memberAuth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据手机号获取会员认证信息
|
||||
*
|
||||
* @param mobile
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public MemberAuthInfoDTO getByMobile(String mobile) {
|
||||
UmsMember member = this.getOne(new LambdaQueryWrapper<UmsMember>()
|
||||
.eq(UmsMember::getMobile, mobile)
|
||||
.select(UmsMember::getId,
|
||||
UmsMember::getOpenid,
|
||||
UmsMember::getStatus
|
||||
)
|
||||
);
|
||||
Assert.isTrue(member != null, "会员不存在");
|
||||
|
||||
MemberAuthInfoDTO memberAuth = new MemberAuthInfoDTO()
|
||||
.setMemberId(member.getId())
|
||||
.setUsername(member.getMobile())
|
||||
.setStatus(member.getStatus());
|
||||
return memberAuth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增会员
|
||||
*
|
||||
* @param memberDTO
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Long addMember(MemberDTO memberDTO) {
|
||||
UmsMember umsMember = new UmsMember();
|
||||
BeanUtil.copyProperties(memberDTO, umsMember);
|
||||
umsMember.setStatus(GlobalConstants.STATUS_YES);
|
||||
|
||||
boolean result = this.save(umsMember);
|
||||
Assert.isTrue(result, "新增会员失败");
|
||||
return umsMember.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录会员信息
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public MemberVO getCurrentMemberInfo() {
|
||||
Long memberId = MemberUtils.getMemberId();
|
||||
UmsMember umsMember = this.getOne(new LambdaQueryWrapper<UmsMember>()
|
||||
.eq(UmsMember::getId, memberId)
|
||||
.select(UmsMember::getId,
|
||||
UmsMember::getNickName,
|
||||
UmsMember::getAvatarUrl,
|
||||
UmsMember::getMobile,
|
||||
UmsMember::getBalance
|
||||
)
|
||||
);
|
||||
MemberVO memberVO = new MemberVO();
|
||||
BeanUtil.copyProperties(umsMember, memberVO);
|
||||
return memberVO;
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import com.youlai.admin.service.ISysRoleService;
|
||||
import com.youlai.common.constant.GlobalConstants;
|
||||
import com.youlai.common.result.Result;
|
||||
import com.youlai.common.web.util.JwtUtils;
|
||||
import com.youlai.common.web.util.UserUtils;
|
||||
import io.swagger.annotations.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
@ -41,7 +42,7 @@ public class RoleController {
|
||||
@ApiParam("每页数量") long pageSize,
|
||||
@ApiParam("角色名称") String name
|
||||
) {
|
||||
List<String> roles = JwtUtils.getRoles();
|
||||
List<String> roles = UserUtils.getRoles();
|
||||
boolean isRoot = roles.contains(GlobalConstants.ROOT_ROLE_CODE); // 判断是否是超级管理员
|
||||
LambdaQueryWrapper<SysRole> queryWrapper = new LambdaQueryWrapper<SysRole>()
|
||||
.like(StrUtil.isNotBlank(name), SysRole::getName, name)
|
||||
@ -56,7 +57,7 @@ public class RoleController {
|
||||
@ApiOperation(value = "角色列表")
|
||||
@GetMapping
|
||||
public Result getRoleList() {
|
||||
List<String> roles = JwtUtils.getRoles();
|
||||
List<String> roles = UserUtils.getRoles();
|
||||
boolean isRoot = roles.contains(GlobalConstants.ROOT_ROLE_CODE); // 判断是否是超级管理员
|
||||
List list = iSysRoleService.list(new LambdaQueryWrapper<SysRole>()
|
||||
.eq(SysRole::getStatus, GlobalConstants.STATUS_YES)
|
||||
@ -75,7 +76,6 @@ public class RoleController {
|
||||
return Result.success(role);
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation(value = "新增角色")
|
||||
@PostMapping
|
||||
public Result saveRole(@RequestBody SysRole role) {
|
||||
@ -113,9 +113,10 @@ public class RoleController {
|
||||
}
|
||||
|
||||
@ApiOperation(value = "删除角色")
|
||||
@ApiImplicitParam(name = "ids", value = "以,分割拼接字符串", required = true, dataType = "String")
|
||||
@DeleteMapping("/{ids}")
|
||||
public Result deleteRole(@PathVariable String ids) {
|
||||
public Result deleteRoles(
|
||||
@ApiParam("删除角色,多个以英文逗号(,)分割") @PathVariable String ids
|
||||
) {
|
||||
boolean result = iSysRoleService.delete(Arrays.asList(ids.split(",")).stream()
|
||||
.map(id -> Long.parseLong(id)).collect(Collectors.toList()));
|
||||
if (result) {
|
||||
|
@ -12,7 +12,7 @@ import com.youlai.admin.pojo.vo.user.UserPageVO;
|
||||
import com.youlai.admin.service.ISysPermissionService;
|
||||
import com.youlai.admin.service.ISysUserService;
|
||||
import com.youlai.common.result.Result;
|
||||
import com.youlai.common.web.util.JwtUtils;
|
||||
import com.youlai.common.web.util.UserUtils;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
@ -116,11 +116,11 @@ public class UserController {
|
||||
public Result<LoginUserVO> getCurrentUser() {
|
||||
LoginUserVO loginUserVO = new LoginUserVO();
|
||||
// 用户基本信息
|
||||
Long userId = JwtUtils.getUserId();
|
||||
Long userId = UserUtils.getUserId();
|
||||
SysUser user = iSysUserService.getById(userId);
|
||||
BeanUtil.copyProperties(user, loginUserVO);
|
||||
// 用户角色信息
|
||||
List<String> roles = JwtUtils.getRoles();
|
||||
List<String> roles = UserUtils.getRoles();
|
||||
loginUserVO.setRoles(roles);
|
||||
// 用户按钮权限信息
|
||||
List<String> perms = iSysPermissionService.listBtnPermByRoles(roles);
|
||||
|
@ -179,7 +179,7 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
|
||||
}
|
||||
} else if (principal instanceof MemberUserDetails) {
|
||||
MemberUserDetails memberUserDetails = (MemberUserDetails) principal;
|
||||
additionalInfo.put("userId", memberUserDetails.getUserId());
|
||||
additionalInfo.put("memberId", memberUserDetails.getMemberId());
|
||||
additionalInfo.put("username", memberUserDetails.getUsername());
|
||||
if (StrUtil.isNotBlank(memberUserDetails.getAuthenticationMethod())) {
|
||||
additionalInfo.put("authenticationMethod", memberUserDetails.getAuthenticationMethod());
|
||||
|
@ -1,10 +1,9 @@
|
||||
package com.youlai.auth.security.core.userdetails.member;
|
||||
|
||||
import com.youlai.common.constant.GlobalConstants;
|
||||
import com.youlai.mall.ums.pojo.dto.MemberAuthDTO;
|
||||
import com.youlai.mall.ums.dto.MemberAuthInfoDTO;
|
||||
import lombok.Data;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.Collection;
|
||||
@ -20,7 +19,7 @@ import java.util.HashSet;
|
||||
@Data
|
||||
public class MemberUserDetails implements UserDetails {
|
||||
|
||||
private Long userId;
|
||||
private Long memberId;
|
||||
private String username;
|
||||
private Boolean enabled;
|
||||
|
||||
@ -35,8 +34,8 @@ public class MemberUserDetails implements UserDetails {
|
||||
*
|
||||
* @param member 小程序会员用户认证信息
|
||||
*/
|
||||
public MemberUserDetails(MemberAuthDTO member) {
|
||||
this.setUserId(member.getUserId());
|
||||
public MemberUserDetails(MemberAuthInfoDTO member) {
|
||||
this.setMemberId(member.getMemberId());
|
||||
this.setUsername(member.getUsername());
|
||||
this.setEnabled(GlobalConstants.STATUS_YES.equals(member.getStatus()));
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import com.youlai.common.enums.AuthenticationMethodEnum;
|
||||
import com.youlai.common.result.Result;
|
||||
import com.youlai.common.result.ResultCode;
|
||||
import com.youlai.mall.ums.api.MemberFeignClient;
|
||||
import com.youlai.mall.ums.pojo.dto.MemberAuthDTO;
|
||||
import com.youlai.mall.ums.dto.MemberAuthInfoDTO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.authentication.AccountExpiredException;
|
||||
import org.springframework.security.authentication.DisabledException;
|
||||
@ -39,9 +39,9 @@ public class MemberUserDetailsServiceImpl implements UserDetailsService {
|
||||
*/
|
||||
public UserDetails loadUserByMobile(String mobile) {
|
||||
MemberUserDetails userDetails = null;
|
||||
Result<MemberAuthDTO> result = memberFeignClient.loadUserByMobile(mobile);
|
||||
Result<MemberAuthInfoDTO> result = memberFeignClient.loadUserByMobile(mobile);
|
||||
if (Result.isSuccess(result)) {
|
||||
MemberAuthDTO member = result.getData();
|
||||
MemberAuthInfoDTO member = result.getData();
|
||||
if (null != member) {
|
||||
userDetails = new MemberUserDetails(member);
|
||||
userDetails.setAuthenticationMethod(AuthenticationMethodEnum.MOBILE.getValue()); // 认证方式:OpenId
|
||||
@ -67,9 +67,9 @@ public class MemberUserDetailsServiceImpl implements UserDetailsService {
|
||||
*/
|
||||
public UserDetails loadUserByOpenId(String openId) {
|
||||
MemberUserDetails userDetails = null;
|
||||
Result<MemberAuthDTO> result = memberFeignClient.loadUserByOpenId(openId);
|
||||
Result<MemberAuthInfoDTO> result = memberFeignClient.loadUserByOpenId(openId);
|
||||
if (Result.isSuccess(result)) {
|
||||
MemberAuthDTO member = result.getData();
|
||||
MemberAuthInfoDTO member = result.getData();
|
||||
if (null != member) {
|
||||
userDetails = new MemberUserDetails(member);
|
||||
userDetails.setAuthenticationMethod(AuthenticationMethodEnum.OPENID.getValue()); // 认证方式:OpenId
|
||||
|
@ -5,12 +5,11 @@ import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.youlai.auth.security.core.userdetails.member.MemberUserDetailsServiceImpl;
|
||||
import com.youlai.common.constant.GlobalConstants;
|
||||
import com.youlai.common.result.Result;
|
||||
import com.youlai.common.result.ResultCode;
|
||||
import com.youlai.mall.ums.api.MemberFeignClient;
|
||||
import com.youlai.mall.ums.pojo.dto.MemberAuthDTO;
|
||||
import com.youlai.mall.ums.pojo.entity.UmsMember;
|
||||
import com.youlai.mall.ums.dto.MemberAuthInfoDTO;
|
||||
import com.youlai.mall.ums.dto.MemberDTO;
|
||||
import lombok.Data;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
@ -53,7 +52,7 @@ public class WechatAuthenticationProvider implements AuthenticationProvider {
|
||||
e.printStackTrace();
|
||||
}
|
||||
String openid = sessionInfo.getOpenid();
|
||||
Result<MemberAuthDTO> memberAuthResult = memberFeignClient.loadUserByOpenId(openid);
|
||||
Result<MemberAuthInfoDTO> memberAuthResult = memberFeignClient.loadUserByOpenId(openid);
|
||||
// 微信用户不存在,注册成为新会员
|
||||
if (memberAuthResult != null && ResultCode.USER_NOT_EXIST.getCode().equals(memberAuthResult.getCode())) {
|
||||
|
||||
@ -63,11 +62,10 @@ public class WechatAuthenticationProvider implements AuthenticationProvider {
|
||||
// 解密 encryptedData 获取用户信息
|
||||
WxMaUserInfo userInfo = wxMaService.getUserService().getUserInfo(sessionKey, encryptedData, iv);
|
||||
|
||||
UmsMember member = new UmsMember();
|
||||
BeanUtil.copyProperties(userInfo, member);
|
||||
member.setOpenid(openid);
|
||||
member.setStatus(GlobalConstants.STATUS_YES);
|
||||
memberFeignClient.add(member);
|
||||
MemberDTO memberDTO = new MemberDTO();
|
||||
BeanUtil.copyProperties(userInfo, memberDTO);
|
||||
memberDTO.setOpenid(openid);
|
||||
memberFeignClient.addMember(memberDTO);
|
||||
}
|
||||
UserDetails userDetails = ((MemberUserDetailsServiceImpl) userDetailsService).loadUserByOpenId(openid);
|
||||
WechatAuthenticationToken result = new WechatAuthenticationToken(userDetails, new HashSet<>());
|
||||
|
@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler;
|
||||
import com.youlai.common.constant.GlobalConstants;
|
||||
import com.youlai.common.mybatis.annotation.DataPermission;
|
||||
import com.youlai.common.web.util.JwtUtils;
|
||||
import com.youlai.common.web.util.UserUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.expression.*;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
||||
@ -38,7 +39,7 @@ public class DataPermissionHandlerImpl implements DataPermissionHandler {
|
||||
DataPermission annotation = method.getAnnotation(DataPermission.class);
|
||||
if (ObjectUtils.isNotEmpty(annotation) && (method.getName().equals(methodName) || (method.getName() + "_COUNT").equals(methodName))) {
|
||||
// 获取当前的用户角色
|
||||
List<String> roles = JwtUtils.getRoles();
|
||||
List<String> roles = UserUtils.getRoles();
|
||||
if (!roles.isEmpty() && roles.contains(GlobalConstants.ROOT_ROLE_CODE)) {
|
||||
// 如果是超级管理员则放行
|
||||
return where;
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.youlai.common.redis;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.config.Config;
|
||||
@ -37,7 +38,10 @@ public class RedissonConfig {
|
||||
singleServerConfig.setAddress("redis://" + host + ":" + port);
|
||||
singleServerConfig.setDatabase(database);
|
||||
singleServerConfig.setConnectionMinimumIdleSize(connectionMinimumIdleSize);
|
||||
singleServerConfig.setPassword(password);
|
||||
if(StrUtil.isNotBlank(password)){
|
||||
singleServerConfig.setPassword(password);
|
||||
}
|
||||
singleServerConfig.setConnectTimeout(10000);
|
||||
return Redisson.create(config);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.youlai.common.web.exception;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.youlai.common.result.Result;
|
||||
@ -21,6 +22,7 @@ import org.springframework.web.servlet.NoHandlerFoundException;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import javax.validation.ValidationException;
|
||||
import java.sql.SQLSyntaxErrorException;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@ -160,6 +162,17 @@ public class GlobalExceptionHandler {
|
||||
return Result.failed(e.getMessage());
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.FORBIDDEN)
|
||||
@ExceptionHandler(SQLSyntaxErrorException.class)
|
||||
public <T> Result<T> processSQLSyntaxErrorException(SQLSyntaxErrorException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
String errorMsg = e.getMessage();
|
||||
if (StrUtil.isNotBlank(errorMsg) && errorMsg.contains("denied to user")) {
|
||||
return Result.failed("数据库用户无操作权限,建议本地搭建数据库环境");
|
||||
} else {
|
||||
return Result.failed(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler(CompletionException.class)
|
||||
|
@ -33,65 +33,4 @@ public class JwtUtils {
|
||||
}
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JWT获取用户ID
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Long getUserId() {
|
||||
Long userId = null;
|
||||
JSONObject jwtPayload = getJwtPayload();
|
||||
if (jwtPayload != null) {
|
||||
userId = jwtPayload.getLong(SecurityConstants.USER_ID_KEY);
|
||||
}
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JWT获取用户ID
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Long getDeptId() {
|
||||
Long id = getJwtPayload().getLong("deptId");
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JWT获取获取用户名
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getUsername() {
|
||||
String username = getJwtPayload().getStr(SecurityConstants.USER_NAME_KEY);
|
||||
return username;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* JWT获取用户角色列表
|
||||
*
|
||||
* @return 角色列表
|
||||
*/
|
||||
public static List<String> getRoles() {
|
||||
List<String> roles;
|
||||
JSONObject payload = getJwtPayload();
|
||||
if (payload.containsKey(SecurityConstants.JWT_AUTHORITIES_KEY)) {
|
||||
roles = payload.getJSONArray(SecurityConstants.JWT_AUTHORITIES_KEY).toList(String.class);
|
||||
} else {
|
||||
roles = Collections.emptyList();
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否「超级管理员」
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static boolean isRoot() {
|
||||
List<String> roles = getRoles();
|
||||
return CollectionUtil.isNotEmpty(roles) && roles.contains("ROOT");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
package com.youlai.common.web.util;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.youlai.common.constant.SecurityConstants;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:xianrui0365@163.com">haoxr</a>
|
||||
* @date 2022/2/12 20:14
|
||||
*/
|
||||
public class MemberUtils {
|
||||
|
||||
/**
|
||||
* 获取当前登录会员的ID
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Long getMemberId() {
|
||||
Long memberId = null;
|
||||
JSONObject jwtPayload = JwtUtils.getJwtPayload();
|
||||
if (jwtPayload != null) {
|
||||
memberId = jwtPayload.getLong("memberId");
|
||||
}
|
||||
return memberId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JWT获取获取用户名
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getUsername() {
|
||||
String username = JwtUtils.getJwtPayload().getStr(SecurityConstants.USER_NAME_KEY);
|
||||
return username;
|
||||
}
|
||||
}
|
@ -19,7 +19,8 @@ import java.util.Base64;
|
||||
/**
|
||||
* 请求工具类
|
||||
*
|
||||
* @author xianrui
|
||||
* @author haoxr
|
||||
* @date 2022/2/12
|
||||
*/
|
||||
@Slf4j
|
||||
public class RequestUtils {
|
||||
@ -30,7 +31,6 @@ public class RequestUtils {
|
||||
return grantType;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取登录认证的客户端ID
|
||||
* <p>
|
||||
|
@ -0,0 +1,89 @@
|
||||
package com.youlai.common.web.util;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.youlai.common.constant.SecurityConstants;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* JWT工具类
|
||||
*
|
||||
* @author haoxr
|
||||
* @date 2022/2/5
|
||||
*/
|
||||
@Slf4j
|
||||
public class UserUtils {
|
||||
|
||||
/**
|
||||
* 解析JWT获取用户ID
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Long getUserId() {
|
||||
Long userId = null;
|
||||
JSONObject jwtPayload = JwtUtils.getJwtPayload();
|
||||
if (jwtPayload != null) {
|
||||
userId = jwtPayload.getLong("userId");
|
||||
}
|
||||
return userId;
|
||||
}
|
||||
|
||||
public static Long getMemberId() {
|
||||
Long memberId = null;
|
||||
JSONObject jwtPayload = JwtUtils.getJwtPayload();
|
||||
if (jwtPayload != null) {
|
||||
memberId = jwtPayload.getLong("memberId");
|
||||
}
|
||||
return memberId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JWT获取用户ID
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Long getDeptId() {
|
||||
Long id = JwtUtils.getJwtPayload().getLong("deptId");
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JWT获取获取用户名
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getUsername() {
|
||||
String username = JwtUtils.getJwtPayload().getStr(SecurityConstants.USER_NAME_KEY);
|
||||
return username;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* JWT获取用户角色列表
|
||||
*
|
||||
* @return 角色列表
|
||||
*/
|
||||
public static List<String> getRoles() {
|
||||
List<String> roles;
|
||||
JSONObject payload = JwtUtils.getJwtPayload();
|
||||
if (payload.containsKey(SecurityConstants.JWT_AUTHORITIES_KEY)) {
|
||||
roles = payload.getJSONArray(SecurityConstants.JWT_AUTHORITIES_KEY).toList(String.class);
|
||||
} else {
|
||||
roles = Collections.emptyList();
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否「超级管理员」
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static boolean isRoot() {
|
||||
List<String> roles = getRoles();
|
||||
return CollectionUtil.isNotEmpty(roles) && roles.contains("ROOT");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user