SpringBoot系列: RestTemplate 快速入门

时间:2022-09-30 07:47:38

====================================
相关的文章
====================================
SpringBoot系列: 与Spring Rest服务交互数据
https://www.cnblogs.com/harrychinese/p/Springboot_SpringRest.html

SpringBoot系列: Spring MVC视图方法的补充
https://www.cnblogs.com/harrychinese/p/springboot_mvc_view_function2.html

[转载]SpringBoot系列: SpringMVC 参数绑定注解解析
https://www.cnblogs.com/harrychinese/p/springboot_mvc_view_function.html

SpringBoot系列: RestTemplate 快速入门
https://www.cnblogs.com/harrychinese/p/springboot_resttemplate.html

====================================
微服务进程间通信
====================================

微服务进程之间的通讯有 http 和 rpc 两种协议, 在 Spring Cloud 项目中一般都以 http 通信, 常用的访问框架有:
1. JdkHttpConnection 组件
2. Apache HttpClient 组件
3. RestTemplate (Spring Framework 提供的 webclient, 缺省是基于 JdkHttpConnection 实现的, 也可以基于 Apache HttpClient 、 OkHttp 实现)
4. Feign (spring-cloud-starter-feign 项目提供的 webclient)
5. OkHttp (Square 开源的 http 客户端)
6. AsyncHttpClient(基于 Netty 的 http 客户端)
7. Retrofit (Square 开源的 http 客户端, 对于 OkHttp 做了封装)

JdkHttpConnection/Apache HttpClient 等 web 客户端是底层客户端, 如果直接在微服务项目中使用, 需要处理很多工作. 其他几个客户端都针对 Rest 服务做了很多封装, 这包括:
1. 连接池
2. 超时设置
3. 请求和响应的编码/解码 (json <-> pojo)
4. 支持异步

因为我们开发的项目是基于 Spring Boot 的, 考虑到集成性和 Spring 官方的支持程度, 自然选择 RestTemplate 或 Feign 了.
有关 http 通信经常会看到 Robin 相关资料, 该技术是 Spring Cloud Netflix 的一个项目, 是一个基于 Http 和 Tcp 的客户端负载均衡器, 支持两种策略 Round robin 或 weigh based. Robin 可以和 RestTemplate/Feign 搭配使用, 为 web 请求提供负载均衡特性.

SpringBoot系列: RestTemplate 快速入门

==========================
pom.xml
==========================
RestTemplate 默认使用 jackson 完成 json 序列化和反序列化.

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>

==========================
RestTemplate 实例化
==========================
RestTemplate 实例最好是由 Spring 容器管理, 而不是在用到时候 new RestTemplate() 一个实例.
可以在 @Controller/@Service/@Configuration 类中, 声明一个 restTemplate bean, 其他地方直接注入即可使用.

@RestController
class HelloController {
//声明 bean
@Bean
@LoadBalanced //增加 load balance 特性.
public RestTemplate restTemplate() {
return new RestTemplate();
} //注入
@Autowired
private RestTemplate restTemplate; private void someMethod(){
//使用 restTemplate
}
}

或者, 先注入 RestTemplateBuilder, 然后通过该 builder 来构建 RestTemplate 实例. 使用 builder 可以为 RestTemplate 定制化东西:
builder.additionalInterceptors() 方法: 可以通过增加拦截器为每次 request 记录 log,
builder.additionalMessageConverters() 方法: 比如增加 MessageConverter 实现特定的 json <-> pojo 的转换,

@RestController
class Hello2Controller {
//注入 RestTemplateBuilder
@Autowired
private void initRestTemplate(RestTemplateBuilder builder){
this.restTemplate=builder.build();
} private RestTemplate restTemplate; private void someMethod(){
//使用 restTemplate
}
}

==========================
RestTemplate 使用
==========================
RestTemplate 主要方法

Http 方法 | RestTemplate 方法
DELETE | delete
GET | getForObject(), getForEntity()
HEAD | headForHeaders()
OPTIONS | OptionsForAllow()
PUT | put
any | exchange(), execute()

