SpringBoot接口防重复和日志切面

简单通过redis过期处理接口重复和日志切面token+ip+参数+spel表单式

引入redis依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

yaml配置redis

spring
  redis:
    host: 10.*.*.37
    password: ***
    database: 12
    port: 6379  

防重复切面注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Description VaildApiRecommit
 *
 * @ClassName VaildApiRecommit
 * @date 2023.03.20 19:27
 **/
@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface VaildApiRecommit {
    /**
     * Description ConstantUtils.EXTAPIHEAD 是否从header头部获取到Authorization 不配置则从参数获取
    **/
    String value();

    /**
     * 提交唯一标识组合 遵循spel表达式
     * primaryKeys = "#processDefineKey"
     */
    String[] primaryKeys() default {};

    /**
     * 校验时间间隔,如果指定覆盖默认系统属性值
     */
    long validateInterval() default 3;
}

接口防重复切面

import java.lang.reflect.Method;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSON;
import com.adapter.common.base.exception.BusinessException;
import com.adapter.common.base.redis.ConstantUtils;
import com.adapter.utils.RedisUtil;

import cn.hutool.core.util.StrUtil;

/**
 * Description ExtApiAopIdempotent
 *
 * @ClassName ExtApiAopIdempotent
 * @date 2023.03.20 19:28
 **/
@Order(0)
@Aspect
@Component
public class ValidApiRecommitAspect {

    @Resource
    private RedisUtil redisUtil;

    @Value("${app.validateInterval}")
    private Long validateInterval;

    @Pointcut("execution(* com.adapter.api..*.*(..))")
    public void rlAop() {

    }

    /**
     * 封装数据
     */
    public HttpServletRequest getRequest() {
        ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        return request;
    }

    /**
     * 异常返回通知,连接点抛出异常
     *
     * @param joinPoint
     *            切入点
     * @param e
     *            异常信息
     */
    @AfterThrowing(pointcut = "rlAop()", throwing = "e")
    public void saveExceptionOperateLog(JoinPoint joinPoint, Throwable e) {
        throw BusinessException.create("重复提交检验失败" + e.getMessage());

    }

    @Before("rlAop()")
    public void before(JoinPoint joinPoint) {
        // 获取被增强的方法相关信息 - 查看方法上是否有次注解
        MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        VaildApiRecommit declaredAnnotation = AnnotationUtils.findAnnotation(method, VaildApiRecommit.class);
        if (declaredAnnotation != null) {
            String values = declaredAnnotation.value();
            String token = null;
            HttpServletRequest request = getRequest();
            if (values.equals(ConstantUtils.EXTAPIHEAD)) {
                token = request.getHeader("Authorization");
            } else {
                token = request.getParameter("Authorization");
            }
            // 获取不到token
            if (StrUtil.isEmpty(token)) {
                throw BusinessException.create("未找到鉴权头部信息");
            }
            // 存入redis的键token + method + ip + 参数
            String key = getValidateKey(method, joinPoint.getArgs(), declaredAnnotation.primaryKeys(), token);
            // 接口获取对应的令牌,如果能够获取该(从redis获取令牌)令牌(将当前令牌删除掉) 就直接执行该访问的业务逻辑
            boolean isToken = redisUtil.hasKey(key);
            // 接口获取对应的令牌,如果获取不到该令牌 直接返回请勿重复提交
            if (isToken) {
                throw BusinessException.create("请勿重复请求");
            } else {
                redisUtil.set(key, key, validateInterval);
            }
        }
    }

