feat:优惠券服务管理员端搭建

This commit is contained in:
dongtiandexue 2021-03-15 23:47:48 +08:00
parent f21dea4f5c
commit 9092d97dbd
28 changed files with 1333 additions and 20 deletions

View File

@ -0,0 +1,12 @@
package com.youlai.mall.sms.pojo.constant;
/**
* @author huawei
* @desc
* @email huawei_code@163.com
* @date 2021/3/10
*/
public class AppConstants {
public static final String COUPON_LOCK = "lock:coupon:";
}

View File

@ -0,0 +1,100 @@
package com.youlai.mall.sms.pojo.domain;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* sms_coupon
* @author
*/
@Data
public class SmsCoupon implements Serializable {
/**
* ID
*/
private Long id;
/**
* 优惠券标题有图片则显示图片无门槛50元优惠券 | 单品最高减2000元
*/
private String title;
/**
* 图片
*/
private String img;
/**
* 1满减券 2叠加满减券 3无门槛券需要限制大小
*/
private Integer type;
/**
* 发布状态, PUBLISH发布DRAFT草稿OFFLINE下线
*/
private String publish;
/**
* 满多少才可以使用为0则不限制金额
*/
private Long conditionPrice;
/**
* 抵扣价格
*/
private Long price;
/**
* 优惠券总量
*/
private Integer publishCount;
/**
* 每张优惠券限领张数默认为1为0不限制
*/
private Integer limitCount;
/**
* 已领取的优惠券数量
*/
private Integer takeCount;
/**
* 已使用的优惠券数量
*/
private Integer usedCount;
/**
* 发放开始时间
*/
private Date startTime;
/**
* 发放结束时间
*/
private Date endTime;
/**
* 自领取之日起有效天数
*/
private Integer validDays;
/**
* 逻辑删除使用
*/
private Integer status;
/**
* 创建时间
*/
private Date gmtCreate;
/**
* 修改时间
*/
private Date gmtModified;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,87 @@
package com.youlai.mall.sms.pojo.domain;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* sms_coupon_record
* @author
*/
@Data
public class SmsCouponRecord implements Serializable {
private Long id;
/**
* 优惠券id
*/
private Long couponId;
/**
* 使用状态 可用 NEW,已使用USED,过期 EXPIRED;
*/
private String useState;
/**
* 用户id
*/
private Long userId;
/**
* 用户昵称冗余字段
*/
private String userName;
/**
* 1满减券 2叠加满减券 3无门槛券
*/
private Integer couponType;
/**
* 优惠券标题
*/
private String couponTitle;
/**
* 满多少才可以使用为0则不限制金额
*/
private Long conditionPrice;
/**
* 抵扣价格
*/
private Long price;
/**
* 开始时间
*/
private Date startTime;
/**
* 结束时间
*/
private Date endTime;
/**
* 订单id
*/
private Long orderId;
/**
* 逻辑删除使用
*/
private Integer status;
/**
* 创建时间
*/
private Date gmtCreate;
/**
* 修改时间
*/
private Date gmtModified;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,14 @@
package com.youlai.mall.sms.pojo.enums;
/**
* @author huawei
* @desc
* @email huawei_code@163.com
* @date 2021/2/28
*/
public enum CouponStateEnum {
NEW,
USED,
EXPIRED;
}

View File

@ -0,0 +1,97 @@
package com.youlai.mall.sms.pojo.form;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* @author huawei
* @desc 优惠券提交表单
* @email huawei_code@163.com
* @date 2021/3/14
*/
@ApiModel("优惠券提交表单")
@Data
public class CouponForm {
/**
* ID
*/
private Long id;
/**
* 优惠券标题有图片则显示图片无门槛50元优惠券 | 单品最高减2000元
*/
@ApiModelProperty("优惠券标题")
@NotBlank(message = "请填写优惠券标题")
private String title;
/**
* 图片
*/
@ApiModelProperty("优惠券图片")
private String img;
/**
* 1满减券 2叠加满减券 3无门槛券需要限制大小
*/
@ApiModelProperty("优惠券类型")
private Integer type;
/**
* 满多少才可以使用为0则不限制金额
*/
@ApiModelProperty("优惠券满减金额为0则不限制金额")
private Long conditionPrice;
/**
* 抵扣价格
*/
@ApiModelProperty("优惠券抵扣价格")
@NotNull(message = "请填写优惠券抵扣金额")
@Min(value = 1,message = "抵扣价格不能小于1")
private Long price;
/**
* 优惠券总量
*/
@ApiModelProperty("优惠券总量")
@NotNull(message = "请填写优惠券总量")
@Min(value = 1,message = "优惠券总量不能小于1")
private Integer publishCount;
/**
* 每张优惠券限领张数默认为1为0不限制
*/
@ApiModelProperty("优惠券限领张数")
@Min(value = 0,message = "优惠券限领张数不能为负数")
private Integer limitCount;
/**
* 发放开始时间
*/
@ApiModelProperty("优惠券发放开始时间")
@NotNull(message = "请填写优惠券发放开始时间")
private Date startTime;
/**
* 发放结束时间
*/
@ApiModelProperty("优惠券发放结束时间")
@NotNull(message = "请填写优惠券发放结束时间")
private Date endTime;
/**
* 自领取之日起有效天数
*/
@ApiModelProperty("自领取之日起有效天数")
@NotNull(message = "请填写正确的有效天数")
@Min(value = 1,message = "有效天数总量不能小于1")
private Integer validDays;
}

View File

@ -0,0 +1,100 @@
package com.youlai.mall.sms.pojo.vo;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* sms_coupon
* @author
*/
@Data
public class SmsCouponVO implements Serializable {
/**
* ID
*/
private Long id;
/**
* 优惠券标题有图片则显示图片无门槛50元优惠券 | 单品最高减2000元
*/
private String title;
/**
* 图片
*/
private String img;
/**
* 1满减券 2叠加满减券 3无门槛券需要限制大小
*/
private Integer type;
/**
* 发布状态, PUBLISH发布DRAFT草稿OFFLINE下线
*/
private String publish;
/**
* 满多少才可以使用为0则不限制金额
*/
private Long conditionPrice;
/**
* 抵扣价格
*/
private Long price;
/**
* 优惠券总量
*/
private Integer publishCount;
/**
* 每张优惠券限领张数默认为1为0不限制
*/
private Integer limitCount;
/**
* 已领取的优惠券数量
*/
private Integer takeCount;
/**
* 已使用的优惠券数量
*/
private Integer usedCount;
/**
* 发放开始时间
*/
private Date startTime;
/**
* 发放结束时间
*/
private Date endTime;
/**
* 自领取之日起有效天数
*/
private Integer validDays;
/**
* 逻辑删除使用
*/
private Integer status;
/**
* 创建时间
*/
private Date gmtCreate;
/**
* 修改时间
*/
private Date gmtModified;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,81 @@
package com.youlai.mall.sms.controller.admin;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.youlai.common.base.BasePageQuery;
import com.youlai.common.result.Result;
import com.youlai.mall.sms.pojo.domain.SmsCoupon;
import com.youlai.mall.sms.pojo.form.CouponForm;
import com.youlai.mall.sms.service.ISmsCouponService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* @author huawei
* @desc 优惠券管理服务
* @email huawei_code@163.com
* @date 2021/3/14
*/
@Api(tags = "优惠券管理服务")
@RestController
@RequestMapping("/api.admin/v1/coupon")
public class CouponController {
@Autowired
private ISmsCouponService couponService;
@ApiOperation("优惠券分页列表查询")
@GetMapping("/page")
public Result page(@ApiParam("条件分页请求入参") BasePageQuery query) {
Page<SmsCoupon> page = new Page<>(query.getPageNum(), query.getPageSize());
return Result.success(couponService.pageQuery(page, query));
}
@ApiOperation("查询优惠券详情")
@RequestMapping("/${couponId}/detail")
public Result detail(@ApiParam("删除商品分页列表查询") @PathVariable("couponId") String couponId) {
return Result.success(couponService.detail(couponId));
}
/**
* 新增优惠券
*
* @return
*/
@ApiOperation("新增优惠券")
@PostMapping()
public Result add(@ApiParam("新增优惠券提交表单") @Validated @RequestBody CouponForm form) {
couponService.add(form);
return Result.success();
}
/**
* 修改优惠券
*
* @return
*/
@ApiOperation("修改优惠券")
@PutMapping()
public Result modify(@ApiParam("修改优惠券提交表单") @Validated @RequestBody CouponForm form) {
if (form.getId() == null) {
return Result.failed("优惠券ID不能为空");
}
couponService.modify(form);
return Result.success();
}
/**
* 删除优惠券
*
* @return
*/
@ApiOperation("删除优惠券")
@DeleteMapping()
public Result del(@ApiParam("优惠券ID") @RequestParam("couponId") String couponId) {
couponService.removeById(couponId);
return Result.success();
}
}

View File

@ -0,0 +1,73 @@
package com.youlai.mall.sms.controller.admin;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.RequestUtils;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @author huawei
* @desc 优惠券领券记录服务
* @email huawei_code@163.com
* @date 2021/3/15
*/
@Api(tags = "优惠券领券记录服务")
@RestController
@RequestMapping("/api.admin/v1/coupon_record")
public class CouponRecordController {
@Autowired
private ICouponRecordService couponRecordService;
@ApiOperation(value = "分页获取会员领券记录")
@GetMapping("/page")
public Result page(BasePageQuery pageQuery) {
Long userId = RequestUtils.getUserId();
QueryWrapper<SmsCouponRecord> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", userId).orderByDesc("create_time");
Page<SmsCouponRecord> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
IPage<SmsCouponRecord> result = couponRecordService.page(page, queryWrapper);
return Result.success(result);
}
@ApiOperation(value = "获取优惠券记录详情")
@GetMapping("/{id}/detail")
public Result detail(@ApiParam(value = "优惠券记录ID") @PathVariable("id") String id) {
Long userId = RequestUtils.getUserId();
QueryWrapper<SmsCouponRecord> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", userId ).eq("id", id);
SmsCouponRecord result = couponRecordService.getOne(queryWrapper);
if (result == null) {
return Result.failed("优惠券记录不存在");
}
return Result.success(result);
}
/**
* 用户领券功能
* 1查询优惠券是否真实存在
* 2校验优惠券信息是否有效是否超额领取是否过期
* 3
*
* @param couponId
* @return
*/
@ApiOperation(value = "用户领券功能")
@PostMapping()
public Result add(@ApiParam(name = "couponId", value = "优惠券ID", required = true)
@RequestParam("couponId") String couponId) {
couponRecordService.add(couponId);
return Result.success();
}
}

View File

@ -2,7 +2,7 @@ package com.youlai.mall.sms.controller.app;
import com.youlai.common.result.Result; import com.youlai.common.result.Result;
import com.youlai.mall.sms.pojo.vo.SmsSeckillSkuVO; import com.youlai.mall.sms.pojo.vo.SmsSeckillSkuVO;
import com.youlai.mall.sms.service.SeckillService; import com.youlai.mall.sms.service.ISeckillService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -25,11 +25,11 @@ import java.util.List;
public class SeckillController { public class SeckillController {
@Autowired @Autowired
private SeckillService seckillService; private ISeckillService ISeckillService;
@GetMapping @GetMapping
public Result getCurrentSeckillSession() { public Result getCurrentSeckillSession() {
List<SmsSeckillSkuVO> currentSeckills = seckillService.getCurrentSeckillSession(); List<SmsSeckillSkuVO> currentSeckills = ISeckillService.getCurrentSeckillSession();
return Result.success(); return Result.success();
} }
} }

View File

@ -0,0 +1,21 @@
package com.youlai.mall.sms.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.youlai.mall.sms.pojo.domain.SmsCoupon;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface SmsCouponDao extends BaseMapper<SmsCoupon> {
int deleteByPrimaryKey(Long id);
int insertSelective(SmsCoupon record);
SmsCoupon selectByPrimaryKey(Long id);
int updateByPrimaryKeySelective(SmsCoupon record);
int updateByPrimaryKey(SmsCoupon record);
int updateTakeStock(@Param("id") String couponId);
}

View File

@ -0,0 +1,18 @@
package com.youlai.mall.sms.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.youlai.mall.sms.pojo.domain.SmsCouponRecord;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SmsCouponRecordDao extends BaseMapper<SmsCouponRecord> {
int deleteByPrimaryKey(Long id);
int insertSelective(SmsCouponRecord record);
SmsCouponRecord selectByPrimaryKey(Long id);
int updateByPrimaryKeySelective(SmsCouponRecord record);
int updateByPrimaryKey(SmsCouponRecord record);
}

View File

@ -1,6 +1,6 @@
package com.youlai.mall.sms.scheduled; package com.youlai.mall.sms.scheduled;
import com.youlai.mall.sms.service.SeckillService; import com.youlai.mall.sms.service.ISeckillService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock; import org.redisson.api.RLock;
import org.redisson.api.RedissonClient; import org.redisson.api.RedissonClient;
@ -23,7 +23,7 @@ public class SeckillSkuScheduled {
private static final String SECKILL_SKU_LATEST_3_DAY= "seckillSkuLatest3Days"; private static final String SECKILL_SKU_LATEST_3_DAY= "seckillSkuLatest3Days";
@Autowired @Autowired
private SeckillService seckillService; private ISeckillService ISeckillService;
@Autowired @Autowired
@ -38,7 +38,7 @@ public class SeckillSkuScheduled {
lock.lock(10, TimeUnit.SECONDS); lock.lock(10, TimeUnit.SECONDS);
try { try {
seckillService.updateSeckillSkuLatest3Days(); ISeckillService.updateSeckillSkuLatest3Days();
} finally { } finally {
lock.unlock(); lock.unlock();
} }

View File

@ -0,0 +1,19 @@
package com.youlai.mall.sms.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.youlai.mall.sms.pojo.domain.SmsCouponRecord;
/**
* @author huawei
* @desc 优惠券领券记录业务接口
* @email huawei_code@163.com
* @date 2021/3/15
*/
public interface ICouponRecordService extends IService<SmsCouponRecord> {
/**
* 用户领券
* @param couponId
*/
void add(String couponId);
}

View File

@ -10,7 +10,7 @@ import java.util.List;
* @email huawei_code@163.com * @email huawei_code@163.com
* @date 2021/3/5 * @date 2021/3/5
*/ */
public interface SeckillService { public interface ISeckillService {
void updateSeckillSkuLatest3Days(); void updateSeckillSkuLatest3Days();

View File

@ -0,0 +1,13 @@
package com.youlai.mall.sms.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.youlai.mall.sms.pojo.domain.SmsCouponRecord;
/**
* @author huawei
* @desc
* @email huawei_code@163.com
* @date 2021/3/14
*/
public interface ISmsCouponRecordService extends IService<SmsCouponRecord> {
}

View File

@ -0,0 +1,48 @@
package com.youlai.mall.sms.service;
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.common.base.BasePageQuery;
import com.youlai.mall.sms.pojo.domain.SmsCoupon;
import com.youlai.mall.sms.pojo.form.CouponForm;
import com.youlai.mall.sms.pojo.vo.SmsCouponVO;
/**
* @author huawei
* @desc
* @email huawei_code@163.com
* @date 2021/3/14
*/
public interface ISmsCouponService extends IService<SmsCoupon> {
/**
* 获取优惠券详情
*
* @param couponId 优惠券ID
*/
SmsCouponVO detail(String couponId);
/**
* 新增优惠券
*
* @param form 新增提交表单
*/
void add(CouponForm form);
/**
* 修改优惠券
*
* @param form 修改优惠券提交表单
*/
void modify(CouponForm form);
IPage<SmsCoupon> pageQuery(Page<SmsCoupon> page, BasePageQuery query);
/**
* 根据已领券数量
* @param couponId
* @return
*/
int updateTakeStock(String couponId);
}

View File

@ -12,7 +12,7 @@ import java.util.List;
* @email huawei_code@163.com * @email huawei_code@163.com
* @date 2021/3/5 * @date 2021/3/5
*/ */
public interface SmsSeckillSessionService extends IService<SmsSeckillSession> { public interface ISmsSeckillSessionService extends IService<SmsSeckillSession> {
/** /**
* 根据起始时间和结束时间查询秒杀活动列表 * 根据起始时间和结束时间查询秒杀活动列表

View File

@ -11,7 +11,7 @@ import java.util.List;
* @email huawei_code@163.com * @email huawei_code@163.com
* @date 2021/3/5 * @date 2021/3/5
*/ */
public interface SmsSeckillSkuRelationService extends IService<SmsSeckillSkuRelation> { public interface ISmsSeckillSkuRelationService extends IService<SmsSeckillSkuRelation> {
/** /**
* 根据秒杀活动ID获取关联商品 * 根据秒杀活动ID获取关联商品

View File

@ -0,0 +1,108 @@
package com.youlai.mall.sms.service.impl;
import cn.hutool.core.date.DateUtil;
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.RequestUtils;
import com.youlai.mall.sms.mapper.SmsCouponRecordDao;
import com.youlai.mall.sms.pojo.domain.SmsCoupon;
import com.youlai.mall.sms.pojo.domain.SmsCouponRecord;
import com.youlai.mall.sms.pojo.enums.CouponStateEnum;
import com.youlai.mall.sms.service.ICouponRecordService;
import com.youlai.mall.sms.service.ISmsCouponService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import static com.youlai.mall.sms.pojo.constant.AppConstants.COUPON_LOCK;
/**
* @author huawei
* @desc 优惠券领券记录业务实现类
* @email huawei_code@163.com
* @date 2021/3/15
*/
@Service
@Slf4j
public class CouponRecordServiceImpl extends ServiceImpl<SmsCouponRecordDao, SmsCouponRecord> implements ICouponRecordService {
@Autowired
private ISmsCouponService couponService;
@Autowired
private RedissonClient redissonClient;
@Override
public void add(String couponId) {
Long userId = RequestUtils.getUserId();
RLock lock = redissonClient.getLock(COUPON_LOCK + couponId);
lock.lock();
try {
SmsCoupon coupon = couponService.getById(couponId);
this.couponCheck(coupon, userId);
// 封装优惠券领取记录对象
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(RequestUtils.getUserId());
couponRecord.setUserName(RequestUtils.getUsername());
couponRecord.setCouponId(coupon.getId());
couponRecord.setId(null);
// 高并发下扣减库存
//高并发下扣减劵库存采用乐观锁,当前stock做版本号,延伸多种防止超卖的问题,一次只能领取1张TODO
int rows = couponService.updateTakeStock(couponId);
if (rows == 1) {
//库存扣减成功才保存
this.save(couponRecord);
} else {
log.warn("发放优惠券失败coupon={}loginUser={}", coupon, userId);
throw new BizException("发放优惠券失败");
}
} finally {
lock.unlock();
}
}
/**
* 优惠券检查
*
* @param couponEntity
* @param userId
*/
private void couponCheck(SmsCoupon couponEntity, long userId) {
//优惠券不存在
if (couponEntity == null) {
throw new BizException("优惠券不存在");
}
//库存不足
if ((couponEntity.getPublishCount() - couponEntity.getTakeCount()) <= 0) {
throw new BizException("优惠券已经被领光了");
}
//是否在领取时间范围
long time = System.currentTimeMillis();
long start = couponEntity.getStartTime().getTime();
long end = couponEntity.getEndTime().getTime();
if (time < start || time > end) {
throw new BizException("优惠券不在领券时间范围内");
}
//用户是否超过限制
int recordNum = this.count(new QueryWrapper<SmsCouponRecord>()
.eq("coupon_id", couponEntity.getId())
.eq("user_id", userId));
if (recordNum >= couponEntity.getLimitCount()) {
throw new BizException("优惠券已经达到领券次数限制");
}
}
}

View File

@ -10,16 +10,15 @@ import com.youlai.mall.sms.pojo.domain.SmsSeckillSession;
import com.youlai.mall.sms.pojo.domain.SmsSeckillSkuRelation; import com.youlai.mall.sms.pojo.domain.SmsSeckillSkuRelation;
import com.youlai.mall.sms.pojo.to.SeckillSkuRedisTO; import com.youlai.mall.sms.pojo.to.SeckillSkuRedisTO;
import com.youlai.mall.sms.pojo.vo.SmsSeckillSkuVO; import com.youlai.mall.sms.pojo.vo.SmsSeckillSkuVO;
import com.youlai.mall.sms.service.SeckillService; import com.youlai.mall.sms.service.ISeckillService;
import com.youlai.mall.sms.service.SmsSeckillSessionService; import com.youlai.mall.sms.service.ISmsSeckillSessionService;
import com.youlai.mall.sms.service.SmsSeckillSkuRelationService; import com.youlai.mall.sms.service.ISmsSeckillSkuRelationService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RSemaphore; import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient; import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -32,17 +31,17 @@ import java.util.stream.Collectors;
*/ */
@Service @Service
@Slf4j @Slf4j
public class SeckillServiceImpl implements SeckillService { public class SeckillServiceImpl implements ISeckillService {
private static final String SECKILL_SESSION_CACHE_PREFIX = "seckill:sessions:"; private static final String SECKILL_SESSION_CACHE_PREFIX = "seckill:sessions:";
private static final String SECKILL_SKU_CACHE_PREFIX = "seckill:skus"; private static final String SECKILL_SKU_CACHE_PREFIX = "seckill:skus";
private static final String SECKILL_SKU_SEMAPHORE = "seckill:stock:"; private static final String SECKILL_SKU_SEMAPHORE = "seckill:stock:";
@Autowired @Autowired
private SmsSeckillSessionService seckillSessionService; private ISmsSeckillSessionService seckillSessionService;
@Autowired @Autowired
private SmsSeckillSkuRelationService seckillSkuRelationService; private ISmsSeckillSkuRelationService seckillSkuRelationService;
@Autowired @Autowired
private RedisUtils redisUtils; private RedisUtils redisUtils;

View File

@ -0,0 +1,19 @@
package com.youlai.mall.sms.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.mall.sms.mapper.SmsCouponRecordDao;
import com.youlai.mall.sms.pojo.domain.SmsCouponRecord;
import com.youlai.mall.sms.service.ISmsCouponRecordService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author huawei
* @desc 优惠券领取记录业务实现类
* @email huawei_code@163.com
* @date 2021/3/14
*/
@Slf4j
@Service
public class SmsCouponRecordServiceImpl extends ServiceImpl<SmsCouponRecordDao, SmsCouponRecord> implements ISmsCouponRecordService {
}

View File

@ -0,0 +1,61 @@
package com.youlai.mall.sms.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.base.BasePageQuery;
import com.youlai.common.web.util.BeanMapperUtils;
import com.youlai.mall.sms.mapper.SmsCouponDao;
import com.youlai.mall.sms.pojo.domain.SmsCoupon;
import com.youlai.mall.sms.pojo.form.CouponForm;
import com.youlai.mall.sms.pojo.vo.SmsCouponVO;
import com.youlai.mall.sms.service.ISmsCouponService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author huawei
* @desc 优惠券服务业务实现类
* @email huawei_code@163.com
* @date 2021/3/14
*/
@Service
@Slf4j
public class SmsCouponServiceImpl extends ServiceImpl<SmsCouponDao, SmsCoupon> implements ISmsCouponService {
@Override
public SmsCouponVO detail(String couponId) {
log.info("根据优惠券ID获取优惠券详情couponId={}", couponId);
SmsCoupon coupon = this.getById(couponId);
return BeanMapperUtils.map(coupon, SmsCouponVO.class);
}
@Override
public void add(CouponForm form) {
log.info("新增优惠券form={}", form);
SmsCoupon coupon = BeanMapperUtils.map(form, SmsCoupon.class);
coupon.setId(null);
this.save(coupon);
}
@Override
public void modify(CouponForm form) {
log.info("新增优惠券form={}", form);
SmsCoupon coupon = BeanMapperUtils.map(form, SmsCoupon.class);
// TODO 如果该优惠券已经有领取记录则优惠券价格限领账户过期时间等相关参数不能修改
// 这里没有考虑太复杂如有需要自行处理
this.updateById(coupon);
}
@Override
public IPage<SmsCoupon> pageQuery(Page<SmsCoupon> page, BasePageQuery query) {
QueryWrapper<SmsCoupon> queryWrapper = new QueryWrapper<>();
IPage<SmsCoupon> iPage = this.page(page,queryWrapper);
return iPage;
}
@Override
public int updateTakeStock(String couponId) {
return this.updateTakeStock(couponId);
}
}

View File

@ -5,7 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.mall.sms.mapper.SmsSeckillSessionMapper; import com.youlai.mall.sms.mapper.SmsSeckillSessionMapper;
import com.youlai.mall.sms.pojo.domain.SmsSeckillSession; import com.youlai.mall.sms.pojo.domain.SmsSeckillSession;
import com.youlai.mall.sms.service.SmsSeckillSessionService; import com.youlai.mall.sms.service.ISmsSeckillSessionService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -19,7 +19,7 @@ import java.util.List;
*/ */
@Service @Service
@Slf4j @Slf4j
public class SmsSeckillSessionServiceImpl extends ServiceImpl<SmsSeckillSessionMapper, SmsSeckillSession> implements SmsSeckillSessionService { public class SmsSeckillSessionServiceImpl extends ServiceImpl<SmsSeckillSessionMapper, SmsSeckillSession> implements ISmsSeckillSessionService {
@Override @Override
public List<SmsSeckillSession> selectByTime(DateTime startTime, DateTime endTime) { public List<SmsSeckillSession> selectByTime(DateTime startTime, DateTime endTime) {
log.info("根据起始时间和结束时间查询秒杀活动列表, startTime={}, endTime={}", startTime, endTime); log.info("根据起始时间和结束时间查询秒杀活动列表, startTime={}, endTime={}", startTime, endTime);

View File

@ -4,7 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.mall.sms.mapper.SmsSeckillSkuRelationMapper; import com.youlai.mall.sms.mapper.SmsSeckillSkuRelationMapper;
import com.youlai.mall.sms.pojo.domain.SmsSeckillSkuRelation; import com.youlai.mall.sms.pojo.domain.SmsSeckillSkuRelation;
import com.youlai.mall.sms.service.SmsSeckillSkuRelationService; import com.youlai.mall.sms.service.ISmsSeckillSkuRelationService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -18,7 +18,7 @@ import java.util.List;
*/ */
@Service @Service
@Slf4j @Slf4j
public class SmsSeckillSkuRelationServiceImpl extends ServiceImpl<SmsSeckillSkuRelationMapper, SmsSeckillSkuRelation> implements SmsSeckillSkuRelationService { public class SmsSeckillSkuRelationServiceImpl extends ServiceImpl<SmsSeckillSkuRelationMapper, SmsSeckillSkuRelation> implements ISmsSeckillSkuRelationService {
@Override @Override
public List<SmsSeckillSkuRelation> selectBySessionId(Long sessionId) { public List<SmsSeckillSkuRelation> selectBySessionId(Long sessionId) {
log.info("根据秒杀活动场次ID查询关联商品列表sessionId={}",sessionId); log.info("根据秒杀活动场次ID查询关联商品列表sessionId={}",sessionId);

View File

@ -0,0 +1,224 @@
<?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="com.youlai.mall.sms.mapper.SmsCouponDao">
<resultMap id="BaseResultMap" type="com.youlai.mall.sms.pojo.domain.SmsCoupon">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="title" jdbcType="VARCHAR" property="title"/>
<result column="img" jdbcType="VARCHAR" property="img"/>
<result column="type" jdbcType="INTEGER" property="type"/>
<result column="publish" jdbcType="VARCHAR" property="publish"/>
<result column="condition_price" jdbcType="BIGINT" property="conditionPrice"/>
<result column="price" jdbcType="BIGINT" property="price"/>
<result column="publish_count" jdbcType="INTEGER" property="publishCount"/>
<result column="limit_count" jdbcType="INTEGER" property="limitCount"/>
<result column="take_count" jdbcType="INTEGER" property="takeCount"/>
<result column="used_count" jdbcType="INTEGER" property="usedCount"/>
<result column="start_time" jdbcType="TIMESTAMP" property="startTime"/>
<result column="end_time" jdbcType="TIMESTAMP" property="endTime"/>
<result column="valid_days" jdbcType="INTEGER" property="validDays"/>
<result column="status" jdbcType="INTEGER" property="status"/>
<result column="gmt_create" jdbcType="TIMESTAMP" property="gmtCreate"/>
<result column="gmt_modified" jdbcType="TIMESTAMP" property="gmtModified"/>
</resultMap>
<sql id="Base_Column_List">
id, title, img, `type`, publish, condition_price, price, publish_count,limit_count, take_count,
used_count, start_time, end_time, valid_days, `status`, gmt_create, gmt_modified
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from sms_coupon
where id = #{id,jdbcType=BIGINT}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
delete
from sms_coupon
where id = #{id,jdbcType=BIGINT}
</delete>
<insert id="insertSelective" keyColumn="id" keyProperty="id"
parameterType="com.youlai.mall.sms.pojo.domain.SmsCoupon" useGeneratedKeys="true">
insert into sms_coupon
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="title != null">
title,
</if>
<if test="img != null">
img,
</if>
<if test="type != null">
`type`,
</if>
<if test="publish != null">
publish,
</if>
<if test="conditionPrice != null">
condition_price,
</if>
<if test="price != null">
price,
</if>
<if test="publishCount != null">
publish_count,
</if>
<if test="limitCount != null">
limit_count,
</if>
<if test="takeCount != null">
take_count,
</if>
<if test="usedCount != null">
used_count,
</if>
<if test="startTime != null">
start_time,
</if>
<if test="endTime != null">
end_time,
</if>
<if test="validDays != null">
valid_days,
</if>
<if test="status != null">
`status`,
</if>
<if test="gmtCreate != null">
gmt_create,
</if>
<if test="gmtModified != null">
gmt_modified,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="title != null">
#{title,jdbcType=VARCHAR},
</if>
<if test="img != null">
#{img,jdbcType=VARCHAR},
</if>
<if test="type != null">
#{type,jdbcType=INTEGER},
</if>
<if test="publish != null">
#{publish,jdbcType=VARCHAR},
</if>
<if test="conditionPrice != null">
#{conditionPrice,jdbcType=BIGINT},
</if>
<if test="price != null">
#{price,jdbcType=BIGINT},
</if>
<if test="publishCount != null">
#{publishCount,jdbcType=INTEGER},
</if>
<if test="limitCount != null">
#{limitCount,jdbcType=INTEGER},
</if>
<if test="takeCount != null">
#{takeCount,jdbcType=INTEGER},
</if>
<if test="usedCount != null">
#{usedCount,jdbcType=INTEGER},
</if>
<if test="startTime != null">
#{startTime,jdbcType=TIMESTAMP},
</if>
<if test="endTime != null">
#{endTime,jdbcType=TIMESTAMP},
</if>
<if test="validDays != null">
#{validDays,jdbcType=INTEGER},
</if>
<if test="status != null">
#{status,jdbcType=INTEGER},
</if>
<if test="gmtCreate != null">
#{gmtCreate,jdbcType=TIMESTAMP},
</if>
<if test="gmtModified != null">
#{gmtModified,jdbcType=TIMESTAMP},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.youlai.mall.sms.pojo.domain.SmsCoupon">
update sms_coupon
<set>
<if test="title != null">
title = #{title,jdbcType=VARCHAR},
</if>
<if test="img != null">
img = #{img,jdbcType=VARCHAR},
</if>
<if test="type != null">
`type` = #{type,jdbcType=INTEGER},
</if>
<if test="publish != null">
publish = #{publish,jdbcType=VARCHAR},
</if>
<if test="conditionPrice != null">
condition_price = #{conditionPrice,jdbcType=BIGINT},
</if>
<if test="price != null">
price = #{price,jdbcType=BIGINT},
</if>
<if test="publishCount != null">
publish_count = #{publishCount,jdbcType=INTEGER},
</if>
<if test="limitCount != null">
limit_count = #{limitCount,jdbcType=INTEGER},
</if>
<if test="takeCount != null">
take_count = #{takeCount,jdbcType=INTEGER},
</if>
<if test="usedCount != null">
used_count = #{usedCount,jdbcType=INTEGER},
</if>
<if test="startTime != null">
start_time = #{startTime,jdbcType=TIMESTAMP},
</if>
<if test="endTime != null">
end_time = #{endTime,jdbcType=TIMESTAMP},
</if>
<if test="validDays != null">
valid_days = #{validDays,jdbcType=INTEGER},
</if>
<if test="status != null">
`status` = #{status,jdbcType=INTEGER},
</if>
<if test="gmtCreate != null">
gmt_create = #{gmtCreate,jdbcType=TIMESTAMP},
</if>
<if test="gmtModified != null">
gmt_modified = #{gmtModified,jdbcType=TIMESTAMP},
</if>
</set>
where id = #{id,jdbcType=BIGINT}
</update>
<update id="updateByPrimaryKey" parameterType="com.youlai.mall.sms.pojo.domain.SmsCoupon">
update sms_coupon
set title = #{title,jdbcType=VARCHAR},
img = #{img,jdbcType=VARCHAR},
`type` = #{type,jdbcType=INTEGER},
publish = #{publish,jdbcType=VARCHAR},
condition_price = #{conditionPrice,jdbcType=BIGINT},
price = #{price,jdbcType=BIGINT},
publish_count = #{publishCount,jdbcType=INTEGER},
limit_count = #{limitCount,jdbcType=INTEGER},
take_count = #{takeCount,jdbcType=INTEGER},
used_count = #{usedCount,jdbcType=INTEGER},
start_time = #{startTime,jdbcType=TIMESTAMP},
end_time = #{endTime,jdbcType=TIMESTAMP},
valid_days = #{validDays,jdbcType=INTEGER},
`status` = #{status,jdbcType=INTEGER},
gmt_create = #{gmtCreate,jdbcType=TIMESTAMP},
gmt_modified = #{gmtModified,jdbcType=TIMESTAMP}
where id = #{id,jdbcType=BIGINT}
</update>
<!-- 更新已领库存数量 -->
<update id="updateTakeStock">
update sms_coupon
set take_count = take_count + 1
where id = #{id}
</update>
</mapper>

View File

@ -0,0 +1,194 @@
<?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="com.youlai.mall.sms.mapper.SmsCouponRecordDao">
<resultMap id="BaseResultMap" type="com.youlai.mall.sms.pojo.domain.SmsCouponRecord">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="coupon_id" jdbcType="BIGINT" property="couponId" />
<result column="use_state" jdbcType="VARCHAR" property="useState" />
<result column="user_id" jdbcType="BIGINT" property="userId" />
<result column="user_name" jdbcType="VARCHAR" property="userName" />
<result column="coupon_type" jdbcType="INTEGER" property="couponType" />
<result column="coupon_title" jdbcType="VARCHAR" property="couponTitle" />
<result column="condition_price" jdbcType="BIGINT" property="conditionPrice" />
<result column="price" jdbcType="BIGINT" property="price" />
<result column="start_time" jdbcType="TIMESTAMP" property="startTime" />
<result column="end_time" jdbcType="TIMESTAMP" property="endTime" />
<result column="order_id" jdbcType="BIGINT" property="orderId" />
<result column="status" jdbcType="INTEGER" property="status" />
<result column="gmt_create" jdbcType="TIMESTAMP" property="gmtCreate" />
<result column="gmt_modified" jdbcType="TIMESTAMP" property="gmtModified" />
</resultMap>
<sql id="Base_Column_List">
id, coupon_id, use_state, user_id, user_name, coupon_type, coupon_title,
condition_price, price, start_time, end_time, order_id, `status`, gmt_create, gmt_modified
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from sms_coupon_record
where id = #{id,jdbcType=BIGINT}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
delete from sms_coupon_record
where id = #{id,jdbcType=BIGINT}
</delete>
<insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="com.youlai.mall.sms.pojo.domain.SmsCouponRecord" useGeneratedKeys="true">
insert into sms_coupon_record
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="couponId != null">
coupon_id,
</if>
<if test="useState != null">
use_state,
</if>
<if test="userId != null">
user_id,
</if>
<if test="userName != null">
user_name,
</if>
<if test="couponType != null">
coupon_type,
</if>
<if test="couponTitle != null">
coupon_title,
</if>
<if test="conditionPrice != null">
condition_price,
</if>
<if test="price != null">
price,
</if>
<if test="startTime != null">
start_time,
</if>
<if test="endTime != null">
end_time,
</if>
<if test="orderId != null">
order_id,
</if>
<if test="status != null">
`status`,
</if>
<if test="gmtCreate != null">
gmt_create,
</if>
<if test="gmtModified != null">
gmt_modified,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="couponId != null">
#{couponId,jdbcType=BIGINT},
</if>
<if test="useState != null">
#{useState,jdbcType=VARCHAR},
</if>
<if test="userId != null">
#{userId,jdbcType=BIGINT},
</if>
<if test="userName != null">
#{userName,jdbcType=VARCHAR},
</if>
<if test="couponType != null">
#{couponType,jdbcType=INTEGER},
</if>
<if test="couponTitle != null">
#{couponTitle,jdbcType=VARCHAR},
</if>
<if test="conditionPrice != null">
#{conditionPrice,jdbcType=BIGINT},
</if>
<if test="price != null">
#{price,jdbcType=BIGINT},
</if>
<if test="startTime != null">
#{startTime,jdbcType=TIMESTAMP},
</if>
<if test="endTime != null">
#{endTime,jdbcType=TIMESTAMP},
</if>
<if test="orderId != null">
#{orderId,jdbcType=BIGINT},
</if>
<if test="status != null">
#{status,jdbcType=INTEGER},
</if>
<if test="gmtCreate != null">
#{gmtCreate,jdbcType=TIMESTAMP},
</if>
<if test="gmtModified != null">
#{gmtModified,jdbcType=TIMESTAMP},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.youlai.mall.sms.pojo.domain.SmsCouponRecord">
update sms_coupon_record
<set>
<if test="couponId != null">
coupon_id = #{couponId,jdbcType=BIGINT},
</if>
<if test="useState != null">
use_state = #{useState,jdbcType=VARCHAR},
</if>
<if test="userId != null">
user_id = #{userId,jdbcType=BIGINT},
</if>
<if test="userName != null">
user_name = #{userName,jdbcType=VARCHAR},
</if>
<if test="couponType != null">
coupon_type = #{couponType,jdbcType=INTEGER},
</if>
<if test="couponTitle != null">
coupon_title = #{couponTitle,jdbcType=VARCHAR},
</if>
<if test="conditionPrice != null">
condition_price = #{conditionPrice,jdbcType=BIGINT},
</if>
<if test="price != null">
price = #{price,jdbcType=BIGINT},
</if>
<if test="startTime != null">
start_time = #{startTime,jdbcType=TIMESTAMP},
</if>
<if test="endTime != null">
end_time = #{endTime,jdbcType=TIMESTAMP},
</if>
<if test="orderId != null">
order_id = #{orderId,jdbcType=BIGINT},
</if>
<if test="status != null">
`status` = #{status,jdbcType=INTEGER},
</if>
<if test="gmtCreate != null">
gmt_create = #{gmtCreate,jdbcType=TIMESTAMP},
</if>
<if test="gmtModified != null">
gmt_modified = #{gmtModified,jdbcType=TIMESTAMP},
</if>
</set>
where id = #{id,jdbcType=BIGINT}
</update>
<update id="updateByPrimaryKey" parameterType="com.youlai.mall.sms.pojo.domain.SmsCouponRecord">
update sms_coupon_record
set coupon_id = #{couponId,jdbcType=BIGINT},
use_state = #{useState,jdbcType=VARCHAR},
user_id = #{userId,jdbcType=BIGINT},
user_name = #{userName,jdbcType=VARCHAR},
coupon_type = #{couponType,jdbcType=INTEGER},
coupon_title = #{couponTitle,jdbcType=VARCHAR},
condition_price = #{conditionPrice,jdbcType=BIGINT},
price = #{price,jdbcType=BIGINT},
start_time = #{startTime,jdbcType=TIMESTAMP},
end_time = #{endTime,jdbcType=TIMESTAMP},
order_id = #{orderId,jdbcType=BIGINT},
`status` = #{status,jdbcType=INTEGER},
gmt_create = #{gmtCreate,jdbcType=TIMESTAMP},
gmt_modified = #{gmtModified,jdbcType=TIMESTAMP}
where id = #{id,jdbcType=BIGINT}
</update>
</mapper>

View File

@ -37,6 +37,11 @@
<version>${dozer.version}</version> <version>${dozer.version}</version>
</dependency> </dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -0,0 +1,20 @@
package com.youlai.common.base;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author huawei
* @desc 基础分页请求对象
* @email huawei_code@163.com
* @date 2021/2/28
*/
@Data
public class BasePageQuery {
@ApiModelProperty(value = "当前页", example = "1")
private int pageNum = 1;
@ApiModelProperty(value = "每页记录数", example = "10")
private int pageSize = 10;
}