Search code examples
spring-bootdecoderesttemplate

the passed param by resttemplate.exchange was not decoded in service side automatically


Below is my REST API code:

 @RequestMapping(value = "/get", method = RequestMethod.POST, produces = { "application/json" })
      @ApiOperation(value = "get data by key.", notes = "return json string value.")
      public JsonObjectResponse<String> get(
          @ApiParam(required = true, name = "regionName", value = "region name") @RequestParam("regionName") String regionName,
          @ApiParam(required = true, name = "key", value = "region key,Default is uuid") @RequestParam("key") String key) throws UnsupportedEncodingException
      {
        JsonObjectResponse<String> jr = new JsonObjectResponse<String>();
        //key = decodeJsonString(key);  // added for junit
        String val = adfService.onPath(regionName).get(key);
        jr.setState(StateCode.SUCCESS);
        jr.setData(JsonObject.create().append(key,val).toJson());

        return jr;
      }

I'm trying to pass parameters:

regionName=/fusion/table1&key={"fusionTbl1DetailNo":"fusionNo001","pk":"PK0001"}
  1. If I call it via swagger-ui, it calls like this:

    http://localhost:8080/service/basic/get?regionName=%2Ffusion%2Ftable1&key=%7B%22fusionTbl1DetailNo%22%3A%22fusionNo001%22%2C%22pk%22%3A%22PK0001%22%7D&token=8652493a-4147-43f4-af3a-bcb117fb7d42`
    

    It encoded the parameters and these parameters also can be decoded automatically in server side correctly.

  2. When I want to add testcase for this API, I use restTemplate.exchange method, code as below:

    UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
    for (Entry<String, String> entry : queryParamMap.entrySet()) {
        builder.queryParam(entry.getKey(), entry.getValue());
    }
    if (uriParamMap != null) {
    
        url = builder.buildAndExpand(uriParamMap).toUriString();
    } else {
        url = builder.toUriString();
    }
    if (StringUtils.isEmpty(requestBody)) {
        if (bodyParamMap != null) {
            requestBody = parseMapToParams(bodyParamMap);
        } else {
            requestBody = "";
        }
    }
    HttpHeaders headers = new HttpHeaders();
    MediaType mediaType = new MediaType("application", "json", Charset.forName("UTF-8"));
    headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
    // headers.add(HttpHeaders.CONTENT_TYPE, "application/json");
    // headers.add("Accept", "application/json");
    // headers.set(HttpHeaders.ACCEPT, "application/json");
    headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
    // headers.add("Accept-Encoding", "gzip, deflate, br");
    headers.set("Accept-Charset", "utf-8");
    headers.set("Accept-Encoding", "gzip");
    headers.add("Accept-Language", "zh-CN,zh;q=0.8,en;q=0.6");
    headers.add("User-Agent",
            "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36");
    
    headers.add(TestBase.TOKEN_HEADER, TestBase.getTokenId());
    HttpEntity<String> request = new HttpEntity<>(body, headers);
    restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
    ResponseEntity<String> response = restTemplate.exchange(url, httpMethod, request, String.class);
    localresponse.set(response);
    System.out.println("response:" + response);
    return response;
    

I used UriComponentsBuilder to append the parameters, it will format the url to

http://localhost:8080/service/basic/get?regionName=/fusion/table1&key=%7B%22fusionTbl1DetailNo%22:%22fusionNo001%22,%22pk%22:%22PK0001%22%7D

for method exchange. However, when the server side received the call, it did not decode the param key, it's value still was:

%7B%22fusionTbl1DetailNo%22:%22fusionNo001%22,%22pk%22:%22PK0001%22%7D

Why is that? I compared the header settings from the swagger calling, added additional settings, no effect :(.


Solution

  • Try like the following:

    ResponseEntity<String> res = restTemplate.exchange("http://localhost:8080/service/basic/get?regionName={arg1}&key={arg2}", HttpMethod.POST, null, String.class,"/fusion/table1", "{\"fusionTbl1DetailNo\":\"fusionNo001\",\"pk\":\"PK0001\"}");
    

    arg1 and arg2 will be replaced by

    "/fusion/table1" and "{\"fusionTbl1DetailNo\":\"fusionNo001\",\"pk\":\"PK0001\"}"

    I send null in requestEntity as no request body and request parameters is in uriVariables.