    /**
     * 获取每次请求Key token + ip+uri+paramsKey
     */
    private String getValidateKey(Method method, Object[] args, String[] primaryKeys, String token) {

        List<String> paramsKey = evalParamsKey(method, args, primaryKeys);
        ServletRequestAttributes requestAttributes =
            (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String requestURI = request.getRequestURI();
        String userIp = request.getRemoteAddr();

        StringBuilder requestKey = new StringBuilder();
        requestKey.append(token);
        if (StringUtils.isNotEmpty(userIp)) {
            requestKey.append(userIp);
        }

        if (StringUtils.isNotEmpty(requestURI)) {
            requestKey.append(requestURI);
        }
        if (!CollectionUtils.isEmpty(paramsKey)) {
            for (String primaryValue : paramsKey) {
                requestKey.append(primaryValue);
            }
        }

        if (CollectionUtils.isEmpty(paramsKey) && args != null) {
            for (Object primaryValue : args) {
                if (primaryValue != null) {
                    requestKey.append(JSON.toJSONString(primaryValue));
                }
            }
        }
        // key压缩
        return new BigInteger(1, DigestUtils.md5Digest(requestKey.toString().getBytes())).toString(16);
    }

    /**
     * Description 解析Spel表达式获取值
     * 
     * @param method
     *            method
     * @param args
     *            请求的参数
     * @param primaryKeys
     *            spel表达式
     * @return java.util.List<java.lang.String>
     * @author
     * @date 20:10 2023/3/20
     **/
    private List<String> evalParamsKey(Method method, Object[] args, String[] primaryKeys) {
        List<String> primaryValues = new ArrayList<>();
        if (primaryKeys != null) {
            for (String primaryKey : primaryKeys) {
                ExpressionParser expressionParser = new SpelExpressionParser();
                Expression expression = expressionParser.parseExpression(primaryKey);
                EvaluationContext context = new StandardEvaluationContext();
                LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
                String[] parameterNames = discoverer.getParameterNames(method);
                for (int i = 0; i < parameterNames.length; i++) {
                    if (args[i] != null) {
                        context.setVariable(parameterNames[i], args[i]);
                    }
                }
                Object primaryValue = expression.getValue(context);
                if (primaryValue != null) {
                    primaryValues.add(JSON.toJSONString(primaryValue));
                }
            }
        }
        return primaryValues;
    }

}

日志切面

import java.lang.annotation.*;

/**
 * @description: 用户行为日志注解
 * 
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface BusinessOperateLog {

    /**
     * 操作模块
     * @return : java.lang.String
     */
    String operateModule() default "";

    /**
     * 操作类型
     * @return
     */
    String operateType() default "";

    /**
     * 操作说明
     * @return
     */
    String operateDesc() default "";
}
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.adapter.dto.log.ManageOperateDTO;
import com.adapter.service.ManageOperateService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * @description: 系统日志
 */
@Order(2)
@Aspect
@Component
@Slf4j
public class SysLogAspect {

//日志持久类   
 @Resource
    private ManageOperateService manageOperateService;

    /****************************************************
     * 系统行为日志
     ********************************************************/

    /**
     * 注解切入点
     */
    @Pointcut(
        value = "execution(* com.adapter.api..*.*(..))")
    public void operateLogPointCut() {
        // 这是一个切入点
    }

    /**
     * 前端用户操作行为成功
     */
    private static final String OPERATE_STATUS_SUCCESS = "1";

    /**
     * 前端用户操作行为失败
     */
    private static final String OPERATE_STATUS_FAIL = "0";

    /**
     * 正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行
     *
     * @param joinPoint
     *            切入点
     * @param keys
     *            返回结果
     */
    @AfterReturning(value = "operateLogPointCut()", returning = "keys")
    public void saveOperateLog(JoinPoint joinPoint, Object keys) {
        operate(joinPoint, OPERATE_STATUS_SUCCESS);
    }

    /**
     * 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行
     *
     * @param joinPoint
     *            切入点
     * @param e
     *            异常信息
     */
    @AfterThrowing(pointcut = "operateLogPointCut()", throwing = "e")
    public void saveExceptionOperateLog(JoinPoint joinPoint, Throwable e) {
        operate(joinPoint, OPERATE_STATUS_FAIL);

    }

    private void operate(JoinPoint joinPoint, String operateStatus) {

        // 从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        // 获取切入点所在的方法
        Method method = signature.getMethod();
        String s = JSONUtil.toJsonStr(joinPoint.getArgs());
        log.info("保存到日志中的参数是:{}", s);
        // 获取操作
        BusinessOperateLog businessOperateLog = AnnotationUtils.findAnnotation(method, BusinessOperateLog.class);
        if (ObjectUtil.isNotEmpty(businessOperateLog)) {
            String desc = "【" + businessOperateLog.operateModule() + "】" + "-【" + businessOperateLog.operateType()
                + "】," + businessOperateLog.operateDesc() + ",参数:" + s;
            ManageOperateDTO manageOperateDTO = new ManageOperateDTO();
            // manageOperateDTO.setManageUserId(SecurityUtil.currentUserId());
            manageOperateDTO.setOperateTime(new Date());
            manageOperateDTO.setOperateStatus(operateStatus);
            manageOperateDTO.setOperateContent(desc);
            // manageOperateDTO.setCreator(SecurityUtil.getCurrentUser().getUserName());
            // manageOperateDTO.setAreaCode(SecurityUtil.getVaildCodes());
            manageOperateService.add(manageOperateDTO);
        }
    }

}

