RestTemple是Spring提供的用于访问Http请求的客户端,RestTemple提供了多种简洁的远程访问服务的方法,省去了很多无用的代码。
相信大家之前都用过apache的HTTPClient类,逻辑繁琐,代码复杂,还要自己编写使用类HttpClientUtil,封装对应的post,get,delete等方法。
RestTemplate的行为可以通过callback回调方法和配置HttpMessageConverter 来定制,用来把对象封装到HTTP请求体,将响应信息放到一个对象中。RestTemplate提供更高等级的符合HTTP的六种主要方法,可以很简单的调用RESTful服务。
创建RestTemplate很简单,只需要把RestTemplate注入到bean里面。
@Configuration
public class RestTempleConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
当然,也可以通过xml文件配置的方式注入。
默认情况下RestTemplate自动帮我们注册了一组HttpMessageConverter用来处理一些不同的contentType的请求。如果现有的转换器不能满足你的需求,你还可以实现org.springframework.http.converter.HttpMessageConverter接口自己写一个。详情参考官方api。
其他相关的配置,也可以在官方文档中查看。当然,对于一个请求来说,超期时间,请求连接时间等都是必不可少的参数,为了更好的适应业务需求,所以可以自己修改restTemplate的配置。
/**
* 替代默认的SimpleClientHttpRequestFactory
* 设置超时时间重试次数
* 同时设置一些拦截器以便监控
* @return
*/
@Bean
public RestTemplate restTemplate() {
//生成一个设置了连接超时时间、请求超时时间、异常重试次数3次
RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(10000).setConnectTimeout(10000).setSocketTimeout(30000).build();
HttpClientBuilder builder = HttpClientBuilder.create().setDefaultRequestConfig(config).setRetryHandler(new DefaultHttpRequestRetryHandler(3, false));
HttpClient httpClient = builder.build();
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);
//做个日志拦截器;从性能上考虑,当前屏蔽该功能
//restTemplate.setInterceptors(Collections.singletonList(new RestTemplateConsumerLogger()));
return restTemplate;
}
RestTemplate提供了六种常用的HTTP方法实现远程服务调用,RestTemplate的方法名遵循一定的命名规范,第一部分表示用哪种HTTP方法调用(get,post),第二部分表示返回类型。
getForObject – 发送GET请求,将HTTP response转换成一个指定的object对象
postForEntity – 发送POST请求,将给定的对象封装到HTTP请求体,返回类型是一个HttpEntity对象
每个HTTP方法对应的RestTemplate方法都有3种。其中2种的url参数为字符串,URI参数变量分别是Object数组和Map,第3种使用URI类型作为参数
exchange 和execute 方法比上面列出的其它方法(如getForObject、postForEntity等)使用范围更广,允许调用者指定HTTP请求的方法(GET、POST、PUT等),并且可以支持像HTTP PATCH(部分更新)。
这次主要讲的是exchange 方法的使用。
exchange(String url, HttpMethod method,@Nullable HttpEntity> requestEntity, Class responseType, Map
参数说明:
url:请求路径
method:请求的方法(GET、POST、PUT等)
requestEntity:HttpEntity对象,封装了请求头和请求体
responseType:返回数据类型
uriVariables:支持PathVariable类型的数据。
创建一个RestTemplate连接
private String getId(String id) {
String url = RemoteUrl + "/id";
//设置Http的Header
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
//设置访问参数
HashMap<String, Object> params = new HashMap<>();
params.put("name", name);
//设置访问的Entity
HttpEntity entity = new HttpEntity<>(params, headers);
ResponseEntity<String> result = null;
try {
//发起一个POST请求
result = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
JSONObject data = JSONObject.parseObject(result.getBody()).getJSONObject("data");
return data.getString("id");
} catch (Exception e) {
logger.error("获取id失败: " + e.getMessage());
}
return null;
}
当然也可以写一个通用的工具类,根据传入的参数来确定请求的路径和内容。工具类肯定是想通过静态方式来直接调用,而不是通过new Util()的方式来使用。但是静态变量/类变量不是对象的属性,而是一个类的属性,spring则是基于对象层面上的依赖注入。
所以我们不能@Autowired或者@resource一个静态变量,使之成为一个spring bean。但是静态方法又不能调用非静态的属性,那么我们该怎么办呢?
@Component
public class HttpUtil {
private static Logger logger = LoggerFactory.getLogger(HttpUtil.class);
@Resource
private RestTemplate restTemplate;
private static HttpUtil httpUtil;
@PostConstruct
public void init(){
httpUtil = this;
httpUtil.restTemplate = this.restTemplate;
}
public static <T> String httpRequest(String url, HttpMethod method, HttpEntity<T> entity){
try {
//发起一个POST请求
ResponseEntity<String> result = httpUtil.restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
return result.getBody();
} catch (Exception e) {
logger.error("请求失败: " + e.getMessage());
}
return null;
}
}
这个时候我们就需要维护一个工具类的静态实例,初始化的时候把restTemplate传进来,这样就可以直接调用HttpUtil.httpRequest()方法。
最后编写controller类,用我们的exchange方法远程调用,就能获取到结果了。一般来说,拿到的结果是一个json类型,我们还需要通过fastjson,Jackson等来处理我们的json字符串,获取到我们想要的数据。