@valid和自定义异常

问题的产生:

当有很多参数需要校验时,比如name,age,email等很多参数都需要判空,或者有长度限制时,如果后端写很多if-else就有很多代码,不美观,不优雅.前端每个参数都效验的话工作量也很大

本文旨在解决这个问题,本文使用@valid 注解来解决这个问题.

首先定义一个

统一结果返回

  1. import lombok.AllArgsConstructor;
  2. import lombok.Data;
  3. import lombok.NoArgsConstructor;
  4. @NoArgsConstructor
  5. @AllArgsConstructor
  6. @Data
  7. public class Result<T> {
  8. private String msg;
  9. private Integer code;
  10. private T data;
  11. private static final Integer successCode = 200;
  12. private static Integer errorCode = 500;
  13. private static final String successMsg = "成功";
  14. private static final Object resultNoData = null;
  15. public static Result successNoResult() {
  16. return new Result(successMsg, successCode, resultNoData);
  17. }
  18. public static <T> Result<T> successWithResult(T data) {
  19. return new Result(successMsg, successCode, data);
  20. }
  21. public static Result successWithCodeAndMsg(Integer code, String msg) {
  22. return new Result(msg, code, resultNoData);
  23. }
  24. public static Result errorNoResult(String msg) {
  25. return new Result(msg, errorCode, resultNoData);
  26. }
  27. public static Result errorWithResult(String msg, Object data) {
  28. return new Result(msg, errorCode, data);
  29. }
  30. public static Result errorWithCodeAndMsg(Integer code, String msg) {
  31. return new Result(msg, code, resultNoData);
  32. }
  33. }

@valid 注解简单使用

先看下简单使用,复杂的自己查api吧

首先在控制层的参数上加上该注解

  1. import javax.validation.Valid;
  2. import java.util.*;
  3. @RestController
  4. @RequestMapping("/test")
  5. public class Test2 {
  6. @RequestMapping("test2")
  7. public Result<User> test2(@Valid User user){
  8. return Result.successWithResult(user);
  9. }
  10. }

然后在实体类中加上如下注解

  1. import javax.validation.constraints.NotBlank;
  2. import javax.validation.constraints.NotNull;
  3. import javax.validation.constraints.Size;
  4. public class User {
  5. /**
  6. * @NotEmpty:不能为null,而且长度必须大于0
  7. * @NotBlank:只用在String上,表示传进来的值不能为null,而且调用trim()后,长度必须大于0
  8. * @NotNull:不能为null,但可以为empty
  9. * @Length(message = "名称不能超过个 {max} 字符", max = 10)
  10. * @Range(message = "年龄范围为 {min} 到 {max} 之间", min = 1, max = 100)
  11. */
  12. @NotNull( message = "ID不能为空")
  13. private Integer id;
  14. @NotBlank( message = "昵称不能为空")
  15. @Size( min = 2,max = 5,message ="昵称的字数个数必须在0和5之间" )
  16. private String name;
  17. public Integer getId() {
  18. return id;
  19. }
  20. public void setId(Integer id) {
  21. this.id = id;
  22. }
  23. public String getName() {
  24. return name;
  25. }
  26. public void setName(String name) {
  27. this.name = name;
  28. }
  29. }

请求该接口

  1. http://localhost:8080/test/test2?id=5&name=xxwwwww

查看效果,如下

可以看到,已经能表示该请求参数错误

但是还有个问题,我们不能直接这样子直接返回给前端,需要返回统一的结果

全局异常处理

Spring-boot对于异常的处理也做了不错的支持,

它提供了一个 @ControllerAdvice注解以及 @ExceptionHandler注解,

前者是用来开启全局的异常捕获,后者则是说明捕获哪些异常,对那些异常进行处理。如下

自定义异常

  1. import lombok.Data;
  2. @Data
  3. public class DefinitionException extends RuntimeException {
  4. private Integer errorCode;
  5. private String errorMsg;
  6. public DefinitionException(){
  7. }
  8. public DefinitionException(Integer errorCode, String errorMsg) {
  9. this.errorCode = errorCode;
  10. this.errorMsg = errorMsg;
  11. }
  12. }

