SpringBoot + Redis 解决海量重复提交问题

if (exists(key)) {

Boolean delete = redisTemplate.delete(key);

return delete;

}

return false;

}

}

自定义注解 AutoIdempotent

自定义一个注解,定义此注解的主要目的是把它添加在需要实现幂等的方法上,凡是某个方法注解了它,都会实现自动幂等。

后台利用反射如果扫描到这个注解,就会处理这个方法实现自动幂等,使用元注解ElementType.METHOD表示它只能放在方法上,etentionPolicy.RUNTIME表示它在运行时。

@Target({ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

public @interface AutoIdempotent {

}

token 创建和检验

token服务接口:我们新建一个接口,创建token服务,里面主要是两个方法,一个用来创建token,一个用来验证token。创建token主要产生的是一个字符串,检验token的话主要是传达request对象,为什么要传request对象呢?主要作用就是获取header里面的token,然后检验,通过抛出的Exception来获取具体的报错信息返回给前端。

public interface TokenService {

/** * 创建token * @return */

public String createToken();

/** * 检验token * @param request * @return */

public boolean checkToken(HttpServletRequest request) throws Exception;

}

token的服务实现类:token引用了redis服务,创建token采用随机算法工具类生成随机uuid字符串,然后放入到redis中(为了防止数据的冗余保留,这里设置过期时间为10000秒,具体可视业务而定),如果放入成功,最后返回这个token值。checkToken方法就是从header中获取token到值(如果header中拿不到,就从paramter中获取),如若不存在,直接抛出异常。这个异常信息可以被拦截器捕捉到,然后返回给前端。

@Service

public class TokenServiceImpl implements TokenService {

@Autowired

private RedisService redisService;

/** * 创建token * * @return */

@Override

public String createToken() {

String str = RandomUtil.randomUUID();

StrBuilder token = new StrBuilder();

try {

token.append(Constant.Redis.TOKEN_PREFIX).append(str);

redisService.setEx(token.toString(), token.toString(),10000L);

boolean notEmpty = StrUtil.isNotEmpty(token.toString());

if (notEmpty) {

return token.toString();

}

}catch (Exception ex){

ex.printStackTrace();

}

return null;

}

/** * 检验token * * @param request * @return */

@Override

public boolean checkToken(HttpServletRequest request) throws Exception {

String token = request.getHeader(Constant.TOKEN_NAME);

if (StrUtil.isBlank(token)) {// header中不存在token

token = request.getParameter(Constant.TOKEN_NAME);

if (StrUtil.isBlank(token)) {// parameter中也不存在token

throw new ServiceException(Constant.ResponseCode.ILLEGAL_ARGUMENT, 100);

}

}

if (!redisService.exists(token)) {

throw new ServiceException(Constant.ResponseCode.REPETITIVE_OPERATION, 200);

}

boolean remove = redisService.remove(token);

if (!remove) {

throw new ServiceException(Constant.ResponseCode.REPETITIVE_OPERATION, 200);

}

return true;

}

}

拦截器的配置

web配置类,实现WebMvcConfigurerAdapter,主要作用就是添加autoIdempotentInterceptor到配置类中,这样我们到拦截器才能生效,注意使用@Configuration注解,这样在容器启动是时候就可以添加进入context中。

@Configuration

public class WebConfiguration extends WebMvcConfigurerAdapter {

@Resource

private AutoIdempotentInterceptor autoIdempotentInterceptor;

/** * 添加拦截器 * @param registry */

@Override

public void addInterceptors(InterceptorRegistry registry) {

registry.addInterceptor(autoIdempotentInterceptor);

super.addInterceptors(registry);

}

}

拦截处理器:主要的功能是拦截扫描到AutoIdempotent到注解到方法,然后调用tokenService的checkToken()方法校验token是否正确,如果捕捉到异常就将异常信息渲染成json返回给前端。

如果您正在学习Spring Boot,推荐一个连载多年还在继续更新的免费教程:http://blog.didispace.com/spring-boot-learning-2x/

/** * 拦截器 */

@Component

public class AutoIdempotentInterceptor implements HandlerInterceptor {

@Autowired

private TokenService tokenService;

/** * 预处理 * * @param request * @param response * @param handler * @return * @throws Exception */

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

if (!(handler instanceof HandlerMethod)) {

return true;

}

HandlerMethod handlerMethod = (HandlerMethod) handler;

Method method = handlerMethod.getMethod();

//被ApiIdempotment标记的扫描

AutoIdempotent methodAnnotation = method.getAnnotation(AutoIdempotent.class);

if (methodAnnotation != null) {

try {

return tokenService.checkToken(request);// 幂等性校验, 校验通过则放行, 校验失败则抛出异常, 并通过统一异常处理返回友好提示

}catch (Exception ex){

ResultVo failedResult = ResultVo.getFailedResult(101, ex.getMessage());

writeReturnJson(response, JSONUtil.toJsonStr(failedResult));

throw ex;

}

}

//必须返回true,否则会被拦截一切请求

return true;

}

@Override

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

}

@Override

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

}

/** * 返回的json值 * @param response * @param json * @throws Exception */

private void writeReturnJson(HttpServletResponse response, String json) throws Exception{

PrintWriter writer = null;

response.setCharacterEncoding(“UTF-8”);

response.setContentType(“text/html; charset=utf-8”);

try {

writer = response.getWriter();

writer.print(json);

} catch (IOException e) {

} finally {

if (writer != null)

writer.close();

}

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!
获取!!(备注Java获取)**

img

最后

[外链图片转存中…(img-hWKTcKAP-1712075360686)]

[外链图片转存中…(img-DrWS35MP-1712075360687)]

[外链图片转存中…(img-Ib7AdB6u-1712075360687)]

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值