详解Spring AOP 实现“切面式”valid校验

2025-05-27 0 62

why:

为什么要用aop实现校验

answer:

spring mvc 默认自带的校验机制 @valid + bindingresult, 但这种默认实现都得在controller方法的中去接收bindingresult,从而进行校验.

eg:

?

1

2

3

4

5

6

7
if (result.haserrors()) {

list<objecterror> allerrors = result.getallerrors();

list<string> errorlists = new arraylist<>();

for (objecterror objecterror : allerrors) {

errorlists.add(objecterror.getdefaultmessage());

}

}

获取errorlists。这样实现的话,每个需要校验的方法都得重复调用,即使封装也是。

可能上面那么说还不能表明spring 的@valid + bindingresult实现,我先举个“栗子”。

1. 栗子(旧版本)

1.1 接口层(idal)

eg: 简单的post请求,@requestbody接收请求数据,@valid + bindingresult进行校验

  1. httpmethid: post
  2. parameters:@requestbody接收请求数据
  3. valid:@valid +bindingresult
?

1

2

3

4

5

6

7

8

9

10

11

12

13

14
@responsebody

@postmapping("body")

public responsevo bodypost(@requestbody @valid testvo body,bindingresult result){

//校验到错误

if (result.haserrors()) {

list<objecterror> allerrors = result.getallerrors();

list<string> lists = new arraylist<>();

for (objecterror objecterror : allerrors) {

lists.add(objecterror.getdefaultmessage());

}

return new responsevo(httpstatus.bad_request.value(), "parameter empty", lists);

}

return new responsevo(httpstatus.ok.value(), "bodypost", null);

}

1.2 实体(vo)校验内容

@valid + bindingresult的校验注解一大堆,网上一摸就有的!

?

1

2

3

4

5

6

7

8

9

10
public class testvo {

@getter

@setter

@min(value = 0,message = "请求参数isstring不能小于0")

private integer isint;

@getter

@setter

@notblank(message = "请求参数isstring不能为空")

private string isstring;

}

1.3 结果测试

详解Spring AOP 实现“切面式”valid校验

2. aop校验(升级版)

可以看到若是多个像bodypost一样都需要对body进行校验的话,那么有一坨代码就必须不断复现,即使改为父类可复用方法,也得去调用。所以左思右想还是觉得不优雅。所以有了aop进行切面校验

2.1 接口层(idal)

是的!你没看错,上面那一坨代码没了,也不需要调用父类的的共用方法。就单单一个注解就完事了:@paramvalid

?

1

2

3

4

5

6
@paramvalid

@responsebody

@postmapping("body")

public responsevo bodypost(@requestbody @valid testvo body,bindingresult result){

return new responsevo("bodypost", null);

}

2.2 自定义注解(annotation)

这个注解也是简简单单的用于方法的注解。

?

1

2

3
@target(elementtype.method)

@retention(retentionpolicy.runtime)

public @interface paramvalid {}

2.3 重点!切面实现(aspect)

切面详解:

@before: 使用注解方式@annotation(xx),凡是使用到所需切的注解(@paramvalid),都会调用该方法

joinpoint: 通过joinpoint获取方法的参数,以此获取bindingresult所校验到的内容

迁移校验封装: 将原先那一坨校验迁移到aspect中:validrequestparams

响应校验结果:

  1. 通过requestcontextholder获取response
  2. 获取响应outputstream
  3. 将bindingresult封装响应
?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58
@aspect

@component

public class paramvalidaspect {

private static final logger log = loggerfactory.getlogger(paramvalidaspect.class);

@before("@annotation(paramvalid)")

public void paramvalid(joinpoint point, paramvalid paramvalid) {

object[] paramobj = point.getargs();

if (paramobj.length > 0) {

if (paramobj[1] instanceof bindingresult) {

bindingresult result = (bindingresult) paramobj[1];

responsevo errormap = this.validrequestparams(result);

if (errormap != null) {

servletrequestattributes res = (servletrequestattributes) requestcontextholder.getrequestattributes();

httpservletresponse response = res.getresponse();

response.setcharacterencoding("utf-8");

response.setcontenttype(mediatype.application_json_utf8_value);

response.setstatus(httpstatus.bad_request.value());

outputstream output = null;

try {

output = response.getoutputstream();

errormap.setcode(null);

string error = new gson().tojson(errormap);

log.info("aop 检测到参数不规范" + error);

output.write(error.getbytes("utf-8"));

} catch (ioexception e) {

log.error(e.getmessage());

} finally {

try {

if (output != null) {

output.close();

}

} catch (ioexception e) {

log.error(e.getmessage());

}

}

}

}

}

}

/**

* 校验

*/

private responsevo validrequestparams(bindingresult result) {

if (result.haserrors()) {

list<objecterror> allerrors = result.getallerrors();

list<string> lists = new arraylist<>();

for (objecterror objecterror : allerrors) {

lists.add(objecterror.getdefaultmessage());

}

return new responsevo(httpstatus.bad_request.value(), "parameter empty", lists);

}

return null;

}

}

2.4 测试结果

详解Spring AOP 实现“切面式”valid校验

看了上面两种结果,就可以对比出使用spring aop 配合@valid + bindingresult进行校验的优点:

  1. 去除代码冗余
  2. aop异步处理
  3. 优化代码实现

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持快网idc。

原文链接:https://juejin.im/post/5a5e1159518825732b19d8ce

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 详解Spring AOP 实现“切面式”valid校验 https://www.kuaiidc.com/76225.html

相关文章

发表评论
暂无评论