spring组件 RestTemplate + @ResponseBody 使用心得
2018-02-27 17:17
931 查看
刚刚给公司两个系统写了一个中间件,用于同步一些数据,用了 RestTemplate 这个家伙,确实相当友好,也简化了 http 请求,但是我也走了很多弯路,也被网上的那些各种不完整的博客坑惨了,下面说重点:
一. RestTemplate 简单配置
二. 依赖注入
有了上面这些,我想需要写工具类,直接 new 一个来使用,或者是写 xml 配置文件来依赖注入都不成问题了
三. 使用
1.第一步请先看看官方文档,别再网上搜,网上的东西都是针对使用者的环境能用,到你那里不一定就能用的
官方文档:https://docs.spring.io/spring/docs/5.0.2.RELEASE/spring-framework-reference/integration.html#rest-client-access
2.@ResponseBody 返回的是 json 字符串,但是 RestTemplate 在 postForObject 的时候,如果返回参数里面包含 List 等组数格式字符串,同时这个数组你用了 object 对象来接收,就会出现结果只有 list 的最后一个值,前面的值都丢失了。如果用了 List 的格式接收就没有这个问题。
解决方法:
3.完整的 RestTemplate 请求:
四. 双重序列化问题:
当使 RestTemplate 返回的参数,如:我上面包装的对象 ResponseResult 的 Data ,有可能是比较复杂的对象,Data 接收到的参数就会直接以 json 串的形式保留下来,如果此时不对该 json 串做正确的反序列化,直接将该 json 串通过接口再发送给其他调用者。问题来了,第三方接到的 Data 会以带转义符的 json 串呈现,正确的做法是:
ps:跟踪了一下源代码,没有找到最初的数据是从哪儿获取出来,又是从哪儿开始反序列化的,如果有知道的朋友,还请留步!!!
一. RestTemplate 简单配置
@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; } }
二. 依赖注入
@Autowired private RestTemplate restTemplate;
有了上面这些,我想需要写工具类,直接 new 一个来使用,或者是写 xml 配置文件来依赖注入都不成问题了
三. 使用
1.第一步请先看看官方文档,别再网上搜,网上的东西都是针对使用者的环境能用,到你那里不一定就能用的
官方文档:https://docs.spring.io/spring/docs/5.0.2.RELEASE/spring-framework-reference/integration.html#rest-client-access
2.@ResponseBody 返回的是 json 字符串,但是 RestTemplate 在 postForObject 的时候,如果返回参数里面包含 List 等组数格式字符串,同时这个数组你用了 object 对象来接收,就会出现结果只有 list 的最后一个值,前面的值都丢失了。如果用了 List 的格式接收就没有这个问题。
解决方法:
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.完整的 RestTemplate 请求:
//这里用的是 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(); ... }
四. 双重序列化问题:
当使 RestTemplate 返回的参数,如:我上面包装的对象 ResponseResult 的 Data ,有可能是比较复杂的对象,Data 接收到的参数就会直接以 json 串的形式保留下来,如果此时不对该 json 串做正确的反序列化,直接将该 json 串通过接口再发送给其他调用者。问题来了,第三方接到的 Data 会以带转义符的 json 串呈现,正确的做法是:
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:跟踪了一下源代码,没有找到最初的数据是从哪儿获取出来,又是从哪儿开始反序列化的,如果有知道的朋友,还请留步!!!
相关文章推荐
- spring组件 RestTemplate + @ResponseBody 使用心得
- Spring boot 发送http请求组件RestTemplate使用实例
- 使用 Spring RestTemplate 调用 rest 服务时自定义请求头(custom HTTP headers)
- Spring3 MVC使用@ResponseBody的乱码问题及解决办法
- SpringMVC@ResponseBody的心得
- 通过 Spring RestTemplate 调用带请求体的 Delete 方法(Delete With Request Body)
- 通过 Spring RestTemplate 调用带请求体的 Delete 方法(Delete With Request Body)
- Spring RestTemplate使用ByteArrayResource上传方式
- spring rest mvc使用RestTemplate调用
- Spring中RestTemplate使用例子
- Spring 4.x 中使用注解 @ResponseBody 返回json数据的配置
- Spring3 MVC使用@ResponseBody的乱码问题及解决办法
- spring的RestTemplate的配置及使用
- SpringMVC@ResponseBody的心得
- Spring3 MVC使用@ResponseBody产生很大的响应头
- Spring3 MVC使用@ResponseBody的乱码问题及解决办法
- Spring 注解的使用 @ResponseBody,@RequestBody
- 使用HttpClient4来构建Spring RestTemplate
- 使用 Spring RestTemplate 调用 rest 服务时自定义请求头(custom HTTP headers)
- Spring3 MVC使用@ResponseBody的乱码问题及解决办法