RestTemplate如何使用带泛型Body的HttpEntity?exchange方法逻辑咨询
1. 如何接收带泛型Body的HttpEntity
RestTemplate.exchange()本身支持接收任意泛型类型的HttpEntity,因为它的参数定义是HttpEntity<?> requestEntity——泛型通配符允许传入任何类型的HttpEntity实例。
你可以直接通过HttpEntity的泛型构造器创建带自定义Body的请求实体,示例代码如下:
// 自定义业务对象 public class User { private String name; private Integer age; // getter、setter省略 } // 构造带泛型Body的HttpEntity MultiValueMap<String, String> headers = new HttpHeaders(); headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); User requestBody = new User("Alice", 25); HttpEntity<User> requestEntity = new HttpEntity<>(requestBody, headers); // 传入exchange方法执行请求 RestTemplate restTemplate = new RestTemplate(); ResponseEntity<SomeResponse> response = restTemplate.exchange( "http://example.com/api/user", HttpMethod.POST, requestEntity, SomeResponse.class );
HttpEntity<T>的泛型仅用于编译期类型校验,确保传入的Body类型符合预期;运行时会被类型擦除,exchange最终通过消息转换器处理实际的Body对象。
2. 处理自定义对象Body时是否会调用toString()
不会直接调用自定义对象的toString()方法。
RestTemplate处理请求体的核心逻辑依赖HttpMessageConverter体系:它会根据请求头的Content-Type选择对应的转换器,将自定义对象序列化为符合格式的请求体(比如JSON、XML)。例如默认的MappingJackson2HttpMessageConverter会用Jackson将对象序列化为JSON字符串,整个过程和toString()完全无关。
只有当没有找到合适的HttpMessageConverter处理当前对象类型时,才会触发兜底逻辑——此时可能调用toString(),但这属于异常场景,正常使用时不会出现。
3. 验证处理逻辑的方法
方法1:给自定义对象的toString()加日志/断点
在自定义对象中重写toString()并添加日志输出:
@Override public String toString() { System.out.println("toString()被调用了!"); return "User{name='" + name + "', age=" + age + "}"; }
运行exchange请求,如果控制台没有打印上述日志,说明toString()未被调用。
方法2:自定义HttpMessageConverter监控序列化过程
继承默认的消息转换器,重写序列化方法并添加日志:
public class LoggingJacksonConverter extends MappingJackson2HttpMessageConverter { @Override protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { System.out.println("正在序列化对象:" + object.getClass().getName()); System.out.println("对象原始内容:" + object); // 此处打印对象不会触发toString,除非显式调用 super.writeInternal(object, type, outputMessage); } }
替换RestTemplate的消息转换器:
RestTemplate restTemplate = new RestTemplate(); restTemplate.getMessageConverters().replaceAll(converter -> { if (converter instanceof MappingJackson2HttpMessageConverter) { return new LoggingJacksonConverter(); } return converter; });
运行请求后,通过日志可确认序列化是由转换器处理,而非调用toString()。
方法3:用MockRestServiceServer捕获请求内容
使用Spring提供的MockRestServiceServer模拟服务端,捕获实际发送的请求体:
RestTemplate restTemplate = new RestTemplate(); MockRestServiceServer server = MockRestServiceServer.createServer(restTemplate); // 配置预期的请求和响应 server.expect(requestTo("http://example.com/api/user")) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().json("{\"name\":\"Alice\",\"age\":25}")) .andRespond(withSuccess("{\"code\":200}", MediaType.APPLICATION_JSON)); // 执行请求 restTemplate.exchange(...) // 验证请求是否符合预期 server.verify();
如果验证通过,说明发送的是JSON格式的请求体,而非toString()的结果。
内容的提问来源于stack exchange,提问作者CDevoss

