根据官网FeignClient的例子,编写一个简单的updateUser接口,定义如下
@RequestMapping("/user")
public interface UserService {
@RequestMapping(value = "/{userId}", method = RequestMethod.GET)
UserDTO findUserById(@PathVariable("userId") Integer userId);
@RequestMapping(value = "/update", method = RequestMethod.POST)
boolean updateUser(@RequestBody UserDTO user);
}
实现类
@Override
public boolean updateUser(UserDTO user)
{
LOGGER.info("===updateUser, id = " + user.getId() + " ,name= " + user.getUsername());
return false;
}
执行单元测试,发现没有获取到预期的输入参数
2018-09-07 15:35:38,558 [http-nio-8091-exec-5] INFO [com.springboot.user.controller.UserController] {} - ===updateUser, id = null ,name= null
原因分析
SpringMVC中使用RequestResponseBodyMethodProcessor类进行入参、出参的解析。以下方法根据参数是否有@RequestBody注解判断是否进行消息体的转换。
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
解决方案
既然MVC使用RequestResponseBodyMethodProcessor进行参数解析,可以实现一个定制化的Processor,修改supportParameter的判断方法。
@Override
public boolean supportsParameter(MethodParameter parameter)
{
//springcloud的接口入参没有写@RequestBody,并且是自定义类型对象 也按JSON解析
if (AnnotatedElementUtils.hasAnnotation(parameter.getContainingClass(), FeignClient.class) && isCustomizedType(parameter.getParameterType())) {
return true;
}
return super.supportsParameter(parameter);
}
此处的判断逻辑可以根据实际框架进行定义,目的是判断到为Spring Cloud定义的接口,并且是自定义对象时,使用@RequestBody相同的内容转换器。
实现定制化的Processor后,还需要让自定义的配置生效,有两种方案可选:
- 直接替换RequestResponseBodyMethodProcessor,在SpringBoot下需要自定义RequestMappingHandlerAdapter。
- 实现WebMvcConfigurer中的addArgumentResolvers接口
这里采用较为简单的第二种方式,初始化时的消息转换器根据需要进行加载:
public class XXXWebMvcConfig implements WebMvcConfigurer
{
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers)
{
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>(5);
messageConverters.add(new ByteArrayHttpMessageConverter());
messageConverters.add(stringHttpMessageConverter);
messageConverters.add(new SourceHttpMessageConverter<>());
messageConverters.add(new AllEncompassingFormHttpMessageConverter());
CustomizedMappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new CustomizedMappingJackson2HttpMessageConverter();
jackson2HttpMessageConverter.setObjectMapper(defaultObjectMapper());
messageConverters.add(jackson2HttpMessageConverter);
ViomiMvcRequestResponseBodyMethodProcessor resolver = new ViomiMvcRequestResponseBodyMethodProcessor(messageConverters);
resolvers.add(resolver);
}
修改完成后,微服务的实现类即可去掉@RequestBody注解。