• 如何实现@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是通过反射获取的具体调用方法,怎么获取不是这里的重点,省略掉获取
    
    
    
  • 相关阅读:
    Java 对象和类
    Java main方法解释
    Android点击EditText文本框之外任何地方隐藏键盘的解决办法
    页面跳转回来之后,网络请求自动刷新
    《买红薯的故事》醍醐灌顶,警钟长鸣。
    字符串比较器,例如按照时间的升序降序,或者姓氏排序
    android中用Intent传数据,如果用传递的是一个类,就将类实现Parcelable接口
    view在使用shape属性加圆角的同时,用代码修改其他background属性(例如颜色)不生效
    android基础学习之布局
    详解安卓项目-闹钟
  • 原文地址:https://www.cnblogs.com/lizo/p/spring.html
Copyright © 2020-2023  润新知