1. dto枚举校验
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = ValueOfEnumValidator.class)
public @interface ValueOfEnum {
Class<? extends Enum<?>> enumClass();
String message() default "ERROR_ENUM_TYPE";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
校验器(使用枚举值name集合):
public class ValueOfEnumValidator implements ConstraintValidator<ValueOfEnum, CharSequence> {
private List<String> acceptedValues;
@Override
public void initialize(ValueOfEnum annotation) {
acceptedValues = Stream.of(annotation.enumClass().getEnumConstants())
.map(Enum::name)
.collect(Collectors.toList());
}
@Override
public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
if(Objects.isNull(value)) {
return true;
}
return acceptedValues.contains(value.toString());
}
}
2. 数字四舍五入
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Round {
int value() default 2;
}
@Aspect
@Component
public class RoundAspect {
@Around("execution(public * com.freaxjj.*Service.*(..))")
public Object format(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = joinPoint.proceed();
//格式化数字
this.formatNumber(result);
return result;
}
/**
* 格式化数字
* @param result
*/
public void formatNumber(Object result) {
if (result instanceof Result) {
Object data = ((Result)result).getData();
if (Objects.isNull(data)) {
return;
}
if (data instanceof List) {
List items = (List) data;
items.forEach(this::resolveNumber);
return;
}
this.resolveNumber(data);
}
}
/**
* 四舍五入number
* @param item
*/
private void resolveNumber(Object item) {
Class clazz = item.getClass();
Field[] fields = clazz.getDeclaredFields();
for(Field field : fields) {
Round round = field.getAnnotation(Round.class);
if(Objects.nonNull(round)) {
try {
field.setAccessible(true);
Object fieldVal = field.get(item);
if(Objects.nonNull(fieldVal)) {
int scale = round.value();
BigDecimal roundedDecimal = new BigDecimal(String.valueOf(fieldVal)).setScale(scale, RoundingMode.HALF_UP);
if(fieldVal instanceof String) {
field.set(item, roundedDecimal.toString());
} else if(fieldVal instanceof BigDecimal) {
field.set(item, roundedDecimal);
} else if(fieldVal instanceof Double) {
field.set(item, roundedDecimal.doubleValue());
} else if(fieldVal instanceof Float) {
field.set(item, roundedDecimal.floatValue());
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
3. 忽略vo字段返回
背景是dubbo默认使用Hessian2序列化框架,没有提供类似@JsonIgnore的注解。在不改动序列化器的情况下,采用的临时方案。用到了asm生成class的工具(其实可以直接使用fastjson或Jackson提供的注解进行序列化成json串或JSONObjcet即可)。
@Documented
//用于类型上
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface JSONFieldIgnore {
}
@Aspect
@Component
public class JSONFieldIgnoreAspect {
@Around("execution(public * com.freaxjj.*Service.*(..))")
public Object format(ProceedingJoinPoint joinPoint) throws Throwable {
Object proceed = joinPoint.proceed();
this.ignoreField(proceed);
return proceed;
}
/**
* 移除字段
* @param proceed
*/
public void ignoreField(Object proceed) {
if (proceed instanceof Result) {
Result result = (Result)proceed;
Object data = result.getData();
if (Objects.nonNull(data)) {
if (data instanceof List) {
List pojoList = (List) data;
List jsonObjs = (List) pojoList.stream().map(this::transform).collect(Collectors.toList());
result.setData(jsonObjs);
return;
}
Object jsonObject = transform(data);
result.setData(jsonObject);
}
}
}
private Object transform(Object pojo) {
JSONFieldIgnore jsonFieldIgnore = pojo.getClass().getAnnotation(JSONFieldIgnore.class);
if(Objects.nonNull(jsonFieldIgnore)) {
//这里可以直接返回json串或JSONObject(项目问题限制)
String jsonString = JSON.toJSONString(pojo);
//使用asm动态生成新的class
Class ignoreFieldClass = ClassUtil.genIgnoreFieldClass(pojo.getClass());
return JSON.parseObject(jsonString, ignoreFieldClass);
}
return pojo;
}
}
ClassUtil:
public class ClassUtil {
/**
* asm生成忽略字段后新的class
* @param clazz
* @return
*/
public static Class<?> genIgnoreFieldClass(Class<?> clazz) {
String className = clazz.getSimpleName() + "IgnoreFields";
Class<?> ignoreFieldClass = ByteClassLoader.getLoadedClass(className);
if(Objects.nonNull(ignoreFieldClass)) {
return ignoreFieldClass;
}
// 创建ClassWriter对象
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
// 定义新类
String owner = className.replace(".", "/");
String superName = clazz.getSuperclass().getName().replace(".", "/");
classWriter.visit(Opcodes.V17, Opcodes.ACC_PUBLIC, owner, null, superName, null);
Field[] fields = clazz.getDeclaredFields();
//生成成员变量
FieldVisitor fv;
for (Field field : fields) {
if (!isIgnore(field)) {
fv = classWriter.visitField(Opcodes.ACC_PRIVATE, field.getName(), getDescriptor(field), null, null);
fv.visitEnd();
}
}
// 创建构造函数
MethodVisitor mvInit = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
// 调用超类的构造函数
mvInit.visitVarInsn(Opcodes.ALOAD, 0);
mvInit.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
//构造函数返回
mvInit.visitInsn(Opcodes.RETURN);
mvInit.visitMaxs(1, 1);
mvInit.visitEnd();
// 创建get、set方法
MethodVisitor mvGetter;
MethodVisitor mvSetter;
for (Field field : fields) {
if (!isIgnore(field)) {
mvGetter = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "get" + capitalize(field.getName()), "()" + getDescriptor(field), null, null);
mvGetter.visitCode();
mvGetter.visitVarInsn(Opcodes.ALOAD, 0);
mvGetter.visitFieldInsn(Opcodes.GETFIELD, owner, field.getName(), getDescriptor(field));
mvGetter.visitInsn(getReturnOpcode(field.getType()));
mvGetter.visitMaxs(1, 1);
mvGetter.visitEnd();
mvSetter = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "set" + capitalize(field.getName()), "(" + getDescriptor(field) + ")V", null, null);
mvSetter.visitCode();
mvSetter.visitVarInsn(Opcodes.ALOAD, 0);
mvSetter.visitVarInsn(Opcodes.ALOAD, 1);
mvSetter.visitFieldInsn(Opcodes.PUTFIELD, owner, field.getName(), getDescriptor(field));
mvSetter.visitInsn(Opcodes.RETURN);
mvSetter.visitMaxs(2, 2);
mvSetter.visitEnd();
}
}
classWriter.visitEnd();
// 加载新定义的类,并返回Class对象
byte[] bytes = classWriter.toByteArray();
return ByteClassLoader.getInstance().defineClass(className, bytes);
}
private static int getReturnOpcode(Class<?> type) {
if (type == void.class) {
return Opcodes.RETURN;
} else if (type == byte.class || type == short.class || type == char.class || type == int.class || type == boolean.class) {
return Opcodes.IRETURN;
} else if (type == float.class) {
return Opcodes.FRETURN;
} else if (type == long.class) {
return Opcodes.LRETURN;
} else if (type == double.class) {
return Opcodes.DRETURN;
} else {
return Opcodes.ARETURN;
}
}
private static String getDescriptor(Field f) {
if (f.getType() == byte.class) {
return "B";
} else if (f.getType() == short.class) {
return "S";
} else if (f.getType() == char.class) {
return "C";
} else if (f.getType() == int.class) {
return "I";
} else if (f.getType() == boolean.class) {
return "Z";
} else if (f.getType() == float.class) {
return "F";
} else if (f.getType() == long.class) {
return "J";
} else if (f.getType() == double.class) {
return "D";
} else {
return "L" + f.getType().getName().replace(".", "/") + ";";
}
}
private static String capitalize(String str) {
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
/**
* 字段是否忽略
* @param field
* @return
*/
private static boolean isIgnore(Field field) {
JsonIgnore jsonIgnoreAnnotation = field.getAnnotation(JsonIgnore.class);
JSONField ignoreAnnotation = field.getAnnotation(JSONField.class);
return Objects.nonNull(jsonIgnoreAnnotation) || (Objects.nonNull(ignoreAnnotation) && !ignoreAnnotation.serialize());
}
}
自定义类加载器(应该有封装好的类可以直接使用)
public class ByteClassLoader extends ClassLoader {
private final static ByteClassLoader instance = new ByteClassLoader();
public static ByteClassLoader getInstance() {
return instance;
}
public Class<?> defineClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
public static Class<?> getLoadedClass(String className) {
return instance.findLoadedClass(className);
}
}