全局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
}