栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

基于SpringBoot参数校验器拓展自定义参数校验

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

基于SpringBoot参数校验器拓展自定义参数校验

基于SpringBoot参数校验器拓展自定义参数校验

想必工作中大家为了保证接口的稳定性与安全性都会对入参进行校验。五花八门的校验写法会让我们的代码不够整洁,本文将介绍如何使用SpringBoot为我们提供的参数校验器,并对其进行扩展,让其能够实现自定义校验。当然在一些互联网项目中,为保证接口的高性能,校验都是放在前端做的,但是在阿里开发规约中是这样说的越是简单的接口越不需要进行参数校验,越是复杂的接口越需要参数校验,因为复杂的接口试错成本很高,校验对接口性能的影响微乎其微。

工程中的使用可参照我的开源项目:https://gitee.com/zhuhuijie/base-platform

在common-web模块中引入在example-business中使用

SpringBoot 参数校验器的使用

本章通过怎么引入SpringBoot的参数校验器,让大家能够搭建一个简单的Demo,文章的第二部分,自定义扩展才是本文的重头戏。

1 首先,pom文件引入参数校验器的依赖

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

2 入参VO,加入相关的注解

常用注解:

  • @NotNull 非空验证

  • @Min(value = 1, message = “年龄不能小于1”)
    @Max(value = 25, message = “年龄不能超过25”)

    值区间验证

  • @Email(message = “必须是邮箱格式”) 邮箱格式验证

  • @Past(message = “生日范围不正确,生日必须是今天以前的”)

    验证是否是过去的时间

import com.fasterxml.jackson.annotation.JsonFormat;
import com.zhj.business.protocol.validhandler.BirthdayValidHandler;
import com.zhj.common.web.valid.annotation.MyValid;
import lombok.Data;

import javax.validation.constraints.*;
import java.util.Date;


@Data
public class StudentInput {

    @NotNull(message = "名字不能为空")
    private String name;
    @Min(value = 1, message = "年龄不能小于1")
    @Max(value = 25, message = "年龄不能超过25")
    private Integer age;
    @NotNull(message = "邮箱不能为空")
    @Email(message = "必须是邮箱格式")
    private String email;
    @NotNull(message = "性别不能为空")
    private Integer sex;
    @NotNull(message = "生日不能为空")
    @Past(message = "生日范围不正确,生日必须是今天以前的")
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
    private Date birthday;
}
3 Controller 中开启校验,切记开启才会生效
import com.zhj.business.protocol.input.StudentInput;
import com.zhj.business.service.StudentService;
import com.zhj.common.core.result.Result;
import com.zhj.common.core.util.ResultUtils;
import com.zhj.data.entity.example.Student;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

@Slf4j
@RestController
@RequestMapping("/student")
public class StudentController {

    @Autowired
    private StudentService studentService;

    @PostMapping("/add")
    public Result add(@Valid @RequestBody StudentInput studentInput) {
        log.info("接收到的学生信息:" + studentInput);
        Student student = new Student();
        BeanUtils.copyProperties(studentInput, student);
        boolean result = studentService.save(student);
        log.info("保存学生的结果" + result);
        return ResultUtils.createSuccess(student);
    }
}
SpringBoot 参数校验器的扩展

本章将通过实现年龄与生日是否匹配的校验为例,为我们展示如何通过注解实现这类复杂的参数校验

1 首先呢,我们扩展需要参数校验器需要通过自定义注解实现
import com.zhj.common.web.valid.constraint.MyParameterValid;
import com.zhj.common.web.valid.handler.MyValidHandler;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MyParameterValid.class) // 对应校验类型
public @interface MyValid {

    
    String message() default "校验失败";

    
    Class[] groups() default {};

    
    Class[] payload() default {};

    
    Class handler();
}
2 实现对Springboot参数校验器的自定义扩展
  • 通过实现ConstraintValidator 官方为我们提供的扩展接口,完成自定义注解的初始化
  • 从新实现校验方法
    • 通过Spring容器获取自定义参数校验处理器MyValidHandler
    • 然后将注解与校验对象传入自定义的校验方法
    • 执行自定义校验方法,根据返回结果判断是否校验通过