注解使用

 public class OperateType {

    private OperateType() {}

    /**
     * 新增
     */
    public final static String ADD = "ADD";

    /**
     * 修改
     */
    public final static String UPDATE = "UPDATE";

    /**
     * 删除
     */
    public final static String DELETE = "DELETE";

    /**
     * 批量删除
     */
    public final static String BATCH_DELETE = "BATCH_DELETE";

    /**
     * 查询
     */
    public final static String QUERY = "QUERY";

    /**
     * 导出
     */
    public final static String EXPORT = "EXPORT";

    /**
     * 导入
     */
    public final static String IMPORT = "IMPORT";

    /**
     * 审核
     */
    public final static String AUDIT = "AUDIT";
}

/**
     * 新增
     *
     * @param entity entity
     * @return boolean
     */
    @VaildApiRecommit(value = ConstantUtils.EXTAPIHEAD)
    @ApiOperation(value = "新增", notes = "新增")
    @PostMapping("/add")
    @BusinessOperateLog(operateModule = "接口新增", operateType = OperateType.ADD, operateDesc = "新增接口")
    public JsonResponse<Boolean> add(@RequestBody @ApiParam(value = "新增数据类", name = "entity") T entity) {
        return JsonResponse.ok(baseService.insert(entity));
    }

redis工具类

