redis进行幂等性

redis基于注解方式实现

package com.zhk.study.annotation;

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

/**
 * ElementType.METHOD:该注解作用于方法上
 * RetentionPolicy.RUNTIME:表示它在运行时
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiIdempotent {

}
package com.zhk.study.annotation;
 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
 
/**
 * 接口幂等性拦截器
 */
@Component
public class ApiIdempotentInterceptor implements HandlerInterceptor {
 
    @Autowired
    private TokenService tokenService;
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
 
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
 
        ApiIdempotent methodAnnotation = method.getAnnotation(ApiIdempotent.class);
        if (methodAnnotation != null) {
            check(request);// 幂等性校验, 校验通过则放行, 校验失败则抛出异常, 并通过统一异常处理返回友好提示
        }
        return true;
    }
 
    private void check(HttpServletRequest request) {
        tokenService.checkToken(request);
    }
 
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    }
 
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    }
}

package com.zhk.study.annotation;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class ExceptionAdvice {

    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ServerResponse responseCode(Exception e) {
        return ServerResponse.error(e.getMessage());
    }
}


package com.zhk.study.annotation;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

@Configuration
public class JedisConfig {

    @Bean(name = "jedisPoolConfig")
    public JedisPoolConfig jedisPoolConfig(){
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(500);
        jedisPoolConfig.setMaxIdle(200);
        jedisPoolConfig.setNumTestsPerEvictionRun(1024);
        jedisPoolConfig.setTimeBetweenEvictionRunsMillis(30000);
        jedisPoolConfig.setMinEvictableIdleTimeMillis(-1);
        jedisPoolConfig.setSoftMinEvictableIdleTimeMillis(10000);
        jedisPoolConfig.setMaxWaitMillis(1500);
        jedisPoolConfig.setTestOnBorrow(true);
        jedisPoolConfig.setTestWhileIdle(true);
        jedisPoolConfig.setTestOnReturn(false);
        jedisPoolConfig.setJmxEnabled(true);
        jedisPoolConfig.setBlockWhenExhausted(false);
        return jedisPoolConfig;
    }

    @Bean
    public JedisPool redisPool() {
        String host = "127.0.0.1";
        int port = 6379;
        return new JedisPool( jedisPoolConfig(),host,port,
        150000,"qv8sqntqmmv5");
    }

}

package com.zhk.study.annotation;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;


@Component
@Slf4j
public class JedisUtil {

    @Autowired
    private JedisPool jedisPool;

    private Jedis getJedis() {
	  return jedisPool.getResource();
    }

    /**
     * 设值
     *
     * @param key
     * @param value
     * @return
     */
    public String set(String key, String value) {
	  Jedis jedis = null;
	  try {
		jedis = getJedis();
		return jedis.set(key, value);
	  } catch (Exception e) {
		log.error("set key:{} value:{} error", key, value, e);
		return null;
	  } finally {
		close(jedis);
	  }
    }

    /**
     * 设值
     *
     * @param key
     * @param value
     * @param expireTime 过期时间, 单位: s
     * @return
     */
    public String set(String key, String value, int expireTime) {
	  Jedis jedis = null;
	  try {
		jedis = getJedis();
		return jedis.setex(key, expireTime, value);
	  } catch (Exception e) {
		log.error("set key:{} value:{} expireTime:{} error", key, value, expireTime, e);
		return null;
	  } finally {
		close(jedis);
	  }
    }

    /**
     * 取值
     *
     * @param key
     * @return
     */
    public String get(String key) {
	  Jedis jedis = null;
	  try {
		jedis = getJedis();
		return jedis.get(key);
	  } catch (Exception e) {
		log.error("get key:{} error", key, e);
		return null;
	  } finally {
		close(jedis);
	  }
    }

    /**
     * 删除key
     *
     * @param key
     * @return
     */
    public Long del(String key) {
	  Jedis jedis = null;
	  try {
		jedis = getJedis();
		return jedis.del(key.getBytes());
	  } catch (Exception e) {
		log.error("del key:{} error", key, e);
		return null;
	  } finally {
		close(jedis);
	  }
    }

    /**
     * 判断key是否存在
     *
     * @param key
     * @return
     */
    public Boolean exists(String key) {
	  System.out.println(key);
	  Jedis jedis = null;
	  try {
		jedis = getJedis();
		return jedis.exists(key.getBytes());
	  } catch (Exception e) {
		log.error("exists key:{} error", key, e);
		return null;
	  } finally {
		close(jedis);
	  }
    }

    /**
     * 设值key过期时间
     *
     * @param key
     * @param expireTime 过期时间, 单位: s
     * @return
     */
    public Long expire(String key, int expireTime) {
	  Jedis jedis = null;
	  try {
		jedis = getJedis();
		return jedis.expire(key.getBytes(), expireTime);
	  } catch (Exception e) {
		log.error("expire key:{} error", key, e);
		return null;
	  } finally {
		close(jedis);
	  }
    }

    /**
     * 获取剩余时间
     *
     * @param key
     * @return
     */
    public Long ttl(String key) {
	  Jedis jedis = null;
	  try {
		jedis = getJedis();
		return jedis.ttl(key);
	  } catch (Exception e) {
		log.error("ttl key:{} error", key, e);
		return null;
	  } finally {
		close(jedis);
	  }
    }

    private void close(Jedis jedis) {
	  if (null != jedis) {
		jedis.close();
	  }
    }

}


package com.zhk.study.annotation;


public enum ResponseCode {

