SpringBoot参数校验入门

这篇具有很好参考价值的文章主要介绍了SpringBoot参数校验入门。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、添加依赖

<!--参数校验-->
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
</dependency>
<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

二、校验注解分类

1.空和非空检查

@NotBlank:只能用于字符串不为null和"",并且字符串调用trim()方法后的length要大于0。

@NotNull:不能为null。

@Null:必须为null。

@NotEmpty:集合对象元素不能为0,集合不能为空。

2.数值检查

@DecimalMax(value):被注释的元素必须是一个数字,其值必须小于等于指定的最大值。

@DecimalMin(value):被注释的元素必须是一个数字,其值必须大于等于指定的最小值。

@Digits(integer,fraction):被注释的元素必须是一个数字,其值必须在可接受的范围内。

@Positive:被注释的元素必须是正数。

@PositiveOrZero:被注释的元素必须是正数或0。

@Negative:被注释的元素必须是负数。

@NegativeOrZero:被注释的元素必须是负数或0。

@Max(value):被注释的元素的值只能小于或等于该值。

@Min(value):被注释的元素的值只能大于或等于该值。

@Range(min,max):被注释的元素必须在min和max之间。

@Length(min,max): 被注释的字符串的长度必须在min和max之间。

3.Boolean 值检查

@AssertTrue:被注释的元素必须为true。

@AssertFalse:被注释的元素必须为false。

4.长度检查

@Size(min,max):判断字符串、集合、数组、Map的长度是否在min和max之间。

5.日期检查

@Past:被注释的元素的日期必须是过去的日期。

@PathOrPresent:被注释的元素的日期必须是过去或现在的日期。

@Future:被注释的元素的日期必须是将来的日期。

@FutureOrPresent:被注释的元素的日期必须是将来或现在的日期。

6.其他

@URL:判断被注释的字符串必须是一个有效的URL。

@SafeHtml:判断提交的HTML是否安全。

三、@Valid和@Validated的区别

@Valid:可以添加在普通方法、构造方法、方法参数、方法返回、成员变量上,表示它们需要进行约束校验。支持嵌套校验,不支持分组校验。

@Validated:可以添加在类、方法参数、普通方法上,不能用在成员变量上。不支持嵌套校验,支持分组校验。

总的来说,绝大多数场景下,我们使用 @Validated 注解即可。

四、普通测试

1.创建一个用于测试的实体类

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

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;

/**
 * @author qinxun
 * @date 2023-06-14
 * @Descripion: 用户登录请求类
 */
@Data
public class UserLoginRequest {

    /**
     * 账号
     */
    @NotBlank(message = "账号不能为空")
    @Length(min = 2, max = 20, message = "账号的长度为2-20位")
    @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号的格式为大小写字母和数字")
    private String username;

    /**
     * 密码
     */
    @NotBlank(message = "密码不能为空")
    @Length(min = 4, max = 16, message = "密码的长度为4-16位")
    private String password;

}

2.创建测试控制器

import com.example.quartzdemo.request.UserLoginRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author qinxun
 * @date 2023-06-14
 * @Descripion: 测试
 */
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {


    /**
     * 登录
     *
     * @param userLoginRequest 使用@Validated校验输入项
     */
    @PostMapping("/login")
    public String login(@Validated UserLoginRequest userLoginRequest) {
        log.info("userLoginRequest:{}", userLoginRequest);
        return "登录验证通过";
    }
}

3.启动程序,进行测试

我们在postman上进行接口的测试

SpringBoot参数校验入门

 没有传入password参数,错误异常提示了密码不能为空。

SpringBoot参数校验入门

 我们传入的username不是大小写字母或数字,错误异常日志提示了账号格式为大小写字母或数字。

SpringBoot参数校验入门

 我们正确填写了账号和密码,验证通过。

五、分组校验测试

1.我们先创建两个分组接口,一个用于新增一个用于修改。

因为新增和修改的需要的参数不一定相同,比如新增的时候不需要ID,但是修改的时候必须要有ID参数,所以需要使用分组来实现我们的需求。

/**
 * @author qinxun
 * @date 2023-06-14
 * @Descripion: 新增用户分组
 */
public interface AddUserGroup {
}
/**
 * @author qinxun
 * @date 2023-06-14
 * @Descripion: 修改用户分组
 */
public interface UpdateUserGroup {
}

2.修改用户实体,在实体类中加上新增和修改的分组

import com.example.quartzdemo.interfaces.AddUserGroup;
import com.example.quartzdemo.interfaces.UpdateUserGroup;
import lombok.Data;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;

