zoukankan      html  css  js  c++  java
  • 如何实现@ResponseBody,把Json字符串转换为指定类型

    1.问题

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

    2.Spring的处理

    2.1 HandlerMethod

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

    HandlerMethod的属性如下

    private final Object bean;
    
    private final BeanFactory beanFactory;
    
    private final Class<?> beanType;
    
    private final Method method;
    
    private final Method bridgedMethod;
    
    private final MethodParameter[] parameters; //重点是这个
    
    private HttpStatus responseStatus;
    
    private String responseStatusReason;
    
    private HandlerMethod resolvedFromHandlerMethod;
    

      

    2.2 如何解析参数的

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

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

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

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

    2.3 如何把body转换为参数类

            @Override
    	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
    			NativeWebRequest 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是通过反射获取的具体调用方法,怎么获取不是这里的重点,省略掉获取
    
    
    
  • 相关阅读:
    数据库锁表及阻塞的原因和解决办法
    JS中的this都有什么用?
    vue打包要点
    Vue.js的虚拟dom
    JS继承方式
    JS中的浅拷贝和深拷贝。
    详解计算机原码,反码,补码。
    经常被问到的面试题1
    eslint规则说明
    git常用命令总结
  • 原文地址:https://www.cnblogs.com/lizo/p/spring.html
Copyright © 2011-2022 走看看