    // 系统模块
    SUCCESS(0, "操作成功"),
    ERROR(1, "操作失败"),
    SERVER_ERROR(500, "服务器异常"),

    // 通用模块 1xxxx
    ILLEGAL_ARGUMENT(10000, "参数不合法"),
    REPETITIVE_OPERATION(10001, "请勿重复操作");

    ResponseCode(Integer code, String msg) {
	  this.code = code;
	  this.msg = msg;
    }

    private Integer code;

    private String msg;

    public Integer getCode() {
	  return code;
    }

    public void setCode(Integer code) {
	  this.code = code;
    }

    public String getMsg() {
	  return msg;
    }

    public void setMsg(String msg) {
	  this.msg = msg;
    }
}



package com.zhk.study.annotation;

import com.fasterxml.jackson.annotation.JsonIgnore;

import java.io.Serializable;

public class ServerResponse implements Serializable{

    private static final long serialVersionUID = 7498483649536881777L;

    private Integer status;

    private String msg;

    private Object data;

    public ServerResponse() {
    }

    public ServerResponse(Integer status, String msg, Object data) {
	  this.status = status;
	  this.msg = msg;
	  this.data = data;
    }

    @JsonIgnore
    public boolean isSuccess() {
	  return this.status == ResponseCode.SUCCESS.getCode();
    }

    public static ServerResponse success() {
	  return new ServerResponse(ResponseCode.SUCCESS.getCode(), null, null);
    }

    public static ServerResponse success(String msg) {
	  return new ServerResponse(ResponseCode.SUCCESS.getCode(), msg, null);
    }

    public static ServerResponse success(Object data) {
	  return new ServerResponse(ResponseCode.SUCCESS.getCode(), null, data);
    }

    public static ServerResponse success(String msg, Object data) {
	  return new ServerResponse(ResponseCode.SUCCESS.getCode(), msg, data);
    }

    public static ServerResponse error(String msg) {
	  return new ServerResponse(ResponseCode.ERROR.getCode(), msg, null);
    }

    public static ServerResponse error(Object data) {
	  return new ServerResponse(ResponseCode.ERROR.getCode(), null, data);
    }

    public static ServerResponse error(String msg, Object data) {
	  return new ServerResponse(ResponseCode.ERROR.getCode(), msg, data);
    }

    public Integer getStatus() {
	  return status;
    }

    public void setStatus(Integer status) {
	  this.status = status;
    }

    public String getMsg() {
	  return msg;
    }

    public void setMsg(String msg) {
	  this.msg = msg;
    }

    public Object getData() {
	  return data;
    }

    public void setData(Object data) {
	  this.data = data;
    }
}


package com.zhk.study.annotation;

/**
 * 业务逻辑异常
 */
public class ServiceException extends RuntimeException{

    private String code;
    private String msg;

    public ServiceException() {
    }

    public ServiceException(String msg) {
        this.msg = msg;
    }

    public ServiceException(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}



package com.zhk.study.annotation;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/token")
public class TokenController {
 
    @Autowired
    private TokenService tokenService;
    
    @GetMapping("/create")
    public ServerResponse token() {
        return tokenService.createToken();
    }

    @ApiIdempotent
    @PostMapping("/testIdempotence")
    public ServerResponse testIdempotence() {
        return tokenService.testIdempotence();
    }
}

package com.zhk.study.annotation;

import javax.servlet.http.HttpServletRequest;

public interface TokenService {

    ServerResponse createToken();

    void checkToken(HttpServletRequest request);

    ServerResponse testIdempotence();
}



package com.zhk.study.annotation;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.UUID;

@Service
public class TokenServiceImpl implements TokenService {
 
    private static final String TOKEN_NAME = "token";

    private static final String TOKEN_PREFIX = "token:";

    // 过期时间, 60s, 一分钟
    private static final Integer EXPIRE_TIME_MINUTE = 60 * 5;
 
    @Autowired
    private JedisUtil jedisUtil;
 
    @Override
    public ServerResponse createToken() {
        String str = UUID.randomUUID().toString().replaceAll("-", "");
        StringBuilder token = new StringBuilder();
        token.append(TOKEN_PREFIX).append(str);

        System.out.println(token.toString()+":::::"+ token.toString());
        jedisUtil.set(token.toString(), token.toString(), EXPIRE_TIME_MINUTE);
 
        return ServerResponse.success(token.toString());
    }
 
    @Override
    public void checkToken(HttpServletRequest request) {
        String token = request.getHeader(TOKEN_NAME);
        if (StringUtils.isBlank(token)) {// header中不存在token
            token = request.getParameter(TOKEN_NAME);
            if (StringUtils.isBlank(token)) {// parameter中也不存在token
                throw new ServiceException(ResponseCode.ILLEGAL_ARGUMENT.getMsg());
            }
        }
 
        if (!jedisUtil.exists(token)) {
            throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getMsg());
        }
 
        Long del = jedisUtil.del(token);
        if (del <= 0) {
            throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getMsg());
        }
    }
    
    @Override
    public ServerResponse testIdempotence() {
        return ServerResponse.success("testIdempotence: success");
    }
 
}

package com.zhk.study.annotation;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * Web配置文件
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    private ApiIdempotentInterceptor apiIdempotentInterceptor;

    /**
     * 跨域
     * @return
     */
    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }



    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(apiIdempotentInterceptor).addPathPatterns("/**");
    }
}

用法切记 创建token的时候 传token这个token有点恶心 是这种 自己可以改一下 本人懒
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张航柯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值