SpringMVC接口測試異常:Can not deserialize instance

以前使用springmvc搭建了restful風格的接口服務,在使用mockmvc進行集成測試的時候出現了異常:Can not deserialize instance of int out of START_OBJECT token。爲何會出現這個問題?怎麼解決這個問題呢?接下來本文詳細分析講解這個問題。 php

1、問題展示

  1. 接口代碼
@ResponseBody
@RequestMapping(value = "/m1", method = RequestMethod.POST)
@ApiOperation(value = "測試方法1", httpMethod = "POST", response = ApiResult.class, notes = "測試方法1")
public ApiResult method1(@ApiParam(required = true, name = "p1", value = "參數1") @RequestBody String p1,
                            @ApiParam(required = true, name = "p2", value = "參數2") @RequestBody Integer p2) throws Exception {

    String content = "p1=" + p1 + ", p2=" + p2;
    System.out.println(content);

    ApiResult<String> result = new ApiResult<String>();
    result.setCode(ResultCode.SUCCESS.getCode());
    result.setData(content);
    return result;
}
  1. 測試代碼
@Test
public void method1Test() throws Exception {
    Map<String, Object> params = new HashMap<String, Object>();
    params.put("p1", "x001");
    params.put("p2", 10010);

    ObjectMapper mapper = new ObjectMapper();
    byte[] content = mapper.writeValueAsBytes(params);
    this.mockMvc.perform(post("/activation/m1").contentType(APPLICATION_JSON_UTF8).content(content).accept(APPLICATION_JSON_UTF8))
            .andExpect(status().isOk())
            .andExpect(content().contentType(APPLICATION_JSON_UTF8))
            .andExpect(jsonPath("$.code").value(2000))
            .andDo(print());

}
  1. 執行上述測試代碼控制檯異常錯誤
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of int out of START_OBJECT token at [Source: org.springframework.mock.web.DelegatingServletInputStream@3e0fa1; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:762)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer._parseInteger(StdDeserializer.java:419)
at com.fasterxml.jackson.databind.deser.std.NumberDeserializers$IntegerDeserializer.deserialize(NumberDeserializers.java:289)
at com.fasterxml.jackson.databind.deser.std.NumberDeserializers$IntegerDeserializer.deserialize(NumberDeserializers.java:271)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3066)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2221)
at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readJavaType(MappingJackson2HttpMessageConverter.java:168)
... 50 more

2、分析問題

  咱們先從接口方法中參數註解@RequestBody提及吧!咱們你們都知道@ResponseBody是把接口方法返回結果轉化成JSON形式提供給方法調用者,那麼相對應的,@RequestBody是把客戶端POST請求content部分轉化成JavaBean對象或者JSON對象。@RequestBody的解析有兩個條件: java

  1. POST請求中content的值必須爲json格式(存儲形式能夠是字符串,也能夠是byte數組);
  2. 被@RequestBody註解的參數類型必須是徹底能夠接收參數值的類型,好比:Map,JSONObject,或者對應的JavaBean;

  @RequestBody將post請求中content值轉爲一個總體對象,該對象包含全部參數名和參數值,因此接口方法必須也是一個參數徹底接收全部參數名和參數值。根據上面展現的代碼來看,@RequestBody將params對象json形式內容轉換成一個總體參數值,不管是p1仍是p2,都沒法接收該參數值。 web

3、解決問題

  在method1方法中定義一個能夠接收總體參數值的對象類型便可,一般可選類型有:Map、JSONObject和JavaBean,JSONObject相對於Map,其取值方法更靈活。下面咱們將在method1方法中定義一個JSONObject類型的參數。 spring

@ResponseBody
@RequestMapping(value = "/m1", method = RequestMethod.POST)
@ApiOperation(value = "測試方法1", httpMethod = "POST", response = ApiResult.class, notes = "測試方法1")
public ApiResult method1(@ApiParam(required = true, name = "p", value = "參數") @RequestBody JSONObject p) throws Exception {

    String content = "p1=" + p.getString("p1") + ", p2=" + p.getInt("p2");
    System.out.println(content);

    ApiResult<String> result = new ApiResult<String>();
    result.setCode(ResultCode.SUCCESS.getCode());
    result.setData(content);
    return result;
}

  測試響應結果正常: json

MockHttpServletResponse:
          Status = 200
   Error message = null
         Headers = {Content-Type=[application/json;charset=UTF-8]}
    Content type = application/json;charset=UTF-8
            Body = {"code":2000,"message":"","data":"p1=x001, p2=10010"}
   Forwarded URL = null
  Redirected URL = null
         Cookies = []

4、擴展

  對POST接口的請求能夠採起表單式和接口客戶端式兩種方法提交。 數組

  1. 表單式提交
      參數形式:p1=v1&p2=v2,服務端接口方法獲取參數能夠採用@RequestParam註解對應參數方式。 restful

  2. 客戶端提交
      這裏的客戶端具體指自定義編碼的客戶端。將全部參數信息組織成一個總體對象,而後轉換成json對象,設置爲post請求content的值,提交到服務端。此時服務端接口方法獲取參數即須要採用本文討論的方式。其實本文method1方法也能夠自定義一個包含p1和p2兩個字段的JavaBean類型,本身能夠嘗試一下,呵呵! mvc

文章做者: xiaohui249
本文連接: http://javatech.wang/index.php/archives/82/ 版本全部 ©轉載時必須以連接形式註明做者和原始出處
相關文章
相關標籤/搜索