import com.adapter.common.base.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class RedisUtil {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    private final static String GET_ERROR_MESSAGE = "获取缓存数据失败";

    private final static String SET_ERROR_MESSAGE = "设置缓存数据失败";

    private final static String DELETE_ERROR_MESSAGE = "删除缓存数据失败";

    /**
     * 根据keys pattern 进行模糊匹配查询存在的key值
     *
     * @param keys K pattern
     * @return
     */
    public Set<String> keys(String keys) {
        try {
            return redisTemplate.keys(keys);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(GET_ERROR_MESSAGE);
        }
    }

    /**
     * 指定缓存失效时间
     *
     * @param key  键
     * @param time 时间(秒)
     * @return
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
            throw BusinessException.create("插入缓存数据失败");
            //return false;
        }
    }

    /**
     * 根据key 获取过期时间
     *
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判断key是否存在
     *
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            //e.printStackTrace();
            log.error(e.getMessage());
            throw BusinessException.create("判断缓存数据失败");
            //return false;
        }
    }

    /**
     * 删除缓存
     *
     * @param key 可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(String... key) {
        if (key != null && key.length > 0) {
            try {
                if (key.length == 1) {
                    redisTemplate.delete(key[0]);
                } else {
                    redisTemplate.delete(CollectionUtils.arrayToList(key));
                }
            } catch (Exception e) {
                log.error(e.getMessage());
                throw BusinessException.create("删除缓存数据失败");
            }
        }
    }

    /**
     * 普通缓存获取
     *
     * @param key 键
     * @return 值
     */
    public Object get(String key) {

        try {
            return key == null ? null : redisTemplate.opsForValue().get(key);
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
            throw BusinessException.create(GET_ERROR_MESSAGE);
        }
    }

    /**
     * 普通缓存放入
     *
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            //e.printStackTrace();
            log.error(e.getMessage());
            throw BusinessException.create("插入缓存数据失败");
            //return false;
        }
    }

    /**
     * 普通缓存放入并设置时间
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
            throw BusinessException.create("插入缓存数据失败");
            //return false;
        }
    }

    /**
     * 递增
     *
     * @param key   键
     * @param delta 要增加几(大于0)
     * @return
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 递减
     *
     * @param key   键
     * @param delta 要减少几(小于0)
     * @return
     */
    public long decr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递减因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }

    // ===============================Hash=================================

    /**
     * HashGet
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return 值
     */
    public Object hget(String key, String item) {
        try {
            return redisTemplate.opsForHash().get(key, item);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(GET_ERROR_MESSAGE);
        }
    }

    /**
     * 获取hashKey对应的所有键值
     *
     * @param key 键
     * @return 对应的多个键值
     */
    public Map<Object, Object> hmget(String key) {
        try {
            return redisTemplate.opsForHash().entries(key);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(GET_ERROR_MESSAGE);
        }
    }

    /**
     * HashSet
     *
     * @param key 键
     * @param map 对应多个键值
     * @return true 成功 false 失败
     */
    public boolean hmset(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            //e.printStackTrace();
            log.error(e.getMessage());
            throw BusinessException.create(GET_ERROR_MESSAGE);
            //return false;
        }
    }

    /**
     * HashSet 并设置时间
     *
     * @param key  键
     * @param map  对应多个键值
     * @param time 时间(秒)
     * @return true成功 false失败
     */
    public boolean hmset(String key, Map<String, Object> map, long time) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            //e.printStackTrace();
            log.error(e.getMessage());
            throw BusinessException.create(GET_ERROR_MESSAGE);
            //return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            //e.printStackTrace();
            log.error(e.getMessage());
            throw BusinessException.create(GET_ERROR_MESSAGE);
            //return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value, long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            //e.printStackTrace();
            log.error(e.getMessage());
            throw BusinessException.create(GET_ERROR_MESSAGE);
            //return false;
        }
    }

    /**
     * 删除hash表中的值
     *
     * @param key  键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    public void hdel(String key, Object... item) {
        try {
            redisTemplate.opsForHash().delete(key, item);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create("删除缓存数据失败");
        }
    }

    /**
     * 判断hash表中是否有该项的值
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
        try {
            return redisTemplate.opsForHash().hasKey(key, item);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(GET_ERROR_MESSAGE);
        }
    }

    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     *
     * @param key  键
     * @param item 项
     * @param by   要增加几(大于0)
     * @return
     */
    public double hincr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, by);
    }

    /**
     * hash递减
     *
     * @param key  键
     * @param item 项
     * @param by   要减少记(小于0)
     * @return
     */
    public double hdecr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, -by);
    }

    // ===============================Set=================================

    /**
     * 根据key获取Set中的所有值
     *
     * @param key 键
     * @return
     */
    public Set<Object> sGet(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(GET_ERROR_MESSAGE);
        }
    }

    /**
     * 根据value从一个set中查询,是否存在
     *
     * @param key   键
     * @param value 值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value) {
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(GET_ERROR_MESSAGE);
        }
    }

    /**
     * 将数据放入set缓存
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(SET_ERROR_MESSAGE);
        }
    }

    /**
     * 将set数据放入缓存
     *
     * @param key    键
     * @param time   时间(秒)
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0) {
                expire(key, time);
            }
            return count;
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(SET_ERROR_MESSAGE);
        }
    }

    /**
     * 获取set缓存的长度
     *
     * @param key 键
     * @return
     */
    public long sGetSetSize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(GET_ERROR_MESSAGE);
        }
    }

    /**
     * 移除值为value的
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 移除的个数
     */
    public long setRemove(String key, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(DELETE_ERROR_MESSAGE);
        }
    }

    // ===============================list=================================

    /**
     * 获取list缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   结束 0 到 -1代表所有值
     * @return
     */
    public List<Object> lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(GET_ERROR_MESSAGE);
        }
    }

    /**
     * 获取list缓存的长度
     *
     * @param key 键
     * @return
     */
    public long lGetListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(GET_ERROR_MESSAGE);
        }
    }

    /**
     * 通过索引 获取list中的值
     *
     * @param key   键
     * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     * @return
     */
    public Object lGetIndex(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(GET_ERROR_MESSAGE);
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(SET_ERROR_MESSAGE);
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(SET_ERROR_MESSAGE);
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(SET_ERROR_MESSAGE);
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(SET_ERROR_MESSAGE);
        }
    }

    /**
     * 根据索引修改list中的某条数据
     *
     * @param key   键
     * @param index 索引
     * @param value 值
     * @return
     */
    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(SET_ERROR_MESSAGE);
        }
    }

    /**
     * 移除N个值为value
     *
     * @param key   键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */
    public long lRemove(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            log.error(e.getMessage());
            throw BusinessException.create(DELETE_ERROR_MESSAGE);
        }
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,为了实现 Spring Boot 接口刷的切面和注解,您需要执行以下步骤: 1. 在您的 Spring Boot 应用中创建一个切面类。在该类中,您可以使用 `@Aspect` 注解声明它是一个切面。 2. 在切面类中创建一个方法,使用 `@Around` 注解声明它是一个环绕通知方法。环绕通知方法可以在目标方法执行前后执行指定的代码。 3. 在环绕通知方法中,使用 `@Pointcut` 注解声明切点,并使用 `ProceedingJoinPoint` 类的 `proceed()` 方法执行目标方法。 4. 在环绕通知方法中,使用注解来声明需要进行刷的方法。您可以自定义注解,并使用 `@Target` 和 `@Retention` 注解来声明该注解可以用在方法上。 5. 在环绕通知方法中,使用注解中的参数来控制方法的访问频率。您可以使用任意方式来实现这一点,例如使用缓存或者计数器。 以下是一个简单的例子,该例子使用了注解 `@AntiBrush` 来声明需要进行刷的方法,并使用了缓存来实现刷功能: ``` @Aspect @Component public class AntiBrushAspect { private Cache<String, AtomicInteger> cache = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build ### 回答2: 首先,我们需要定义一个自定义注解,用于标识某个接口需要进行刷限制。我们可以定义一个名为AntiSpam的注解,代码如下: ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AntiSpam { int limit() default 10; // 默认限制为10秒内只能请求10次 } ``` 接下来,我们需要实现一个切面来拦截带有AntiSpam注解的接口。首先,需要引入以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> ``` 然后,在你的Spring Boot应用程序中创建一个名为AntiSpamAspect的类,代码如下: ```java @Aspect @Component public class AntiSpamAspect { private ConcurrentHashMap<String, Long> methodLastAccessTimeMap = new ConcurrentHashMap<>(); @Around("@annotation(antiSpam)") public Object handleAntiSpam(ProceedingJoinPoint joinPoint, AntiSpam antiSpam) throws Throwable { String methodName = joinPoint.getSignature().toShortString(); Long lastAccessTime = methodLastAccessTimeMap.get(methodName); long currentTime = System.currentTimeMillis(); if (lastAccessTime != null && currentTime - lastAccessTime < (antiSpam.limit() * 1000)) { throw new RuntimeException("操作频率过高,请稍后再试!"); } else { methodLastAccessTimeMap.put(methodName, currentTime); return joinPoint.proceed(); } } } ``` 在上面的代码中,我们使用了ConcurrentHashMap来存储每个方法最后一次访问的时间。在处理切面时,我们会根据方法名从map中获取上一次访问时间,并与当前时间进行比较。如果两次访问间隔小于限定时间,则抛出异常,否则继续执行方法。 最后,我们需要在Spring Boot的主类上添加@EnableAspectJAutoProxy注解,开启切面的自动代理功能。 至此,我们已经完成了Spring Boot接口刷的切面和注解实现。接下来,只需要在需要进行刷的接口方法上添加@AntiSpam注解,并在需要处理切面的类上添加@Component注解即可。 ### 回答3: 在Spring Boot中实现接口刷功能,可以通过切面和注解的方式来实现。 首先,我们需要定义一个自定义注解,用于标识需要进行接口刷限制的方法。可以命名为@RateLimit。 ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RateLimit { int value(); // 设置接口频率限制值,比如每秒允许访问的次数 int timeout() default 1; // 设置超时时间,默认1秒 } ``` 接下来,我们可以定义一个切面类,用于处理接口刷逻辑。可以命名为RateLimitAspect。 ```java @Aspect @Component public class RateLimitAspect { private Map<String, Long> requestCounts = new ConcurrentHashMap<>(); // 记录请求次数的Map @Around("@annotation(rateLimit)") public Object around(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable { String methodName = joinPoint.getSignature().toLongString(); int limit = rateLimit.value(); int timeout = rateLimit.timeout(); long currentTime = System.currentTimeMillis(); if (!requestCounts.containsKey(methodName)) { requestCounts.put(methodName, currentTime); return joinPoint.proceed(); } long lastTime = requestCounts.get(methodName); long interval = currentTime - lastTime; if (interval < timeout * 1000) { if (requestCounts.get(methodName + "_count") == null) { requestCounts.put(methodName + "_count", 1L); } else { long count = requestCounts.get(methodName + "_count"); if (count >= limit) { throw new RuntimeException("接口调用频率过高,请稍后再试!"); } requestCounts.put(methodName + "_count", count + 1); } } else { requestCounts.remove(methodName); requestCounts.remove(methodName + "_count"); } requestCounts.put(methodName, currentTime); return joinPoint.proceed(); } } ``` 在切面类中,我们使用了一个Map来记录接口每次请求的时间和次数。如果接口调用频率超过限制,则阻止请求继续执行,并抛出异常。 使用@Around注解和@RateLimit注解来标识切面和需要进行限制的方法。通过@Around注解,我们可以在接口方法的执行前后进行处理,从而实现刷逻辑。 最后,我们需要在Spring Boot的启动类上添加@EnableAspectJAutoProxy注解,开启切面自动代理功能。 ```java @SpringBootApplication @EnableAspectJAutoProxy public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 这样,就可以在需要进行接口刷限制的方法上添加@RateLimit注解,并在超过限制的情况下阻止请求继续执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值