SpringBoot + validation 接口参数校验的思路详解

有参数传递的地方都少不了参数校验。在web开发中,前端的参数校验是为了用户体验,后端的参数校验是为了安全。试想一下,如果在controller层中没有经过任何校验的参数通过service层、dao层一路来到了数据库就可能导致严重的后果,最好的结果是查不出数据,严重一点就是报错,如果这些没有被校验的参数中包含了恶意代码,那就可能导致更严重的后果。

实践

一、引入依赖

<!--引入spring-boot-starter-validation-->
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

二、使用校验

在controller层的参数校验可以分为两种场景:

单个参数校验
实体类参数校验

2.1 单参数校验

/**
 * 参数校验测试 控制类
 * @author oyc
 */
@RestController
@RequestMapping("user")
@Validated
public class RequestParamsValidatedController {

 private Logger logger = LoggerFactory.getLogger(this.getClass());

 @GetMapping
 public User test(@NotNull(message = "姓名不能为空") String name,
      @NotNull(message = "年龄不能为空") @Max(value = 99, message = "不能大于200岁") Integer age) {
  logger.info("name:" + name + " -age:" + age);
  return new User(name, age);
 }
}

2.2 实体类参数校验

/**
 * 参数校验测试 控制类
 * @author oyc
 */
@RestController
@RequestMapping("user")
@Validated
public class RequestParamsValidatedController {

 private Logger logger = LoggerFactory.getLogger(this.getClass());

 @PostMapping
 public User save(@Validated User user) {
  logger.info(user.toString());
  return user;
 }
}
package com.oycbest.springbootvalidated.vo;

import javax.validation.constraints.*;
import java.io.Serializable;

/**
 * 用户实体类
 * @author oyc
 */
public class User implements Serializable {
 private String userId;

 @NotNull(message = "用户名不能为空")
 private String userName;

 @NotNull(message = "年龄不能为空")
 @Max(value = 100, message = "年龄不能大于100岁")
 private int age;

 @NotNull(message = "邮箱不能为空")
 @Email(message = "邮箱格式不正确")
 private String email;

 @NotNull(message = "电话号码不能为空")
 private String phoneNumber;

 public User(@NotNull(message = "用户名不能为空") String userName, int age) {
  this.userName = userName;
  this.age = age;
 }

 public User() {
 }

 public User(String userId, @NotNull(message = "用户名不能为空") String userName, int age, String email, String phoneNumber) {
  this.userId = userId;
  this.userName = userName;
  this.age = age;
  this.email = email;
  this.phoneNumber = phoneNumber;
 }

 public String getUserId() {
  return userId;
 }

 public void setUserId(String userId) {
  this.userId = userId;
 }

 public String getUserName() {
  return userName;
 }

 public void setUserName(String userName) {
  this.userName = userName;
 }

 public int getAge() {
  return age;
 }

 public void setAge(int age) {
  this.age = age;
 }

 public String getEmail() {
  return email;
 }

 public void setEmail(String email) {
  this.email = email;
 }

 public String getPhoneNumber() {
  return phoneNumber;
 }

 public void setPhoneNumber(String phoneNumber) {
  this.phoneNumber = phoneNumber;
 }

 @Override
 public String toString() {
  return "User{" +
    "userId='" + userId + '\'' +
    ", userName='" + userName + '\'' +
    ", age=" + age +
    ", email='" + email + '\'' +
    ", phoneNumber='" + phoneNumber + '\'' +
    '}';
 }
}

2.3 定义统一异常处理

package com.oycbest.springbootvalidated.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.List;
import java.util.Set;

/**
 * 全局异常处理
 *
 * @author oyc
 */
@ControllerAdvice
@Component
public class GlobalExceptionHandler {
 private Logger logger = LoggerFactory.getLogger(this.getClass());

 @Bean
 public MethodValidationPostProcessor methodValidationPostProcessor() {
  return new MethodValidationPostProcessor();
 }

 @ExceptionHandler
 @ResponseBody
 @ResponseStatus(HttpStatus.BAD_REQUEST)
 public String handle(ValidationException exception) {
  logger.error("请求异常:" + exception.getMessage());
  if (exception instanceof ConstraintViolationException) {
   ConstraintViolationException exs = (ConstraintViolationException) exception;

   Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
   for (ConstraintViolation<?> item : violations) {
    //打印验证不通过的信息
    logger.error("请求异常:" + item.getMessage());
   }
  }
  return "请求异常: " + exception.getMessage();
 }

 @ResponseBody
 @ExceptionHandler(value = BindException.class)
 public String bindException(Exception e) {
  if (e instanceof BindException) {
   BindException exs = (BindException) e;
   List<FieldError> fieldErrors = exs.getFieldErrors();
   for (FieldError item : fieldErrors) {
    logger.error("请求异常:" + item.getDefaultMessage());
   }
  }
  logger.error("数据绑定异常:" + e.getMessage());
  return "数据绑定异常";
 }

 @ResponseBody
 @ExceptionHandler(value = Exception.class)
 public String defaultException(Exception e) {
  logger.error("请求异常:" + e.getMessage());
  return "请求异常 " + e.getMessage();
 }

}

三、约束性注解(简单)说明


注解


功能


@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

