SpringMVC自定义注解进行参数校验

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qmqm011/article/details/83006670

在我的另一篇博客中(SpringMVC),学习了如何使用Spring MVC结合Hibernate的校验框架validation(它和hibernate没有任何关系)对参数进行校验。在实际项目中,参数的校验逻辑可能比较复杂,这时我们可以自定义注解来实现参数校验,下面是一个简单的例子。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.wuy</groupId>
    <artifactId>custom-validation</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>custom-validation</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- Web起步依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 测试相关 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- hibernate validator相关依赖 -->
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.jboss.logging</groupId>
            <artifactId>jboss-logging</artifactId>
            <version>3.3.2.Final</version>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>
        <!-- lombok简化代码 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- JSON -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.51</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.yml

server:
  port: 8080

程序启动类

package com.wuy.customvalidation;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CustomValidationApplication {

    public static void main(String[] args) {
        SpringApplication.run(CustomValidationApplication.class, args);
    }
}

User.java

package com.wuy.customvalidation.entity;

import com.wuy.customvalidation.validation.Phone;
import lombok.Data;

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

@Data
public class User implements Serializable {

    private static final long serialVersionUID = -1L;

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

    @Phone(message = "手机号不正确")
    private String phone;

}

这个类就是我们要进行验证的POJO,@Phone是我们自定义的注解,用于对phone这个字段进行验证。我们看看@Phone的源码。

编写自定义注解

package com.wuy.customvalidation.validation;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD})
@Constraint(validatedBy = PhoneConstraintValidator.class)
public @interface Phone {

    String message() default "Phone num is invalid";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

@Documented、@Retention、@Target是元注解,这里不做深入,message方法指定验证失败时的错误信息,默认是“Phone num is invalid”。我们主要看看@Constraint注解,它有一个validatedBy属性,用于指定具体进行验证的类,PhoneConstraintValidator的源码如下:

package com.wuy.customvalidation.validation;

import org.springframework.util.StringUtils;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class PhoneConstraintValidator implements ConstraintValidator<Phone, String> {

    @Override
    public void initialize(Phone constraintAnnotation) {

    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (StringUtils.isEmpty(value)) {
            return false;
        }
        return value.matches("^\\d{11}$");
    }

}

PhoneConstraintValidator类实现了ConstraintValidator接口,第一个泛型指定自定义的注解Phone这个类,第二个泛型指定要验证的参数的类型,这里是String。initialize方法用于做一些初始化,具体的验证逻辑写在isValid方法里面,这个方法返回false表示验证失败,返回true表示验证成功。这里的验证逻辑是,手机号符合11位数字即可。

编写Controller

代码如下:

package com.wuy.customvalidation.controller;

import com.alibaba.fastjson.JSON;
import com.wuy.customvalidation.entity.User;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.stream.Collectors;

@RestController
public class TestController {

    @RequestMapping("/save")
    @ResponseBody
    public String save(@Valid User user, BindingResult errors) {
        if (errors.hasErrors()) {
            errors.getAllErrors().stream()
                    .map(DefaultMessageSourceResolvable::getDefaultMessage)
                    .forEach(System.out::println);
            return JSON.toJSONString(errors.getAllErrors().stream()
                    .map(DefaultMessageSourceResolvable::getDefaultMessage)
                    .collect(Collectors.joining("; ")));
        }
        return JSON.toJSONString(user);
    }

}

@Valid注解用于标注需要进行验证的POJO,BindingResult用于捕获验证失败的信息。注意:@Valid和BindingResult是配对出现,并且顺序是固定的(一前一后)。方法中,首先判断是否有错误信息,如果有,先是将错误信息全部打印到控制台,然后将错误信息以“;”分割后返回给调用者;如果验证通过,则直接返回User对象。这里用到了Java 8的Stream API,关于Java 8的新特性,可以参考我相应的文章。

至此,自定义注解进行参数校验即完成。

猜你喜欢

转载自blog.csdn.net/qmqm011/article/details/83006670