点评项目-8-全局ID生成器、秒杀优惠卷

发布于:2024-10-16 ⋅ 阅读:(133) ⋅ 点赞:(0)

全局ID生成器

利用 redis 的自增 key 和时间戳,完成 id 的生成

@Component
public class CreateOnlyId {
    //设置开始的时间戳,可以通过打印系统当前时间设置,
    private static final long begin = 1640995200L;
    private StringRedisTemplate stringRedisTemplate;

    public CreateOnlyId(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    //生成全局id
    public long createID(String preKey){
        //id生成时间,31位的时间,可以使用 69 年
        LocalDateTime now = LocalDateTime.now();
        long curSecond = now.toEpochSecond(ZoneOffset.UTC);
        long pre = curSecond - begin;
        //通过 redis 自增,key 每天更新一次,可以保证大访量也不会超出 32 位
        String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));//获取当前日期
        String key = "idr:"+preKey+":"+date;
        Long increment = stringRedisTemplate.opsForValue().increment(key);//自增
        return pre << 32 | increment;
    }
}

测试:

    //id生成器测试
    @Test
    void idCreate(){
        //生成十个 id
        for(int i=0;i<10;i++){
            long id = createOnlyId.createID("cache:shop:1");
            System.out.println(Long.toBinaryString(id));
        }
    }

执行结果(前面还单独测试了两次,所有此处序列号从3开始):

10100111100100110001110110100000000000000000000000000000011
10100111100100110001110111000000000000000000000000000000100
10100111100100110001110111000000000000000000000000000000101
10100111100100110001110111000000000000000000000000000000110
10100111100100110001110111000000000000000000000000000000111
10100111100100110001110111000000000000000000000000000001000
10100111100100110001110111000000000000000000000000000001001
10100111100100110001110111000000000000000000000000000001010
10100111100100110001110111000000000000000000000000000001011
10100111100100110001110111000000000000000000000000000001100

秒杀优惠卷

普通优惠卷的封装 Pojo 类

/**
 * 优惠卷封装类
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("tb_voucher")
public class Voucher implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * 商铺id
     */
    private Long shopId;

    /**
     * 代金券标题
     */
    private String title;

    /**
     * 副标题
     */
    private String subTitle;

    /**
     * 使用规则
     */
    private String rules;

    /**
     * 支付金额
     */
    private Long payValue;

    /**
     * 抵扣金额
     */
    private Long actualValue;

    /**
     * 优惠券类型
     */
    private Integer type;

    /**
     * 优惠券类型
     */
    private Integer status;
    /**
     * 库存
     */
    @TableField(exist = false)
    private Integer stock;

    /**
     * 生效时间
     */
    @TableField(exist = false)
    private LocalDateTime beginTime;

    /**
     * 失效时间
     */
    @TableField(exist = false)
    private LocalDateTime endTime;

    /**
     * 创建时间
     */
    private LocalDateTime createTime;


    /**
     * 更新时间
     */
    private LocalDateTime updateTime;
    
}

 秒杀优惠卷的 Pojo 类,与 普通优惠卷 是一对一关系

/**
 * 秒杀优惠券表,与优惠券是一对一关系
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("tb_seckill_voucher")
public class SeckillVoucher implements Serializable {

    private static final long serialVersionUID = 1L;

    public SeckillVoucher() {
    }

    public SeckillVoucher(Long voucherId, Integer stock, LocalDateTime beginTime, LocalDateTime endTime) {
        this.voucherId = voucherId;
        this.stock = stock;
        this.beginTime = beginTime;
        this.endTime = endTime;
    }

    /**
     * 关联的优惠券的id
     */
    @TableId(value = "voucher_id", type = IdType.INPUT)
    private Long voucherId;

    /**
     * 库存
     */
    private Integer stock;

    /**
     * 创建时间
     */
    private LocalDateTime createTime;

    /**
     * 生效时间
     */
    private LocalDateTime beginTime;

    /**
     * 失效时间
     */
    private LocalDateTime endTime;

    /**
     * 更新时间
     */
    private LocalDateTime updateTime;

}

对于秒杀优惠卷,我们将每一个秒杀优惠卷都绑定一个普通优惠卷,这样前端发送请求只需发送优惠卷请求即可。

共需要实现三个请求

1.新增普通优惠卷,直接将其存入数据库即可,请求路径:/voucher

2.新增秒杀优惠卷,将其对应的普通卷拿到后,封装成秒杀卷,再将其存入数据库,并且将其库存存入 redis 缓存,请求路径:/voucher/seckill

3.查询店铺 id 下的所有优惠卷,请求路径:/voucher/list/{shopId}

controller:

@RestController
@RequestMapping("/voucher")
public class VoucherController {

