自定义类型转换-表单请求或JSON请求的转换器

表单类型参数

有时候需要将前台传来一些特定格式的数据对象转化成特定的Java对象,这个时候类型转换器就派上用场了。这里简单介绍使用比较简单的Converter接口。Converter是Spring 3.0后的一个函数式接口,只有一个方法,将source转化成target。

首先需要定义自己的转换器,需要实现Converter<S,T>接口,convert就是具体的转换方法。

一般推荐使用ConditionalGenericConverter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.util.Set;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.stereotype.Component;

public class CustomConditionalConverter implements ConditionalGenericConverter {

@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return targetType.hasAnnotation(Key.class);
}

@Override
public Set<ConvertiblePair> getConvertibleTypes() {
// getConvertibleTypes方法返回可转换的源类型和目标类型的配对,
// 如果只关心,字符串类型的转换。
// return Collections.singleton(new ConvertiblePair(String.class, String.class));

// 如果全部都关注
return null;
}

@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return null;
}
Key annotation = targetType.getAnnotation(Key.class);
try {
return annotation.using().newInstance().convert(source);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

然后需要将自定义的转换器进行注册:

1
2
3
4
5
6
7
8
@Configuration
public class CustomWebMvcConfig extends WebMvcConfigurerAdapter{
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new CustomConditionalConverter());
}
}

1
2
3
4
5
6
7
8
9
10
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Key {
Class<? extends Convert> using();
}
1
2
3
public abstract class Convert<T, P> {
abstract P convert(T t);
}

JSON类型参数

1
2
3
4
5
6
7
8
9
10
11
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.Data;

@Data
public class TestReq {

@JsonDeserialize(using = DateDeserializer.class)
private Integer createTime;

private String value;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class DateDeserializer extends JsonDeserializer<Integer> {

@Override
public Integer deserialize(JsonParser parser, DeserializationContext context) throws IOException {
String dateStr = parser.getValueAsString();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
LocalDateTime parse = LocalDateTime.parse(dateStr, formatter);
long epochSecond = parse.toEpochSecond(ZoneOffset.ofHours(8));
return (int)epochSecond;
}
}
  • 表单类型:通过继承Converter配置自定义参数转换器。
  • JSON类型:配置自定义的Jackson反序列化器。