到此这篇关于SpringBoot + validation 接口参数校验的文章就介绍到这了,更多相关SpringBoot + validation 接口参数校验内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 在SpringBoot: SpringBoot里面创建导出Excel的接口教程

    在Web项目中,难免需要导出Excel这样的功能,后端接口怎么实现呢,Controller代码在下面,复制到项目的Controller中即可使用: 首先加入Excel的依赖,本例中我们用apache的poi: <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dep

  • SpringBoot后端接口的实现(看这一篇就够了)

    摘要:本文演示如何构建起一个优秀的后端接口体系,体系构建好了自然就有了规范,同时再构建新的后端接口也会十分轻松. 一个后端接口大致分为四个部分组成:接口地址(url).接口请求方式(get.post等).请求数据(request).响应数据(response).如何构建这几个部分每个公司要求都不同,没有什么"一定是最好的"标准,但一个优秀的后端接口和一个糟糕的后端接口对比起来差异还是蛮大的,其中最重要的关键点就是看是否规范! 本文就一步一步演示如何构建起一个优秀的后端接口体系,体系构建

  • SpringBoot基于Sentinel在服务上实现接口限流

    Sentinel是阿里巴巴开源的限流器熔断器,并且带有可视化操作界面. 在日常开发中,限流功能时常被使用,用于对某些接口进行限流熔断,譬如限制单位时间内接口访问次数:或者按照某种规则进行限流,如限制ip的单位时间访问次数等. 之前我们已经讲过接口限流的工具类ratelimter可以实现令牌桶的限流,很明显sentinel的功能更为全面和完善.来看一下sentinel的简介: https://github.com/spring-cloud-incubator/spring-cloud-alibab

  • SpringBoot整合Swagger3生成接口文档过程解析

    前后端分离的项目,接口文档的存在十分重要.与手动编写接口文档不同,swagger是一个自动生成接口文档的工具,在需求不断变更的环境下,手动编写文档的效率实在太低.与新版的swagger3相比swagger2配置更少,使用更加方便. 一.pom文件中引入Swagger3依赖 <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId

  • springboot基于过滤器实现接口请求耗时统计操作

    Spring Boot中实现一个过滤器相当简单,实现javax.servlet.Filter接口即可. 下面以实现一个记录接口访问日志及请求耗时的过滤器为例: 1.定义ApiAccessFilter类,并实现Filter接口 @Slf4j @WebFilter(filterName = "ApiAccessFilter", urlPatterns = "/*") public class ApiAccessFilter implements Filter { @Ov

  • springboot+vue+对接支付宝接口+二维码扫描支付功能(沙箱环境)

    1. 什么是支付宝接口(沙箱环境)? 记录时间:2020年10月15日3:55 现如今,手机支付已相当普遍,而作为开发人员应该对手机支付操作有所了解.而支付宝接口是支付宝提供的一个接口,用来对接软件应用程序在进行金钱交易使用.然后对于编程爱好者而言,想学习这一点就有点难,因为要想使用支付宝接口,必须前提是使用软件应用程序,软件应用程序需要向支付宝申请,提交一系列资料,这一点是实现不了的.这就对开发者增加了一定的难度,因为产品没有上线,然后需要对接支付宝接口就是很大的问题,所以出现了沙箱环境,具有

  • SpringBoot实现API接口多版本支持的示例代码

    一.简介 产品迭代过程中,同一个接口可能同时存在多个版本,不同版本的接口URL.参数相同,可能就是内部逻辑不同.尤其是在同一接口需要同时支持旧版本和新版本的情况下,比如APP发布新版本了,有的用户可能不选择升级,这是后接口的版本管理就十分必要了,根据APP的版本就可以提供不同版本的接口. 二.代码实现 本文的代码实现基于SpringBoot 2.3.4-release 1.定义注解 ApiVersion @Target({ElementType.TYPE, ElementType.METHOD}

  • SpringBoot服务上实现接口限流的方法

    Sentinel是阿里巴巴开源的限流器熔断器,并且带有可视化操作界面. 在日常开发中,限流功能时常被使用,用于对某些接口进行限流熔断,譬如限制单位时间内接口访问次数:或者按照某种规则进行限流,如限制ip的单位时间访问次数等. 之前我们已经讲过接口限流的工具类ratelimter可以实现令牌桶的限流,很明显sentinel的功能更为全面和完善.来看一下sentinel的简介: https://github.com/spring-cloud-incubator/spring-cloud-alibab

  • springboot统一接口返回数据的实现

    一,没有异常的情况,正常返回数据 希望接口统一返回的数据格式如下: { "status": 0, "msg": "成功", "data": null } 和接口数据对应的bean /** * 统一返回结果的实体 * @param <T> */ public class Result<T> implements Serializable { private static final long serial

  • Spring Boot接口幂等插件用法示例解析

    幂等概述 幂等性原本是数学上的概念,即使公式:f(x)=f(f(x)) 能够成立的数学性质.用在编程领域,则意为对同一个系统,使用同样的条件,一次请求和重复的多次请求对系统资源的影响是一致的. 幂等性是分布式系统设计中十分重要的概念,具有这一性质的接口在设计时总是秉持这样的一种理念:调用接口发生异常并且重复尝试时,总是会造成系统所无法承受的损失,所以必须阻止这种现象的发生. 实现幂等的方式很多,目前基于请求令牌机制适用范围较广.其核心思想是为每一次操作生成一个唯一性的凭证,也就是 token.一

随机推荐