====================================
相关的文章
====================================
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 请求提供负载均衡特性.

==========================
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系列: JdbcTemplate 快速入门

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

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

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

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

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

  4. SpringBoot整合ActiveMQ快速入门

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

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

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

  6. SpringBoot简介与快速入门

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

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

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

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

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

  9. Maven系列之快速入门

    文章结构 唯快不破---Maven快速入门 稳打稳扎---Maven核心知识 实用为先---Maven如何建立Web项目  1   唯快不破---Maven快速入门       1.1 Maven项目 ...

随机推荐

  1. SSH实战 &#183; 用spring框架下的hibernatetemplate的get方法出现的问题

    用get方法查询:      return this.getHibernateTemplate().get(Product.class, pid); 出现错误为:id to load is requi ...

  2. 如何将网页的title前面的图标替换成自己的图标

    首先要准备自己的图标,图标必须是.ico格式的图片,网上有很多在线工具可以将自己的图片转换成ico格式的图片,这里给大家介绍两个网站 在线ico转换工具:生成的图标是可以选尺寸的,原图片的大小不限制 ...

  3. 导航效果css

    <!doctype html> <html> <head> <meta charset="utf-8" /> <style&g ...

  4. 归并排序(Merge Sort)

    归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序列:即先使每个子序列有序,再使子序 ...

  5. input type=&quot;submit&quot; 和&quot;button&quot;有什么区别?

    http://www.zhihu.com/question/20839977 在一个页面上画一个按钮,有四种办法: <input type="button" /> 这就 ...

  6. JAVA之旅(十八)——基本数据类型的对象包装类,集合框架,数据结构,Collection,ArrayList,迭代器Iterator,List的使用

    JAVA之旅(十八)--基本数据类型的对象包装类,集合框架,数据结构,Collection,ArrayList,迭代器Iterator,List的使用 JAVA把完事万物都定义为对象,而我们想使用数据 ...

  7. 【算法】LeetCode算法题-Count And Say

    这是悦乐书的第153次更新,第155篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第12题(顺位题号是38).count-and-say序列是整数序列,前五个术语如下: ...

  8. 【C/C++】Rotate Array

    实现数组旋转(循环右移) 如数组 [1, 2, 3, 4, 5, 6, 7],右移 3 位则为 [5, 6, 7, 1, 2, 3, 4] 首先使用泛型函数 void Rotate(void *fro ...

  9. 第一次怎么把本地git仓库的内容push到远程仓库?

    使用git push origin <分支名> -f 这种方式可以用本地仓库的内容覆盖远程仓库.

  10. VMware vSphere 创建虚拟机步骤及三种磁盘规格

    https://blog.csdn.net/hanzheng260561728/article/details/80471899 http://www.mycitrix.cn/esxi-disk-mo ...