java后台与前端交互时,如果java参数属性是枚举类型,则交互时需要进行序列化与反序列化
Base枚举(所有枚举实现这个Base枚举,在做序列化处理时能够较好的进行枚举的纺一处理)
public interface BaseEnum, T> {
//值,数据库中,以及程序中一般传递的都是这个值
public T getCode();
public String getMessage();
}
需要返回给前端的枚举,加上@JsonSerialize(using = JsonEnumSerializer.class)注解,JsonEnumSerializer是自定义序列化类
@JsonSerialize(using = JsonEnumSerializer.class)
public enum TestEnum implements BaseEnum {
T1(1,"test1");
private Integer code;
private String message;
TestEnum(int code, String message) {
this.code = code;
this.message = message;
}
@Override
public Integer getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
}
自定义枚举序列化规则,继承JsonSerializer类并重写serialize方法
import com.example.chaosdemo.enums.BaseEnum;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.google.common.base.Throwables;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* 返回 "enum": {"code": "2","message": "tom2"} 格式给前端
*/
public class JsonEnumSerializer extends JsonSerializer {
@Override
public void serialize(BaseEnum value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
try {
//类的全限定名
String name = value.getClass().getName();
//类的code值
Object code = value.getCode();
String message = value.getMessage();
//这里也不用反射了,性能不好,所以直接new一个map再做序列化
Map jsonMap = new HashMap<>();
jsonMap.put("code", code);
jsonMap.put("message", message);
serializers.defaultSerializeValue(jsonMap, gen);
} catch (Exception e) {
// logger.error("JsonEnumSerializer serialize error: " + Throwables.getStackTraceAsString(e));
System.out.println("JsonEnumSerializer serialize error: " + Throwables.getStackTraceAsString(e));
throw new RuntimeException(e);
}
}
}
测试:
controller控制层
@Slf4j
@RestController
public class EnumTestController {
@RequestMapping(value = "/enum")
public TestDTO enumTest(@RequestBody TestDTO testDTO) throws JsonProcessingException {
log.info("enum");
testDTO.setTestEnum(TestEnum.T1);
return testDTO;
}
}
返回的DTO
public class TestDTO {
private TestEnum testEnum;
public TestEnum getTestEnum() {
return testEnum;
}
public void setTestEnum(TestEnum testEnum) {
this.testEnum = testEnum;
}
}
前端接收到的数据
用到3个类
1.自定义反序列化类
import com.example.chaosdemo.enums.BaseEnum;
import com.example.chaosdemo.utils.ReflectionUtils;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonStreamContext;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.google.common.base.Throwables;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.lang.reflect.Field;
/**
* restful接口中,自定义获取枚举规则的方式。枚举类上加上@JsonDeserialize(using = JsonEnumDeserializer.class) 前端只要传code的值过来就能转成枚举接收
*/
public class JsonEnumDeserializer extends JsonDeserializer {
@Override
public BaseEnum deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
try {
//前端输入的值
String inputParameter = p.getText();
if (StringUtils.isBlank(inputParameter)) {
return null;
}
JsonStreamContext parsingContext = p.getParsingContext();
String currentName = parsingContext.getCurrentName();//字段名
Object currentValue = parsingContext.getCurrentValue();//前端注入的对象(ResDTO)
Field field = ReflectionUtils.getField(currentValue.getClass(), currentName); // 通过对象和属性名获取属性的类型
Class enumClass = field.getType();
return DefaultInputJsonToEnum.getEnum(inputParameter, enumClass);
} catch (Exception e) {
// logger.error("JsonEnumDeserializer deserialize error: " + Throwables.getStackTraceAsString(e));
System.out.println("JsonEnumDeserializer deserialize error: " + Throwables.getStackTraceAsString(e));
throw new RuntimeException(e);
}
}
}
2.转成对应的枚举的类
import com.example.chaosdemo.enums.BaseEnum;
import com.google.common.base.Throwables;
import java.lang.reflect.Method;
/**
* 传入的参数中,去相应的枚举code中获取
*/
public class DefaultInputJsonToEnum{
// private static final Logger logger = LoggerFactory.getFrameworkLogger(DefaultInputJsonToEnum.class);
public static BaseEnum getEnum(String inputParameter, Class enumClass) {
try {
Method valuesMethod = enumClass.getDeclaredMethod("values");
BaseEnum[] values = (BaseEnum[]) valuesMethod.invoke(null);
BaseEnum baseEnum = null;
for (BaseEnum value : values) {
//因为inputParameter都是string类型的,code + "" 转成字符串才能比较
if (inputParameter.equals(value.getCode() + "")) {
baseEnum = value;
break;
} else {
continue;
}
}
//如果都拿不到,那就直接抛出异常了
if (baseEnum == null) {
throw new RuntimeException("输入参数不符合预期");
}
return baseEnum;
} catch (Exception e) {
// logger.error("getEnum error: " + Throwables.getStackTraceAsString(e));
throw new RuntimeException(e);
}
}
private BaseEnum getEnumByName(String inputParameter, Class enumClass) {
try {
Method valueOfMethod = enumClass.getDeclaredMethod("valueOf", String.class);
return (BaseEnum) valueOfMethod.invoke(null, inputParameter);
} catch (Exception e) {
//这里异常无需抛出,因为这个枚举根据name获取不到就直接抛出异常了...
//logger.warn("未获取枚举的name值,入参: " + inputParameter + "," + "class : " + enumClass);
return null;
}
}
}
3.反射工具
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.util.proxy.ProxyObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.aop.framework.Advised;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 反射工具
*
* @author Chenzx
*
*/
public class ReflectionUtils {
public static ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
// javassist.ClassPool dubbo中包含此包
private static ClassPool classPool = ClassPool.getDefault();
public static List getAllFields(Class> clazz) {
if (clazz == Object.class || clazz.isPrimitive())
return Collections.emptyList();
try {
classPool.insertClassPath(new ClassClassPath(clazz));
CtClass cc = classPool.get(clazz.getName());
List ctClasses = new ArrayList();
ctClasses.add(cc);
while (!(cc = cc.getSuperclass()).getName().equals(Object.class.getName()))
ctClasses.add(0, cc);
List fields = new ArrayList();
for (CtClass ctc : ctClasses) {
for (CtField cf : ctc.getDeclaredFields()) {
int accessFlag = cf.getModifiers();
if (Modifier.isFinal(accessFlag) || Modifier.isStatic(accessFlag))
continue;
fields.add(cf.getName());
}
}
return fields;
} catch (Exception e) {
e.printStackTrace();
return Collections.emptyList();
}
}
public static Class> getGenericClass(Class> clazz) {
return getGenericClass(clazz, 0);
}
public static Class> getGenericClass(Class> clazz, int index) {
return getGenericClass(clazz.getGenericSuperclass(), index);
}
public static Class> getGenericClass(Type genType, int index) {
if (genType instanceof ParameterizedType) {
ParameterizedType pramType = (ParameterizedType) genType;
Type[] params = pramType.getActualTypeArguments();
if ((params != null) && (params.length > index))
return params[index] instanceof Class ? (Class>) params[index] : null;
}
return null;
}
public static Class> getActualClass(Object object) {
Class> c = object.getClass();
if (object instanceof ProxyObject)
c = c.getSuperclass();
return c;
}
public static String[] getParameterNames(Constructor> ctor) {
return getParameterNames(null, ctor);
}
public static String[] getParameterNames(Method method) {
return getParameterNames(method, null);
}
private static String[] getParameterNames(Method method, Constructor> ctor) {
Annotation[][] annotations = method != null ? method.getParameterAnnotations() : ctor.getParameterAnnotations();
String[] names = new String[annotations.length];
/*
* boolean allbind = true; loop: for (int i = 0; i < annotations.length;
* i++) { Annotation[] arr = annotations[i]; for (Annotation a : arr) {
* if (a instanceof Param) { String s = ((Param) a).value(); if
* (StringUtils.isNotBlank(s)) { names[i] = s; continue loop; } } }
* allbind = false; } if (!allbind) {
*/
String[] namesDiscovered = method != null ? parameterNameDiscoverer.getParameterNames(method)
: parameterNameDiscoverer.getParameterNames(ctor);
if (namesDiscovered == null)
return null;
for (int i = 0; i < names.length; i++)
if (names[i] == null)
names[i] = namesDiscovered[i];
// }
return names;
}
public static String[] getParameterNames(JoinPoint jp) {
if (!jp.getKind().equals(JoinPoint.METHOD_EXECUTION))
return null;
Class> clz = jp.getTarget().getClass();
MethodSignature sig = (MethodSignature) jp.getSignature();
Method method;
try {
method = clz.getDeclaredMethod(sig.getName(), sig.getParameterTypes());
if (method.isBridge())
method = BridgeMethodResolver.findBridgedMethod(method);
return getParameterNames(method);
} catch (Exception e) {
return null;
}
}
public static Field getField(Class> clazz, String name) throws NoSuchFieldException {
try {
Field f = clazz.getDeclaredField(name);
f.setAccessible(true);
return f;
} catch (NoSuchFieldException e) {
if (clazz == Object.class)
throw e;
return getField(clazz.getSuperclass(), name);
}
}
@SuppressWarnings("unchecked")
public static T getFieldValue(Object o, String name) {
try {
Field f = getField(o.getClass(), name);
return (T) f.get(o);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
public static void setFieldValue(Object o, String name, Object value) {
try {
Field f = getField(o.getClass(), name);
f.set(o, value);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
public static Object getTargetObject(Object proxy) {
while (proxy instanceof Advised) {
try {
return getTargetObject(((Advised) proxy).getTargetSource().getTarget());
} catch (Exception e) {
e.printStackTrace();
return proxy;
}
}
return proxy;
}
public static String getCurrentMethodName() {
return Thread.currentThread().getStackTrace()[2].getMethodName();
}
}
@JsonDeserialize(using = JsonEnumDeserializer.class)
效果与上面的自定义序列化一样,如果没有特殊要求可以直接使用此注解,就不用写自定义序列化规则了