异常处理

  1. @ControllerAdvice
  2. public class GlobalExceptionHandler {
  3. /**
  4. * 处理自定义异常
  5. */
  6. @ExceptionHandler(value = DefinitionException.class)
  7. @ResponseBody
  8. public Result bizExceptionHandler(DefinitionException definitionException) {
  9. Result result=new Result();
  10. result.setCode(definitionException.getErrorCode());
  11. result.setMsg(definitionException.getErrorMsg());
  12. return result;
  13. }
  14. /**
  15. * 处理异常
  16. */
  17. @ExceptionHandler(value = Exception.class)
  18. @ResponseBody
  19. public Result runtimeExceptionHandler(Exception exception) {
  20. Result result=new Result();
  21. result.setCode(500);
  22. result.setMsg(exception.getMessage());
  23. return result;
  24. }
  25. }

测试代码

  1. @RequestMapping("test3")
  2. public Result<String> test3(){
  3. int i=1/0;
  4. return Result.successWithResult("test3");
  5. }
  6. @RequestMapping("test4")
  7. public Result<String> test4(){
  8. throw new DefinitionException(500,"啊哦,报错了");
  9. }

查看结果

将@valid注解抛的异常也返回统一格式

我们再请求一下这个接口

  1. http://localhost:8080/test/test2?id=5&name=xxwwwww

看下结果

返回格式是统一的格式了,但是返回的信息不太友好,我们看看怎么优化

debug一下,看看这个是什么异常

我们看到,这个异常是org.springframework.validation.BindException类的,

我们看下这个类的具体内容,我们只要我们想要的信息就行

这里,我们只要这个信息就可以了我们改动后如下

  1. /**
  2. * 处理异常
  3. */
  4. @ExceptionHandler(value = Exception.class)
  5. @ResponseBody
  6. public Result runtimeExceptionHandler(Exception exception) {
  7. Result result=new Result();
  8. if(exception instanceof BindException){//注解类异常
  9. StringBuilder sb = new StringBuilder();
  10. BindException bindException= (BindException) exception;
  11. BindingResult bindingResult = bindException.getBindingResult();
  12. List<ObjectError> allErrors = bindingResult.getAllErrors();
  13. for (ObjectError item : allErrors) {
  14. sb
  15. .append(item.getDefaultMessage())
  16. .append(',');
  17. }
  18. sb.deleteCharAt(sb.length()-1);
  19. result.setCode(500);
  20. result.setMsg(sb.toString());
  21. }
  22. return result;
  23. }

再请求该接口,得到结果

到此为止,我们已经得到了我们想要的结果

优化代码

最后,我们在优化一下全局异常处理代码如下

  1. import com.yoocar.util.Result;
  2. import org.springframework.validation.BindException;
  3. import org.springframework.validation.BindingResult;
  4. import org.springframework.validation.ObjectError;
  5. import org.springframework.web.bind.annotation.ControllerAdvice;
  6. import org.springframework.web.bind.annotation.ExceptionHandler;
  7. import org.springframework.web.bind.annotation.ResponseBody;
  8. import java.util.List;
  9. @ControllerAdvice
  10. public class GlobalExceptionHandler {
  11. /**
  12. * 处理自定义异常
  13. */
  14. @ExceptionHandler(value = Exception.class)
  15. @ResponseBody
  16. public Result exceptionHandler(Exception exception) {
  17. Result result=new Result();
  18. //自定义类型异常
  19. if(exception instanceof DefinitionException){
  20. DefinitionException definitionException= (DefinitionException) exception;
  21. result.setCode(definitionException.getErrorCode());
  22. result.setMsg(definitionException.getErrorMsg());
  23. }else if(exception instanceof BindException){//@valid注解抛出的异常
  24. //使用StringBuilder来拼接错误信息,减少对象开销
  25. StringBuilder stringBuilder = new StringBuilder();
  26. //获取并拼接所有错误信息
  27. BindException bindException= (BindException) exception;
  28. BindingResult bindingResult = bindException.getBindingResult();
  29. List<ObjectError> allErrors = bindingResult.getAllErrors();
  30. for (ObjectError item : allErrors) {
  31. stringBuilder.append(item.getDefaultMessage())
  32. .append(',');
  33. }
  34. //删除最后一个逗号
  35. stringBuilder.deleteCharAt(stringBuilder.length()-1);
  36. result.setCode(600);//这里自定义了600用于表示参数有误
  37. result.setMsg(stringBuilder.toString());
  38. }else {//其他异常
  39. result.setCode(500);
  40. result.setMsg(exception.getMessage());
  41. }
  42. return result;
  43. }
  44. }

至此,本文结束.文章中若有错误和疏漏之处,还请各位大佬不吝指出,谢谢大家!