    @Resource
    private VoucherService voucherService;

    //查询店铺优惠卷列表
    @GetMapping("/list/{shopId}")
    public Result shopVoucherList(@PathVariable("shopId") Long shopId){
        List<Voucher> list = voucherService.queryVoucherList(shopId);
        return Result.ok(list);
    }

    //新增普通卷
    @PostMapping
    public Result addVoucher(@RequestBody Voucher voucher){
        voucherService.add(voucher);
        return Result.ok(voucher.getId());
    }

    //新增优惠卷
    @PostMapping("/seckill")
    public Result addSecKillVoucher(@RequestBody Voucher voucher){
        voucherService.addSecKill(voucher);
        return Result.ok(voucher.getId());
    }
}

Service:

public interface UserService {

    Result login(LoginFormDTO loginFormDTO, HttpSession session);

    Result sendCode(String phone, HttpSession session);

}
@Service
public class VoucherServiceImpl implements VoucherService {

    @Resource
    private VoucherMapper voucherMapper;
    @Resource
    private VoucherSeckillMapper voucherSeckillMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public List<Voucher> queryVoucherList(long shopId) {
        return voucherMapper.selectVouchers(shopId);
    }

    @Override
    public void add(Voucher voucher) {
        //普通卷直接存到数据库即可
        voucherMapper.insert(voucher);
    }

    @Override
    public void addSecKill(Voucher voucher) {
        //先添加一个普通卷到数据库中
        add(voucher);
        //再创建普通卷对应的秒杀卷对象,并存到数据库中
        SeckillVoucher seckillVoucher = new SeckillVoucher(voucher.getId(),voucher.getStock(),voucher.getBeginTime(),voucher.getEndTime());
        voucherSeckillMapper.insert(seckillVoucher);
        //保存秒杀库存到 redis 中
        stringRedisTemplate.opsForValue().set("Voucher:seckill:"+voucher.getId(), voucher.getStock().toString());
    }
}

Mapper:

@Mapper
public interface VoucherMapper extends BaseMapper<Voucher> {
    //查询店铺的所有优惠卷
    @Select("select * from tb_voucher where shop_id = #{shopId}")
    List<Voucher> selectVouchers(@Param("shopId") long shopId);
}
@Mapper
public interface VoucherSeckillMapper extends BaseMapper<SeckillVoucher> {
}

测试:

 

查询所有优惠卷:

 查询结果:

{

    "success": true,

    "errorMsg": null,

    "data": [

        {

            "id": 1,

            "shopId": 1,

            "title": "50元代金券",

            "subTitle": "周一至周日均可使用",

            "rules": "全场通用\\n无需预约\\n可无限叠加\\不兑现、不找零\\n仅限堂食",

            "payValue": 4750,

            "actualValue": 5000,

            "type": 0,

            "status": 1,

            "stock": null,

            "beginTime": null,

            "endTime": null,

            "createTime": "2022-01-04T09:42:39",

            "updateTime": "2022-01-04T09:43:31"

        },

        {

            "id": 10,

            "shopId": 1,

            "title": "100元秒杀券",

            "subTitle": "周一至周日均可使用",

            "rules": "全场通用\\n无需预约\\n可无限叠加\\不兑现、不找零\\n仅限堂食",

            "payValue": 3000,

            "actualValue": 5000,

            "type": 1,

            "status": 1,

            "stock": null,

            "beginTime": null,

            "endTime": null,

            "createTime": "2022-01-04T09:42:39",

            "updateTime": "2022-01-04T09:43:31"

        },

        {

            "id": 11,

            "shopId": 1,

            "title": "200元秒杀券",

            "subTitle": "周一至周日均可使用",

            "rules": "全场通用\\n无需预约\\n可无限叠加\\不兑现、不找零\\n仅限堂食",

            "payValue": 3000,

            "actualValue": 5000,

            "type": 1,

            "status": 1,

            "stock": null,

            "beginTime": null,

            "endTime": null,

            "createTime": "2022-01-04T09:42:39",

            "updateTime": "2022-01-04T09:43:31"

        },

        {

            "id": 12,

            "shopId": 1,

            "title": "100元优惠券",

            "subTitle": "周一至周日均可使用",

            "rules": "全场通用\\n无需预约\\n可无限叠加\\不兑现、不找零\\n仅限堂食",

            "payValue": 4500,

            "actualValue": 5000,

            "type": 1,

            "status": 1,

            "stock": null,

            "beginTime": null,

            "endTime": null,

            "createTime": "2022-01-04T09:42:39",

            "updateTime": "2022-01-04T09:43:31"

        }

    ],

    "total": null

}


网站公告

今日签到

点亮在社区的每一天
去签到