/**
 * @author qinxun
 * @date 2023-06-14
 * @Descripion: 用户登录请求类
 */
@Data
public class UserLoginRequest {


    /**
     * 用户ID
     */
    @NotNull(message = "用户ID不能为空", groups = UpdateUserGroup.class)
    private Long id;

    /**
     * 账号
     */
    @NotBlank(message = "账号不能为空", groups = {AddUserGroup.class, UpdateUserGroup.class})
    @Length(min = 2, max = 20, message = "账号的长度为2-20位")
    @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号的格式为大小写字母和数字")
    private String username;

    /**
     * 密码
     */
    @NotBlank(message = "密码不能为空", groups = {AddUserGroup.class, UpdateUserGroup.class})
    @Length(min = 4, max = 16, message = "密码的长度为4-16位")
    private String password;

}

我们设置ID只能是修改的时候才会判断是否存在,账号和密码在新增和修改的时候都要判断存在。

3.在控制器中测试

import com.example.quartzdemo.interfaces.AddUserGroup;
import com.example.quartzdemo.interfaces.UpdateUserGroup;
import com.example.quartzdemo.request.UserLoginRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author qinxun
 * @date 2023-06-14
 * @Descripion: 测试
 */
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {


    /**
     * 登录
     *
     * @param userLoginRequest 使用@Validated校验输入项
     */
    @PostMapping("/login")
    public String login(@Validated UserLoginRequest userLoginRequest) {
        log.info("userLoginRequest:{}", userLoginRequest);
        return "登录验证通过";
    }

    /**
     * 新增用户
     *
     * @param userLoginRequest 使用@Validated校验输入项 校验的注解中加上了新增分组的参数
     */
    @PostMapping("/add")
    public String add(@Validated(AddUserGroup.class) UserLoginRequest userLoginRequest) {
        log.info("userLoginRequest:{}", userLoginRequest);
        return "新增用户验证通过";
    }

    /**
     * 修改用户
     *
     * @param userLoginRequest 使用@Validated校验输入项 校验的注解中加上了修改分组的参数
     */
    @PostMapping("/update")
    public String update(@Validated(UpdateUserGroup.class) UserLoginRequest userLoginRequest) {
        log.info("userLoginRequest:{}", userLoginRequest);
        return "修改用户验证通过";
    }


}

我们继续在postman上进行接口的测试

SpringBoot参数校验入门

 可以看到我们在新增的时候没有传入ID参数校验通过了。

接下来我们现在调试修改的接口,没有传递ID参数。

SpringBoot参数校验入门

 我们在调试修改接口的时候,没有传递ID参数,验证不能通过了。

最后我们加上ID参数,验证通过。

SpringBoot参数校验入门

 六、错误提示的友好处理。

1.创建校验不通过的枚举类

/**
 * @author qinxun
 * @date 2023-06-14
 * @Descripion: 业务层异常枚举
 */
public enum ServiceExceptionEnum {
    SUCCESS(0, "成功"),
    ERROR(1, "失败"),
    SYS_ERROR(1000, "服务端发生异常"),
    MISSING_REQUEST_PARAM_ERROR(1001, "参数缺失"),
    INVALID_REQUEST_PARAM_ERROR(1002, "请求参数不合法");

    private final String message;

    private final int code;

    ServiceExceptionEnum(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public int getCode() {
        return code;
    }
}

2.统一返回结果实体类

package com.example.quartzdemo.common;

import com.example.quartzdemo.enums.ServiceExceptionEnum;

import java.io.Serializable;

/**
 * @author qinxun
 * @date 2023-06-14
 * @Descripion: 统一返回结果实体类
 */
public class CommonResult<T> implements Serializable {


    /**
     * 错误码
     */
    private Integer code;
    /**
     * 错误提示
     */
    private String message;
    /**
     * 返回数据
     */
    private T data;

    /**
     * 成功
     *
     * @param data
     * @param <T>
     * @return
     */
    public static <T> CommonResult<T> success(T data) {
        CommonResult<T> commonResult = new CommonResult<>();
        commonResult.setCode(ServiceExceptionEnum.SUCCESS.getCode());
        commonResult.setMessage(ServiceExceptionEnum.SUCCESS.getMessage());
        commonResult.setData(data);
        return commonResult;
    }

    /**
     * 失败
     *
     * @param message
     * @param <T>
     * @return
     */
    public static <T> CommonResult<T> error(String message) {
        CommonResult<T> commonResult = new CommonResult<>();
        commonResult.setCode(ServiceExceptionEnum.ERROR.getCode());
        commonResult.setMessage(message);
        return commonResult;
    }