@valid和自定义异常的更多相关文章

  1. @Valid 数据校验 + 自定义全局异常信息

    关于javax.validation.Validator校验的使用 对于要校验的实体类:其需要校验的字段上需要添加注解 实际例子 使用:首先要拿到 validator的子类 Validator val ...

  2. 【springboot】@Valid参数校验

    转自: https://blog.csdn.net/cp026la/article/details/86495659 扯淡: 刚开始写代码的时候对参数的校验要么不做.要么写很多类似 if( xx == ...

  3. 小白解决CENTOS7错误:Cannot find a valid baseurl for repo: base/7/x86_6

    刚入手的MacBook想着学点东西,本汪还是决定玩玩CentOS服务器,安装好了VirtualBox + CentOS. 打开一看,懵逼了!命令行! 行吧,先装个图形界面: $sudo yum gro ...

  4. 记一个mvn奇怪错误: Archive for required library: 'D:/mvn/repos/junit/junit/3.8.1/junit-3.8.1.jar' in project 'xxx' cannot be read or is not a valid ZIP file

    我的maven 项目有一个红色感叹号, 而且Problems 存在 errors : Description Resource Path Location Type Archive for requi ...

  5. Leetcode 笔记 35 - Valid Soduko

    题目链接:Valid Sudoku | LeetCode OJ Determine if a Sudoku is valid, according to: Sudoku Puzzles - The R ...

  6. 安装CentOS7文字界面版后,无法联网,用yum安装软件提示 cannot find a valid baseurl for repo:base/7/x86_64 的解决方法

    *无法联网的明显表现会有: 1.yum install出现 Error: cannot find a valid baseurl or repo:base 2.ping host会提示unknown ...

  7. [LeetCode] Valid Word Square 验证单词平方

    Given a sequence of words, check whether it forms a valid word square. A sequence of words forms a v ...

  8. [LeetCode] Valid Word Abbreviation 验证单词缩写

    Given a non-empty string s and an abbreviation abbr, return whether the string matches with the give ...

  9. [LeetCode] Graph Valid Tree 图验证树

    Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), ...

随机推荐

  1. linux系统解压命令总结

    原文链接:https://www.cnblogs.com/lhm166/articles/6604852.html tar -c: 建立压缩档案 -x:解压 -t:查看内容 -r:向压缩归档文件末尾追 ...

  2. Maven遇到的各种问题

    1.遇到报错-Dmaven.multiModuleProjectDirectory system propery is not set.Check $M2_HOME environment varia ...

  3. 微信小程序:小程序中使用Less

    配置: 首选项 -> 设置 -> 用户 -> 扩展 (找到EasyLess插件,编辑setting.json文件进行配置) 点击vscode左下角的à设置à点击右上角的à添加以上代码 ...

  4. JavaScript疑难点

    什么是闭包 我个人理解闭包就是函数中嵌套函数,但是嵌套的那个函数必须是返回值,才构成闭包: //标准的闭包 function fn(){ var i=1; return function fnn(){ ...

  5. 后端程序员之路 49、SSDB

    正如Redis似乎是为替换memcached一样,SSSB是一个国人开发的旨在替换Redis的kv数据库. SSDB - 高性能的支持丰富数据结构的 NoSQL 数据库, 替代 Redishttp:/ ...

  6. JPEG解码——(5)反量化和逆ZigZag变换

    本篇是该系列的第五篇,承接上篇huffman解码,介绍接下来的两个步骤--反量化和逆zigzag变换,即IDCT前的两个步骤. 需要说明的是,这两个步骤可以颠倒,本人的实现是,先反量化,再逆ZigZa ...

  7. pytorch(16)损失函数(二)

    5和6是在数据回归中用的较多的损失函数 5. nn.L1Loss 功能:计算inputs与target之差的绝对值 代码: nn.L1Loss(reduction='mean') 公式: \[l_n ...

  8. KL散度相关理解以及视频推荐

    以下内容基于对[中字]信息熵,交叉熵,KL散度介绍||机器学习的信息论基础这个视频的理解,请务必先看几遍这个视频. 假设一个事件可能有多种结果,每一种结果都有其发生的概率,概率总和为1,也即一个数据分 ...

  9. IDEA中便捷内存数据库H2的最简使用方式

    在IDEA中有时候为了练习,需要使用到数据库,但如果自己工作或开发机子上本来没有安装数据库,也没有可用的远程数据库时,我们可以直接在IDEA环境上使用便捷式的内存数据库H2,关于H2更多知识就自己去找 ...

  10. Java 哈希表(google 公司的上机题)

    1 哈希表(散列)-Google 上机题 1) 看一个实际需求,google 公司的一个上机题: 2) 有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,住址..),当输入该 ...