优雅的进行封装实体的参数校验

发布于 2024-06-09 15:14:17 字数 4127 浏览 14 评论 0

假如你现在在做一个成绩录入系统,你愉快地用 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 怎么办? Studentscore 分数,假如写错了,写成 101 分怎么办? Studentmobile 11 位手机号码,假如填错了,多写了一位怎么办?...等等

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

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

优雅的解决方式

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

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.Length;

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 对象的验证工作:

import javax.validation.Valid;

@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 信息吐给前端,此时返回给前端的数据就清楚得多:

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

永不分离

暂无简介

0 文章
0 评论
831 人气
更多

推荐作者

13886483628

文章 0 评论 0

流年已逝

文章 0 评论 0

℡寂寞咖啡

文章 0 评论 0

笑看君怀她人

文章 0 评论 0

wkeithbarry

文章 0 评论 0

素手挽清风

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文