微前端架构如何改变企业的开发模式与效率提升
684
2022-10-14
Spring Boot项目传参校验的最佳实践指南
目录场景还原神注解加持数据异常统一拦截总结
场景还原
简单业务场景模拟:
假如你现在在做一个成绩录入系统,你愉快地用Spring Boot框架写了一个后台接口,用于接收前台浏览器传过来的 Student对象,并插入后台数据库。
我们将传入的 Student对象定义为:
public class Student {
private String name; // 姓名
private Integer score; // 考试分数(满分100分)
private String mobile; // 电话号码(11位)
}
然后写一个Post请求的后台接口,来接收网页端传过来的 Student对象:
@RestController
public class TestController {
@Autowired
private StudentService studentService;
@PostMapping("/add")
public String addStudent( @RequestBody Student student ) {
studentService.addStudent( student ); // 将student对象存入数据库
return "SUCCESS";
}
}
此时我想你一定看出来了上面这段代码的漏洞,因为我们并没有对传入的 Student对象做任何数据校验,比如:
Student对象里三个字段的某一个忘传了,为 null怎么办?Student的 score分数,假如写错了,写成 101分怎么办?Student的 mobile11位手机号码,假如填错了,多写了一位怎么办?...等等
这些数据虽然在前端页面一般会做校验,但我们作为一个严谨且良心的后端开发工程师,我们肯定要对传入的每一项数据做严格的校验,所以我们应该怎么写?
@PostMapping("/add")
public String addStudent( @RequestBody Student student ) {
if( student == null )
return "传入的Student对象为null,请传值";
if( student.getName()==null || "".equals(student.getName()) )
return "传入的学生姓名为空,请传值";
if( student.getScore()==null )
return "传入的学生成绩为null,请传值";
if( (student.getScore()<0) || (student.getScore()>100) )
return "传入的学生成绩有误,分数应该在0~100之间";
if( student.getMobile()==null || "".equals(student.getMobile()) )
return "传入的学生电话号码为空,请传值";
if( student.getMobile().length()!=11 )
return "传入的学生电话号码长度有误,应为11位";
studentService.addStudent( student ); // 将student对象存入mysql数据库
return "SUCCESS";
}
写是写完了,就是感觉手有点酸,并且心有点累,这个 Student对象倒还好,毕竟内部仅3个字段,假如一个复杂的对象有30个字段怎么办?简直不敢想象!
神注解加持
其实Spring框架很早版本开始,就通过注解的方式,来方便地为我们提供了各项交互数据的校验工作,比如http://上面的例子,我们只需要在传入的 Student实体类的字段中加入对应注解即可方便的解决问题:
public class Student {
@NotNull(message = "传入的姓名为null,请传值")
@NotEmpty(message = "传入的姓名为空字符串,请传值")
private String name; // 姓名
@NotNull(message = "传入的分数为null,请传值")
@Min(value = 0,message = "传入的学生成绩有误,分数应该在0~100之间")
@Max(value = 100,message = "传入的学生成绩有误,分数应该在0~100之间")
private Integer score; // 分数
@NotNull(message = "传入的电话为null,请传值")
@NotEmpty(message = "传入的电话为空字符串,请传值")
@Length(min = 11, max = 11, message = "传入的电话号码长度有误,必须为11位")
private String mobile; // 电话号码
}
当然,于此同时,我们还需要在对象入口处,加上注解 @Valid来开启对传入 Student对象的验证工作:
@PostMapping("/add")
public String addStudent( @RequestBody @Valid Student student ) {
// 棒棒哒!原先各种繁杂的参数校验工作统统都省了!一行代码不用写
studentService.addStudent( student ); // 将student对象存入MySQL数据库
return "SUCCESS";
}
这时候,如果某个字段传入错误,比如我传数据的时候,将学生的成绩误传为 101分,则接口返回结果便会提示出错误详情:
当然,关于这个事情的原理,既然用到了注解,无非用的也就是java里的各种反射等知识来实现的,感兴趣的小伙伴可以借此机会研究一下!
数据异常统一拦截
上面利用注解的方式做统一数据校验感觉十分美好,但唯一美中不足的就是返回的结果太过繁杂,不一定使我们需要的格式,我们需要做统一处理,比如:我只想将具体参数校验的错误提示信息给抠出来返回给前端即可。
为此,我们为项目配置全局统一异常-来格式化所有数据校验的返回结果。
@ControllerAdvice
@ResponseBody
public class GlobalExceptionInterceptor {
@ExceptionHandler(value = Exception.class)
public String exceptionHandler(HttpServletRequest request, Exception e) {
String failMsg = null;
if (e instanceof MethodArgumentNotValidException) {
// 拿到参数校验具体异常信息提示
failMsg = ((MethodArgumentNotValidException) e).getBindingResult().getFieldError().getDefaultMessage();
}
return failMsg; // 直接吐回给前端
}
}
如上面代码所示,我们全局统一拦截了参数校验异常 MethodArgumentNotValidException,并仅仅只拿到对应异常的详细 Message信息吐给前端,此时返回给前端的数据就清楚得多:
可以的,非常优雅!
总结
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~