SpringBoot整合Validation统一结果封装和全局异常捕获和参数校验

前言

什么是Validation?

相信大家都用过hibernate-validation 的校验工具,对我们参数校验的工具。

为什么要用它?

相信大家在开发过程中肯定会写if-else判断吧!!

Validation可以帮助我们简化这些操作,大大提高我们的开发效率

如何使用?

1,引入依赖包 pom.xml

        <!--SpringMvc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--参数校验-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

这里我们引入lombok和mvc依赖,方便后续封装统一返回结果

lombok:通过注解形式简化 setter和getter的操作

mvc:接口所需的包

2,编写类

package com.demo.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.NotBlank;

/**
 * @Program: SpringBoot
 * @ClassName User
 * @Author: liutao
 * @Description:
 * @Create: 2023-09-15 22:16
 * @Version 1.0
 **/

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @NotBlank(message = "用户名不能为空")
    @Length(min = 3, max = 6, message = "用户名长度不能低于3个字符且不能超过6个字符")
    private String username;
    @NotBlank(message = "密码不能为空")
    private String password;
}

3,编写web接口

package com.demo.controller;

import com.demo.domain.User;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;

/**
 * @Program: SpringBoot
 * @ClassName TestController
 * @Author: liutao
 * @Description: 测试接口
 * @Create: 2023-09-15 22:16
 * @Version 1.0
 **/
@Validated
@RestController
public class TestController {
        @GetMapping("/get")
        String get(@NotBlank(message = "不能为空") String name) {
            return name;
        }
        @PostMapping("/save")
        User save(@Valid @RequestBody User user) {
            return user;
        }


}

ps:这里需要注意对类校验的参数 必须加上 @Valid 注解如上述 post请求一样

而对于对接口单个入参进行校验则必须在当前类加上 @Validated 注解 如上述get请求相同

4,测试

get请求测试

post请求

这里我用了全局异常捕获和统一结果封装,下面将为大家讲解!!

 封装统一返回结果

1,封装

package com.demo.common;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Program: SpringBoot
 * @ClassName Result
 * @Author: liutao
 * @Description: 封装统一结果
 * @Create: 2023-09-15 22:47
 * @Version 1.0
 **/

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result<T> {
    private Integer code;
    private String msg;
    private T data;

    public static<T> Result<T> success(Integer code, String msg, T data) {
        return new Result<T>(code, msg, data);
    }

    public static<T> Result<T> success(Integer code, T data) {
        return new Result<T>(code, "成功", data);
    }

    public static<T> Result<T> success(Integer code) {
        return new Result<T>(code, "成功", null);
    }
    public static <T> Result<T> error(Integer code, String msg) {
        return new Result<T>(code,msg,null);
    }


}

2,使用

这里我们修改一下上面的get 请求如下所示:

@GetMapping("/ok")
Result<String> ok() {
    return Result.success(200);
}

3,效果

 全局异常捕获

在未使用全局异常捕获之前如下图:

我们可以看到测试效果,很难发现异常是什么对吧!!我们只有去看后台才知道那儿出问题了

我们可以看到后台已经抛出异常

接下来我们全局捕获异常

自定义一个ServiceException

package com.demo.exception;

import lombok.Getter;

/**
 * @Program: SpringBoot
 * @ClassName ServiceException
 * @Author: liutao
 * @Description: 自定义异常类
 * @Create: 2023-09-15 23:00
 * @Version 1.0
 **/

@Getter
public class ServiceException extends RuntimeException {
    private final Integer code;
    public ServiceException(Integer code, String msg) {
        super(msg);
        this.code = code;
    }
}

定义一个GlobalExceptionHandler

package com.demo.exception;

import com.demo.common.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.stream.Collectors;

/**
 * @Program: SpringBoot
 * @ClassName GlobalExceptionHandler
 * @Author: liutao
 * @Description: 全局异常拦截
 * @Create: 2023-09-15 22:46
 * @Version 1.0
 **/
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler
    @ResponseBody
    public Result<String> handle(ServiceException se) {
        log.error("业务异常" + se);
        return Result.error(se.getCode(), se.getMessage());
    }

    /**参数校验的拦截**/
    @ExceptionHandler(value = {BindException.class, ValidationException.class, MethodArgumentNotValidException.class})
    public ResponseEntity<Result<String>> handleValidatedException(Exception e) {
        Result<String> result = null;
        if (e instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
            String errorMessages = ex.getBindingResult().getAllErrors().stream()
                    .map(ObjectError::getDefaultMessage)
                    .collect(Collectors.joining(";"));
            result = Result.error(HttpStatus.BAD_REQUEST.value(), errorMessages);
        } else if (e instanceof ConstraintViolationException) {
            ConstraintViolationException ex = (ConstraintViolationException) e;
            String errorMessages = ex.getConstraintViolations().stream()
                    .map(ConstraintViolation::getMessage)
                    .collect(Collectors.joining(";"));
            result = Result.error(HttpStatus.BAD_REQUEST.value(), errorMessages);
        } else if (e instanceof BindException) {
            BindException ex = (BindException) e;
            String errorMessages = ex.getAllErrors().stream()
                    .map(ObjectError::getDefaultMessage)
                    .collect(Collectors.joining(";"));
            result = Result.error(HttpStatus.BAD_REQUEST.value(), errorMessages);
        }
        return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
    }
}

然后我们再来测试

再看后台

我们可以发现后台也没有抛出异常!!

结尾

到这里我们的文章就结束了!!

如果我们的文章对你的开发有用欢迎关注,点赞,收藏三连!!

将不定时发布原创精品文章,see you!!

阅读剩余
THE END