思路:首先是个springcloud项目,需要配好nacos对redis的连接,然后redis也要在自己的配置文件配好支持本地ip的访问设置,不是原来的127.0.0.1。然后需要自定义接口,以及对自定义注解进行调用的类进行控制,使自定义注解在controller某个方法中可以实现重复访问的控制。
nacos中配置的redis连接
spring:
redis:
host: 10.11.6.82
port: 6379
password: 123456
lettuce:
pool:
enabled: true
max-active: 100
max-wait: -1
max-idle: 50
min-idle: 5
redis本身的配置
//1.redis.windows.conf配置文件
//需要notepad++编辑 全局搜索protected-mode默认是yes,需要改成no
//搜索bind 把这行配置的127.0.0.1给注释掉#
//以下是改好的效果
protected-mode no
#bind 127.0.0.1
//2.redis.windows.service,conf配置同上,也修改那两个地方 省略步骤。。。
//3.之后用redis可视化软件连接redis
//案例中是ip是 10.11.6.82 改成你自己的
// post是6379
// password是123456 改成你自己的
项目中自定义注解
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CheckRepeatCommit {
String channel() default "APP";
int expireTime() default 3;
}
项目中操作自定义注解的类
import cn.hutool.core.util.StrUtil;
import com.dykj.common.base.utils.RegUtil;
import com.dykj.common.core.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
@Component
@Aspect
@Slf4j
public class CheckRepeatCommitAspect {
@Autowired
private RegUtil regUtil;
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Pointcut("@annotation(com.dykj.file.utils.CheckRepeatCommit)")
private void checkRepeatCommit() {
}
@Around("checkRepeatCommit()")
public Object checkRepeatCommit(ProceedingJoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getName();
Object target = joinPoint.getTarget();
//得到拦截的方法
Method method = getMethodByClassAndName(target.getClass(), methodName);
log.info("验证是否重复提交:" + "调用方法:" + method);
//请求的方法名
String className = joinPoint.getTarget().getClass().getName();
String channel = "";
String bizKey = method.getName();
int expireTime = 0;
// 获取当前请求方法的注解,根据注解配置获取参数
CheckRepeatCommit checkRepeatCommit = method.getAnnotation(CheckRepeatCommit.class);
//String userNo = SysUserContextHolder.getSysUser().getUserNo();
String userNo =regUtil.getLoginUserId();
String key;
if (checkRepeatCommit != null) {
//注解上的描述
channel = checkRepeatCommit.channel();
expireTime = checkRepeatCommit.expireTime();
key = getRepeatCommitLock(channel, className, bizKey, userNo, expireTime);
if (StringUtils.isBlank(key)) {
throw new BusinessException("ResultEnum.RE_COMMIT");
}
}
return joinPoint.proceed();
}
/**
* 根据类和方法名得到方法
*/
public Method getMethodByClassAndName(Class c, String methodName) {
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals(methodName)) {
return method;
}
}
return null;
}
public String getRepeatCommitLock(String channel, String module, String bizKey, String userNo, int expireTime) {
if (StringUtils.isEmpty(module) || StringUtils.isEmpty(bizKey)) {
throw new BusinessException("getRepeatCommitLock{} 参数不能为空!");
}
String redisKey = channel + StrUtil.COLON + module + StrUtil.COLON + bizKey + StrUtil.COLON + userNo;
long count = redisTemplate.opsForValue().increment(redisKey, 1);
if (count == 1) {
if (expireTime == 0) {
expireTime = 60;
}
redisTemplate.expire(redisKey, expireTime, TimeUnit.SECONDS);
return redisKey;
} else {
return null;
}
}
}
controller中需要使用到接口防重复校验的接口
@CheckRepeatCommit
@PostMapping("One")
public String One(){
return "hello! app!";
}
测试效果
//访问这个接口,快速去redis可视化工具查看到这条存储的信息(时间设置很短,看手速能看到效果)
//访问次数在这个redis这个key存在的期间不能无限访问,需要过了这个时间才可以。
regUtil
import cn.hutool.extra.spring.SpringUtil;
import com.dykj.common.core.redis.utils.RedisUtil;
import com.dykj.mybatis.sys.mapper.SysConfigMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
@Component
@RequiredArgsConstructor
public class RegUtil {
private final HttpServletRequest httpServletRequest;
private final RedisUtil redisUtil;
/**
* 获取登录用户信息
* @return Object 需要类型转换
*/
public Object getLoginUser(){
String token = httpServletRequest.getHeader("Authorization");
return redisUtil.get(token);
}
/**
* 获取登录用户名称
* @return String
*/
public String getLoginUserName(){
String token = httpServletRequest.getHeader("Authorization");
return JWTUtil.getUserName(token);
}
/**
* 获取登录用户ID
* @return String
*/
public String getLoginUserId(){
String token = httpServletRequest.getHeader("Authorization");
return JWTUtil.getUserId(token);
}
/**
* 获取登录用户区县代码
* @return String
*/
public String getAdministrativeCode(){
String token = httpServletRequest.getHeader("Authorization");
return JWTUtil.getadministrativeCode(token);
}
/**
* 获取访问的url
* @return String
*/
public String getUrl(){
return httpServletRequest.getRequestURI();
}
/**
* 获取IP地址
*/
public String getIpAddr() {
String ip = null, unknown = "unknown", seperator = ",";
int maxLength = 15;
try {
ip = httpServletRequest.getHeader("x-forwarded-for");
if (!StringUtils.hasLength(ip) || unknown.equalsIgnoreCase(ip)) {
ip = httpServletRequest.getHeader("Proxy-Client-IP");
}
if (!StringUtils.hasLength(ip) || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
ip = httpServletRequest.getHeader("WL-Proxy-Client-IP");
}
if (!StringUtils.hasLength(ip) || unknown.equalsIgnoreCase(ip)) {
ip = httpServletRequest.getHeader("HTTP_CLIENT_IP");
}
if (!StringUtils.hasLength(ip) || unknown.equalsIgnoreCase(ip)) {
ip = httpServletRequest.getHeader("HTTP_X_FORWARDED_FOR");
}
if (!StringUtils.hasLength(ip) || unknown.equalsIgnoreCase(ip)) {
ip = httpServletRequest.getRemoteAddr();
}
} catch (Exception e) {
throw e;
}
// 使用代理,则获取第一个IP地址
if (!StringUtils.hasLength(ip) && ip.length() > maxLength) {
int idx = ip.indexOf(seperator);
if (idx > 0) {
ip = ip.substring(0, idx);
}
}
return ip;
}
/**
* 根据key返回系统配置的value
* @param key 值
* @return value 值
*/
public String getConfig(String key){
SysConfigMapper sysConfigMapper = SpringUtil.getBean(SysConfigMapper.class);
if(redisUtil.hasKey(3,key))
{
return redisUtil.get(3,key).toString();
}
String value = sysConfigMapper.getValue(key);
redisUtil.set(3,key,value);
return value;
}
}
抛出异常的工具类
public class BusinessException extends RuntimeException{
private static final long serialVersionUID = 1L;
/**
* 错误码
*/
private Integer code;
/**
* 错误提示
*/
private String message;
public BusinessException(String message) {
this.message = message;
}
public BusinessException(int code, String message) {
this.code = code;
this.message = message;
}
public BusinessException(int code, String msg, Throwable cause) {
this.message = msg;
this.code = code;
}
public BusinessException(Throwable cause) {
super(cause);
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
JWT获取token中用户信息
import cn.hutool.core.util.StrUtil;
import io.jsonwebtoken.*;
import java.util.Date;
public class JWTUtil {
//过期时间
private static final long tokenExpiration = 24*60*60*1000;
//签名秘钥
private static final String tokenSignKey = "xidkngeoiaIdf;ge%dlslgsld;saldfjlkcjvlskjdf39";
//根据参数生成token
public static String createToken(String userId, String userName, String administrativeCode) {
return Jwts.builder()
.setSubject("DYKJ-USER")
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
.claim("userId", userId)
.claim("userName", userName)
.claim("administrativeCode",administrativeCode)
.signWith(SignatureAlgorithm.HS512, tokenSignKey)
.compressWith(CompressionCodecs.GZIP)
.compact();
}
/*
* 根据token字符串得到用户id
* @param token
*/
public static String getUserId(String token) {
if(StrUtil.isBlank(token)){
return null;
}
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return claims.get("userId").toString();
}
/*
* 根据token字符串得到用户名称
* @param token
*/
public static String getUserName(String token) {
if(StrUtil.isBlank(token)){
return null;
}
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return (String)claims.get("userName");
}
/*
* 根据token字符串得到区县代码
* @param token
*/
public static String getadministrativeCode(String token) {
if(StrUtil.isBlank(token)){
return null;
}
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return (String)claims.get("administrativeCode");
}
}