1. springboot controller @RequestMappiing方法在接收参数时,在类型转换上没有那么严格,用数字类型接收参数,传字符串也能正常转换;用boolean类型接收参数,传数字也能转成对应的true或false;
2. springboot在做参数反序列化时默认使用的是jackson,因此只要熟悉jackson序列化方式,就可以知道如何下手;
3. 以一个小demo入手,首先定义一个简单对象Obj,包含Boolean类型的cycle属性,Long类型的num属性:
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Obj {
private Boolean cycle;
private Long num;
}
使用jackson进行反序列化,其中json串中cycle属性值设置为数字型5,num属性值设置为字符串“10”,反序列化为Obj对象成功,数字5解析为true,字符串“10”解析为数字10,这就是jackson默认没有强制转换的现象,与springboot默认的参数反序列化一致:
public class Test {
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
String s = "{\"cycle\": 5, \"num\": \"10\"}";
Obj obj = objectMapper.readValue(s, Obj.class);
System.out.println(obj);
}
}
---------------------控制台-----------------------------
Obj(cycle=true, num=10)
如果想让jackson强制类型转换,增加一行配置,执行发现报错,反序列化失败:
public class Test {
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, false);
String s = "{\"cycle\": 5, \"num\": \"10\"}";
Obj obj = objectMapper.readValue(s, Obj.class);
System.out.println(obj);
}
}
------------------------控制台----------------------------------
Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot coerce Number (5) for type `java.lang.Boolean` (enable `MapperFeature.ALLOW_COERCION_OF_SCALARS` to allow)
at [Source: (String)"{"cycle": 5, "num": "10"}"; line: 1, column: 11] (through reference chain: test11.Obj["cycle"])
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1329)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer._verifyNumberForScalarCoercion(StdDeserializer.java:857)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer._parseBooleanFromInt(StdDeserializer.java:197)
at com.fasterxml.jackson.databind.deser.std.NumberDeserializers$BooleanDeserializer._parseBoolean(NumberDeserializers.java:231)
at com.fasterxml.jackson.databind.deser.std.NumberDeserializers$BooleanDeserializer.deserialize(NumberDeserializers.java:199)
at com.fasterxml.jackson.databind.deser.std.NumberDeserializers$BooleanDeserializer.deserialize(NumberDeserializers.java:175)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:127)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2992)
at test11.Test11.main(Test11.java:20)
4. 因此在springboot中如果想让参数反序列化时执行强制类型转换,也需要增加MapperFeature.ALLOW_COERCION_OF_SCALARS,false 的配置,具体如何配置,我们从springboot autoconfig 自动配置入手,首先找到org.springframework.boot:spring-boot-autoconfigure jar包
然后找到jackson的自动配置类JacksonAutoConfiguration
为什么这个类在springboot启动的时候会被加载,是因为springboot在启动时会自动加载META-INF/spring.factories文件中配置的类,而JacksonAutoConfiguration就配置在此文件中(至于springboot为什么会自动加载这个文件,是写在源码中的,大家有兴趣可以去阅读)
继续回到 JacksonAutoConfiguration 类,可以看到此类中还包含一个静态内部类Jackson2ObjectMapperBuilderCustomizerConfiguration,并且配置了@EnableConfigurationProperties({JacksonProperties.class}),其中的JacksonProperties就是在类初始化时从application配置文件引入配置加载到JacksonProperties中的属性中去:
JacksonProperties类使用@ConfigurationProperties标识从application配置文件中spring.jackson为前缀引入对应配置项,我们关心的类型强制转换配置就在mapper属性中:
通过MapperFeature可以看到ALLOW_COERCION_OF_SCALARS默认是true,即默认不强制转换类型:
因此在springboot中如果想使参数反序列化时,执行强制类型转换,只需要在application.yml配置文件中增加如下配置即可生效:
spring:
jackson:
mapper:
ALLOW_COERCION_OF_SCALARS: false