有关于幂等操作--redis实现

本文介绍了一种基于注解和拦截器的幂等性检查方案,通过在方法上添加注解,利用拦截器检查请求参数,防止重复提交,确保系统的稳定性和数据一致性。

1.写一个标注

2,在需要幂等的方法上加上这个标注

3.用拦截器,拦截每一个请求,从请求中获取参数,如果带有标注则进行幂等检查,如果没有则不作

4.具体幂等检查(根据请求中的token和url来作为key,检查redis中是否存在

然后设置该key在redis中有效期,比如2秒)

代码如下

标注:

@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SameUrlData {

}
@Component
public class SameUrlDataInterceptor extends HandlerInterceptorAdapter {
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		if (handler instanceof HandlerMethod) {
			HandlerMethod handlerMethod = (HandlerMethod) handler;
			Method method = handlerMethod.getMethod();
			SameUrlData annotation = method.getAnnotation(SameUrlData.class);
			if (annotation != null) {
				if (repeatDataValidator(request)) {
					// 请求数据相同
					JSONObject result = new JSONObject();
					result.put("statusCode", "500");
					result.put("message", "Do not submit repeatedly");
					response.setCharacterEncoding("UTF-8");
					response.setContentType("application/json; charset=utf-8");
					response.getWriter().write(result.toString());
					response.getWriter().close();
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * 验证同一个url数据是否相同提交,相同返回true
	 * 
	 * @param httpServletRequest
	 * @return
	 */
	public boolean repeatDataValidator(HttpServletRequest httpServletRequest) {
		// 获取请求参数map
		Map<String, String[]> parameterMap = httpServletRequest.getParameterMap();
		Iterator<Map.Entry<String, String[]>> it = parameterMap.entrySet().iterator();

		Map<String, String[]> parameterMapNew = new HashMap<>();
		while (it.hasNext()) {
			Map.Entry<String, String[]> entry = it.next();
			parameterMapNew.put(entry.getKey(), entry.getValue());
		}

		String token = httpServletRequest.getHeader("Auth-token");

		if (StringUtil.isBlank(token)) {
			// 如果没有token,直接放行
			return false;
		}
		// 过滤过后的请求内容
		String params = JSONObject.toJSONString(parameterMapNew);

		System.out.println("params===========" + params);

		String url = httpServletRequest.getRequestURI();
		Map<String, String> map = new HashMap<>();
		// key为接口,value为参数
		map.put(url, params);
		String nowUrlParams = map.toString();

		StringRedisTemplate smsRedisTemplate = SpringContextHolder.getBean(StringRedisTemplate.class);
		String redisKey = token + url;
		String preUrlParams = smsRedisTemplate.opsForValue().get(redisKey);
		if (preUrlParams == null) {// 如果上一个数据为null,表示还没有访问页面

			// 存放并且设置有效期,2秒
			smsRedisTemplate.opsForValue().set(redisKey, nowUrlParams, 2, TimeUnit.SECONDS);
			return false;

		} else {// 否则,已经访问过页面

			if (preUrlParams.equals(nowUrlParams)) {
				// 如果上次url+数据和本次url+数据相同,则表示重复添加数据
				return true;
			} else {// 如果上次 url+数据 和本次url加数据不同,则不是重复提交
				smsRedisTemplate.opsForValue().set(redisKey, nowUrlParams, 1, TimeUnit.SECONDS);
				return false;
			}

		}
	}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值