如何實現@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是通過反射獲取的具體調用方法,怎么獲取不是這里的重點,省略掉獲取
 
        

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM