refactor: 订单流程优化和项目重构

This commit is contained in:
郝先瑞 2022-02-14 00:00:45 +08:00
parent 78817eaafd
commit 00c35f20fd
63 changed files with 940 additions and 743 deletions

View File

@ -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("订单线程"));
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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:已删除)
*/

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
// 在前面加上wxoweixin 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);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -35,14 +35,9 @@ public interface IPmsSkuService extends IService<PmsSku> {
/**
* 锁定库存
* 锁定商品库存
*/
Result lockStock(List<LockStockDTO> list);
/**
* 锁定库存
*/
// Boolean lockStockTcc(List<LockStockDTO> list);
boolean lockStock(LockStockDTO lockStockDTO);
/**
* 解锁库存

View File

@ -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() + "库存不足");

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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查询优惠券是否真实存在

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
/**
* 会员名(openIdmobile)
*/
private String username;
/**
* 状态(1:正常0禁用)
*/
private Integer status;
}

View File

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

View File

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

View File

@ -1,4 +1,4 @@
package com.youlai.mall.ums.pojo.dto;
package com.youlai.mall.ums.dto;
import lombok.Data;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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