当前位置:

首页 > 编程开发 > SpringBoot怎么进行参数校验

SpringBoot怎么进行参数校验

介绍在日常的接口开发中,为了防止非法参数对业务造成影响,经常需要对接口的参数进行校验,例如登录的时候需要校验用户名和密码是否为空,添加用户的时候校验用户邮箱地址、手机号码格式是否正确。靠代码对接口参数一个个校验的话就太繁琐了,代码可读性极差。Validator框架就是为了解决开发人员在开发的时候少写代码,提升开发效率;Validator专门用来进行接口参数校验,例如常见的必填校验,email格式校验,用户名必须位于6到12之间等等。接下来我们看看在SpringbBoot中如何集成参数校验框架。1.Spri

介绍

在日常的接口开发中,为了防止非法参数对业务造成影响,经常需要对接口的参数进行校验,例如登录的时候需要校验用户名和密码是否为空,添加用户的时候校验用户邮箱地址、手机号码格式是否正确。 靠代码对接口参数一个个校验的话就太繁琐了,代码可读性极差。

Validator框架就是为了解决开发人员在开发的时候少写代码,提升开发效率;Validator专门用来进行接口参数校验,例如常见的必填校验,email格式校验,用户名必须位于6到12之间等等。

接下来我们看看在SpringbBoot中如何集成参数校验框架。

1.SpringBoot中集成参数校验

1.1引入依赖


  org.springframework.boot
  spring-boot-starter-validation

1.2定义参数实体类

package com.didiplus.modules.sys.domain;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;

/**
 * Author: didiplus
 * Email: 972479352@qq.com
 * CreateTime: 2022/4/25
 * Desc: 字典类型领域模型
 */

@Data
@ApiModel(value = "字典类型")
public class SysDictType {

    @ApiModelProperty("ID")
    private String id;

    @NotBlank(message = "字典名称必填项")
    @ApiModelProperty(value = "字典名称",example = "用户ID")
    private String typeName;

    @NotBlank(message = "字典编码不能为空")
    @ApiModelProperty(value = "字典编码")
    private String typeCode;

    @Email(message = "请填写正确的邮箱地址")
    @ApiModelProperty(value = "字典编码")
    private String email;

    @ApiModelProperty(value = "字典描述")
    private String description;

    @NotBlank(message = "字典状态不能为空")
    @ApiModelProperty(value = "字典状态")
    private String enable;
}

常见的约束注解如下:

注解功能
@AssertFalse可以为null,如果不为null的话必须为false
@AssertTrue可以为null,如果不为null的话必须为true
@DecimalMax设置不能超过最大值
@DecimalMin设置不能超过最小值
@Digits设置必须是数字且数字整数的位数和小数的位数必须在指定范围内
@Future日期必须在当前日期的未来
@Past日期必须在当前日期的过去
@Max最大不得超过此最大值
@Min最大不得小于此最小值
@NotNull不能为null,可以是空
@Null必须为null
@Pattern必须满足指定的正则表达式
@Size集合、数组、map等的size()值必须在指定范围内
@Email必须是email格式
@Length长度必须在指定范围内
@NotBlank字符串不能为null,字符串trim()后也不能等于""
@NotEmpty不能为null,集合、数组、map等size()不能为0;字符串trim()后可以等于""
@Range值必须在指定范围内
@URL必须是一个URL

1.3定义校验类进行测试

package com.didiplus.modules.sys.controller;

import com.didiplus.modules.sys.domain.SysDictType;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Author: didiplus
 * Email: 972479352@qq.com
 * CreateTime: 2022/4/25
 * Desc: 数据字典控制器
 */
@RestController
@Api(tags = "数据字典")
@RequestMapping("/api/sys/dictType")
public class SysDictTypeController {

    @ApiOperation("字典添加")
    @PostMapping("/add")
    public SysDictType add(@Validated @RequestBody SysDictType sysDictType) {
        return  sysDictType;
    }

    @ApiOperation("字典修改")
    @PutMapping("/edit")
    public SysDictType edit(@Validated @RequestBody SysDictType sysDictType) {
        return  sysDictType;
    }


}

这里我们先定义两个方法add,edit,都是使用了 @RequestBody注解,用于接受前端发送的json数据。

1.4打开接口文档模拟提交数据

SpringBoot怎么进行参数校验

通过接口文档看到前三个字段都是必填项。

SpringBoot怎么进行参数校验

由于email的格式不对就被拦截了,提示是因为邮箱地址不对。

2.参数异常加入全局异常处理器

虽然我们之前定义了全局异常拦截器,也看到了拦截器确实生效了,但是Validator校验框架返回的错误提示太臃肿了,不便于阅读,为了方便前端提示,我们需要将其简化一下。

直接修改之前定义的 RestExceptionHandler,单独拦截参数校验的三个异常:

javax.validation.ConstraintViolationException

org.springframework.validation.BindException

org.springframework.web.bind.MethodArgumentNotValidException

代码如下:

