如何简单实现一个自定义校验注解。
validator实现了java的校验器API,里面提供了很多校验器注解,但是有时候这些注解不能满足我们的业务校验。
validator也提供了自定义注解的接口,我们只要继承这个接口,并且实现它的方法,就能完成一个简单的自定义注解
注解类
package com.custom;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
//这个注解能使用在哪里
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
//这个注解什么时候执行
@Retention(RUNTIME)
//这个注解对应的校验器类,(这个类一般实现了校验器接口)
@Constraint(validatedBy = { ParamNotNullValidator2.class })
public @interface ParamNotNull2 {
//异常消息
String message() default "参数不能为空----自定义注解";
//剩下的自己按需要加
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
package com.custom;
import com.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
//第一个参数指定注解类,第二个指定校验值类型
public class ParamNotNullValidator2 implements ConstraintValidator<ParamNotNull2,String> {
@Autowired
private DeptService deptService;
//校验方法,里面写自己需要校验的逻辑
public boolean isValid(String value, ConstraintValidatorContext context) {
//先判断这个值是否为null和""
if( value == null || value.equals("") ){
return false;
//调用业务类方法
String name = deptService.queryOne(value);
if(name == null){
return true;
}else {
return false;
package com.controller;
import com.entity.Dept;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.validation.Valid;
@Controller
public class TestDeptController {
//使用@Valid声明使用校验器
@RequestMapping("/queryOne")
public String queryOne(@Valid Dept dept, BindingResult bindingResult, Model model){
if(bindingResult.hasErrors()){
model.addAttribute("msg",bindingResult.getFieldError("name"));
}else {
model.addAttribute("msg","这个名字可以用");
return "index";
package com.entity;
import com.custom.ParamNotNull2;
public class Dept {
private int id;
public int getId() {
return id;
public void setId(int id) {
this.id = id;
@ParamNotNull2
private String name;
public String getName() {
return name;
public void setName(String name) {
this.name = name;
@Override
public String toString() {
return "Dept{" +
"id=" + id +
", name='" + name + '\'' +
'}';
主页面JSP
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<title>Title</title>
</head>
<form action="/queryOne" method="post">
<input type="text" name="name"/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
成功或者失败跳转JSP
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<title>Title</title>
</head>
<h1>${msg}</h1>
</body>
</html>
这样我们就实现了一个基于Spring Mvc的自定义校验器
说一说常见的异常:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.validation.ValidationException: HV000028: Unexpected exception during isValid call.
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
这个异常:说明你写的自定义控制器里面的isValid方法里面执行出现了异常,常见的错误:用户界面使用form表单提交,那么控制器方法的value参数,当用户没有传参的时候,是一个null对象,如果使用
equals判断这个value是否为"",会出现这个异常,下面还有一条异常提示NullPointerException,这说明这个value没有值时会给个null对象,使用equals是会出现异常的,因为它是在校验器方法执行的
所以会报上面的异常,解决办法,去掉equals("")判断,换成==null,或者让equals在后面判断
如果不使用form表单提交的数据,如果用户没有传值的情况下,不会给null对象给value,会给一个"",说明:get请求方法是通过Url传值,所以会给一个"",post请求会给一个null对象,至于方法里面的逻辑如何判断
,各位就见仁见智了。