240
世界上有2种人,一种懂二进制,另一种不懂二进制。

commons.tools.utils.HttpContextUtils Http工具类

HTTP工具类

背景

每个服务发展到一定阶段,必不可少的需要调用外部服务,目前最常见,最通用的就是HTTP协议了,由此我们发展出来HTTP工具类。每个团队发展出了适合自己用的Http工具类,拿我个人举例,根据我不同阶段不同水平接触它,对它的要求也越来越不一样:

  1. step 1:实现功能即可。
  2. step 2:要求简洁方便,一句代码解决。
  3. step 3:功能强大,支持我的各种header需求,支持Https,各种返回类型的需求(能转化成我想要的java对象最好了)。
  4. step 4:还要能看到状态码,异常不要自己说吃掉就吃掉 。需要支持我的请求和响应日志,同时不要把我最烦人的日志打印出来(文件流) 。
  5. step 5:考虑到以后业务需求,我还想在请求前和请求后做点东西,统一处理部分Http,要求动态扩展 。
  6. step 6:支持这么多功能,仍要有一套统一的调用方法,最终要简单易用。

经历完这些阶段,之前自己设计的HttpUtil.java也经历了:简单封装,完善,解耦,参考,补充,重构等这些阶段。

回头想想,其实这些不仅仅是个人或者某个公司才有的需求或问题,是Java web一个组件问题,其他人有没有什么更完善的解决方法呢。最终发现Spring已经给我们提供了这样的工具类RestTemplate,以上说的功能一个不少,果然出于真实践。

RestTemplate组件

RestTemplateSpring 3.0 就有了,它不是HttpClientHttpConnection的替代品,而是基于这写Http请求框架二次封装简单易用的工具类。它会替你屏蔽底层枯燥重复的Http请求封装,向上提供一个功能齐全强大的Http工具。Spring真正吸引人的不仅仅是一个java框架这么简单,它会站在我们的立场考虑,充分考虑到我们的需求,最终给我们提供最简单易用的一套解决方法。

配置

RestTemplate实例仅需要配置ClientHttpRequestFactory

配置RestTemplate

//http builder
@Bean
public HttpClientBuilder getHttpClientBuilder() throws KeyManagementException, NoSuchAlgorithmException {
    HttpClientBuilder consumer = HttpClients.custom();
    PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(RegistryBuilder.<ConnectionSocketFactory>create()
            .register("https", new SSLConnectionSocketFactory(SSLContextBuilder.create().build()))
            .register("http", new PlainConnectionSocketFactory())
            .build());
    consumer.setConnectionManager(poolingHttpClientConnectionManager);
    return consumer;
}

// clientHttpFactory
@Bean
public ClientHttpRequestFactory getClientHttpRequestFactory(HttpClientBuilder httpClientBuilder) {
    ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClientBuilder.build());
    return requestFactory;
}
// restTempalteBean
@Bean
public RestTemplate getRestTemplate(ClientHttpRequestFactory requestFactory) {
    RestTemplate restTemplate = new RestTemplate();
    restTemplate.setRequestFactory(requestFactory);
    //类Spring MVC中的自定义消息转化
    restTemplate.setMessageConverters(Arrays.<HttpMessageConverter<?>>asList(
            new StringHttpMessageConverter(StandardCharsets.UTF_8),
            new ByteArrayHttpMessageConverter()));
    //自定义异常处理
    restTemplate.setErrorHandler(new ResponseErrorHandler() {
          @Override
          public boolean hasError(ClientHttpResponse response) throws IOException {
                return false;
          }

          @Override
          public void handleError(ClientHttpResponse response) throws IOException {
          }
    });
    //面向切面请求的filter,你可以在请求前和请求后做些事
    restTemplate.getInterceptors().add((request, bytesBody, execution)->{
        return execution.execute(request, bytesBody);  
    });
    return restTemplate;
}

使用