package com.didiplus.common.web.response.Handler;

import com.didiplus.common.web.response.Result;

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.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;

import java.util.stream.Collectors;

/**
 * Author: didiplus
 * Email: 972479352@qq.com
 * CreateTime: 2022/4/24
 * Desc:  默认全局异常处理。
 */
@RestControllerAdvice
public class RestExceptionHandler {
    /**
     * 默认全局异常处理。
     * @param e the e
     * @return ResultData
     */
    @ExceptionHandler(value = {BindException.class, ValidationException.class, MethodArgumentNotValidException.class})
    public ResponseEntity> handleValidatedException(Exception e) {
            Result  result = null;
            if (e instanceof  MethodArgumentNotValidException) {
                MethodArgumentNotValidException ex =(MethodArgumentNotValidException)  e;
                result = Result.failure(HttpStatus.BAD_REQUEST.value(),
                                ex.getBindingResult().getAllErrors().stream()
                                        .map(ObjectError::getDefaultMessage)
                                        .collect(Collectors.joining(";"))
                                );
            } else  if (e instanceof ConstraintViolationException){
                ConstraintViolationException ex = (ConstraintViolationException) e;
                result = Result.failure(HttpStatus.BAD_REQUEST.value(),
                                        ex.getConstraintViolations().stream()
                                                .map(ConstraintViolation::getMessage)
                                                .collect(Collectors.joining(";"))
                                        );
            }else  if (e instanceof BindException) {
                BindException  ex = (BindException ) e;
                result = Result.failure(HttpStatus.BAD_REQUEST.value(),
                                        ex.getAllErrors().stream()
                                                .map(ObjectError::getDefaultMessage)
                                                .collect(Collectors.joining(";"))
                                        );
            }
            return new ResponseEntity<>(result,HttpStatus.BAD_REQUEST);
    }
}

美化之后错误信息提示更加友好

SpringBoot怎么进行参数校验

3.自定义参数校验

虽然Spring Validation 提供的注解基本上够用,但是面对复杂的定义,我们还是需要自己定义相关注解来实现自动校验。
比如上面实体类中添加的sex性别属性,只允许前端传递传 M,F 这2个枚举值,如何实现呢?

3.1创建自定义注解

package com.didiplus.common.annotation;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * Author: didiplus
 * Email: 972479352@qq.com
 * CreateTime: 2022/4/26
 * Desc:
 */
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Repeatable(EnumString.List.class)
@Documented
@Constraint(validatedBy = EnumStringValidator.class)//标明由哪个类执行校验逻辑
public @interface EnumString {

    String message() default "value not in enum values.";

    Class[] groups() default {};

    Class[] palyload() default {};
    /**
     * @return date must in this value array
     */
    String[] value();

    /**
     * Defines several {@link EnumString} annotations on the same element.
     *
     * @see EnumString
     */
    @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
    @Retention(RUNTIME)
    @Documented
    @interface List {

        EnumString[] value();
    }


}

3.2自定义校验逻辑

package com.didiplus.common.annotation;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Arrays;
import java.util.List;


/**
 * Author: didiplus
 * Email: 972479352@qq.com
 * CreateTime: 2022/4/26
 * Desc:
 */
public class EnumStringValidator implements ConstraintValidator {
    private List enumStringList;

    @Override
    public void initialize(EnumString constraintAnnotation) {
        enumStringList = Arrays.asList(constraintAnnotation.value());

    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
        if(value == null) {
            return true;
        }
        return enumStringList.contains(value);
    }
}

3.3在字段上增加注解

    @ApiModelProperty(value = "性别")
    @EnumString(value = {"F","M"}, message="性别只允许为F或M")
    private String sex;

3.4体验效果

SpringBoot怎么进行参数校验

4.分组校验

一个对象在新增的时候某些字段是必填,在更新是有非必填。如上面的 SysDictTypeid 属性在新增操作时都是必填。 面对这种场景你会怎么处理呢?

其实 Validator校验框架已经考虑到了这种场景并且提供了解决方案,就是分组校验。 要使用分组校验,只需要三个步骤:

4.1定义分组接口

package com.didiplus.common.base;

import javax.validation.groups.Default;

/**
 * Author: didiplus
 * Email: 972479352@qq.com
 * CreateTime: 2022/4/26
 * Desc:
 */
public interface ValidGroup extends Default {

    interface Crud extends ValidGroup{
        interface Create extends Crud{

        }

        interface Update extends Crud{

        }

        interface Query extends Crud{

        }

        interface Delete extends Crud{

        }
    }
}

4.2在模型中给参数分配分组

    @Null(groups = ValidGroup.Crud.Create.class)
    @NotNull(groups = ValidGroup.Crud.Update.class,message = "字典ID不能为空")
    @ApiModelProperty("ID")
    private String id;

4.3体现效果

SpringBoot怎么进行参数校验

SpringBoot怎么进行参数校验

本文内容来源于互联网,如有侵权请联系删除。
作者最新文章
编程开发
相关文章 更多
using namespace 使用中遇到的问题怎么解决
using namespace 使用中遇到的问题怎么解决

