Browse Source

feat: 更新业务逻辑

master
xc-yjs 8 months ago
parent
commit
cd0167c680
  1. 44
      nla-coupon-service/src/main/java/cn/nla/coupon/controller/CouponController.java
  2. 21
      nla-coupon-service/src/main/java/cn/nla/coupon/controller/CouponRecordController.java
  3. 29
      nla-coupon-service/src/main/java/cn/nla/coupon/mapper/CouponMapper.java
  4. 16
      nla-coupon-service/src/main/java/cn/nla/coupon/mapper/CouponRecordMapper.java
  5. 100
      nla-coupon-service/src/main/java/cn/nla/coupon/model/entity/CouponEntity.java
  6. 86
      nla-coupon-service/src/main/java/cn/nla/coupon/model/entity/CouponRecordEntity.java
  7. 16
      nla-coupon-service/src/main/java/cn/nla/coupon/service/CouponRecordService.java
  8. 30
      nla-coupon-service/src/main/java/cn/nla/coupon/service/CouponService.java
  9. 20
      nla-coupon-service/src/main/java/cn/nla/coupon/service/impl/CouponRecordServiceImpl.java
  10. 132
      nla-coupon-service/src/main/java/cn/nla/coupon/service/impl/CouponServiceImpl.java
  11. 36
      nla-coupon-service/src/main/resources/mapper/CouponMapper.xml
  12. 26
      nla-coupon-service/src/main/resources/mapper/CouponRecordMapper.xml

44
nla-coupon-service/src/main/java/cn/nla/coupon/controller/CouponController.java

@ -0,0 +1,44 @@
package cn.nla.coupon.controller;
import cn.nla.common.enums.CouponCategoryEnum;
import cn.nla.common.util.JsonData;
import cn.nla.coupon.service.CouponService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* <p>
* 优惠券表 前端控制器
* </p>
*
* @author YJs
* @since 2024-08-08
*/
@Api(tags = "优惠券控制器")
@RestController
@RequestMapping("/cop/coupon/v1")
public class CouponController {
@Resource
private CouponService couponService;
@ApiOperation("分页查询优惠券")
@GetMapping("page_coupon")
public JsonData pageCouponList(
@ApiParam(value = "当前页") @RequestParam(value = "page", defaultValue = "1") int page,
@ApiParam(value = "每页显示多少条") @RequestParam(value = "size", defaultValue = "10") int size) {
return JsonData.buildSuccess(couponService.pageCouponActivity(page, size));
}
/**
* 领取优惠券
*/
@ApiOperation("领取优惠券")
@GetMapping("/add/promotion/{coupon_id}")
public JsonData addPromotionCoupon(@ApiParam(value = "优惠券id", required = true) @PathVariable("coupon_id") long couponId) {
return couponService.addCoupon(couponId, CouponCategoryEnum.PROMOTION);
}
}

21
nla-coupon-service/src/main/java/cn/nla/coupon/controller/CouponRecordController.java

@ -0,0 +1,21 @@
package cn.nla.coupon.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 优惠券领劵记录 前端控制器
* </p>
*
* @author YJs
* @since 2024-08-08
*/
@RestController
@RequestMapping("/couponRecordEntity")
public class CouponRecordController {
}

29
nla-coupon-service/src/main/java/cn/nla/coupon/mapper/CouponMapper.java

@ -0,0 +1,29 @@
package cn.nla.coupon.mapper;
import cn.nla.coupon.model.entity.CouponEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
/**
* <p>
* 优惠券表 Mapper 接口
* </p>
*
* @author YJs
* @since 2024-08-08
*/
public interface CouponMapper extends BaseMapper<CouponEntity> {
/**
* 扣减存储
*/
int reduceStock(@Param("couponId") long couponId);
/**
* 扣减存储
*
* @param couponId 优惠卷id
* @param oldVersion 版本号
*/
int reduceStockOpt(@Param("couponId") long couponId, @Param("oldVersion") long oldVersion);
}