1. delete() 方法, 在 url 资源执行 http DELETE 操作.
2. exchange() 方法, 通用的 web 请求方法, 返回一个 ResponseEntity 对象, 这个对象是从响应体映射而来. 该方法支持多种 web method, 是其他 RestTemplate 方法的基础.
3. execute() 方法, 是 exchange() 方法的基础.
4. getForEntity() 方法, 发送一个 GET 请求, 返回一个通用的 ResponseEntity 对象, 使用该对象可以得到 Response 字符串.
5. getForObject() 方法, 发送一个 GET 请求, 返回一个 pojo 对象.
6. headForHeaders() 方法, 发送一个 HEAD 请求, 返回包含特定资源 url 的 http 头.
8. optionsForAllow() 方法, 发送一个 HTTP OPTIONS 请求, 返回对于特定 url 的 Allow 头信息.
9. PostForEntity() 方法, 发送一个 Post 请求, 返回一个 ResponseEntity 对象, 这个对象是从响应体映射而来.
10. PostForObject() 方法, 发送一个 POST 请求, 返回一个特定的对象, 该对象是从响应体映射而来.
11. PostForLocation() 方法, 发送一个 POST 请求, 返回新创建资源的 URL.
12. put() 方法, 发送 PUT 请求.

--------------------------
获取 plain json
--------------------------

ResponseEntity<String> response=restTemplate.getForEntity(url, String.class)
// 获取包含 plain text Body 的 response
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
// 获取 status code
System.out.println("status code:" + response.getStatusCode());
// 使用 jackson 解析 json 字符串
// class: com.fasterxml.jackson.databind.ObjectMapper
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(response.getBody());
JsonNode value = root.path("type");

--------------------------
获取 Pojo 对象
--------------------------
如果 Rest 服务返回下面的 json 格式:
{ "firstName":"John" , "lastName":"Doe" }

RestTemplate 很容易可以将 json 转成对象:
Employee foo = restTemplate.getForObject(url, Employee.class);

如果 Rest 服务返回下面的 json 格式, json 中有一个根节点 employees, 其包含了多个 Employee 信息.

{
"employees": [
{ "firstName":"John" , "lastName":"Doe" },
{ "firstName":"Anna" , "lastName":"Smith" },
{ "firstName":"Peter" , "lastName":"Jones" }
]
}

对于这种格式的 json, 我们仍然可以使用 getForObject() 方法, 只要基于 Employee 类 做个 list wrapper 类即可.

public class EmployeeList {
private List<Employee> employees;
public EmployeeList() {
employees = new ArrayList<>();
}
// standard constructor and getter/setter
}
EmployeeList response = restTemplate.getForObject(
"http://localhost:8080/employees",
EmployeeList.class);
List<Employee> employees = response.getEmployees();

--------------------------
获取 json 数组对象
--------------------------
虽然 restTemplate.getForObject() 能很方便地将 json 转成 pojo, 但仅仅适合于处理单个对象的情形. 下面的 json 直接返回了一个数组, 这时使用 getForObject() 就不管用了.

[
{ "firstName":"John" , "lastName":"Doe" },
{ "firstName":"Anna" , "lastName":"Smith" },
{ "firstName":"Peter" , "lastName":"Jones" }
]

我们可以使用 exchange() 方法, 最关键一点是将 List<Employee> 类型传进去, 这样 RestTemplate 就知道如何将 json 数组转成 object list 了.

ResponseEntity<List<Employee>> response = restTemplate.exchange(
"http://localhost:8080/employees/",
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<Employee>>(){});
List<Employee> employees = response.getBody();

--------------------------
向 url 传参
--------------------------
在 POST 和 GET 等方法, 最后一个形参往往是 url 参数变量, 比如:
getForEntity(String url,Class responseType,Object...urlVariables)
getForEntity(String url,Class responseType,Map urlVariables)

处理方式 1:
如果要使用数组或可变参数方式传入 url param, url 的参数必须使用数字下标来占位.

String url = http://USER-SERVICE/user.do?name={1}&age={2};
String[] urlVariables=["jason",26];

处理方式 2:
如果要 Map 传入 url param, url 的参数必须使用 named 方式占位

String url = http://USER-SERVICE/user.do?name={name}&age={age};
Map<String, Object> urlVariables = new HashMap<String, Object>();
urlVariables.put("name",jason);
urlVariables.put("age",26);

--------------------------
设置 header, Post 一个 json 串
--------------------------

String url="url";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
String body="some json body";
HttpEntity<String> requestEntity = new HttpEntity<String>(body, headers);
ResponseEntity<String> response= restTemplate.postForEntity(url, requestEntity, String.class);

HttpEntity 经常被用到, 它可以将 Headers 和要提交的数据合并成一个对象, 作为 request 对象传参给 POST/PUT/PATCH 等很多方法.

