【在线OJ系统】自定义注解实现分布式ID无感自增

实现思路

首先自定义参数注解,然后根据AOP思想,找到该注解作用的切点,也就是mapper层对于mapper层的接口在执行前都会执行该aop操作:获取到对于的方法对象,根据方法对象获取参数列表,根据参数列表判断某个参数上是否加有自定义的注解,如果有则读取注解中的value值,并通过传入对象的引用拿到该对象,此时判断该对象的id值是否位空,如果为空则生成全局唯一id并赋值

代码实现
复制代码
package com.cloud.cloud_oj_learn.aspects;

import com.cloud.cloud_oj_common.annotations.GenerateId;
import com.cloud.cloud_oj_common.enums.Keys;
import jakarta.annotation.Resource;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: PG
 * Date: 2024-04-16
 * Time: 18:49
 */
@Aspect
@Component
public class GenerateIdAspect {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    // 初始时间戳
    private static final long BEGIN_TIME = 1640995200L;

    // 序列化位数
    private static final int BITE = 32;

    public Long getNext(String tableName) {
        // 1.生成时间戳
        LocalDateTime now = LocalDateTime.now();
        long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
        long timestamp = nowSecond - BEGIN_TIME;

        // 2,生成序列化号
        String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        long count = stringRedisTemplate.opsForValue().increment(Keys.GENERATE_ID.getKey() + tableName + ":" + date);

        // 3.拼接  返回
        return Long.valueOf(timestamp << BITE | count);
    }


    @Before("execution(* com.cloud.cloud_oj_learn.mapper.*.*(..))")
    public void before(JoinPoint joinPoint) {
        // 获取方法签名
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        // 获取方法对象
        Method method = methodSignature.getMethod();
        // 获取方法参数值数组
        Object[] args = joinPoint.getArgs();
        // 获取方法注解
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        for (int i = 0; i < parameterAnnotations.length; i++) {
            for (Annotation annotation : parameterAnnotations[i]) {
                if (annotation instanceof GenerateId) {
                    try {
                        // 获取参数对象
                        Object arg = args[i];
                        // 获取这个对象的类文件
                        Class<?> clazz = arg.getClass();
                        // 获取这个对象的id属性
                        Field idField = clazz.getDeclaredField("id");
                        // 设置字段修改权限
                        idField.setAccessible(true);
                        // 获取注解上的value值
                        String value = ((GenerateId) annotation).value();
                        // 获取该value对应的下一个id
                        Long nextId = getNext(value);
                        // 判断是否为空, 如果为空就赋值 
                        if (idField.get(arg) == null) {
                            idField.set(arg, nextId);
                        }
                    } catch (NoSuchFieldException | IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }

}

图示

相关推荐
码界筑梦坊8 分钟前
171-基于Flask的笔记本电脑数据可视化分析系统
python·信息可视化·flask·毕业设计·echarts
编啊编程啊程2 小时前
JUC之AQS
java·开发语言·jvm·c++·kafka
hui函数4 小时前
Flask电影投票系统全解析
后端·python·flask
好学且牛逼的马5 小时前
GOLANG 接口
开发语言·golang
ahauedu5 小时前
AI资深 Java 研发专家系统解析Java 中常见的 Queue实现类
java·开发语言·中间件
韭菜钟5 小时前
在Qt中用cmake实现类似pri文件的功能
开发语言·qt·系统架构
闲人编程6 小时前
Python第三方库IPFS-API使用详解:构建去中心化应用的完整指南
开发语言·python·去中心化·内存·寻址·存储·ipfs
计算机编程小咖6 小时前
《基于大数据的农产品交易数据分析与可视化系统》选题不当,毕业答辩可能直接挂科
java·大数据·hadoop·python·数据挖掘·数据分析·spark
CTRA王大大7 小时前
【golang】制作linux环境+golang的Dockerfile | 如何下载golang镜像源
linux·开发语言·docker·golang
zhangfeng11337 小时前
以下是基于图论的归一化切割(Normalized Cut)图像分割工具的完整实现,结合Tkinter界面设计及Python代码示
开发语言·python·图论