测试
测试非DTO参数
准备如下测试代码:
1
2
3
4
5
6
7
8
9
|
@Validated
@Service
public class TmpService {
public void doService(@JNotBlank String inputParam) {
// do something
}
}
|
这份代码有两个地方需要注意:
- 类上的注解只能为
@Validated
,@Valid并不会生效。
- 方法参数不需要
@Validated
、@Valid
,我看网上有些教程写了,其实是不需要的。
测试DTO参数
准备如下代码:
1
2
3
4
5
6
7
8
9
|
@Validated
@Service
public class TmpService {
public void doService(@Valid TestRequest request) {
// do something
}
}
|
在我的测试中,类上的@Validated
注解和方法上的@Valid
注解,缺一不可,我觉得这是一种非常让人迷惑的写法,一不小心就可能翻车。
小结
message提示的问题
实验中我其实是有其他收获的,我发现当方法校验失败时,得到的返回结果是(基于我小小开发了一下的校验框架):
1
2
3
4
5
6
|
{
"code": 0,
"msg": "doService.inputParam 为空或长度为0"
}
|
也就是说basePath会指明方法及方法的参数。这说明了一个问题,我们开发的用于Request的注解,最好只用于Controller层,否则的话会将内部实现的一些细节暴露给用户。当然不仅仅是我们开发的注解,框架的注解也同样需要存在这个问题,甚至因为没有足够的提示信息,框架的提示信息更让人迷惑。
1
2
3
4
5
6
|
{
"code": 0,
"msg": "不能为空"
}
|
貌似说我们为注解加上message就可以完事了,这样用户就可以得到清晰明了的信息了,但是,我们应该好好思考一下,我们应该将service层参数校验的信息抛给用户么?我决定在下面好好讨论一下。
1
2
3
4
5
6
|
{
"code": 0,
"msg": "inputParam不能为空"
}
|
关于异常的讨论
异常目前主要分为两种:系统异常和业务异常,数据库无法获取链接,属于系统异常,一个给定的Id无法从数据库中找到数据,属于业务异常。这些异常都能很好的区分。
但是因为我们开发的Service往往需要提供给第其他人用,我们需要对传入的参数进行非空等校验,校验失败的时候,我们该抛出什么样的异常呢?系统的还是业务的?我目前的想法还是算作业务异常吧,因为我们写的Service本质上就是业务Service,所以这些Service抛出的异常理应为业务异常。
从这个分析的角度,我们Controller中对Request的校验失败属于业务异常、Service层方法对参数的校验数据也属于业务异常,我们可以用相同的方式处理。
异常捕获的问题
目前在参数校验方面,我发现了三种不同的异常,但是我目前用到的主要是两种:
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
|
@ResponseBody
@ExceptionHandler(value = {
MethodArgumentNotValidException.class,
ConstraintViolationException.class,
BindException.class})
public Response exceptionHandler(Exception e) {
String message = "参数校验失败";
if (e instanceof BindException) {
message = ((BindException) e).getBindingResult().getFieldError().getDefaultMessage();
} else if (e instanceof ConstraintViolationException) {
Optional<String> messageOptional = ((ConstraintViolationException) e).getConstraintViolations()
.stream()
.map(ConstraintViolation::getMessage)
.findFirst();
message = messageOptional.get();
} else {
message = ((MethodArgumentNotValidException) e).getBindingResult().getFieldError().getDefaultMessage();
}
return new Response(0, message);
}
|
Service层校验失败,抛出来的就是ConstraintViolationException异常。
另外,关于异常处理,我收集了一段非常不错的代码,之所以觉得它用的好,是因为它使用了orElse,这个方法我使用的次数非常的少。
1
2
3
4
5
6
7
|
message e.getConstraintViolations()
.stream()
.findFirst()
.map(ConstraintViolation::getMessage)
.orElse("参数校验失败"))
|
这是我目前收集的信息。
参考资料
- spring boot 参数校验这么做简洁实用