场景还原 

简单业务场景模拟:

假如你现在在做一个成绩录入系统,你愉快地用Spring Boot框架写了一个后台接口,用于接收前台浏览器传过来的 Student对象,并插入后台数据库。

我们将传入的 Student对象定义为:

public class Student {    private String name;    // 姓名    private Integer score;  // 考试分数(满分100分)    private String mobile;  // 电话号码(11位)}

然后写一个Post请求的后台接口,来接收网页端传过来的 Student对象:

  1. @RestController

  2. public class TestController {


  3.    @Autowired

  4.    private StudentService studentService;


  5.    @PostMapping("/add")

  6.    public String addStudent( @RequestBody Student student ) {

  7.        studentService.addStudent( student ); // 将student对象存入数据库

  8.        return "SUCCESS";

  9.    }

  10. }

此时我想你一定看出来了上面这段代码的漏洞,因为我们并没有对传入的 Student对象做任何数据校验,比如:

Student对象里三个字段的某一个忘传了,为 null怎么办?Studentscore分数,假如写错了,写成 101分怎么办?Studentmobile11位手机号码,假如填错了,多写了一位怎么办?...等等

这些数据虽然在前端页面一般会做校验,但我们作为一个严谨且良心的后端开发工程师,我们肯定要对传入的每一项数据做严格的校验,所以我们应该怎么写?

  1. @PostMapping("/add")

  2. public String addStudent( @RequestBody Student student ) {


  3.    if( student == null )

           return "传入的Student对象为null,请传值";

       if( student.getName()==null || "".equals(student.getName()) )

  4.        return "传入的学生姓名为空,请传值";

  5.    if( student.getScore()==null )

  6.        return "传入的学生成绩为null,请传值";

  7.    if( (student.getScore()<0) || (student.getScore()>100) )

  8.        return "传入的学生成绩有误,分数应该在0~100之间";

  9.    if( student.getMobile()==null || "".equals(student.getMobile()) )

  10.        return "传入的学生电话号码为空,请传值";

  11.    if( student.getMobile().length()!=11 )

  12.        return "传入的学生电话号码长度有误,应为11位";


  13.    studentService.addStudent( student ); // 将student对象存入MySQL数据库

  14.    return "SUCCESS";

  15. }

写是写完了,就是感觉手有点酸,并且心有点累,这个 Student对象倒还好,毕竟内部仅3个字段,假如一个复杂的对象有30个字段怎么办?简直不敢想象!


 神注解加持! 

其实Spring框架很早版本开始,就通过注解的方式,来方便地为我们提供了各项交互数据的校验工作,比如上面的例子,我们只需要在传入的 Student实体类的字段中加入对应注解即可方便的解决问题:

  1. public class Student {


  2.    @NotNull(message = "传入的姓名为null,请传值")

  3.    @NotEmpty(message = "传入的姓名为空字符串,请传值")

  4.    private String name;    // 姓名


  5.    @NotNull(message = "传入的分数为null,请传值")

  6.    @Min(value = 0,message = "传入的学生成绩有误,分数应该在0~100之间")

  7.    @Max(value = 100,message = "传入的学生成绩有误,分数应该在0~100之间")

  8.    private Integer score;  // 分数


  9.    @NotNull(message = "传入的电话为null,请传值")

  10.    @NotEmpty(message = "传入的电话为空字符串,请传值")

  11.    @Length(min = 11, max = 11, message = "传入的电话号码长度有误,必须为11位")

  12.    private String mobile;  // 电话号码

  13. }

当然,于此同时,我们还需要在对象入口处,加上注解 @Valid来开启对传入 Student对象的验证工作:

  1. @PostMapping("/add")

  2. public String addStudent( @RequestBody  @Valid Student student ) {


  3.    // 棒棒哒!原先各种繁杂的参数校验工作统统都省了!一行代码不用写


  4.    studentService.addStudent( student ); // 将student对象存入MySQL数据库

  5.    return "SUCCESS";

  6. }

这时候,如果某个字段传入错误,比如我传数据的时候,将学生的成绩误传为 101分,则接口返回结果便会提示出错误详情:

当然,关于这个事情的原理,既然用到了注解,无非用的也就是Java里的各种反射等知识来实现的,感兴趣的小伙伴可以借此机会研究一下!


 数据异常统一拦截 

上面利用注解的方式做统一数据校验感觉十分美好,但唯一美中不足的就是返回的结果太过繁杂,不一定使我们需要的格式,我们需要做统一处理,比如:我只想将具体参数校验的错误提示信息给抠出来返回给前端即可。

为此,我们为项目配置全局统一异常拦截器来格式化所有数据校验的返回结果。

  1. @ControllerAdvice

  2. @ResponseBody

  3. public class GlobalExceptionInterceptor {


  4.  @ExceptionHandler(value = Exception.class)

  5.  public String exceptionHandler(HttpServletRequest request, Exception e) {

  6.    String failMsg = null;

  7.    if (e instanceof MethodArgumentNotValidException) {

  8.      // 拿到参数校验具体异常信息提示

  9.      failMsg = ((MethodArgumentNotValidException) e).getBindingResult().getFieldError().getDefaultMessage();

  10.    }

  11.    return failMsg; // 直接吐回给前端

  12.  }

  13. }

如上面代码所示,我们全局统一拦截了参数校验异常 MethodArgumentNotValidException,并仅仅只拿到对应异常的详细 Message信息吐给前端,此时返回给前端的数据就清楚得多:

可以的,非常优雅!

每天进步一点点!Peace!

2019.12.25晚,圣诞节快乐!



©著作权归作者所有:来自51CTO博客作者mb5fdcae83766b7的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 芋道 Spring Boot 对象转换 MapStruct 入门
  2. 【第767期】你不懂JS:混合(淆)“类”的对象
  3. 【第766期】你不懂JS:对象
  4. 芋道 Spring Boot JPA 入门(三)之基于注解查询
  5. 在 JavaScript 中对象的深拷贝(及其工作原理)[每日前端夜话0x8F]
  6. 芋道 Spring Boot MyBatis 入门(二)之 MyBatis + 注解
  7. SpringBoot 中 @SpringBootApplication注解背后的三体结构探秘
  8. C#基础入门第十二天(面向对象多态,File操作流,泛型集合)
  9. Spring 注解编程之模式注解

随机推荐

  1. PHP中三种设置脚本最大执行时间的方法
  2. 在PHP中通过GD库创建简单的图片(图文详解)
  3. 如何将curl获取到的json对象转成数组
  4. php如何修改数组的值?
  5. PHP在图片中用 imagettftext() 添加水印(
  6. 如何解决php中curl传递数据太慢
  7. php如何设置权限?
  8. php代码如何在html文件里面执行(详解)
  9. 如何解决php中curl_init()函数不可用
  10. php中如何进行小写转换?