16
nla-coupon-service/src/main/java/cn/nla/coupon/mapper/CouponRecordMapper.java

@ -0,0 +1,16 @@
package cn.nla.coupon.mapper;
import cn.nla.coupon.model.entity.CouponRecordEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 优惠券领劵记录 Mapper 接口
* </p>
*
* @author YJs
* @since 2024-08-08
*/
public interface CouponRecordMapper extends BaseMapper<CouponRecordEntity> {
}

100
nla-coupon-service/src/main/java/cn/nla/coupon/model/entity/CouponEntity.java

@ -0,0 +1,100 @@
package cn.nla.coupon.model.entity;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 优惠券表
* </p>
*
* @author YJs
* @since 2024-08-08
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("coupon")
public class CouponEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 优惠卷类型[NEW_USER注册赠券TASK任务卷PROMOTION促销劵]
*/
private String category;
/**
* 发布状态, PUBLISH发布DRAFT草稿OFFLINE下线
*/
private String publish;
/**
* 优惠券图片
*/
private String couponImg;
/**
* 优惠券标题
*/
private String couponTitle;
/**
* 抵扣价格
*/
private BigDecimal price;
/**
* 每人限制张数
*/
private Integer userLimit;
/**
* 优惠券开始有效时间
*/
private Date startTime;
/**
* 优惠券失效时间
*/
private Date endTime;
/**
* 优惠券总量
*/
private Integer publishCount;
/**
* 库存
*/
private Integer stock;
private Date createTime;
/**
* 满多少才可以使用
*/
private BigDecimal conditionPrice;
/**
* 版本
*/
private Long version;
}

86
nla-coupon-service/src/main/java/cn/nla/coupon/model/entity/CouponRecordEntity.java

@ -0,0 +1,86 @@
package cn.nla.coupon.model.entity;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 优惠券领劵记录
* </p>
*
* @author YJs
* @since 2024-08-08
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("coupon_record")
public class CouponRecordEntity implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 优惠券id
*/
private Long couponId;
/**
* 创建时间获得时间
*/
private Date createTime;
/**
* 使用状态: 可用NEW,已使用USED,过期EXPIRED;
*/
private String useState;
/**
* 用户id
*/
private Long userId;
/**
* 用户昵称
*/
private String userName;
/**
* 优惠券标题
*/
private String couponTitle;
/**
* 开始时间
*/
private Date startTime;
/**
* 结束时间
*/
private Date endTime;
/**
* 订单id
*/
private Long orderId;
/**
* 抵扣价格
*/
private BigDecimal price;
/**
* 满多少才可以使用
*/
private BigDecimal conditionPrice;
}

16
nla-coupon-service/src/main/java/cn/nla/coupon/service/CouponRecordService.java

@ -0,0 +1,16 @@
package cn.nla.coupon.service;
import cn.nla.coupon.model.entity.CouponRecordEntity;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 优惠券领劵记录 服务类
* </p>
*
* @author YJs
* @since 2024-08-08
*/
public interface CouponRecordService extends IService<CouponRecordEntity> {
}

30
nla-coupon-service/src/main/java/cn/nla/coupon/service/CouponService.java

@ -0,0 +1,30 @@
package cn.nla.coupon.service;
import cn.nla.common.enums.CouponCategoryEnum;
import cn.nla.common.util.JsonData;
import cn.nla.coupon.model.entity.CouponEntity;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.Map;
/**
* <p>
* 优惠券表 服务类
* </p>
*
* @author YJs
* @since 2024-08-08
*/
public interface CouponService extends IService<CouponEntity> {
Map<String, Object> pageCouponActivity(int page, int size);
/**
* 领劵接口
* 1获取优惠券是否存在
* 2校验优惠券是否可以领取时间库存超过限制
* 3扣减库存
* 4保存领劵记录
*/
JsonData addCoupon(Long couponId, CouponCategoryEnum category);
}

20
nla-coupon-service/src/main/java/cn/nla/coupon/service/impl/CouponRecordServiceImpl.java

