如何实现@ResponseBody,把Json字符串转换为指定类型

发布日期:2019-04-27

1.问题

spring 是如何把 http中的body,转换为指定类的,里面的难点其实在于泛型的处理。

2.Spring的处理

2.1 HandlerMethod

这个类Spring对Method的封装,例如使用@RequestMapping注解方法,会使用HandlerMethod封装(其实是其子类InvocableHandlerMethod)。然后由InvocableHandlerMethod对其进行调用

HandlerMethod的属性如下

private final Object beanprivate final BeanFactory beanFactoryprivate final Class<?> beanTypeprivate final Method methodprivate final Method bridgedMethodprivate final MethodParameter[] parameters //重点是这个private HttpStatus responseStatusprivate String responseStatusReasonprivate HandlerMethod resolvedFromHandlerMethod

  

2.2 如何解析参数的

参考InvocableHandlerMethod的getMethodArgumentValues的方法,其中会使用各种HandlerMethodArgumentResolver 对Spring mvc调用参数解析

例如,路径的中的参数 /path/${var} 使用的PathVariableMapMethodArgumentResolver 相关注解 @PathVariable

例如,header中的参数 使用 RequestHeaderMapMethodArgumentResolver 来解析,相关注解@RequestHeader

那么@ResponseBody使用的RequestResponseBodyMethodProcessor来解析的,

2.3 如何把body转换为参数类

@Overridepublic Object resolveArgument(MethodParameter parameter ModelAndViewContainer mavContainerNativeWebRequest webRequest WebDataBinderFactory binderFactory) throws Exception {parameter = parameter.nestedIfOptional()Object arg = readWithMessageConverters(webRequest parameter parameter.getNestedGenericParameterType())....return adaptArgumentIfNecessary(arg parameter)}

 

 其中readWithMessageConverters方法是重点,注意MethodParameter其实就是HandlerMethod中的属性

继续往里面跳

GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter

...body = genericConverter.read(targetType contextClass inputMessage)

 其中上面的那段代码就是读取http的body,并转换为指定类。我们就拿常见Fastjson的FastJsonHttpMessageConverter中的代码来看,很简单

public Object read(Type type // Class<?> contextClass // HttpInputMessage inputMessage // ) throws IOException HttpMessageNotReadableException { return readType(getType(type contextClass) inputMessage) } private Object readType(Type type HttpInputMessage inputMessage) throws IOException { try { InputStream in = inputMessage.getBody() return JSON.parseObject(in fastJsonConfig.getCharset() type fastJsonConfig.getFeatures()) } catch (JSONException ex) { throw new HttpMessageNotReadableException("JSON parse error: " + ex.getMessage() ex) } catch (IOException ex) { throw new HttpMessageNotReadableException("I/O error while reading input message" ex) } }

3 如何自己实现

通过上面的分析,如何实现一个简单的数据mock回放,(假设的我们mock的数据使用json来存储的)

// 第一步:创建一个HandlerMethod HandlerMethod handlerMethod = new HandlerMethod(bean method) // 第二步:获取返回类型的MethodParameter MethodParameter methodParameter = handlerMethod.getReturnType().nestedIfOptional() // 第三步:使用Fastjson反序列化 JSONObject.parseObject(phxResult.getVal() methodParameter.getNestedGenericParameterType())//注,bean是调用的类的实例,method是通过反射获取的具体调用方法,怎么获取不是这里的重点,省略掉获取