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