Spring component RestTemplate + @ResponseBody experience

I just wrote a middleware for the two systems of the company to synchronize some data. I used RestTemplate, which is really friendly and simplifies http requests. The complete blog pit is miserable. Here are the key points:

1. RestTemplate simple configuration

@Configuration
public class RestTemplateConfig {
    @Bean
    @ConditionalOnMissingBean({ RestOperations.class, RestTemplate.class })
    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
        RestTemplate restTemplate = new RestTemplate(factory);
        <!--使用 utf-8 编码集的 conver 替换默认的 conver(默认的 string conver 的编码集为"ISO-8859-1")-->
        List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
        Iterator<HttpMessageConverter<?>> iterator = messageConverters.iterator();
        <!--!!!!!!!!!!严重警告,一定不要这么配置,这样就改变的convert的顺序,当接口采用@requestbody接收的时候,会报 parse error-->
        <!--while (iterator.hasNext()) {-->
        <!--    HttpMessageConverter<?> converter = iterator.next();-->
        <!--    if (converter instanceof StringHttpMessageConverter) {-->
        <!--        iterator.remove();-->
        <!--    }-->
        <!--}-->
        <!--messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));-->
        
        <!--正确姿势-->
        while (iterator.hasNext()) {
            HttpMessageConverter<?> converter = iterator.next();
            if (converter instanceof StringHttpMessageConverter) {
                ((StringHttpMessageConverter) converter).setDefaultCharset(Charset.forName("utf-8"));
            }
        }
        return restTemplate;
    }

    @Bean
    @ConditionalOnMissingBean({ClientHttpRequestFactory.class})
    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setReadTimeout(15000);
        factory.setConnectTimeout(15000);
        return factory;
    }
}

2. Dependency Injection

@Autowired
private RestTemplate restTemplate;

With the above, I think it is not a problem to write a tool class, use a new one directly, or write an xml configuration file for dependency injection.

3. Use 1. The first step is to look at the official documents, and don't search online. Everything on the Internet can be used for the user's environment, and it may not be available to you.

官方文档:>https://docs.spring.io/spring/docs/5.0.2.RELEASE/spring-framework-reference/integration.html#rest-client-access

2. @ResponseBody returns a json string, but when RestTemplate is in postForObject, if the return parameter contains array format strings such as List, and you use the object object to receive this array, the result will only be the last of the list. A value, the previous values ​​are lost. If you use the format of List to receive, there is no such problem. Solution:

import com.alibaba.fastjson.JSON;
import springfox.documentation.spring.web.json.Json;

@RestController
@RequestMapping("/customer")
public class CustomerController {

    @Autowired
    private RestTemplate restTemplate;
    
    @PostMapping("/push")
    //接收参数请设置为 json 接收:即给接收参数加上 @RequestBody  注解,可以简化 RestTemplate 传递的参数封装
    public Object push(@RequestBody List<Customer> customers) {
        //将返回对象包装为 Json 对象返回,而不是 json 字符串
        return new Json(JSON.toJSONString(Object object));
    }

3. Complete RestTemplate request:

//这里用的是 postForObject ,其他请求方式大同小异
//因为前面接收使用了 @RequestBody  注解方式,以 json 格式接收,这里的请求参数 object 不需要任何封装,直接使用就行了
Object object = new Object();
ResponseResult entity = 
    restTemplate.postForObject("http://192.168.82.15:9900/pool/customer/list", object , ResponseResult.class);

//此时 entity.getData() 实际上是一个 json 字符串
//转化对象内的 Object 对象
Page<Customer> ids = com.alibaba.fastjson.JSONObject.parseObject(entity.getData().toString(), Page.class);
//转化对象内的 Array 对象
List<Long> ids = com.alibaba.fastjson.JSONArray.parseArray(entity.getData().toString(), Long.class);

System.out.println(ids);

return ids;
我的 ResponseResult 对象:
@ApiModel("响应结果对象")
public class ResponseResult implements Serializable {
    @ApiModelProperty("响应码")
    private Integer code = ResponseCode.SUCCESS;
    @ApiModelProperty("响应消息")
    private String msg;
    @ApiModelProperty("响应数据")
    private Object data;
    @ApiModelProperty("响应时间")
    private Date time = new Date();
    ...
}

4. Double serialization problem:

When the parameters returned by RestTemplate, such as the Data of the object ResponseResult I wrapped above, may be more complex objects, the parameters received by Data will be directly retained in the form of json strings. Correct deserialization, directly send the json string to other callers through the interface. The problem is, the Data received by the third party will be presented as a json string with escape characters. The correct way is:

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sword.ttttttttttt.entity.Student;

import java.io.IOException;
import java.util.ArrayList;

public class TestMain {

    public static void main(String[] args) {
        Student s = new Student();
        s.setName("abc");
        s.setId(1);
        s.setAge(null);
        s.setList(new ArrayList<String>());

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        try {
            //第一次序列化
            String ss = objectMapper.writeValueAsString(s);
            //第二次序列化
            String string = objectMapper.writeValueAsString(ss);
            //反序列化第二次的序列化,而不是用replace或者substring之类的方法来解析
            String student = objectMapper.readValue(string, String.class);
            //反序列化第一次的序列化,得到正确的对象
            Student object = objectMapper.readValue(student, Student.class);

        } catch (JsonProcessingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

ps: I tracked the source code, but I couldn't find where the original data was obtained and where the deserialization started. If you have any friends who know, please stop! ! !

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325174315&siteId=291194637