Springboot 使用AOP实现防止接口重复提交

Springboot 使用AOP实现防止接口重复提交,第1张

在传统的web项目中,防止重复提交,通常做法是:后端生成一个唯一的提交令牌(uuid),并存储在服务端。页面提交请求携带这个提交令牌,后端验证并在第一次验证后删除该令牌,保证提交请求的唯一性。

思路没有问题,但是需要前后端都稍加改动,如果在业务开发完再加这个的话,改动量未免有些大了。无需前端配合,纯后端处理,是最清爽的。设计思路如下:

自定义注解@RreventReSubmit标记所有Controller中的提交请求。通过AOP 对所有标记@RreventReSubmit的方法拦截。在业务方法执行前,获取当前用户的 token(或者JSessionId)+ 当前请求地址,作为一个唯一 KEY,去获取 Redis 分布式锁(如果此时并发获取,只有一个线程会成功获取锁)。当有请求调用接口时,到redis中查找相应的key,如果能找到,则说明重复提交,如果找不到,则执行 *** 作。业务方法执行后,释放锁。

切面类需要使用@Aspect和@Component这两个注解做标注。

在想要防止重复提交的接口上添加注解即可使用。

一、问题

在书写controller时 我们一般会先定义一个baseController,里面设置获取一些通用业务信息,比如获取当前登录用户信息等。

这种情况下的baseController里 ,不会做RequestMapping 也就是web请求不会直接到这个父类,这种继承是不会有任何问题的。

当有些业务的controller 也需要被继承呢,类似这种 带有requestMapping 注解

如果我们写一个这样的业务类来继承它

那么就会有惊喜

简单说 就会告诉你 模糊的映射 也就是无法确定请求分配到哪个controller的方法

二、原因

容易看出子类MisSyncZYJController 继承了MisSyncController 连带requestMapping 也设为一样,requestMapping 可以理解为请求派发的命名空间,相同的空间里,子类享有父类protected及其以上的访问权限,当容器启动做方法请求映射时,就会发现父类的一般请求方法,全部都没有明确派发地址了。

三 处理

1、隔离命名空间,这是最简单的,直接把子类的requestMapping 多一级或者换个名称

类似

2、 放弃继承带有requestMapping的一般业务类,而只继承没有请求派发的一般父类,类似上文提到的baseController

3、带有疑问的不可行方案,技术上讲,如果把父类的方法设置为private(private方法不影响web请求派发),子类是不可访问的,那么我们不改requestMapping,把有问题的业务父类方法设置成private时可以吗,答案是 no

看到尽管已经标记为private ,依然还是报模糊的映射规则。

不过话说回来 就算这个方案技术可行,也是不符合主流规范的,纯粹测试,至于原因 有待深究。

四、引申

如果两个没有关联 或者说并行的controller想用一样的映射空间 比如'/misSync', 可以吗,答案是没问题的。

只是在找请求的时候,本来只要在一个misSync对应的controller里找,现在变成要找其他也标记为misSync的controller,如果一个controller已经非常庞大,命名空间也不能改,确实也可以考虑这样拆分一部分出去。

当然最好还是一个命名空间一个controller,方便跟踪请求了。

Spring Boot充分利用了JavaConfig的配置模式以及“约定优于配置”的理念,能够极大的简化基于Spring MVC的Web应用和REST服务开发。 Spring 4倡导微服务的架构,针对这一理念,近来在微博上也有一些有价值的讨论,如这里和这里。微服务架构倡导将功能拆分到离散的服务中,独立地进行部署,Spring Boot能够很方便地将应用打包成独立可运行的JAR包,因此在开发模式上很契合这一理念。目前,Spring Boot依然是050的里程碑版本,因此相关的文档尚不完善,本文将会以一个简单的样例来介绍基于这个项目的开发过程。 要Spring Boot进行功能开发,需要使用Gradle或者Maven作为构建工具。在本例中,我们会使用Eclipse和Maven插件进行开发。要使用Spring Boot

给你提供一个思路:

1、写个静态类,定义静态变量,把所有要用到的service(假设AOP拦截到service层)实现类都写成key,value的形式,如:

Map modeMap=new HashMap();

mapput("UserServiceImpl","用户管理")//用于记录类与模块的对应关系。

2、写静态变量,把定义的方法与日志中记录的描述对应。

methodMapput("add_UserInfo",'添加用户信息');

methodMapput("update_UserInfo",'修改用户信息');

3、写AOP切入点:

@Resource(name = "baseDao")

private BaseDao baseDao;

@Pointcut("execution ( comwebservice())")

// 切入点作用域

private void anyMethod() {

}// 声明一个切入点应用方法

@SuppressWarnings("unchecked")

@AfterReturning(pointcut = "anyMethod()", returning = "result")

public void doAfterReturning(JoinPoint join, Object result) {

String classname = joingetTarget()getClass()getName();//获取当前的类名

String method = joingetSignature()getName();//方法名

//再在上述静态MAP里找模块名字和方法描述,略

//下述session中获取当前用户信息,略

>

一、用户名密码登录处理过程(spring security实现的处理流程):

1密码登录的请求会进入一个叫做UsernamePasswordAuthenticationFilter的过滤器

2这个过滤器会拿到用户名和密码组装成UsernamePasswordAuthenticationToken这样一个对象

3然后过滤器把这个token对象传给AuthenticationManager

4AuthenticationManager会在一堆AuthenticationProvider中挑出一个处理认证请求

这个挑选的依据是:这个authenticationProvider中有一个supports()方法会判断当前这个provider是否支持传进来的UsernamePasswordAuthenticationToken,如果支持,就用当前的Provider来认证这个token。

5在认证的过程中会调UserDetailsService来获取用户的信息,跟传进来的登录信息进行比对,如果认证通过会把UsernamePasswordAuthenticationToken 做一个标志,标记为已认证放进session中。

二、手机号验证码登录处理过程:(spring security没有实现,应该我们自己去仿照用户名密码登录去实现)

1短信验证码登录的请求进入我们自己写的SmsAuthenticationFilter过滤器

2这个过滤器会从请求中拿到手机号封装成一个SmsAuthenticationToken这样一个对象

3然后过滤器会把这个token传给系统中唯一的AuthenticationManager

4AuthenticationManager还是会检索系统中的所有的AuthenticationProvider,这里我们要实现一个SmsAuthenticationProvider,

用这个provider来检索token中的手机号。

5这个过程中还是会调用UserDetailsService来获取用户信息,来跟登录信息进行比对,如果认证通过会把SmsAuthenticationToken 标志为已认证,放进session中。

注意:为什么验证短信验证码的逻辑不像用户名密码的验证逻辑写在DaoAuthenticationProvider一样写在SmsAuthenticationProvider中呢?主要是因为我们想要重用这个短信验证,例如支付的时候需要短信验证,所以我们单独写一个过滤器来实现短信验证码的功能,放在SmsAuthenticationFilter之前。

以上就是关于Springboot 使用AOP实现防止接口重复提交全部的内容,包括:Springboot 使用AOP实现防止接口重复提交、springmvc controller 的继承问题、使用springboot做的一个服务通过url地址嵌到一个系统里,app有个发送邮件等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/9634499.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-30
下一篇 2023-04-30

发表评论

登录后才能评论

评论列表(0条)

保存