美文网首页
SpringBoot 自定义表单校验工具

SpringBoot 自定义表单校验工具

作者: 东方不喵 | 来源:发表于2019-01-08 20:23 被阅读40次

在项目开发的时候,对于表单的校验非常必要,而SpringBoot 集成的 Hibernate-validator 大部分被用来校验表单传参,对于Json映射就不能使用了。而且有时候需要校验 Collection<Entity> 时也不能使用。所以为了简便开发,可以编写一套自己的校验工具类。
GitHub https://github.com/oldguys/MultipleDataSourceDemo

Step1:引文Maven依赖

<!-- 自动构建 Getter & Setter 插件 (如果选择自己手动创建Getter & Setter 方法可以不引用) -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.18</version>
    <scope>provided</scope>
</dependency>

Step2: 编写统一异常处理模板类。用于统一表单异常处理。

  1. 自定义异常类
package com.oldguy.example.modules.common.exceptions;
/**
 * @Date: 2019/1/8 0008
 * @Author: ren
 * @Description: 自定义异常类
 */
public class FormValidException extends RuntimeException {

    public FormValidException(String message){
        super(message);
    }
}

  1. 基于 SpringBoot 的自定义异常处理工具
package com.oldguy.example.modules.common.handles;

import com.oldguy.example.modules.common.dto.HttpResult;
import com.oldguy.example.modules.common.exceptions.FormValidException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * @Date: 2019/1/8 0008
 * @Author: ren
 * @Description: 自定义异常处理工具
 */
@RestControllerAdvice
public class FormExceptionHandle {

    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    @ExceptionHandler(FormValidException.class)
    public Object FormException(FormValidException e){
        return new HttpResult(HttpStatus.BAD_REQUEST.value(),e.getMessage(),null);
    }
}
  1. 统一结果类。
package com.oldguy.example.modules.common.dto;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;

/**
 * @Date: 2019/1/8 0008
 * @Author: ren
 * @Description: 统一结果类
 */
@Data
public class HttpResult {

    private Integer code;

    private String message;

    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    private Object data;

    public HttpResult(Integer code, String message, Object data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }
    
}

Step3: 编写异常处理工具类

package com.oldguy.example.modules.common.utils;


import com.oldguy.example.modules.common.exceptions.FormValidException;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.validation.constraints.NotNull;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @author ren
 * @date 2019/1/8
 */
public class FormValidateUtils {

    /**
     * 校验入口
     * Map<校验注解,异常信息>
     */
    private static Map<Class, String> annotationsType = new HashMap<>();

    /**
     * 基本数据类型
     */
    private static Set<Class> baseType = new HashSet<>();

    static {
        annotationsType.put(NotBlank.class, "message");
        annotationsType.put(NotNull.class, "message");
        annotationsType.put(NotEmpty.class, "message");

        baseType.add(Integer.class);
        baseType.add(Long.class);
        baseType.add(Boolean.class);
        baseType.add(Float.class);
        baseType.add(Double.class);
        baseType.add(String.class);
        baseType.add(Character.class);
        baseType.add(Byte.class);
    }

    /**
     * 校验入口
     *
     * @param object
     */
    public static void validate(Object object) {
        validate(object.getClass(), object, false);
    }

    /**
     * @param object
     * @param cascade 级联校验 关联关系字段
     */
    public static void validate(Object object, boolean cascade) {
        validate(object.getClass(), object, cascade);
    }

    /**
     *  校验集合
     * @param obj
     */
    public static void validateCollection(Object obj) {
        validateCollection(obj.getClass(), obj, false);
    }

    /**
     *  校验集合
     * @param obj
     * @param cascade
     */
    public static void validateCollection(Object obj, boolean cascade) {
        validateCollection(obj.getClass(), obj, cascade);
    }


    /**
     * 校验集合对象
     *
     * @param clazz
     * @param obj
     * @param cascade
     */
    private static void validateCollection(Class clazz, Object obj, boolean cascade) {

        // 校验集合对象
        if (obj instanceof Collection) {

            Log4jUtils.getInstance(FormValidateUtils.class).debug("validate Array");
            Collection collection = Collection.class.cast(obj);

            if (collection.isEmpty()) {
                String errorMessage = "集合不能为空!";
                Log4jUtils.getInstance(FormValidateUtils.class).debug(errorMessage);
                throw new FormValidException(errorMessage);
            }

            for (Object item : collection) {
                if (!ObjectUtils.isEmpty(item)) {
                    validate(item, true);
                }
            }
            return;
        }
    }