    /**
     * 失败
     *
     * @param message
     * @param <T>
     * @return
     */
    public static <T> CommonResult<T> error(int code, String message) {
        CommonResult<T> commonResult = new CommonResult<>();
        commonResult.setCode(code);
        commonResult.setMessage(message);
        return commonResult;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "CommonResult{" +
                "code=" + code +
                ", message='" + message + '\'' +
                ", data=" + data +
                '}';
    }
}

3.创建全局异常处理类

package com.example.quartzdemo.exception;

import com.example.quartzdemo.common.CommonResult;
import com.example.quartzdemo.enums.ServiceExceptionEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

/**
 * @author qinxun
 * @date 2023-06-14
 * @Descripion: 全局异常处理
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理 MissingServletRequestParameterException 异常
     * <p>
     * SpringMVC 参数不正确
     */
    @ResponseBody
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public CommonResult missingServletRequestParameterExceptionHandler(HttpServletRequest req, MissingServletRequestParameterException ex) {
        log.error("[missingServletRequestParameterExceptionHandler]", ex);
        // 包装 CommonResult 结果
        return CommonResult.error(ServiceExceptionEnum.MISSING_REQUEST_PARAM_ERROR.getCode(),
                ServiceExceptionEnum.MISSING_REQUEST_PARAM_ERROR.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(value = ConstraintViolationException.class)
    public CommonResult constraintViolationExceptionHandler(HttpServletRequest req, ConstraintViolationException ex) {
        log.error("[constraintViolationExceptionHandler]", ex);
        // 拼接错误
        StringBuilder detailMessage = new StringBuilder();
        for (ConstraintViolation<?> constraintViolation : ex.getConstraintViolations()) {
            // 使用 ; 分隔多个错误
            if (detailMessage.length() > 0) {
                detailMessage.append(";");
            }
            // 拼接内容到其中
            detailMessage.append(constraintViolation.getMessage());
        }
        // 包装 CommonResult 结果
        return CommonResult.error(
                ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getMessage() + ":" + detailMessage.toString());
    }

    @ResponseBody
    @ExceptionHandler(value = BindException.class)
    public CommonResult bindExceptionHandler(HttpServletRequest req, BindException ex) {
        log.info("========进入了 bindException======");
        log.error("[bindExceptionHandler]", ex);
        // 拼接错误
        StringBuilder detailMessage = new StringBuilder();
        for (ObjectError objectError : ex.getAllErrors()) {
            // 使用 ; 分隔多个错误
            if (detailMessage.length() > 0) {
                detailMessage.append(";");
            }
            // 拼接内容到其中
            detailMessage.append(objectError.getDefaultMessage());
        }
        // 包装 CommonResult 结果
        return CommonResult.error(ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getCode(),
                ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getMessage() + ":" + detailMessage.toString());
    }

    @ResponseBody
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public CommonResult MethodArgumentNotValidExceptionHandler(HttpServletRequest req, MethodArgumentNotValidException ex) {
        log.info("-----------------进入了 MethodArgumentNotValidException-----------------");
        log.error("[MethodArgumentNotValidException]", ex);
        // 拼接错误
        StringBuilder detailMessage = new StringBuilder();
        for (ObjectError objectError : ex.getBindingResult().getAllErrors()) {
            // 使用 ; 分隔多个错误
            if (detailMessage.length() > 0) {
                detailMessage.append(";");
            }
            // 拼接内容到其中
            detailMessage.append(objectError.getDefaultMessage());
        }
        // 包装 CommonResult 结果
        return CommonResult.error(ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getCode(),
                ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getMessage() + ":" + detailMessage.toString());
    }


    /**
     * 处理其它 Exception 异常
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    public CommonResult exceptionHandler(HttpServletRequest req, Exception e) {
        // 记录异常日志
        log.error("[exceptionHandler]", e);
        // 返回 ERROR CommonResult
        return CommonResult.error(ServiceExceptionEnum.SYS_ERROR.getCode(),
                ServiceExceptionEnum.SYS_ERROR.getMessage());
    }
}

我们重新做postman上进行调试

SpringBoot参数校验入门

 我们可以看到错误异常的的提示很友好了。文章来源地址https://www.toymoban.com/news/detail-490583.html

到了这里,关于SpringBoot参数校验入门的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 浅析SpringBoot的API参数校验

    目录 1 前言 2 使用步骤 2.1 pom.xml中引入依赖 2.2 在参数前添加@Pattern注解 2.3 在类上添加@Validated注解 2.4 编写异常处理器 在我们编写后端项目的时候,常常需要对前端传送的数据进行校验。当然,我们可以使用if-else来进行校验,不过这样会使得我们的代码相当繁琐,因此我们

    2024年01月25日
    浏览(24)
  • SpringBoot第13讲:SpringBoot接口如何参数校验国际化

    本文是SpringBoot第13讲,上文我们学习了如何对SpringBoot接口进行参数校验,但是如果需要有国际化的信息(比如返回校验结果有中英文),应该如何优雅处理呢? 软件的国际化 :软件开发时,要使它能同时应对世界不同地区和国家的访问,并针对不同地区和国家的访问,提供相

    2024年02月12日
    浏览(42)
  • Springboot实现优雅的参数校验(Spring Validation)和 if else说再见

    当我们想提供可靠的 API 接口,对参数的校验,以保证最终数据入库的正确性,是 必不可少 的活。比如下图就是 我们一个项目里 新增一个菜单校验 参数的函数,写了一大堆的 if else 进行校验,非常的不优雅,比起枯燥的CRUD来说,参数校验更是枯燥。这只是一个创建菜单的

    2023年04月15日
    浏览(40)
  • Springboot开发时,对前端的请求参数,后端用于接受的实体类有没有必要校验为null?

    分析过程:         首先==null对于引用类型是判断这个对象有没有被加载到内存当中。对象的产生是由声明、是实列化、初始化三个过程.         初始化: RequestzbszAdd requestzbszAdd; 也就是声明一个变量         实列化:使用new         初始化:new  RequestzbszAdd()

    2024年02月09日
    浏览(44)
  • Springboot 入门指南:控制反转和依赖注入的含义和实现方式

    目录 一、什么是控制反转(IoC)? 二、什么是依赖注入(DI)? 三、如何在 springboot 中使用 IoC 和 DI? 总结 控制反转(Inversion of Control,简称 IoC)是一种设计原则,它的目的是降低代码之间的耦合度,提高模块化和可测试性。控制反转的含义是,将对象的创建、配置和管理

    2024年02月11日
    浏览(44)
  • 后端表情包依赖+自定义注解实现校验

    开发过程中遇到小程序登记信息填写文本时可能输入表情包,需要后端校验 由于字段太多,所以用自定义注解的方式来实现 步骤1:在pom文件中加入表情包依赖 步骤2: 自定义注解类 步骤3: 在请求的实体使用这个注解,需要要在controller中加入@Validated注解,校验才会生效

    2024年02月16日
    浏览(33)
  • java如何优雅的实现参数非空校验,快速实现参数非空校验,使用@valid实现参数非空校验

    在java项目接口中,有些必传参数需要进行非空校验,如果参数过多,代码会繁杂且冗余,如何优雅的对参数进行非空校验,下面是实现流程 用实体类接收参数,使用非空注解编辑参数内容 使用 @Valid 注解对参数进行拦截,整体进行非空校验 如果是SpringBoot项目,引入web开发包

    2024年02月08日
    浏览(49)
  • Spring boot Websocket 添加授权校验(校验Header)

            最近需要用到websocket,并且确认是在登录成功的情况下才能连接,看了下,websocket 5.8以上已经支持校验了,但是由于我项目是spring boot 2.7.9,为了兼容,只能考虑通过在websocket 的header中带上验证信息,进行校验,详细如下 1.首先往spring boot pom 内加入 websocket的依赖

    2024年02月07日
    浏览(31)
  • 接收来自客户端的参数使用【JSR303校验框架】进行校验参数是否合法

    目录 1:JSR303校验 1.1:统一校验的需求 1.2:统一校验实现 1.3:分组校验 1.4:校验规则不满足? 前端请求后端接口传输参数,是在controller中校验还是在Service中校验? 答案是都需要校验,只是分工不同。 Contoller中校验请求参数的合法性,包括:必填项校验,数据格式校验,

    2023年04月27日
    浏览(44)
  • 还在用 if else 做参数校验?快来学习高级参数校验吧

    在上一篇文章 Springboot实现优雅的参数校验(Spring Validation)和 if else说再见,我们介绍了 Spring Validation 的初级用法,在实际开发中,无论是 Bean Validation 定义的约束,还是 Hibernate Validator 附加的约束,都是无法满足我们复杂的业务场景。所以,我们需要自定义约束。开发自定

    2023年04月14日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包