Skip to content

Commit

Permalink
FluentValidator 链式调用验证器
Browse files Browse the repository at this point in the history
  • Loading branch information
tianbin committed Aug 22, 2021
1 parent e555646 commit aa306f5
Show file tree
Hide file tree
Showing 14 changed files with 543 additions and 2 deletions.
43 changes: 43 additions & 0 deletions src/main/java/common/exception/ClientViewException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package common.exception;

import common.util.DataUtils;

public class ClientViewException extends RuntimeException {

private Long code;

private String message;

public Long getCode() {
return code;
}

public void setCode(Long code) {
this.code = code;
}

public String getMsg() {
return message;
}

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

public ClientViewException() { super(); }

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

public ClientViewException(String message, Object... args) {
super(DataUtils.format(message, args));
}

public ClientViewException(Long code, String message){
super(message);
this.code = code;
this.message = message;
}

}
83 changes: 83 additions & 0 deletions src/main/java/common/util/DataUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package common.util;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.helpers.MessageFormatter;

import java.util.Collection;
import java.util.List;

/**
* Created by nibnait on 2021/08/18
*/
@Slf4j
public class DataUtils {

/**
* 返回 list1 - (list1 ∩ list2)
*/
public static <T> List<T> difference(Collection<T> list1, Collection<T> list2) {
return Lists.newArrayList(Sets.difference(Sets.newHashSet(list1), Sets.newHashSet(list2)));
}

/**
* 返回交集 list1 ∩ list2
*/
public static <T> List<T> intersection(Collection<T> list1, Collection<T> list2) {
return Lists.newArrayList(Sets.intersection(Sets.newHashSet(list1), Sets.newHashSet(list2)));
}

/**
* @param format abc{}e
* @param args d
* @return abcde
*/
public static String format(String format, Object... args) {
return MessageFormatter.arrayFormat(format, args).getMessage();
}

/**
* @param clazz 类型不可为抽象类/接口
*/
public static <T> T parseObject(String s, Class<T> clazz) {
if (StringUtils.isBlank(s) || "null".equalsIgnoreCase(s)) {
try {
return clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
log.error(e.getMessage(), e);
return null;
}
}
try {
return JSON.parseObject(s, clazz);
} catch (Throwable e) {
log.error(e.getMessage(), e);
return null;
}
}

public static <T> List<T> parseArray(String s, Class<T> clazz) {
if (StringUtils.isBlank(s) || "null".equalsIgnoreCase(s)) {
return Lists.newArrayList();
}
return JSON.parseArray(s, clazz);
}

public static String toJsonStringObject(Object o) {
if (o == null) {
return JSON.toJSONString(Maps.newHashMap());
}
return JSON.toJSONString(o);
}

public static String toJsonStringArray(Object o) {
if (o == null) {
return JSON.toJSONString(Lists.newArrayList());
}
return JSON.toJSONString(o);
}
}
136 changes: 136 additions & 0 deletions src/main/java/common/util/validate/FluentValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package common.util.validate;

import common.util.validate.context.ValidateContext;
import common.util.validate.context.ValidateContextAttrKey;
import common.util.validate.context.ValidateElement;
import common.util.validate.context.ValidateResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

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

/**
* 链式调用验证器,参考fluent-validator的简单实现
* https://github.com/neoremind/fluent-validator
*/
@Slf4j
public class FluentValidator {
/**
* 验证器链,惰性求值期间就是不断的改变这个链表,及时求值期间就是遍历链表依次执行验证
*/
private List<ValidateElement> ValidateElementList = new ArrayList<>();

/**
* 验证器上下文
*/
private ValidateContext context = new ValidateContext();

/**
* 私有构造方法,只能通过checkAll创建对象
*/
private FluentValidator() {
}

/**
* 创建FluentValidator对象
*
* @return
*/
public static FluentValidator checkAll() {
return new FluentValidator();
}

/**
* 使用验证器进行验证
*
* @param validator 验证器
* @return
*/
public <T> FluentValidator on(Validator<T> validator) {
ValidateElementList.add(new ValidateElement(null, validator));
return this;
}

/**
* 使用验证器验证指定对象
*
* @param t 待验证对象
* @param validator 验证器
* @return
*/
public <T> FluentValidator on(T t, Validator<T> validator) {
ValidateElementList.add(new ValidateElement(t, validator));
return this;
}

/**
* 使用验证器验证指定对象
*
* @param t 待验证对象
* @param validator 验证器
* @param condition 条件,为true时才会将验证器加入验证器列表中
* @return
*/
public <T> FluentValidator on(T t, Validator<T> validator, boolean condition) {
if (condition) {
ValidateElementList.add(new ValidateElement(t, validator));
}
return this;
}

/**
* 执行各个验证器中的验证逻辑
*
* @return
*/
public FluentValidator doValidate() {
if (CollectionUtils.isEmpty(ValidateElementList)) {
log.info("Nothing to validate");
return null;
}
try {
for (ValidateElement element : ValidateElementList) {
Object target = element.getTarget();
Validator validator = element.getValidator();
validator.validate(context, target);
}
} catch (Exception e) {
log.error("FluentValidator.doValidate error ", e);
throw e;
}
return this;
}

/**
* 转换为对外的验证结果,在<code>FluentValidator.on(..).on(..).doValidate()</code>这一连串计算后的“及时求值”收殓出口。
*
* @return 对外验证结果
*/
public ValidateResult result() {
return context.result();
}

/**
* 将键值对放入上下文
*
* @param key 键
* @param value 值
* @return FluentValidator
*/
public FluentValidator putAttribute2Context(ValidateContextAttrKey key, Object value) {
if (context == null) {
context = new ValidateContext();
}
context.setAttribute(key, value);
return this;
}

/**
* 获取验证器上下文
*/
public ValidateContext getContext() {
return context;
}

}
24 changes: 24 additions & 0 deletions src/main/java/common/util/validate/Validator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package common.util.validate;

import common.util.validate.context.ValidateContext;

/**
* 验证器接口。
* <p/>
* 泛型<t>T</t>表示待验证对象的类型
*
*/
public interface Validator<T> {

/**
* 执行验证
* <p/>
* 如果发生错误内部需要调用{@link ValidateContext#addErrorMsg(String)}方法,也即<code>context.addErrorMsg(String)
* </code>来添加错误,该错误会被添加到结果存根{@link ValidateContext#result()} 的错误消息列表中。
*
* @param context 验证上下文
* @param t 待验证对象
*/
void validate(ValidateContext context, T t);

}
Loading

0 comments on commit aa306f5

Please sign in to comment.