import com.zhj.common.web.util.ApplicationContextUtils;
import com.zhj.common.web.valid.annotation.MyValid;
import com.zhj.common.web.valid.handler.MyValidHandler;
import lombok.extern.slf4j.Slf4j;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Optional;


@Slf4j
public class MyParameterValid implements ConstraintValidator {

    private MyValid myValid;

    @Override
    public void initialize(MyValid constraintAnnotation) {
        this.myValid = constraintAnnotation;
    }

    
    @Override
    public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
        log.info("自定义参数校验触发" + o);
        if (null != o) {
            Class handler = myValid.handler();
            // 交给 MyValidHandler 处理校验
            MyValidHandler myValidHandler = ApplicationContextUtils.getBean(handler);
            return Optional
                    .ofNullable(myValidHandler)
                    .map(myValidHandler1 -> {
                return myValidHandler.valid(myValid, o);
            }).orElse(false);
        }
        return true;
    }
}
3 自定义处理接口

自定义校验方法通过实现该接口,重写校验方法

通过接口的多实现从而实现各种自定义处理。

import com.zhj.common.web.valid.annotation.MyValid;


public interface MyValidHandler {

    
    boolean valid(MyValid myValid, T data);
}
4 获取Spring容器中对象的工具类

通过Spring上下文根据类名查找对应的实现

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;


@Component
public class ApplicationContextUtils {

    @Autowired
    private ApplicationContext applicationContext;

    
    private static ApplicationContext staticApplicationContext;

    @PostConstruct
    private void init() {
        ApplicationContextUtils.staticApplicationContext = applicationContext;
    }

    public static  T getBean(Class cls) {
        if (staticApplicationContext != null) {
            return staticApplicationContext.getBean(cls);
        }
        return null;
    }
}
5 在入参VO类上添加自定义注解

handler = BirthdayValidHandler.class 将自定义校验方法的类名传入,该类需要实现自定义处理接口

import com.fasterxml.jackson.annotation.JsonFormat;
import com.zhj.business.protocol.validhandler.BirthdayValidHandler;
import com.zhj.common.web.valid.annotation.MyValid;
import lombok.Data;

import javax.validation.constraints.*;
import java.util.Date;


@Data
@MyValid(message = "年龄和生日不匹配", handler = BirthdayValidHandler.class)
public class StudentInput {

    @NotNull(message = "名字不能为空")
    private String name;
    @Min(value = 1, message = "年龄不能小于1")
    @Max(value = 25, message = "年龄不能超过25")
    private Integer age;
    @NotNull(message = "邮箱不能为空")
    @Email(message = "必须是邮箱格式")
    private String email;
    @NotNull(message = "性别不能为空")
    private Integer sex;
    @NotNull(message = "生日不能为空")
    @Past(message = "生日范围不正确,生日必须是今天以前的")
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
    private Date birthday;
}
6 创建注解所写类名,实现自定义校验

切记需要将该对象注册进Spring容器中,否则扩展方式无法获取到该实例

本示例是实现,年龄与生日关系的校验,年龄和生日必须匹配才会校验成功

import com.zhj.business.protocol.input.StudentInput;
import com.zhj.common.web.valid.annotation.MyValid;
import com.zhj.common.web.valid.handler.MyValidHandler;
import org.springframework.stereotype.Component;

import java.util.Calendar;
import java.util.Date;


@Component
public class BirthdayValidHandler implements MyValidHandler {

    @Override
    public boolean valid(MyValid myValid, StudentInput data) {
        Integer age = data.getAge();
        Date birthday = data.getBirthday();
        if (age == null || birthday == null) return true;
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        int currYear = calendar.get(Calendar.YEAR);
        calendar.setTime(birthday);
        int birYear = calendar.get(Calendar.YEAR);
        return currYear - birYear == age;
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/389990.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号