前言

        数据校验是交互式网站一个不可或缺的功能,前端的js校验可以涵盖大部分的校验职责,如用户名唯一性,生日格式,邮箱格式校验等等常用的校验。但是为了避免用户绕过浏览器,使用http工具直接向后端请求一些违法数据,服务端的数据校验也是必要的,可以防止脏数据落到数据库中等等。

 一、数据校验的两种方式

1、基于注解形式的数据校验

JSR提供的校验注解:         
@Null   被注释的元素必须为 null    
@NotNull    被注释的元素必须不为 null    
@AssertTrue     被注释的元素必须为 true    
@AssertFalse    被注释的元素必须为 false    
@Min(value)     被注释的元素必须是一个数字,其值必须大于等于指定的最小值    
@Max(value)     被注释的元素必须是一个数字,其值必须小于等于指定的最大值    
@DecimalMin(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值    
@DecimalMax(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值    
@Size(max=, min=)   被注释的元素的大小必须在指定的范围内    
@Digits (integer, fraction)     被注释的元素必须是一个数字,其值必须在可接受的范围内    
@Past   被注释的元素必须是一个过去的日期    
@Future     被注释的元素必须是一个将来的日期    
@Pattern(regex=,flag=)  被注释的元素必须符合指定的正则表达式    

Hibernate Validator提供的校验注解:  
@NotBlank(message =)   验证字符串非null,且长度必须大于0    
@Email  被注释的元素必须是电子邮箱地址    
@Length(min=,max=)  被注释的字符串的大小必须在指定的范围内    
@NotEmpty   被注释的字符串的必须非空    
@Range(min=,max=,message=)  被注释的元素必须在合适的范围内

2、基于Validator接口形式的数据校验

(1)Validator的实现类:需实现Validator接口的supports方法和validate方法。

         Supports方法用于判断当前的Validator实现类是否支持校验当前需要校验的实体类,只有当supports方法的返回结果为true的时候,该Validator接口实现类的validate方法才会被调用来对当前需要校验的实体类进行校验。

         Validate 方法用于定义校验规则。

(2)ValidationUtils类:校验工具类,提供了校验实体类、实体字段的方法,返回一个自定义的校验对象。

(3)ValidationResult类:校验返回结果类 

二、数据校验实战

项目结构如下:

                         

java 后端验签 java后端数据校验_java 后端验签

 

1、基于Validator接口形式的数据校验

创建一个POJO类,即数据校验的实体

package com.scb.spittr.springValidator;

import lombok.Data;

import java.io.Serializable;

@Data
public class User implements Serializable {
    private String username;
    private String sex;
    private Integer age;
}

 创建Validator的实现类

package com.scb.spittr.springValidator;

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

public class UserValidator implements Validator {
    @Override
    public boolean supports(Class<?> clazz) {
        //对上诉的User进行数据校验
        return User.class.equals(clazz);
    }

    //对目标类target进行校验,并将校验错误记录在errors中
    //Errors是Spring用来存放错误信息的对象
    @Override
    public void validate(Object object, Errors errors) {
        // 验证username、sex和age是否为null
        ValidationUtils.rejectIfEmpty(errors, "username", null, "用户名不能为空");
        ValidationUtils.rejectIfEmpty(errors, "sex", null, "性别不能为空");
        ValidationUtils.rejectIfEmpty(errors, "age", null, "年龄不能为空");
    }
}

 进行Spring MVC配置

package com.scb.spittr.springValidator;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan("com.scb.spittr.springValidator")
public class WebConfig extends WebMvcConfigurerAdapter {

    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // TODO Auto-generated method stub
        super.addResourceHandlers(registry);
    }

}

 控制层

package com.scb.spittr.springValidator;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.DataBinder;
import org.springframework.validation.Errors;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping(value = "/user")
public class UserController {
    @RequestMapping(value="/userForm",method=RequestMethod.GET)
    public String userForm(Model model){
        User user=new User();
        // model中添加属性user,值是user对象
        model.addAttribute("user",user);
        return "userForm";
    }

    //使用DataBinder来设定当前Controller需要使用的Validator
    //@initBinder可以直接在你的controller中提供数据绑定(被注解方法不能有返回值,即返回void)
    @InitBinder
    public void InitBinder(DataBinder binder){
        // 设置验证的类为UserValidator
        binder.setValidator(new UserValidator());
    }

    //在需要校验的pojo前边添加@Validated,在需要校验的pojo后边添加Errors(或其子类BindingResult)用来接收校验出错信息
    @RequestMapping(value="/register",method=RequestMethod.POST)
    public String register(@Validated User user, Errors errors){
        // 如果Errors对象有Field错误的时候,重新跳回注册页面,否则正常提交
        if (errors.hasFieldErrors())
            return "userForm";
        return "submit";
    }
}

 前端界面

userForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>基于Validator接口的验证</title>
</head>
<body>
<h3>注册页面</h3>
<form:form modelAttribute="user" method="post" action="register" >
    <table>
        <tr>
            <td>姓名:</td>
            <td><form:input path="username"/></td>
            <td><font color="red"><form:errors path="username"/></font></td>
        </tr>
        <tr>
            <td>性别:</td>
            <td><form:input path="sex"/></td>
            <td><font color="red"><form:errors path="sex"/></font></td>
        </tr>
        <tr>
            <td>年龄:</td>
            <td><form:input path="age"/></td>
            <td><font color="red"><form:errors path="age"/></font></td>
        </tr>
        <tr>
            <td><input type="submit" value="注册"/></td>
        </tr>
    </table>
</form:form>
</body>
</html>

 submit.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>success</title>
</head>
<body>
<h3>验证成功页面</h3>
</body>
</html>

 运行结果:(当提交null时,将得到以下结果)

java 后端验签 java后端数据校验_html_02

 2、基于注解形式的数据校验

创建Student数据校验对象

package com.scb.spittr.javaValidation;

import lombok.Data;

import javax.validation.constraints.*;

@Data
public class Student {
    @Min(value = 100000,message = "sno must be greater than or equal to {value}")
    private Integer sno;

    @Size(min = 2,max = 30,message = "sname must be between {min} and {max} characters long.")
    private String sname;

    @DecimalMin(value = "10",message = "age must be greater than or equal to {value}")
    private int sage;

}

 Student的控制层

package com.scb.spittr.javaValidation;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping(value = "/student")
public class StudentController {
    @RequestMapping(value = "/stuForm", method = RequestMethod.GET)
    public String stuForm(Model model) {
        Student student = new Student();
        // model中添加属性student,值是student对象
        model.addAttribute("student", student);
        return "stuForm";
    }


    @RequestMapping(value = "/register", method = RequestMethod.POST)
    public String register(@Validated Student student, Errors errors) {
        // 如果Errors对象有Field错误的时候,重新跳回注册页面,否则正常提交
        if (errors.hasFieldErrors())
            return "stuForm";
        return "submit";
    }
}

 stuForm.jsp界面

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>使用注解形式的验证</title>
</head>
<body>
<h3>注册页面</h3>
<form:form modelAttribute="student" method="post" action="register" >
    <table>
        <tr>
            <td>学号:</td>
            <td><form:input path="sno"/></td>
            <td><font color="red"><form:errors path="sno"/></font></td>
        </tr>
        <tr>
            <td>姓名:</td>
            <td><form:input path="sname"/></td>
            <td><font color="red"><form:errors path="sname"/></font></td>
        </tr>
        <tr>
            <td>年龄:</td>
            <td><form:input path="sage"/></td>
            <td><font color="red"><form:errors path="sage"/></font></td>
        </tr>
        <tr>
            <td><input type="submit" value="注册"/></td>
        </tr>
    </table>
</form:form>
</body>
</html>

 运行结果:

java 后端验签 java后端数据校验_Spring Validation_03

3、自定义校验注解

 创建自定义的密码注解

package com.scb.spittr.annotation;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

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

@Target( { METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = PasswordValidator.class)
@Documented
public @interface Password {

    String message() default "{密码必须是5~10位数字和字母组合}";

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

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

 

package com.scb.spittr.annotation;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class PasswordValidator implements ConstraintValidator<Password, String> {

    //5~10位的数字与字母组合
    private static Pattern pattern = Pattern.compile("(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{5,10}");

    public void initialize(Password constraintAnnotation) {
        //do nothing
    }

    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null) {
            return false;
        }
        Matcher m = pattern.matcher(value);
        return m.matches();
    }
}

 创建数据校验对象

package com.scb.spittr.annotation;

import lombok.Data;

import javax.validation.constraints.Pattern;

@Data
public class Login {
    @Pattern(regexp = "^[1-9]\\d*$",message = "id must be positive integer")
    private String id;
    //使用自定义的数据校验注解
    @Password
    private String password;
}

 控制层

package com.scb.spittr.annotation;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/login")
public class LoginController {
    @RequestMapping(value = "loginForm",method = RequestMethod.GET)
    public String loginForm(Model model) {
        Login login = new Login();
        // model中添加属性login,值是login对象
        model.addAttribute("login", login);
        return "loginForm";
    }


    @RequestMapping(value = "/register", method = RequestMethod.POST)
    public String register(@Validated Login login, Errors errors) {
        // 如果Errors对象有Field错误的时候,重新跳回注册页面,否则正常提交
        if (errors.hasFieldErrors())
            return "loginForm";
        return "submit";
    }
}

 前端loginForm.jsp界面

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>自定义校验标签测试</title>
</head>
<body>
<h3>注册页面</h3>
<form:form modelAttribute="login" method="post" action="register" >
    <table>
        <tr>
            <td>ID:</td>
            <td><form:input path="id"/></td>
            <td><font color="red"><form:errors path="id"/></font></td>
        </tr>
        <tr>
            <td>Password:</td>
            <td><form:input path="password"/></td>
            <td><font color="red"><form:errors path="password"/></font></td>
        </tr>
        <tr>
            <td><input type="submit" value="注册"/></td>
        </tr>
    </table>
</form:form>
</body>
</html>

 运行结果:

java 后端验签 java后端数据校验_java 后端验签_04