问题场景
接口参数需要做校验,基于JSR303等框架需要写不同的Vo类来支持,比如添加接口不需要强制ID,而修改接口又必须要ID,就可能需要两个Vo类传入。为了解决这类场景,可以写个参数动态校验工具类
工具代码
import lombok.extern.slf4j.Slf4j;
import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Objects;
import java.util.function.Function;
/**
* 参数校验
*/
@Slf4j
public class VerifyUtil {
/**
* 使Function获取序列化能力
*/
@FunctionalInterface
public interface SFunction<T, R> extends Function<T, R>, Serializable {
}
@SafeVarargs
public static <T> String check(Object params, VerifyUtil.SFunction<T, ?>... fns) {
Class<?> clazz = params.getClass();
try {
for (VerifyUtil.SFunction<T, ?> fn : fns) {
// 从function取出序列化方法
Method writeReplaceMethod;
try {
writeReplaceMethod = fn.getClass().getDeclaredMethod("writeReplace");
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
// 从序列化方法取出序列化的lambda信息
// JDK9以下
// boolean isAccessible = writeReplaceMethod.isAccessible();
// JDK9及以上
boolean isAccessible = writeReplaceMethod.canAccess(fn);
writeReplaceMethod.setAccessible(true);
SerializedLambda serializedLambda;
try {
serializedLambda = (SerializedLambda) writeReplaceMethod.invoke(fn);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
writeReplaceMethod.setAccessible(isAccessible);
// 从lambda信息取出method、field、class等
String fieldName = serializedLambda.getImplMethodName().substring("get".length());
fieldName = fieldName.replaceFirst(fieldName.charAt(0) + "", (fieldName.charAt(0) + "").toLowerCase());
// 通过反射直接获取名为username的属性
Field declaredField = clazz.getDeclaredField(fieldName);
if (declaredField.getModifiers() == Modifier.PRIVATE) {
declaredField.setAccessible(true);
Object value = declaredField.get(params);
// 判断是否为空
if (value instanceof String) {
// 字符不能为空字符
if (Objects.equals(value, "")) {
return declaredField.getName() + "不能为空";
}
} else {
if (Objects.isNull(value)) {
return declaredField.getName() + "不能为空";
}
}
}
}
} catch (Exception e) {
log.error("校验失败", e);
}
return null;
}
}
使用方式
public Result<String> login(SysUser params) {
// 校验
String check = VerifyUtil.check(params, SysUser::getUsername, SysUser::getPassword);
if (Objects.nonNull(check)) {
return Result.failMsg(check);
}
// 更复杂的检验在此做
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysUser::getUsername, params.getUsername());
wrapper.eq(SysUser::getPassword, params.getPassword());
wrapper.eq(SysUser::getDeleted, 1);
SysUser sysUser = this.getOne(wrapper);
if (Objects.isNull(sysUser)) {
return Result.failMsg("用户名或密码错误");
} else {
return Result.successMsg("登录成功");
}
}