命名空间的基本概念与常见引入问题在C++等编程语言中,命名空间(namespace)是一种将代码标识符(如变量、函数、类名)封装在特定名称下的机制,其主要目的是避免命名冲突,尤其是在大型项目或使用多个第三方库时。使用“using namespace”指令可以将指定命名空间中的所有名称引入当前作用域,

c语言函数递归 实操经验总结:这些技巧很实用
c语言函数递归 实操经验总结:这些技巧很实用

理解递归的基本原理在C语言中,递归是一种函数调用自身的编程技术。要掌握它,首先需要理解其核心思想:将一个复杂的大问题,分解为一个或几个与原问题相似但规模更小的子问题,直到子问题足够简单,可以直接求解。这个过程通常包含两个关键部分:递归出口和递归体。递归出口定义了问题何时不再继续分解,即最简单、可直接

c语言函数递归 怎么选?常见方案对比分析
c语言函数递归 怎么选?常见方案对比分析

递归函数的基本概念与适用场景在C语言编程中,递归是一种函数调用自身的编程技巧。它并非适用于所有问题,但在处理某些具有自相似结构的问题时,能提供极其清晰和优雅的解决方案。递归的核心思想是将一个大规模问题分解为一个或多个同类型但规模更小的子问题,直到子问题简单到可以直接求解。典型的适用场景包括树形结构的

Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解
Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解

理解内存管理的基石在Objective-C的编程世界中,内存管理是开发者必须掌握的核心技能之一。它直接关系到应用的性能、稳定性与资源利用效率。与一些采用自动垃圾回收机制的语言不同,Objective-C在很长一段时间里,依赖一套基于引用计数的、需要开发者部分介入的管理规则。这套规则的核心思想是明确的

如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏
如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏

理解 dealloc 的角色与时机在 iOS 应用开发中,内存管理是保障应用性能与稳定性的基石。dealloc 方法是 Objective-C 中对象生命周期结束时的关键回调,它标志着对象即将被系统回收内存。正确理解其触发时机至关重要:当一个对象的引用计数降为零时,运行时系统会自动调用该对象的 de

深入理解 Objective-C 中的 dealloc 方法:内存管理核心机制
深入理解 Objective-C 中的 dealloc 方法:内存管理核心机制

内存管理的基石在Objective-C的世界里,内存管理是开发者必须掌握的核心技能之一。作为一门在手动引用计数(MRC)时代诞生的语言,Objective-C要求程序员对对象的生命周期有清晰的认识。dealloc方法正是这一生命周期中至关重要的终点站。它是一个实例方法,当对象的引用计数降为零时,系统

理解 native2ascii:Java 国际化开发中的字符编码工具
理解 native2ascii:Java 国际化开发中的字符编码工具

native2ascii 工具的基本定位在Ja va应用程序的国际化与本地化开发过程中,处理非拉丁字符集是一个常见且关键的环节。Ja va内部使用Unicode字符集来统一表示全球各种语言的文字,但其属性文件(.properties)在历史上要求使用ASCII编码,或者更准确地说,要求非ASCII字

如何使用 native2ascii 转换中文字符为 Unicode 转义序列
如何使用 native2ascii 转换中文字符为 Unicode 转义序列

理解 native2ascii 工具的基本用途在软件开发,特别是涉及国际化处理的场景中,开发者常常需要处理不同编码的文本资源。native2ascii 是 Ja va 开发工具包(JDK)中提供的一个命令行实用程序,其主要功能是将包含本地字符编码(非ASCII字符)的文件,转换为包含 Unicode

Java native2ascii 命令详解:解决属性文件乱码问题
Java native2ascii 命令详解:解决属性文件乱码问题

native2ascii 命令的由来与作用在Ja va开发中,处理国际化资源文件是一个常见需求。资源文件通常以.properties格式存储,用于支持多语言界面。然而,Ja va属性文件默认采用ISO-8859-1字符集编码,这导致了一个直接的问题:当文件中包含非拉丁字符(如中文、日文、韩文等)时,

一个 memwatch 实战案例:定位野指针问题
一个 memwatch 实战案例:定位野指针问题

内存监控工具的价值与挑战在软件开发,尤其是使用C/C++这类手动管理内存的语言时,内存错误是程序员最常遭遇的难题之一。其中,野指针问题因其隐蔽性和破坏性,往往成为最难定位的“幽灵”缺陷。它可能潜伏在代码中,在特定条件下才被触发,导致程序崩溃、数据损坏或难以预测的行为。传统的调试手段,如打印日志或使用

查看更多
精品专题 更多
装机必备
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows
Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

macOS软件
macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

Mac软件 更多
灵活计算器
灵活计算器
macOS/iOS/Android

灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

赤友清理大师
赤友清理大师
macOS

赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

WINDOWS 更多
Windows 10
Windows 10
Windows

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘
Windows/macOS/iOS/Android

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。