为了方便抽象出公共方法,我们需要将所有的枚举类型统一实现一个接口,该接口定义方法返回能唯一确定枚举值的属性。
public interface BaseEnum<C> {
/**
* 能唯一确定一个枚举的字段
* @return
*/
C getName();
}
下面以这个枚举进行阐述:
@Getter
@AllArgsConstructor
public enum HobbyEnum implements BaseEnum<String> {
SWIM("游泳", "SWIM"),
RUN("跑步", "RUN"),
SING("唱歌", "SING";
private String code;
private String name;
public static AccountCategoryEnum parse(String name) {
return Arrays.stream(AccountCategoryEnum.values()).filter(e -> e.getName().equals(name)).findFirst().orElse(null);
}
public static AccountCategoryEnum parseByCode(String code) {
return Arrays.stream(AccountCategoryEnum.values()).filter(e -> e.getCode().equals(code)).findFirst().orElse(null);
}
}
1. 单个枚举作为字段与前端交互:
@JsonSerialize(using = JsonEnumSerializer.class)
@JsonDeserialize(using = JsonEnumDeerializer.class)
private AccountCategoryEnum accountCategoryEnum;
(1)后端序列化枚举值给前端:
import com.datayes.mom.internalAccount.enums.BaseEnum;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class JsonEnumSerializer extends JsonSerializer<BaseEnum> {
@Override
public void serialize(BaseEnum baseEnum, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
try {
Map<String, Object> jsonMap = new HashMap<>();
Method[] m = baseEnum.getClass().getDeclaredMethods();
for (int i = 0; i < m.length; i++) {
if (m[i].getName().startsWith("get") && !Modifier.isStatic(m[i].getModifiers())) {
String fieldName = m[i].getName().substring(3);
jsonMap.put(fieldName, m[i].invoke(baseEnum));
}
}
serializerProvider.defaultSerializeValue(jsonMap, jsonGenerator);
} catch (Exception e) {
log.error("枚举序列化出错:[{}]", e);
}
}
}
(2)后端反序列化前端的json转为枚举值:
import com.datayes.mom.internalAccount.enums.BaseEnum;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonStreamContext;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
@Slf4j
public class JsonEnumDeerializer extends JsonDeserializer<BaseEnum> {
@Override
public BaseEnum deserialize(JsonParser p, DeserializationContext ctcx) throws IOException {
//前端输入的值
String inputParameter = p.getText();
if (StringUtils.isEmpty(inputParameter)) {
return null;
}
//获取对应的枚举类
Class enumClass = getEnumClass(p);
return getEnum(inputParameter, enumClass);
}
private Class getEnumClass(JsonParser p) {
JsonStreamContext parsingContext = p.getParsingContext();
//字段名
String currentName = parsingContext.getCurrentName();
//前端注入的对象(ResDTO)
Object currentValue = parsingContext.getCurrentValue();
// 通过对象和属性名获取属性的类型
Field field = ReflectionUtils.findField(currentValue.getClass(), currentName);
return field.getType();
}
private BaseEnum getEnum(String inputParameter, Class enumClass) {
BaseEnum baseEnum = null;
try {
Method valuesMethod = enumClass.getDeclaredMethod("values");
BaseEnum[] values = (BaseEnum[]) valuesMethod.invoke(null);
baseEnum = Arrays.stream(values).filter(e -> (e.getName()+"").equals(inputParameter)).findFirst().orElse(null);
} catch (Exception e) {
log.error("枚举反序列化出错[{}]", e);
}
//如果都拿不到,那就直接抛出异常了
if (baseEnum == null) {
throw new RuntimeException("输入参数不符合预期");
}
return baseEnum;
}
}
2. List枚举作为字段与前端交互:
(1)后端序列化枚举值给前端:
import com.datayes.mom.internalAccount.enums.BaseEnum;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
public class JsonEnumListSerializer extends JsonSerializer<List<BaseEnum>> {
@Override
public void serialize(List<BaseEnum> baseEnums, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
try {
List<Map<String, Object>> jsonMaps = new ArrayList<>();
if(CollectionUtils.isNotEmpty(baseEnums)){
for(BaseEnum baseEnum : baseEnums){
if(baseEnum != null){
Map<String, Object> jsonMap = new HashMap<>();
Method[] m = baseEnum.getClass().getDeclaredMethods();
for (int i = 0; i < m.length; i++) {
if (m[i].getName().startsWith("get") && !Modifier.isStatic(m[i].getModifiers())) {
String fieldName = m[i].getName().substring(3);
jsonMap.put(fieldName, m[i].invoke(baseEnum));
}
}
jsonMaps.add(jsonMap);
}
}
}
serializerProvider.defaultSerializeValue(jsonMaps, jsonGenerator);
} catch (Exception e) {
log.error("枚举序列化出错:[{}]", e);
}
}
}
(2)后端反序列化前端的json转为枚举值:
import com.datayes.mom.internalAccount.enums.BaseEnum;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonStreamContext;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Slf4j
public class JsonEnumListDeerializer extends JsonDeserializer<List<BaseEnum>> {
@Override
public List<BaseEnum> deserialize(JsonParser p, DeserializationContext ctcx) throws IOException {
//前端输入的值
String inputParameter = p.getText();
if (StringUtils.isEmpty(inputParameter)) {
return null;
}
//获取对应的枚举类
Class enumClass = getEnumClass(p);
String[] params = inputParameter.split("\\|");
List<BaseEnum> result = new ArrayList<>();
for(String param : params){
result.add(getEnum(param, enumClass));
}
return result;
}
private Class getEnumClass(JsonParser p) {
JsonStreamContext parsingContext = p.getParsingContext();
//字段名
String currentName = parsingContext.getCurrentName();
//前端注入的对象(ResDTO)
Object currentValue = parsingContext.getCurrentValue();
// 通过对象和属性名获取属性的类型
Field field = ReflectionUtils.findField(currentValue.getClass(), currentName);
return (Class)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0];
}
private BaseEnum getEnum(String inputParameter, Class enumClass) {
BaseEnum baseEnum = null;
try {
Method valuesMethod = enumClass.getDeclaredMethod("values");
BaseEnum[] values = (BaseEnum[]) valuesMethod.invoke(null);
baseEnum = Arrays.stream(values).filter(e -> (e.getName() + "").equals(inputParameter)).findFirst().orElse(null);
} catch (Exception e) {
log.error("枚举反序列化出错[{}]", e);
}
//如果都拿不到,那就直接抛出异常了
if (baseEnum == null) {
throw new RuntimeException("输入参数不符合预期");
}
return baseEnum;
}
}
3. 与数据库交互
public class AccountPropertyEnumHandler extends BaseTypeHandler<List<AccountPropertyEnum>> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, List<AccountPropertyEnum> parameters, JdbcType jdbcType) throws SQLException {
if(CollectionUtils.isEmpty(parameters)){
ps.setString(i, null);
}
String s = parameters.stream().filter(p -> p != null).map(p -> p.getName()).collect(Collectors.joining("|"));
ps.setString(i, s);
}
@Override
public List<AccountPropertyEnum> getNullableResult(ResultSet rs, String columnName) throws SQLException {
String s = rs.getString(columnName);
return getAccountPropertyEnums(s);
}
@Override
public List<AccountPropertyEnum> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String s = rs.getString(columnIndex);
return getAccountPropertyEnums(s);
}
@Override
public List<AccountPropertyEnum> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String s = cs.getString(columnIndex);
return getAccountPropertyEnums(s);
}
private List<AccountPropertyEnum> getAccountPropertyEnums(String s) {
if(StringUtils.isBlank(s)){
throw new BadRequestException("存在脏数据,产品性质为空");
}
List<AccountPropertyEnum> result = new ArrayList<>();
String[] ps = s.split("\\|");
for(String p : ps){
AccountPropertyEnum parse = AccountPropertyEnum.parse(StringUtils.trim(p));
if(parse == null){
throw new BadRequestException("存在脏数据,产品性质无法解析");
}
result.add(parse);
}
return result;
}
}