Java 篇-项目实战-天机学堂(从0到1)-day9

java 篇: 1.基础地基 2.设计原理 3.项目实战


产品原型分析:

执行提供的 sql 语句,新建微服务模块,copy learning 模块的 pom.xml 文件当中的 dependence 到 build 部分,和三个 yml 文件,去掉 pom.xml 当中用不到的依赖,改下 bootstrap.yml 当中的代码,mp 生成代码,这里改为这个

导入枚举相关类,替换实体类当中对应部分,主键自增改为雪花增长。前期准备工作完成。

实现新增优惠券接口:

代码实现:

资源加 s

涉及两张表记得加事务

coupon 实体类,当中字段可能和 mysql 当中关键字撞了,得加上注解,1 左边那个。怎么知道是不是关键字,就把这条 sql 语句放到 Query Console 当中,如果有颜色,就是关键字

接着在前端页面进行测试

记得开 search 服务,然后给 type 字段添加默认值,输入的优惠券名称有长度限制

实现分页查询优惠券接口:

测试:

成功

还可以按条件过滤

实现发放接口:

代码实现:

id 用该是用来拼接路径的吧,而 id 在 DTO 里面有

进行测试:

立即发放:

定时发放:

兑换码算法:

里面的字母和数字不全是因为去掉了容易混淆的字母和数字,比如大写 i 和小写 L 那才叫容易混淆 Il 还有 v v 和 w 也是 VV W。

uuid 生成的是 128 位的二进制数,展示的时候转成了 16 进制。

雪花算法生成的是 64 位二进制数,最终以十进制形式表现出来。

能不能把二进制转为上面的 32 个字母或数字呢,当然可以。32=2 的 5 次方,就是最多能表示 5 个空的二进制数。

那就将二进制数每五个分为一组,计算十进制数,作为脚标,去取对应的字母或数字。这就是所谓的 Base32,Base64 也同理,只不过是字母或数字的总数为 64 罢了。

但是长度不超过 10 字符,比特位最多 50 位,那 uuid 和雪花都不行,那我不能截吗,截了,你能保证是唯一的吗

那现在就剩下自增 id 了可以 redis 自增也可以数据库自增,但是 redis 自增,因为它是单线程的,所以 id 一定不会重复。对于数据量大,要满足 10 亿以上,2 的 32 次方足够,也就是 32 个比特位,那长度就是 6.4 字符,也满足不超过 10 字符的要求,我们只需要把自增 id 转成下面这种字符形式就可以了。

那这么多数字 BitMap 存的下么,巧了

BitMap 刚好能存这么多

这里代码部分,已经准备好了,直接导入就行,一个是自增 id 变对应的字符的,一个就是生成和校验的。

这里进行简单的单元测试

异步生成兑换码:

代码实现:

先进行线程池配置

在 CouponServiceImpl 当中添加生成兑换码的逻辑

复制代码
package com.tianji.promotion.service.impl;

import com.tianji.common.constants.ErrorInfo;
import com.tianji.promotion.domain.po.Coupon;
import com.tianji.promotion.domain.po.ExchangeCode;
import com.tianji.promotion.mapper.ExchangeCodeMapper;
import com.tianji.promotion.service.IExchangeCodeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.promotion.utils.CodeUtil;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

import static com.tianji.promotion.constants.PromotionConstants._COUPON_CODE_SERIAL_KEY_;

_/**_
_ * <p>_
_ * 兑换码 服务实现类_
_ * </p>_
_ *_
_ * @author 叶小鸡_
_ * @since 2026-05-01_
_ */_
@Service
public class ExchangeCodeServiceImpl extends ServiceImpl<ExchangeCodeMapper, ExchangeCode> implements IExchangeCodeService {

    private BoundValueOperations<String, String> serialOps;

    public ExchangeCodeServiceImpl(StringRedisTemplate redisTemplate){
        this.serialOps = redisTemplate.boundValueOps(_COUPON_CODE_SERIAL_KEY_);
    }
    @Override
    @Async("generateExchangeCodeExecutor")
    public void asyncGenerateCode(Coupon coupon) {
        //发放数量
        Integer totalNum = coupon.getTotalNum();
        //1.获取Redis自增序列号
        Long result = serialOps.increment(totalNum);
        if (result == null){
            return;
        }
        int maxSerialNum = result.intValue();
        List<ExchangeCode> list = new ArrayList<>(totalNum);
        for (int serialNum = maxSerialNum -totalNum + 1; serialNum <= maxSerialNum; serialNum++) {
            //2.生成兑换码
            String code = CodeUtil._generateCode_(serialNum, coupon.getId());
            ExchangeCode e = new ExchangeCode();
            e.setCode(code);
            e.setId(serialNum);
            e.setExchangeTargetId(coupon.getId());
            e.setExpiredTime(coupon.getIssueEndTime());
            list.add(e);
        }
        //3.保存数据库
        saveBatch(list);
    }
}

记得先在启动类开启异步

具体的实现类当中这个和线程池配置当中的方法名一致

接下来具体看实现类代码:

分为三步走

1.获取 Redis 自增序列号

2.生成兑换码

3.保存数据库

涉及 Redis 操作,先定义一个常量 KEY

这里采用这种构造器注入的方法,直接绑定 KEY,避免反复传入 key 参数。

红色:得到的是 Long 类型,但是下面需要 int 类型,所以转换一下

绿色:批量操作

橙色:为啥不直接从 1 开始,因为 maxSerialNum 是 redis 自增的,它不一定都等于 totalNum

别忘了把这改成 INPUT 类型

测试:

先新增指定发放的优惠券:

这里为啥不是从 1 开始的呢,因为之前测试过了,redis 当中还有数据。

作业实现删除优惠券接口:

作业实现根据 id 查询优惠券接口:

作业实现暂停发放接口:

这里事务,感觉像是针对并发场景,目前不确定,过。


如果对你有帮助的话,请点赞,关注,收藏。热爱可抵一切!👍 ❤️ 🔥

相关推荐
小短腿的代码世界1 小时前
Qt券商接口封装深度解析:统一API设计与多源适配
开发语言·qt·单元测试
wearegogog1231 小时前
基于Q-learning的栅格地图路径规划MATLAB仿真程序
开发语言·算法·matlab
@#¥&~是乱码鱼啦1 小时前
Spring分层架构:Controller、Service、Mapper数据链路,IOC的真实工作意义
java·spring·架构
xieliyu.1 小时前
Java手搓数据结构:从零模拟实现无头双向非循环链表
java·数据结构·链表
csbysj20201 小时前
Java 条件语句
开发语言
薪火铺子2 小时前
SpringMVC请求处理流程源码解析(第3篇):视图渲染与异常处理
java·后端·spring
Ulyanov2 小时前
《现代 Python 桌面应用架构实战:PySide6 + QML 从入门到工程化》 开发环境搭建与工具链极简主义 —— 拒绝臃肿,构建工业级基座
开发语言·python·qt·ui·架构·系统仿真
逻辑驱动的ken2 小时前
Java高频面试场景题19
java·开发语言·面试·职场和发展·求职招聘
初心未改HD2 小时前
Go语言net/http与Web开发:构建高性能HTTP服务
开发语言·golang