parent
c403a5b7f2
commit
c4292172ed
15 changed files with 388 additions and 27 deletions
@ -0,0 +1,17 @@ |
||||
package com.huoran.iasf.common.aop.annotation; |
||||
|
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
/** |
||||
* @Description 不重复提交注解 |
||||
*/ |
||||
|
||||
@Target(ElementType.METHOD) // 作用到方法上
|
||||
@Retention(RetentionPolicy.RUNTIME) // 运行时有效
|
||||
public @interface NoRepeatSubmit { |
||||
|
||||
String name() default "name:"; |
||||
} |
@ -0,0 +1,86 @@ |
||||
package com.huoran.iasf.common.aop.aspect; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
|
||||
import com.huoran.iasf.common.aop.annotation.NoRepeatSubmit; |
||||
import com.huoran.iasf.common.exception.BusinessException; |
||||
import com.huoran.iasf.common.exception.code.BaseResponseCode; |
||||
import com.huoran.iasf.common.utils.Constant; |
||||
import com.huoran.iasf.common.utils.R; |
||||
import io.jsonwebtoken.Claims; |
||||
import io.jsonwebtoken.Jwts; |
||||
import lombok.Synchronized; |
||||
import org.apache.commons.logging.Log; |
||||
import org.apache.commons.logging.LogFactory; |
||||
import org.aspectj.lang.ProceedingJoinPoint; |
||||
import org.aspectj.lang.annotation.Around; |
||||
import org.aspectj.lang.annotation.Aspect; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.util.StringUtils; |
||||
import org.springframework.web.context.request.RequestContextHolder; |
||||
import org.springframework.web.context.request.ServletRequestAttributes; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
import static com.huoran.iasf.service.HttpApiSessionService.APP_SECRET; |
||||
|
||||
|
||||
/** |
||||
* @Description aop解析注解 |
||||
*/ |
||||
|
||||
@Aspect |
||||
@Component |
||||
public class NoRepeatSubmitAop { |
||||
|
||||
private Log logger = LogFactory.getLog(getClass()); |
||||
|
||||
@Autowired |
||||
private RedisServiceAop redisService; |
||||
|
||||
@Synchronized |
||||
@Around("execution(* com.huoran.*.controller.*.*(..)) && @annotation(noRepeatSubmit)") |
||||
public Object around(ProceedingJoinPoint pjp, NoRepeatSubmit noRepeatSubmit) throws Throwable { |
||||
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); |
||||
HttpServletRequest request = attributes.getRequest(); |
||||
String token = request.getHeader(Constant.ACCESS_TOKEN); |
||||
//如果header中不存在token,则从参数中获取token
|
||||
if (StringUtils.isEmpty(token)) { |
||||
token = request.getParameter(Constant.ACCESS_TOKEN); |
||||
} |
||||
if (StringUtils.isEmpty(token)) { |
||||
throw new BusinessException(BaseResponseCode.TOKEN_ERROR); |
||||
} |
||||
// 校验并解析token,如果token过期或者篡改,则会返回null
|
||||
Claims claims = checkJWT(token); |
||||
if (null == claims) { |
||||
throw new BusinessException(BaseResponseCode.TOKEN_ERROR); |
||||
} |
||||
String key = token + "-" + request.getServletPath(); |
||||
if ( !redisService.haskey(key) ) {// 如果缓存中有这个url视为重复提交
|
||||
Object o = pjp.proceed(); |
||||
redisService.setCacheObject(key, 0, 1, TimeUnit.SECONDS); |
||||
return o; |
||||
} else { |
||||
redisService.setCacheObject(key, 0, 1, TimeUnit.SECONDS);//点了同样的URL继续限制,直到2次点击中间间隔超过了限制
|
||||
return R.fail("请勿重复提交或者操作过于频繁!"); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 校验token |
||||
*/ |
||||
public Claims checkJWT(String token) { |
||||
|
||||
try { |
||||
final Claims claims = Jwts.parser().setSigningKey(APP_SECRET). |
||||
parseClaimsJws(token).getBody(); |
||||
return claims; |
||||
} catch (Exception e) { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,228 @@ |
||||
package com.huoran.iasf.common.aop.aspect; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.data.redis.core.*; |
||||
import org.springframework.stereotype.Component; |
||||
|
||||
import java.util.*; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
/** |
||||
* @Description RedisService |
||||
*/ |
||||
@Component |
||||
@SuppressWarnings(value = {"unchecked", "rawtypes"}) |
||||
public class RedisServiceAop { |
||||
|
||||
@Autowired |
||||
public RedisTemplate redisTemplate; |
||||
|
||||
/** |
||||
* 缓存基本的对象,Integer、String、实体类等 |
||||
* |
||||
* @param key 缓存的键值 |
||||
* @param value 缓存的值 |
||||
* @return 缓存的对象 |
||||
*/ |
||||
public <T> ValueOperations<String, T> setCacheObject(String key, T value) { |
||||
ValueOperations<String, T> operation = redisTemplate.opsForValue(); |
||||
operation.set(key, value); |
||||
return operation; |
||||
} |
||||
|
||||
/** |
||||
* 缓存基本的对象,Integer、String、实体类等 |
||||
* |
||||
* @param key 缓存的键值 |
||||
* @param value 缓存的值 |
||||
* @param timeout 时间 |
||||
* @param timeUnit 时间颗粒度 |
||||
* @return 缓存的对象 |
||||
*/ |
||||
public <T> ValueOperations<String, T> setCacheObject(String key, T value, Integer timeout, TimeUnit timeUnit) { |
||||
ValueOperations<String, T> operation = redisTemplate.opsForValue(); |
||||
operation.set(key, value, timeout, timeUnit); |
||||
return operation; |
||||
} |
||||
|
||||
/** |
||||
* 获得缓存的基本对象。 |
||||
* |
||||
* @param key 缓存键值 |
||||
* @return 缓存键值对应的数据 |
||||
*/ |
||||
public <T> T getCacheObject(String key) { |
||||
ValueOperations<String, T> operation = redisTemplate.opsForValue(); |
||||
return operation.get(key); |
||||
} |
||||
|
||||
/** |
||||
* 删除单个对象 |
||||
* |
||||
* @param key |
||||
*/ |
||||
public void deleteObject(String key) { |
||||
redisTemplate.delete(key); |
||||
} |
||||
|
||||
/** |
||||
* 删除集合对象 |
||||
* |
||||
* @param collection |
||||
*/ |
||||
public void deleteObject(Collection collection) { |
||||
redisTemplate.delete(collection); |
||||
} |
||||
|
||||
/** |
||||
* 缓存List数据 |
||||
* |
||||
* @param key 缓存的键值 |
||||
* @param dataList 待缓存的List数据 |
||||
* @return 缓存的对象 |
||||
*/ |
||||
public <T> ListOperations<String, T> setCacheList(String key, List<T> dataList) { |
||||
ListOperations listOperation = redisTemplate.opsForList(); |
||||
if (null != dataList) { |
||||
int size = dataList.size(); |
||||
for (int i = 0; i < size; i++) { |
||||
listOperation.leftPush(key, dataList.get(i)); |
||||
} |
||||
} |
||||
return listOperation; |
||||
} |
||||
|
||||
/** |
||||
* 获得缓存的list对象 |
||||
* |
||||
* @param key 缓存的键值 |
||||
* @return 缓存键值对应的数据 |
||||
*/ |
||||
public <T> List<T> getCacheList(String key) { |
||||
List<T> dataList = new ArrayList<T>(); |
||||
ListOperations<String, T> listOperation = redisTemplate.opsForList(); |
||||
Long size = listOperation.size(key); |
||||
|
||||
for (int i = 0; i < size; i++) { |
||||
dataList.add(listOperation.index(key, i)); |
||||
} |
||||
return dataList; |
||||
} |
||||
|
||||
/** |
||||
* 缓存Set |
||||
* |
||||
* @param key 缓存键值 |
||||
* @param dataSet 缓存的数据 |
||||
* @return 缓存数据的对象 |
||||
*/ |
||||
public <T> BoundSetOperations<String, T> setCacheSet(String key, Set<T> dataSet) { |
||||
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key); |
||||
Iterator<T> it = dataSet.iterator(); |
||||
while (it.hasNext()) { |
||||
setOperation.add(it.next()); |
||||
} |
||||
return setOperation; |
||||
} |
||||
|
||||
/** |
||||
* 获得缓存的set |
||||
* |
||||
* @param key |
||||
* @return |
||||
*/ |
||||
public <T> Set<T> getCacheSet(String key) { |
||||
Set<T> dataSet = new HashSet<T>(); |
||||
BoundSetOperations<String, T> operation = redisTemplate.boundSetOps(key); |
||||
dataSet = operation.members(); |
||||
return dataSet; |
||||
} |
||||
|
||||
/** |
||||
* 缓存Map |
||||
* |
||||
* @param key |
||||
* @param dataMap |
||||
* @return |
||||
*/ |
||||
public <T> HashOperations<String, String, T> setCacheMap(String key, Map<String, T> dataMap) { |
||||
HashOperations hashOperations = redisTemplate.opsForHash(); |
||||
if (null != dataMap) { |
||||
for (Map.Entry<String, T> entry : dataMap.entrySet()) { |
||||
hashOperations.put(key, entry.getKey(), entry.getValue()); |
||||
} |
||||
} |
||||
return hashOperations; |
||||
} |
||||
|
||||
/** |
||||
* 获得缓存的Map |
||||
* |
||||
* @param key |
||||
* @return |
||||
*/ |
||||
public <T> Map<String, T> getCacheMap(String key) { |
||||
Map<String, T> map = redisTemplate.opsForHash().entries(key); |
||||
return map; |
||||
} |
||||
|
||||
/** |
||||
* 获得缓存的基本对象列表 |
||||
* |
||||
* @param pattern 字符串前缀 |
||||
* @return 对象列表 |
||||
*/ |
||||
public Collection<String> keys(String pattern) { |
||||
return redisTemplate.keys(pattern); |
||||
} |
||||
|
||||
/** |
||||
* |
||||
* @param key |
||||
* @return |
||||
*/ |
||||
public boolean haskey(String key){ |
||||
return redisTemplate.hasKey(key); |
||||
} |
||||
|
||||
public Long getExpire(String key){ |
||||
return redisTemplate.getExpire(key); |
||||
} |
||||
|
||||
|
||||
public <T> ValueOperations<String, T> setBillObject(String key, List<Map<String, Object>> value) { |
||||
ValueOperations<String, T> operation = redisTemplate.opsForValue(); |
||||
operation.set(key, (T) value); |
||||
return operation; |
||||
} |
||||
/** |
||||
* 缓存list<Map<String, Object>> |
||||
* |
||||
* @param key 缓存的键值 |
||||
* @param value 缓存的值 |
||||
* @param timeout 时间 |
||||
* @param timeUnit 时间颗粒度 |
||||
* @return 缓存的对象 |
||||
*/ |
||||
public <T> ValueOperations<String, T> setBillObject(String key, List<Map<String, Object>> value, Integer timeout, TimeUnit timeUnit) { |
||||
ValueOperations<String, T> operation = redisTemplate.opsForValue(); |
||||
operation.set(key,(T)value, timeout, timeUnit); |
||||
return operation; |
||||
} |
||||
/** |
||||
* 缓存Map |
||||
* |
||||
* @param key |
||||
* @param dataMap |
||||
* @return |
||||
*/ |
||||
public <T> HashOperations<String, String, T> setCKdBillMap(String key, Map<String, T> dataMap) { |
||||
HashOperations hashOperations = redisTemplate.opsForHash(); |
||||
if (null != dataMap) { |
||||
for (Map.Entry<String, T> entry : dataMap.entrySet()) { |
||||
hashOperations.put(key, entry.getKey(), entry.getValue()); |
||||
} |
||||
} |
||||
return hashOperations; |
||||
} |
||||
} |
Loading…
Reference in new issue