@ -0,0 +1,20 @@
package cn.nla.coupon.service.impl;
import cn.nla.coupon.model.entity.CouponRecordEntity;
import cn.nla.coupon.mapper.CouponRecordMapper;
import cn.nla.coupon.service.CouponRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 优惠券领劵记录 服务实现类
* </p>
*
* @author YJs
* @since 2024-08-08
*/
@Service
public class CouponRecordServiceImpl extends ServiceImpl<CouponRecordMapper, CouponRecordEntity> implements CouponRecordService {
}

132
nla-coupon-service/src/main/java/cn/nla/coupon/service/impl/CouponServiceImpl.java

@ -0,0 +1,132 @@
package cn.nla.coupon.service.impl;
import cn.nla.common.enums.BizCodeEnum;
import cn.nla.common.enums.CouponCategoryEnum;
import cn.nla.common.enums.CouponPublishEnum;
import cn.nla.common.enums.CouponStateEnum;
import cn.nla.common.exception.BizException;
import cn.nla.common.interceptor.LoginInterceptor;
import cn.nla.common.model.LoginUser;
import cn.nla.common.util.CommonUtil;
import cn.nla.common.util.JsonData;
import cn.nla.coupon.mapper.CouponRecordMapper;
import cn.nla.coupon.model.VO.CouponVO;
import cn.nla.coupon.model.entity.CouponEntity;
import cn.nla.coupon.mapper.CouponMapper;
import cn.nla.coupon.model.entity.CouponRecordEntity;
import cn.nla.coupon.service.CouponService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
/**
* <p>
* 优惠券表 服务实现类
* </p>
*
* @author YJs
* @since 2024-08-08
*/
@Slf4j
@Service
public class CouponServiceImpl extends ServiceImpl<CouponMapper, CouponEntity> implements CouponService {
@Resource
private CouponRecordMapper couponRecordMapper;
@Override
public Map<String, Object> pageCouponActivity(int page, int size) {
Page<CouponEntity> pageInfo = new Page<>(page, size);
IPage<CouponEntity> couponDOIPage = baseMapper.selectPage(pageInfo,
Wrappers.<CouponEntity>lambdaQuery().eq(CouponEntity::getPublish, CouponPublishEnum.PUBLISH)
.eq(CouponEntity::getCategory, CouponCategoryEnum.PROMOTION)
.orderByDesc(CouponEntity::getCreateTime));
Map<String, Object> pageMap = new HashMap<>(3);
//总条数
pageMap.put("total_record", couponDOIPage.getTotal());
//总页数
pageMap.put("total_page", couponDOIPage.getPages());
pageMap.put("current_data", couponDOIPage.getRecords().stream().map(this::beanProcess).collect(Collectors.toList()));
return pageMap;
}
@Override
public JsonData addCoupon(Long couponId, CouponCategoryEnum category) {
LoginUser loginUser = LoginInterceptor.threadLocal.get();
CouponEntity coupon = baseMapper.selectOne(
Wrappers.<CouponEntity>lambdaQuery().eq(CouponEntity::getId, couponId)
.eq(CouponEntity::getCategory, category.name()));
//优惠券是否可以领取
this.checkCoupon(coupon, loginUser.getId());
//构建领劵记录
CouponRecordEntity couponRecord = new CouponRecordEntity();
BeanUtils.copyProperties(coupon, couponRecord);
couponRecord.setCreateTime(new Date());
couponRecord.setUseState(CouponStateEnum.NEW.name());
couponRecord.setUserId(loginUser.getId());
couponRecord.setUserName(loginUser.getName());
couponRecord.setCouponId(couponId);
couponRecord.setId(null);
//扣减库存
// int rows = baseMapper.reduceStock(couponId);
//⾼并发下扣减劵库存,采⽤乐观锁,当前stock做版本号,延伸多种防⽌超卖的问题,⼀次只能领取1张
// 数据库添加字段: version INT DEFAULT 1, 根据当前的版本号更新
int rows = baseMapper.reduceStockOpt(couponId, coupon.getVersion());
if (rows == 1) {
//库存扣减成功才保存
couponRecordMapper.insert(couponRecord);
} else {
log.warn("发放优惠券失败:{},⽤ 户:{}", coupon, loginUser);
throw new BizException(BizCodeEnum.COUPON_NO_STOCK);
}
return JsonData.buildSuccess();
}
private CouponVO beanProcess(CouponEntity entity) {
CouponVO couponVO = new CouponVO();
BeanUtils.copyProperties(entity, couponVO);
return couponVO;
}
/**
* 校验是否可以领取
*/
private void checkCoupon(CouponEntity coupon, Long userId) {
if (coupon == null) {
throw new BizException(BizCodeEnum.COUPON_NO_EXITS);
}
//库存是否足够
if (coupon.getStock() <= 0) {
throw new BizException(BizCodeEnum.COUPON_NO_STOCK);
}
//判断是否是否发布状态
if (!coupon.getPublish().equals(CouponPublishEnum.PUBLISH.name())) {
throw new BizException(BizCodeEnum.COUPON_GET_FAIL);
}
//是否在领取时间范围
long time = CommonUtil.getCurrentTimestamp();
long start = coupon.getStartTime().getTime();
long end = coupon.getEndTime().getTime();
if (time < start || time > end) {
throw new BizException(BizCodeEnum.COUPON_OUT_OF_TIME);
}
//用户是否超过限制
int recordNum = couponRecordMapper.selectCount(
Wrappers.<CouponRecordEntity>lambdaQuery().eq(CouponRecordEntity::getCouponId, coupon.getId())
.eq(CouponRecordEntity::getUserId, userId));
if (recordNum >= coupon.getUserLimit()) {
throw new BizException(BizCodeEnum.COUPON_OUT_OF_LIMIT);
}
}
}