    private static void validate(Class clazz, Object obj, boolean cascade) {
        if (clazz.equals(Object.class)) {
            return;
        }

        Log4jUtils.getInstance(FormValidateUtils.class).debug("validate Object");

        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            validateField(obj.getClass(), field, obj);
            if (cascade) {
                validateObjectField(field, obj);
            }
        }

        Class superClass = clazz.getSuperclass();
        if (!superClass.equals(Object.class)) {
            validate(superClass, obj, cascade);
        }

    }

    /**
     * 校验对象数据类型
     * 只用于校验 级联的 关联对象数据
     *
     * @param field
     * @param obj
     */
    private static void validateObjectField(Field field, Object obj) {

        String getMethodName = ReflectUtils.tranFieldToGetterMethodName(field.getName());
        Object value = null;
        try {
            // 不需要校验
            Method method = obj.getClass().getMethod(getMethodName);
            if (null == method) {
                return;
            }
            value = method.invoke(obj);
            if (null == value) {
                return;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        // 剔除基本数据类型
        if (baseType.contains(value.getClass())) {
            Log4jUtils.getInstance(FormValidateUtils.class).debug("Base Type");
            return;
        }

        // 级联校验
        if (value instanceof Collection) {

            Log4jUtils.getInstance(FormValidateUtils.class).debug("validate Collection");
            Collection collection = Collection.class.cast(value);
            for (Object item : collection) {
                if (!ObjectUtils.isEmpty(item)) {
                    validate(item, true);
                }
            }
        } else if (value instanceof Map) {

            // Map 一般不做表单参数,需要可以自行扩展
            Log4jUtils.getInstance(FormValidateUtils.class).debug("validate Map");

        } else if (value instanceof Object) {

            // 递归校验 对象参数
            Log4jUtils.getInstance(FormValidateUtils.class).debug("validate field [ " + value.getClass().getName() + " ]");
            validate(value, true);
        }


    }

    /**
     * 检验基本数据类型
     *
     * @param clazz
     * @param field
     * @param object
     */
    private static void validateField(Class clazz, Field field, Object object) {

        String getMethod = ReflectUtils.tranFieldToGetterMethodName(field.getName());

        String errorMessage = null;
        try {

            Method method = clazz.getMethod(getMethod);
            // 不具备Get方法,不做校验
            if (null == method) {
                return;
            }
            Object value = method.invoke(object);

            for (Class key : annotationsType.keySet()) {
                Annotation annotation = field.getAnnotation(key);
                if (null != annotation) {
                    Object obj = key.cast(annotation);

                    Log4jUtils.getInstance(FormValidateUtils.class).debug(field.getClass().getSimpleName() + ":" + obj);

                    // 非空有效值,不做校验
                    if (!ObjectUtils.isEmpty(value)) {
                        return;
                    }

                    Method messageMethod = key.getMethod(annotationsType.get(key));
                    if (null != messageMethod) {
                        errorMessage = (String) messageMethod.invoke(obj);
                        if (StringUtils.isEmpty(errorMessage)) {
                            errorMessage = field.getName() + " 出现异常";
                        }
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        if (!StringUtils.isEmpty(errorMessage)) {
            Log4jUtils.getInstance(FormValidateUtils.class).warn("表单校验异常:" + errorMessage);
            // 抛出自定义异常,用于统一的异常捕获
            throw new FormValidException(errorMessage);
        }
    }


}

其中Log4jUtils为自定义日志处理类,可以忽略。另外具有一个转换Get Method 的方法

    public static String tranFieldToGetterMethodName(String field) {
        field = "get" + field.substring(0, 1).toUpperCase() + field.substring(1, field.length());
        return field;
    }

以上就完成了自定义校验工具类的编写,可以进行测试了。

  1. 测试类
package com.oldguy.example.common;

import com.oldguy.example.modules.common.utils.FormValidateUtils;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

/**
 * @Date: 2019/1/8 0008
 * @Author: ren
 * @Description:
 */
public class FormValidateTest {

    @Test
    public void testList(){

        List<FormEntity> list = new ArrayList<>();
        list.add(new FormEntity());
        FormValidateUtils.validateCollection(list);

    }

    @Test
    public void testNoCascade(){

        FormEntity entity = new FormEntity();

        FormEntity.FormItem item = new FormEntity.FormItem();
        entity.setItem1(item);

        List<FormEntity.FormItem> list = new ArrayList<>();
        list.add(item);
        entity.setItemList(list);

        FormValidateUtils.validate(entity);

    }

    @Test
    public void testCascade(){

        FormEntity entity = new FormEntity();

        FormEntity.FormItem item = new FormEntity.FormItem();
        entity.setItem1(item);

        List<FormEntity.FormItem> list = new ArrayList<>();
        list.add(item);
        entity.setItemList(list);

        FormValidateUtils.validate(entity,true);

    }
}

  1. 测试参数类
package com.oldguy.example.common;

import javax.validation.constraints.NotNull;

/**
 * @Date: 2019/1/8 0008
 * @Author: ren
 * @Description:
 */
public class AbstractForm {


    @NotNull(message = "测试继承 id")
    private Long id;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

  1. 参数类
package com.oldguy.example.common;

import lombok.Data;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.NotEmpty;

import javax.validation.constraints.NotNull;
import java.util.List;

/**
 * @Date: 2019/1/8 0008
 * @Author: ren
 * @Description:
 */
@Data
public class FormEntity extends AbstractForm{

    @NotBlank(message = "测试 message")
    private String message;

    @NotBlank(message = "测试 comment")
    private String comment;

    @NotEmpty(message = "测试 List")
    public List<FormItem> itemList;

    @NotNull(message = "item1 不为空")
    public FormItem item1;

    public FormItem item2;

    @Data
    public static class FormItem{

        @NotNull(message = "测试级联 code")
        private Integer code;

        @NotBlank(message = "测试级联 message")
        private String message;

    }

    public void setMessage(String message) {
        this.message = message;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public void setItemList(List<FormItem> itemList) {
        this.itemList = itemList;
    }

    public void setItem1(FormItem item1) {
        this.item1 = item1;
    }

    public void setItem2(FormItem item2) {
        this.item2 = item2;
    }
}

结果:
[图片上传中...(QQ截图20190108202259.png-539101-1546950193064-0)]

到此完成了 SpringBoot 自定义参数校验模板工具类的编写
代码可以参考 GitHub https://github.com/oldguys/MultipleDataSourceDemo

相关文章

  • SpringBoot 自定义表单校验工具

    在项目开发的时候,对于表单的校验非常必要,而SpringBoot 集成的 Hibernate-validator ...

  • SpringBoot对表单做数据校验

    1. SpringBoot对表单数据校验的技术特点 1.1 SpringBoot中使用了Hibernate-val...

  • elementui表单自定义校验及嵌套验证

    自定义校验规则额外参数 多个输入框校验逻辑一致 ElementUI表单校验prop的嵌套写法页面中的表单经常会有校...

  • 15.《Angular表单校验》

    一、使用Angular自带的表单校验器 运行结果: 二、自定义表单校验器 当然我们也可以将验证器方法独立出来 使用...

  • antd - form表单校验踩坑记录

    form表单校验时,发现提示信息一直不显示 原因:是因为form表单中有用到了自定义校验,但是callback没有...

  • el-form校验失败

    表单校验不报错,但是校验方法一直进不去,原因是因为自定义校验规则的时候没有else callback()

  • SpringBoot 表单参数校验

    在前后端分离如此盛行的今天,普遍使用 Json 进行数据交互,为了保证数据的完整与有效性,我们一般会在前端提交数据...

  • Jquery validation

    前端表单验证框架 页面引入 默认校验规则 封装后检验器 自定义rules举例(校验用户长度等) Example

  • Hibernate-Validation

    一.依赖架包: 二.校验工具类 三、校验返回对象 四.自定义注解 五、自定义密码校验类 标准实现者如hiberna...

  • Vue+element - ui 自定义动态表单带校验

    Vue+element - ui 自定义动态表单带校验 父组件对应的数据 子组件

网友评论

      本文标题:SpringBoot 自定义表单校验工具

      本文链接:https://www.haomeiwen.com/subject/xygbrqtx.html