使用Spring的RestTemplate进行接口调用
1.常见的http服务的通信方式
经常使用的方式有HttpClient、OkHttp、RestTemplate。其中RestTemplate是一种更优雅的调用RESTful服务的方式。
RestTemplate使用了模版方法的设计模式,借助 RestTemplate,Spring应用可以很方便地访问REST资源。
2.主要的方法
get请求常用方法:
getForObject //返回响应内容
getForEntity //返回响应体
post请求常用方法:
postForObject //返回响应内容
postForEntity //返回响应体
二合一的方法:
exchange //该方法的参数可以设置不同请求方法,可以选择get或者post
3.客户端和服务端
3.1 服务端
新建一个spring-boot项目。引入依赖。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.73</version>
</dependency>
</dependencies>
server:
port: 8090
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;
@RestController
@CrossOrigin
public class IndexController {
@GetMapping("/getData")
public String getData() {
return "hello, get method";
}
@PostMapping("/postData")
public String postData(HttpServletRequest request, HttpServletResponse response) throws IOException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
System.out.println(request.getRemoteUser());
System.out.println(request.getAuthType());
System.out.println(request.getContentType());
System.out.println(request.getContextPath());
System.out.println(request.getRemoteAddr());
System.out.println(request.getRemoteHost());
System.out.println(request.getRemotePort());
//1.读取header中的数据,通过key来获取
System.out.println(request.getHeader("username"));
System.out.println("=====================");
BufferedReader reader = request.getReader();
//2.读取body中的数据
String line = null;
while ((line = reader.readLine()) != null){
System.out.println(line);
}
return "hello, post method";
}
}
3.2 客户端
新建一个客户端的项目。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.yqd</groupId>
<artifactId>hello-rest-template</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>hello-rest-template</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.73</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
server:
port: 8091
添加RestTemplate的配置类
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
// 支持中文编码
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(Charset.forName("UTF-8")));
return restTemplate;
}
/**RestTemplate 支持至少三种HTTP客户端库:JDK自带的HttpURLConnection,Apache HttpComponents,OkHttp。
* 从各种HTTP客户端性能以及易用程度评测来看,OkHttp 优于 Apache HttpComponents、Apache HttpComponents优于HttpURLConnection。
* 所以我个人更建议大家将底层HTTP实现切换为okHTTP。
*/
@Bean
public ClientHttpRequestFactory myClientHttpRequestFactory() {
OkHttp3ClientHttpRequestFactory factory= new OkHttp3ClientHttpRequestFactory(); //此处使用自定义的OkHttp客户端,需要引入okhttp依赖,已在pom中引入
factory.setReadTimeout(2000);//从服务器获取数据超时时间 单位为ms
factory.setConnectTimeout(2000);//连接超时时间 单位为ms
return factory;
}
}
4.客户端发送get请求
@Autowired
private RestTemplate restTemplate;
@Test
void getMethod() {
String url = "http://localhost:8090/getData";
//String result = restTemplate.getForObject(url, String.class); //直接返回响应内容
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);//返回响应体
System.out.println(responseEntity.getStatusCode()); //200 OK
System.out.println(responseEntity.getStatusCodeValue()); 200
System.out.println(responseEntity.getBody());//hello, get method
System.out.println(responseEntity.getClass()); //class org.springframework.http.ResponseEntity
System.out.println(responseEntity.getHeaders());//[Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", Content-Type:"text/plain;charset=UTF-8", Content-Length:"17", Date:"Mon, 11 Jan 2021 12:04:14 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]
}
5.客户端发送post请求
@Test
public void testPost() throws UnsupportedEncodingException {
String url = "http://localhost:8090/postData";
//1、header
HttpHeaders header = new HttpHeaders();
header.add("username", "tom");
header.add("charset", "utf-8");
header.add("Content-Type", "application/json");
//2、body 有两种数据封装方式,第一种是使用MultiValueMap,第二种是直接用JSONObject发送json对象
// MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
// requestBody.add("data", "123456");
JSONObject requestBody = new JSONObject();//放入body中的json参数
requestBody.put("data", "123456");
//3、把header和body封装到请求中
HttpEntity<JSONObject> httpEntity = new HttpEntity<>(requestBody, header);
//4、提交请求,得到响应
//String response = restTemplate.postForObject(url, httpEntity, String.class); //直接返回响应内容
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, httpEntity, String.class);//返回响应体
System.out.println(responseEntity.toString()); //<200,hello, post method,[Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", Content-Type:"text/plain;charset=UTF-8", Content-Length:"18", Date:"Mon, 11 Jan 2021 12:05:42 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]>
}
6.使用exchange方法
只需要把getForEntity、postForEntity等方法换成exchange就可以了
@Test
public void testExchage() throws UnsupportedEncodingException {
String url = "http://localhost:8090/postData";
//1、header
HttpHeaders header = new HttpHeaders();
header.add("username", "tom");
header.add("charset", "utf-8");
header.add("Content-Type", "application/json");
//2、body 有两种数据封装方式,第一种是使用MultiValueMap,第二种是直接用JSONObject发送json对象
// MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
// requestBody.add("data", "123456");
JSONObject requestBody = new JSONObject();//放入body中的json参数
requestBody.put("data", "123456");
//3、把header和body封装到请求中
HttpEntity<JSONObject> entity = new HttpEntity<JSONObject>(requestBody, header);
//4、提交请求
ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
System.out.println(exchange.toString());
}
7.如何自定义请求拦截器
7.1 增加CustomInterceptor类
public class CustomInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
HttpHeaders headers = request.getHeaders();
// 加入自定义请求头
headers.add("xy","1024" );
System.out.println("通过请求拦截器查看请求头:"+headers);
// 请求继续被执行
return execution.execute(request, body);
}
}
7.2 在RestTemplate配置类中增加配置
RestTemplateConfig中增加如下拦截器配置。
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
//配置自定义的请求拦截处理器
restTemplate.setInterceptors(Arrays.asList(new CustomInterceptor()));
// 支持中文编码
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(Charset.forName("UTF-8")));
return restTemplate;
}
测试的时候会发现每次打印请求头信息,说明请求经过了拦截器。如果在请求时有其他需求,比如动态增加头部信息,校验头部信息等可以在拦截器中修改。
8.如何自定义请求异常处理
8.1 增加CustomErrorHandler类
public class CustomErrorHandler implements ResponseErrorHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomErrorHandler.class);
/**
* 返回false表示不管response的status是多少都返回没有错
* 这里可以自己定义那些status code你认为是可以抛Error
*/
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
return response.getStatusCode().value() != 200 && response.getStatusCode().value() !=302;
}
/**
* 这里面可以实现你自己遇到了Error进行合理的处理
*/
@Override
public void handleError(ClientHttpResponse response) throws IOException {
System.out.println("请求中有错误");
}
/**
* 重载方法
*/
@Override
public void handleError(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {
LOGGER.error("=======================ERROR============================");
LOGGER.error("DateTime:{}", DateUtil.generateTimeFormatter(response.getHeaders().getDate(),"yyyy-MM-dd HH:mm:ss"));
LOGGER.error("HOST:{},URI:{}", url.getHost(),url.getPath());
LOGGER.error("Method:{}", method.name());
LOGGER.error("Exception:{}", response.getStatusCode());
LOGGER.error("========================================================");
}
}
8.2 在RestTemplate配置类中增加配置
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
//配置自定义的请求拦截处理器
restTemplate.setInterceptors(Arrays.asList(new CustomInterceptor()));
//配置自定义的请求异常处理器
restTemplate.setErrorHandler(new CustomErrorHandler());
// 支持中文编码
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(Charset.forName("UTF-8")));
return restTemplate;
}
测试的时候,启动服务器,请求的url设置一个错误参数,可以看到错误信息,而不会报RestTemplate默认的异常。
默认异常:(后台报红)
org.springframework.web.client.HttpClientErrorException$NotFound: 404
配置之后的异常:(后台不会报红)
拦截器查看请求头:[Accept:"text/plain, application/json, application/*+json, */*", username:"tom", charset:"utf-8", Content-Type:"application/json", Content-Length:"17", xy:"1024"]
2021-01-14 19:05:24.024 ERROR 22768 --- [ main] com.yqd.config.CustomErrorHandler : =======================ERROR============================
2021-01-14 19:05:24.025 ERROR 22768 --- [ main] com.yqd.config.CustomErrorHandler : DateTime:2021-01-14 19:05:23
2021-01-14 19:05:24.025 ERROR 22768 --- [ main] com.yqd.config.CustomErrorHandler : HOST:localhost,URI:/postData1
2021-01-14 19:05:24.025 ERROR 22768 --- [ main] com.yqd.config.CustomErrorHandler : Method:POST
2021-01-14 19:05:24.025 ERROR 22768 --- [ main] com.yqd.config.CustomErrorHandler : Exception:404 NOT_FOUND
2021-01-14 19:05:24.025 ERROR 22768 --- [ main] com.yqd.config.CustomErrorHandler : ========================================================
HTTP 响应状态:404 NOT_FOUND
<404,{"timestamp":"2021-01-14T11:05:24.024+00:00","status":404,"error":"Not Found","message":"","path":"/postData1"},[Connection:"keep-alive", Content-Type:"application/json", Date:"Thu, 14 Jan 2021 11:05:23 GMT", Keep-Alive:"timeout=60", Transfer-Encoding:"chunked", Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers"]>
使用Spring的RestTemplate进行接口调用的更多相关文章
- Spring AOP在函数接口调用性能分析及其日志处理方面的应用
面向切面编程可以实现在不修改原来代码的情况下,增加我们所需的业务处理逻辑,比如:添加日志.本文AOP实例是基于Aspect Around注解实现的,我们需要在调用API函数的时候,统计函数调用的具体信 ...
- Spring框架下的 “接口调用、MVC请求” 调用参数、返回值、耗时信息输出
主要拦截前端或后天的请求,打印请求方法参数.返回值.耗时.异常的日志.方便开发调试,能很快定位到问题出现在哪个方法中. 前端请求拦截,mvc的拦截器 import java.util.Date; im ...
- Spring中RestTemplate进行Http调用
Spring中的RestTemplate类源自spring-web,http调用中设置超时时间.设置连接池管理等非常重要,保证了系统的可用性,避免了长时间连接不上或者等待数据返回,拖垮系统. 现贴出工 ...
- 【多线程】java多线程Completablefuture 详解【在spring cloud微服务之间调用,防止接口超时的应用】【未完成】
参考地址:https://www.jianshu.com/p/6f3ee90ab7d3 示例: public static void main(String[] args) throws Interr ...
- spring boot下接口调用失败重试方案
背景: 在项目开发中,有时候会出现接口调用失败,本身调用又是异步的,如果是因为一些网络问题请求超时,总想可以重试几次把任务处理掉. 一些RPC框架,比如dubbo都是有重试机制的,但是并不是每一个项目 ...
- spring boot2X整合Consul一使用RestTemplate实现服务调用
Consul可以用于实现分布式系统的服务发现与配置 服务调用有两种方式: A.使用RestTemplate 进行服务调用 负载均衡——通过Ribbon注解RestTemplate B.使用Feign ...
- 对Spring 的RestTemplate进行包装
Spring的RestTemplate及大地简化了REST Client的开发,但每次还要编写大量的模板代码,代码不够简洁.我对他进行了一次包装,采用接口来声明REST接口,使用Annotation对 ...
- Spring Cloud Feign 服务消费调用(三)
序言 Spring Cloud Netflix的微服务都是以HTTP接口的形式暴露的,所以可以用Apache的HttpClient或Spring的RestTemplate去调用 而Feign是一个使用 ...
- springcloud费话之Eureka接口调用(feign)
目录: springcloud费话之Eureka基础 springcloud费话之Eureka集群 springcloud费话之Eureka服务访问(restTemplate) springcloud ...
随机推荐
- 处理fMRI数据的一些常用Matlab命令
背景 处理fMRI数据常常用到MATLAB,在此记录一些常用代码及功能. 1.读取原始DICOM数据 1-1 读入dicom图像并绘图: Image = dicomread('fMRI.dcm'); ...
- java_day 02
一.方法的传入参数可以为一个 类 类型 有往方法里传 int ,double ,char 类型的值的,第一次学习到居然还能往方法里传 类 定义好一个 Phone 类 实例化对象 ,并且往 method ...
- html2canvas实现浏览器截图的原理(包含源码分析的通用方法)
DevUI是一支兼具设计视角和工程视角的团队,服务于华为云DevCloud平台和华为内部数个中后台系统,服务于设计师和前端工程师. 官方网站:devui.design Ng组件库:ng-devui(欢 ...
- 怎样用Python自制好看的指数估值图
对于以定投指数的方式理财的朋友,最需要关注的指标便是各个指数的估值,在指数低估时买入,高估时卖出,那如何制作一张估值图来跟踪指数的估值情况呢?本文就从0到1介绍如何用 Matplotlib 画一张漂亮 ...
- python pip命令的安装与实验安装scrapy
大家在使用python时候,很多时候导入模块都会发现该模块不存在,那么我们就需要下载安装,可是有时候安装会出现各种问题,大家回去请教别人,大部分程序员会回答你:pip install 什么等,可是你p ...
- Collection集合重难点梳理,增强for注意事项和三种遍历的应用场景,栈和队列特点,数组和链表特点,ArrayList源码解析, LinkedList-源码解析
重难点梳理 使用到的新单词: 1.collection[kəˈlekʃn] 聚集 2.empty[ˈempti] 空的 3.clear[klɪə(r)] 清除 4.iterator 迭代器 学习目标: ...
- 【故障公告】redis内存耗尽造成博客后台无法保存
非常抱歉,今天上午11:00~11:30左右,由于 redis 服务器内存耗尽造成博客后台故障--保存博文时总是提示"请求太过频繁,请稍后再试",由此给您带来麻烦,请您谅解. 由于 ...
- swift笔记简录
一,变量和常量 /***************************基本数据类型*************************/ /****************************** ...
- (二)、vim即gvim的炫酷搜索模式与技巧
一.进入搜索模式 1. 打开文件,狂按 <Esc> 进入normal模式,然后按 / 或者 :/ 进入搜索模式,添加上关键字例如world,按回车即搜索world: :/wo ...
- 聊两句XSS(跨站脚本攻击)
XSS(跨站脚本攻击),聊两句,五毛的. XSS的危害: 窃取Cookie,盗用用户身份信息 这玩意儿是大多数XSS的目标,也好解决,可以先治个标,直接设置HttpOnly=true ,即不允许客户端 ...