36
nla-coupon-service/src/main/resources/mapper/CouponMapper.xml

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.nla.coupon.mapper.CouponMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="cn.nla.coupon.model.entity.CouponEntity">
<id column="id" property="id" />
<result column="category" property="category" />
<result column="publish" property="publish" />
<result column="coupon_img" property="couponImg" />
<result column="coupon_title" property="couponTitle" />
<result column="price" property="price" />
<result column="user_limit" property="userLimit" />
<result column="start_time" property="startTime" />
<result column="end_time" property="endTime" />
<result column="publish_count" property="publishCount" />
<result column="stock" property="stock" />
<result column="create_time" property="createTime" />
<result column="condition_price" property="conditionPrice" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, category, publish, coupon_img, coupon_title, price, user_limit, start_time, end_time, publish_count, stock, create_time, condition_price
</sql>
<!--扣减库存-->
<update id="reduceStock">
update coupon set stock=stock-1 where id = #{couponId}
</update>
<!--扣减库存(加版本号,支持高并发下不超发问题)-->
<update id="reduceStockOpt">
update coupon set stock=stock-1,version=version+1 where id = #{couponId} and stock>0 and version=#{oldVersion}
</update>
</mapper>

26
nla-coupon-service/src/main/resources/mapper/CouponRecordMapper.xml

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.nla.coupon.mapper.CouponRecordMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="cn.nla.coupon.model.entity.CouponRecordEntity">
<id column="id" property="id" />
<result column="coupon_id" property="couponId" />
<result column="create_time" property="createTime" />
<result column="use_state" property="useState" />
<result column="user_id" property="userId" />
<result column="user_name" property="userName" />
<result column="coupon_title" property="couponTitle" />
<result column="start_time" property="startTime" />
<result column="end_time" property="endTime" />
<result column="order_id" property="orderId" />
<result column="price" property="price" />
<result column="condition_price" property="conditionPrice" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, coupon_id, create_time, use_state, user_id, user_name, coupon_title, start_time, end_time, order_id, price, condition_price
</sql>
</mapper>
Loading…
Cancel
Save