在项目开发的时候,对于表单的校验非常必要,而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: 编写统一异常处理模板类。用于统一表单异常处理。
- 自定义异常类
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);
}
}
- 基于 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);
}
}
- 统一结果类。
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;
}
以上就完成了自定义校验工具类的编写,可以进行测试了。
- 测试类
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);
}
}
- 测试参数类
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;
}
}
- 参数类
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
网友评论