--------------------------
Post 一个对象 list
--------------------------
Post 操作可以直接使用 restTemplate.postForObject() 方法, 该方法即可 Post 单个对象, 也可以 Post 对象的 List.

List<Employee> newEmployees = new ArrayList<>();
newEmployees.add(new Employee(3, "Intern"));
newEmployees.add(new Employee(4, "CEO")); restTemplate.postForObject(
"http://localhost:8080/employees/",
newEmployees,
ResponseEntity.class);

--------------------------
使用 HEAD 获取 headers
--------------------------

HttpHeaders httpHeaders = restTemplate.headForHeaders(fooResourceUrl);
assertTrue(httpHeaders.getContentType().includes(MediaType.APPLICATION_JSON));

--------------------------
文件上传下载
--------------------------
参考 https://www.jianshu.com/p/bbd9848c0cfc

@Test
public void upload() throws Exception {
Resource resource = new FileSystemResource("/home/lake/github/wopi/build.gradle");
MultiValueMap multiValueMap = new LinkedMultiValueMap();
multiValueMap.add("username","lake");
multiValueMap.add("files",resource);
ActResult result = testRestTemplate.postForObject("/test/upload",multiValueMap,ActResult.class);
Assert.assertEquals(result.getCode(),0);
} @Test
public void download() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.set("token","xxxxxx");
HttpEntity formEntity = new HttpEntity(headers);
String[] urlVariables = new String[]{"admin"};
ResponseEntity<byte[]> response = testRestTemplate.exchange("/test/download?username={1}",HttpMethod.GET,formEntity,byte[].class,urlVariables);
if (response.getStatusCode() == HttpStatus.OK) {
Files.write(response.getBody(),new File("/home/lake/github/file/test.gradle"));
}
}

--------------------------
定制化 RestTemplate
--------------------------
增加一个自定义 ErrorHandler:
restTemplate.setErrorHandler(errorHandler);

设定 httpClient 的工厂类:
restTemplate.setRequestFactory(requestFactory);
可以为 RestTemplate 设定 httpClient 的工厂类, 主要有两个工厂类:
1. SimpleClientHttpRequestFactory 工厂类, 这是缺省的工厂类, 底层用的是 jdk 的 HttpConnection, 默认超时为-1.
2. HttpComponentsClientHttpRequestFactory 底层用的是 Apache HttpComponents HttpClient, 比 JDK 的 HttpConnection 强大, 可以配置连接池和证书等, 支持 https.
3. OkHttp3ClientHttpRequestFactory 底层使用的是 square 公司开源的 OkHttp, 该客户端支持 https 等高级特性,  pom.xml 需要增加依赖.
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>3.8.1</version>
        </dependency>

====================================
参考
====================================
https://www.jianshu.com/p/bbd9848c0cfc
http://www.cnblogs.com/okong/p/springcloud-four.html
https://my.oschina.net/lifany/blog/688889
http://www.cnblogs.com/okong/p/springcloud-four.html
https://blog.csdn.net/QiaoRui_/article/details/80453799

https://spring.io/guides/gs/consuming-rest/
https://www.tutorialspoint.com/spring_boot/spring_boot_rest_template.htm
https://www.baeldung.com/rest-template
https://www.baeldung.com/spring-rest-template-list

