前后端交互枚举转换
get请求(参数放url)
提供两个接口,分别处理以code(int类型)和name(String类型)进行转换的枚举
public interface IFeIntegerEnum {
int getCode();
static <E extends Enum<?> & IFeIntegerEnum> Optional<E> codeOf(Class<E> enumClass, int value) {
return Arrays.stream(enumClass.getEnumConstants()).filter(e -> e.getCode() == value).findAny();
}
}
public interface IFeStringEnum {
int getName();
static <E extends Enum<?> & IFeStringEnum> Optional<E> codeOf(Class<E> enumClass, String name) {
return Arrays.stream(enumClass.getEnumConstants()).filter(e -> e.getName().equals(name)).findAny();
}
}
然后需要两个枚举转换工厂
@Component
public class IntegerToEnumConvertFactory implements ConverterFactory<String, IFeIntegerEnum> {
@Override
@Nonnull
public <T extends IFeIntegerEnum> Converter<String, T> getConverter(@Nonnull Class<T> targetType) {
return new IntegerToEnum(targetType);
}
private static class IntegerToEnum<T extends Enum<T> & IFeIntegerEnum> implements Converter<String, T> {
private final Class<T> type;
public IntegerToEnum(Class<T> type) {
this.type = type;
}
@Override
public T convert(@Nonnull String source) {
return IFeIntegerEnum.codeOf(this.type,Integer.parseInt(source)).orElseThrow(IllegalArgumentException::new);
}
}
}
@Component
public class StringToEnumConvertFactory implements ConverterFactory<String, IFeStringEnum> {
@Override
@Nonnull
public <T extends IFeStringEnum> Converter<String, T> getConverter(@Nonnull Class<T> targetType) {
return new StringToEnum(targetType);
}
private static class StringToEnum<T extends Enum<T> & IFeIntegerEnum> implements Converter<String, T> {
private final Class<T> type;
public StringToEnum(Class<T> type) {
this.type = type;
}
@Override
public T convert(@Nonnull String source) {
return IFeStringEnum.codeOf(this.type,source).orElseThrow(IllegalArgumentException::new);
}
}
}
还需要在WebMvcConfigurer中配置下
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverterFactory(integerToEnumConvertFactory);
registry.addConverterFactory(stringToEnumConvertFactory);
}
}
最后如何看下实际使用
public enum LolEnum implements IFeIntegerEnum,IFeStringEnum {
Q(0,"q技能"),
W(1,"w技能"),
E(2,"e技能"),
R(3,"r技能");
private final int code;
private final String name;
LolEnum (int code,String name){
this.code = code;
this.name = name;
}
@Override
public int getCode(){
return code;
}
@Override
public int getName(){
return name;
}
}
则此时无论前端传0,1,2,3还是qwer技能到后端,后端用此枚举都能正常转换,注意这是传参放url的形势,比较麻烦,如果放body就很简单了
post请求(参数放body)
此时可以用json工具自动处理,以jackson为例,直接用@JsonCreator和@JsonValue即可
public enum LolEnum {
Q(0,"q技能"),
W(1,"w技能"),
E(2,"e技能"),
R(3,"r技能");
private final int code;
private final String name;
LolEnum (int code,String name){
this.code = code;
this.name = name;
}
/**
* 前端传参反序列化为枚举
*/
@JsonCreator
public static LolEnum valueOfCode(int code ) {
return Arrays.stream(LolEnum.values()).filter(item -> item.getCode() == code).findFirst().orElseThrow(IllegalArgumentException::new);
}
/**
* 序列化到前端时返回数字,同理加到getName上则返回字符串
*/
@JsonValue
public int getCode(){
return code;
}
public int getName(){
return name;
}
}
后端与数据库交互枚举转换
public interface IDBIntegerEnum {
int getCode();
static <E extends Enum<?> & IDBIntegerEnum> Optional<E> codeOf(Class<E> enumClass, int value) {
return Arrays.stream(enumClass.getEnumConstants()).filter(e -> e.getCode() == value).findAny();
}
}
@MappedTypes(IDBIntegerEnum.class)
@MappedJdbcTypes(JdbcType.INTEGER)
public class IntegerEnumTypeHandler<E extends Enum<?> & IDBIntegerEnum> extends BaseTypeHandler<E> {
private final Class<E> type;
public IntegerEnumTypeHandler(Class<E> type) {
if(type == null){
throw new IllegalArgumentException("Type argument cannot be null");
}
this.tyoe = type;
}
/**
* 用于定义在Mybatis设置参数时该如何把Java类型参数转换为对应的数据库类型
*
* @param ps 当前PreparedStatement对象
* @param i 当前参数的位置
* @param parameter 当前参数的Java对象
* @param jdbcType 当前参数的数据库类型
*/
@Override
public void setNonNullParameter(PreparedStatement ps,int i,E parameter,JdbcType jdbcType) throws SQLException {
ps.setInt(i,parameter.getCode());
}
/**
* 用于在Mybatis获取数据结果集时如何把数据库类型转换为对应的java类型
*
* @param rs 当前的结果集
* @param columnName 当前的字段名称
* @return 转换后的java对象
*/
@Override
public E getNullableResult(ResultSet rs,String columnName) throws SQLException {
int columnValue = rs.getInt(columnName);
return rs.wasNull()?null:enumOf(columnValue);
}
/**
* 用于在Mybatis通过字段位置获取数据结果集时如何把数据库类型转换为对应的java类型
*
* @param rs 当前的结果集
* @param columnIndex 当前的字段位置
* @return 转换后的java对象
*/
@Override
public E getNullableResult(ResultSet rs,int columnIndex) throws SQLException {
int columnValue = rs.getInt(columnIndex);
return rs.wasNull()?null:enumOf(columnValue);
}
/**
* 用于在Mybatis在调用存储过程后把数据库类型转换为对应的java类型
*
* @param cs 当前CallableStatement
* @param columnIndex 当前的字段位置
* @return 转换后的java对象
*/
@Override
public E getNullableResult(CallableStatement cs,int columnIndex) throws SQLException {
int columnValue = cs.getInt(columnIndex);
return rs.wasNull()?null:enumOf(columnValue);
}
private E enumOf(int value){
return IDBIntegerEnum.codeOf(type,value).orElseThrow(()->new IllegalArgumentException("Cannot convert "+value+" to "+type.getSimpleName()+" by code value."));
}
}