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 查询优惠券接口:

作业实现暂停发放接口:

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


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

相关推荐
WiChP11 小时前
【V0.1B10】从零开始的2D游戏引擎开发之路
java·数据库·游戏引擎
一然明月11 小时前
qt基本用法
开发语言·qt
云烟成雨TD11 小时前
Spring AI Alibaba 1.x 系列【60】检查点机制原理与全流程剖析
java·人工智能·spring
ForgeAI码匠12 小时前
Maven 多模块项目如何避免越写越乱?Forge Admin 的模块边界实践
java·人工智能·开源·maven
hef28812 小时前
Prism图形设计从入门到精通:外观设置、图层顺序与微调技巧
开发语言
z落落12 小时前
C# 数组 最终完整版全套笔记(一维+多维+交错+引用类型+对象数组)
java·笔记·c#
Access开发易登软件12 小时前
Access 和 SQLite,根本不在一个赛道上
java·jvm·数据库·sqlite·excel·vba·access开发
小马爱打代码12 小时前
Spring源码 第十篇:Spring 5 源码深度拆解 - Spring 类型转换与校验体系
java·spring
长谷深风11112 小时前
Java 面试高频:反射机制与异常体系全面解析
java·开发语言·面试·exception·java 反射·java 异常·class 对象
过期动态12 小时前
【LeetCode 热题 100】盛最多水的容器
java·数据结构·spring boot·算法·leetcode·spring cloud·职场和发展