SpringBoot系列: RestTemplate 快速入门的更多相关文章

  1. SpringBoot系列&colon; JdbcTemplate 快速入门

    对于一些小的项目, 我们没有必要使用MyBatis/JPA/Hibernate等重量级技术, 直接使用Spring JDBC 即可, Spring JDBC 是对 jdbc的简单封装, 很容易掌握. ...

  2. Flask开发系列之快速入门

    Flask开发系列之快速入门 文档 一个最小的应用 调试模式 路由 变量规则 构造 URL HTTP 方法 静态文件 模板渲染 访问请求数据 环境局部变量 请求对象 文件上传 Cookies 重定向和 ...

  3. Springboot 完整搭建快速入门,必看!

    前言 手把手教你Springboot微服务项目搭建快速入门,通过本文学习Springboot的搭建快速入门,掌握微服务大致的配置服务,后续将会继续将核心组件引入到项目中,欢迎关注,点赞,转发. Spr ...

  4. BIML 101 - ETL数据清洗 系列 - BIML 快速入门教程 - 序

    BIML 101 - BIML 快速入门教程 做大数据的项目,最花时间的就是数据清洗. 没有一个相对可靠的数据,数据分析就是无木之舟,无水之源. 如果你已经进了ETL这个坑,而且预算有限,并且有大量的 ...

  5. SpringBoot整合ActiveMQ快速入门

    Spring Boot 具有如下特性: 为基于 Spring 的开发提供更快的入门体验 开箱即用,没有代码生成,也无需 XML 配置.同时也可以修改默认值来满足特定的需求. 提供了一些大型项目中常见的 ...

  6. springboot笔记02——快速入门quickstart

    前言 学习一个新的框架,往往会用一个quickstart快速入门,这次就写一下springboot的quickstart程序. 开发环境 JDK 1.8 Springboot 2.1.6 Maven ...

  7. SpringBoot简介与快速入门

    一.SpringBoot简介 1.1 原有Spring优缺点分析 1.1.1 Spring的优点分析 Spring是Java企业版(Java Enterprise Edition,JEE,也称J2EE ...

  8. SpringBoot系列之从入门到精通系列教程

    对应SpringBoot系列博客专栏,例子代码,本博客不定时更新 Spring框架:作为JavaEE框架领域的一款重要的开源框架,在企业应用开发中有着很重要的作用,同时Spring框架及其子框架很多, ...

  9. BIML 101 - ETL数据清洗 系列 - BIML 快速入门教程 - 连接数据库执行SQL语句

    BIML 101 - BIML 快速入门教程 第一节 连接数据库执行SQL语句 本小节将用BIML建一个简单的可以执行的包. 新建一个biml文件,贴入下面的代码 1 <Biml xmlns=& ...

随机推荐

  1. CentOS 6&period;5 RPM包方式安装 Mysql 5&period;6

    1. 下载MySQL 5.6 下载页面:http://dev.mysql.com/downloads/mysql/此处选择“Red Hat Enterprise Linux 6 / Oracle Li ...

  2. 【iCore3 双核心板&lowbar;FPGA】例程十:锁相环实验——锁相环使用

    实验指导书及代码包下载: http://pan.baidu.com/s/1boeODjx iCore3 购买链接: https://item.taobao.com/item.htm?id=524229 ...

  3. hdu2825Wireless Password&lpar;ac&plus;dp&rpar;

    链接 状压dp+ac dp[i+1][next[j]][st|tt]表示第i+1长度结点为next[j]状态为st|tt的时候的ans; dp[i+1][next[j]][st|tt]+=dp[i][ ...

  4. MYSQL注入天书之HTTP头部介绍

    Background-5 HTTP头部介绍 在利用抓包工具进行抓包的时候,我们能看到很多的项,下面详细讲解每一项. HTTP头部详解 1. Accept:告诉WEB服务器自己接受什么介质类型,*/* ...

  5. Linq使用之标准运算符方法

    #region linq的标准查询运算符(即lambda方式) 注:C#不支持标准查询运算符中带有整形参数(索引)的重载 // 1.标准查询运算符之筛选方法——where            //I ...

  6. Android Fragment类方法

    public void onStart() 当该Fragment对象对用户可见时,该方法会被调用.该方法通常会跟它的Activity的生命周期的Activity.onStart()方法绑定. publ ...

  7. 洛谷-求同构数的个数-NOIP2013提高组复赛

    题目描述 Description 所谓同构数是指这样的数,即它出现在它的平方数的右端.例如,5的平方是25 (即5×5=25),5是25右端的数,那么5就是同构数.又如,25的平方是625(即25×2 ...

  8. SpringBoot12 QueryDSL01之QueryDSL介绍、springBoot项目中集成QueryDSL

    1 QueryDSL介绍 1.1 背景 QueryDSL的诞生解决了HQL查询类型安全方面的缺陷:HQL查询的扩展需要用字符串拼接的方式进行,这往往会导致代码的阅读困难:通过字符串对域类型和属性的不安 ...

  9. 在Centos中部署nginx

    准备工作: nginx的安装依赖openSSL,zlib和pcre Openssl下载地址: http://www.openssl.org/ zlib下载地址: http://www.zlib.net ...

  10. 第一周Access课总结

    一.问:这节课学到了什么知识? 答:这周课程迎来新的学习领域,作为初次学Access有了一定的了解,Access是office办公软件中的一个极为重要的组成部分,它可以对大量的数据进行存储,查找,统计 ...