举几个简单的例子:

  • 简单Get请求,获取状态码,获取body体
@Test
public void testGet() {
    ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://www.baidu.com", String.class);
    System.out.println("statusCode : " + responseEntity.getStatusCodeValue());
    System.out.println("body : " + responseEntity.getBody());
    System.out.println("body : " + responseEntity.toString());
}
  • 获取字节流
@Test
public void testGetByteBody() {
    ResponseEntity<byte[]> responseEntity = restTemplate.getForEntity("http://192.168.24.119/downlaod.jpg", byte[].class);
    System.out.println("statusCode : " + responseEntity.getStatusCodeValue());
    System.out.println("body : " + Arrays.toString(responseEntity.getBody()));
}
  • 自定义请求头,获取想要的Java实体
@Test
public void testPostWithJsonObject() {
    // add jsonConvert
    restTemplate.getMessageConverters().add(new FastJsonHttpMessageConverter());

    Map<String, String> postBody = new HashMap<>();
    postBody.put("username","1");
    postBody.put("password","12312");

    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.add(HttpHeaders.CONTENT_TYPE, "application/json");
    HttpEntity<Map<String,String>> httpRequest = new HttpEntity<>(postBody, httpHeaders);

    ResponseEntity<byte[]> responseEntity = restTemplate.postForEntity("http://192.168.24.119/login", httpRequest, byte[].class);
    System.out.println("statusCode : " + responseEntity.getStatusCodeValue());
    System.out.println("body : " + new String(responseEntity.getBody()));
}

完毕

其他用法

restTemplate整体使用方法是比较简单的,这里讲解几个比较核心的方法

/**
* 最基本最全的执行方法
* @param url 请求地址
* @param HttpMethod 请求方法
* @param RequestCallback 是一个请求前的拦截器,在这里可以对请求头,请求体做出自定义的操作
* @param ResponseExtractor 是请求执行后的拦截器,或者说是一个提取器,自定义转化并返回一个结果。
* @return ResponseExtractor 非常有意思的返回结果
**/
ResponseExtractor restTemplate.execute(Url, HttpMethod, RequestCallback, ResponseExtractor)
/**
 * 在restTemplate.execute上封装,可以将返回结果转化成基本的bean并返回
* @param url 请求地址
* @param HttpMethod 请求方法
* @param HttpEntity 参数HttpEntity可以设置headers和body,它实现的功能也是在RequestCallback基础上实现的
* @param Type 代表你希望接收一个什么样的返回值(当然,你需要有一个自定义实现的ResponseExtractor, 也就是MessageConvert)
* @param UriVars url上的变量值的替换具体值
* @return ResponseEntity<T> 其中T就是第三个参数对应的返回类型,可以通过getBody获取,除此之外ResponseEntity还能获得状态码,headers等信息
**/
ResponseEntity<T> restTemplate.exchange(Url, HttpMethod, HttpEntity, Type, UriVars...)
/**
 * 进一步封装,将请求方法写到方法名上
**/
ResponseEntity<T> restTemplate.postForEntity(URL,Request, Type, uriVars...)
/**
 * 再进一步封装,如果你只关心值,该方法可以让你直接获取你想要的值。它的返回值类型直接就是第三个参数`Type`的值
**/
<T> restTemplate.postForObject(URL,Request, Type, uriVars...)
/**
 * 它针对`post`请求,返回的状态码为`302`的请求,获取其header中Location(重定向后的URL)的值
 **/
URI restTemplate.postForLocation(Url,Request)

总结

总结来说,关于RestTemplate从配置到使用来说是比较简单的,看着方法就能猜出来其使用的途径,但是又包装的恰到好处,各个设计模式用的也非常6,称之为规范一点都不过分



来源:{
  作者:新签名
  链接:https://www.jianshu.com/p/df7cbf2d07eb
}
 

 

posted @ 2022-06-17 11:23  _Origin  阅读(474)  评论(0编辑  收藏  举报