目标
本指南将引导您完成创建使用RESTful Web服务的应用程序的过程,官网指导用的是Consuming,我感觉这个意思就是说,我们的搭建的服务器看做一个客户,对另一个服务器发送一个请求,消耗了另一个服务器的一个RESTful形式的Web服务。
我们将使用Spring的RestTemplate 来构建一个应用,这个应用可以从 https://gturnquist-quoters.cfapps.io/api/random取回一个随机的Spring boot 的 quotation ,这个quotation 我有点懵,这啥意思,后来感觉翻译成语录更好,因为返回的内容都是夸Spring的,如下图
还是老样子,https://github.com/spring-guides/gs-consuming-rest.git github直接下载下来,Eclipse打开
插入 file->import
获取REST资源
完成项目设置后,您可以创建一个使用RESTful服务的简单应用程序。
RESTful服务已设置在了 https://gturnquist-quoters.cfapps.io/api/random。本次设计的简单应用程序 随机获取有关Spring Boot的语录,并将其作为JSON文档返回。
如果您通过网络浏览器或curl请求该URL,则会收到看起来像这样的JSON文档
{
type: "success",
value: {
id: 10,
quote: "Really loving Spring Boot, makes stand alone Spring apps easy."
}
}
通过浏览器或curl获取时,这很容易,但并不是很有用。
使用REST Web服务的一种更有用的方法是编程方式。为了帮助您完成该任务,Spring提供了一个名为的便捷模板类RestTemplate。
下面两句不太好理解官方指南是RestTemplate makes interacting with most RESTful services a one-line incantation. And it can even bind that data to custom domain types.
RestTemplate 这个类让与大多数RESTful 形式服务 的交互成为了一个一行的咒语(可以的,这个B给你120,20分附加的),它甚至可以将数据绑定到自定义域类型(这个不太懂)
首先,您需要创建一个域类来包含你所需的数据,就是上面那个有type value两个属性的。以下清单显示了Quote该类,您可以将其用作域类
package com.example.consumingrest;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Quote {
private String type;
private Value value;
public Quote() {
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Value getValue() {
return value;
}
public void setValue(Value value) {
this.value = value;
}
@Override
public String toString() {
return "Quote{" +
"type='" + type + '\'' +
", value=" + value +
'}';
}
}
这个简单的Java类具有一些属性和与这些属性相匹配的Getter方法。它@JsonIgnoreProperties 这个注释,用在Jackson JSON处理库中,来指示应忽略此类型中未绑定的任何属性,上面是未绑定的,就是我们这里只绑定了type 和value两个属性,其他的属性再JSON处理的时候就直接忽略了。
补充一下:本文代码使用了@JsonIgnoreProperties(ignoreUnknown = true),我们直接查看JsonIgnoreProperties的文档就会发现这句话
// To ignore any unknown properties in JSON input without exception:
//为了忽略JSON输入的任意未知的属性而不会报错
@JsonIgnoreProperties(ignoreUnknown=true)
但是文档中的另一句没太理解
// to prevent specified fields from being serialized or deserialized
// (i.e. not include in JSON output; or being set even if they were included)
@JsonIgnoreProperties({ “internalId”, “secretKey” })
然后看到这个博客Spring Boot程序中@JsonIgnoreProperties与@JsonIgnore基本使用
-
@JsonIgnore注解用来忽略某些字段,可以用在变量或者Getter方法上,用在Setter方法时,和变量效果一样。这个注解一般用在我们要忽略的字段上。
-
@JsonIgnoreProperties(ignoreUnknown = true),将这个注解写在类上之后,就会忽略类中不存在的字段。这个注解还可以指定要忽略的字段,例如@JsonIgnoreProperties({ “password”, “secretKey” })
-
@JsonFormat可以帮我们完成格式转换。例如对于Date类型字段,如果不适用JsonFormat默认在rest返回的是long,如果我们使用@JsonFormat(timezone = “GMT+8”, pattern = “yyyy-MM-dd HH:mm:ss”),就返回"2018-11-16 22:58:15"
额,转的又多了,看到好的文章总想多复制点。。。。
要将数据直接绑定到自定义类型,您需要指定变量名称,使其与从API返回的JSON文档中的键完全相同。如果您的变量名称和JSON文档中的密钥不匹配,则可以使用@JsonProperty批注指定JSON文档的确切密钥。(此示例将每个变量名称与一个JSON键匹配,因此在这里您不需要该注释。)
但是由于返回的JSON其实是可以看成两层嵌套,所以还需要一个附加的类来表示内部的value属性。该Value级满足了这一需求
{
type: "success",
value: {
id: 10,
quote: "Really loving Spring Boot, makes stand alone Spring apps easy."
}
}
代码
package com.example.consumingrest;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Value {
private Long id;
private String quote;
public Value() {
}
public Long getId() {
return this.id;
}
public String getQuote() {
return this.quote;
}
public void setId(Long id) {
this.id = id;
}
public void setQuote(String quote) {
this.quote = quote;
}
@Override
public String toString() {
return "Value{" +
"id=" + id +
", quote='" + quote + '\'' +
'}';
}
}
完成申请
现在,您需要向ConsumingRestApplication 这个包含Main函数的类中添加一些其他内容,以使其显示来自我们RESTful源的报价。您需要添加:
- 记录器,用于将得到的返回数据发送到日志(在此示例中为控制台)。
- A RestTemplate,它使用Jackson JSON处理库来处理传入的数据。
- 在启动时CommandLineRunner运行RestTemplate(因此获取我们的语录)。
代码如下:
package com.example.consumingrest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class ConsumingRestApplication {
private static final Logger log = LoggerFactory.getLogger(ConsumingRestApplication.class);
public static void main(String[] args) {
SpringApplication.run(ConsumingRestApplication.class, args);
}
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
@Bean
public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
return args -> {
Quote quote = restTemplate.getForObject(
"https://gturnquist-quoters.cfapps.io/api/random", Quote.class);
log.info(quote.toString());
};
}
}
理解补充:
RestTemplate是Spring中对HttpClient的再次封装,简化了发起HTTP请求以及处理响应的过程,抽象层级更高,减少消费者的模板代码,使冗余代码更少。比如建立连接,构造请求头和请求体,然后根据响应,解析响应信息,最后关闭连接。
在项目中,当我们需要远程调用一个HTTP接口时,我们经常会用到RestTemplate这个类。这个类是Spring框架提供的一个工具类。
RestTemplate是一个同步的Rest API客户端。下面我们就来介绍下RestTemplate的常用功能。
下面代码就是使用RestTemplateBuilder配置RestTemplate,我们如果想使用RestTemplate,必须配置一下,更多关于RestTemplate的用法
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
//Build a new {@link RestTemplate} instance and configure it using this builder.
}
然后什么是Bean?
SpringBean是被实例的,组装的及被Spring容器管理的Java对象
RestTemplate.getForObject方法
Retrieve a representation by doing a GET on the specified URL.The response (if any) is converted and returned.
通过对指定的URL进行一个GET请求 来得到一个返回,并且这个返回可以被转换为指定的形式
参数:
Parameters:
url:the URLresponse
Type:the type of the return value
总结就是:
我们平时会将一个对象转换为json格式发给前端,这里则是从浏览器获取了一个json并转换为对象,果然是consume
理解CommandLineRunner
Interface used to indicate that a bean should run when it is contained within a SpringApplication. Multiple CommandLineRunner beans can be defined with in the same application context and can be ordered using the Orderedinterface or @Order annotation.
CommandLineRunner首先本质是一个接口,用于指示应当运行的 包含在SpringApplication中 bean。可以在同一应用程序上下文中用定义多个CommandLineRunner bean,并且可以使用Orderedinterface或@Order注释进行排序。
使用spring boot管理应用的生命周期,@Bean Spring可以从当前方法获取一个bean
这里使用了一个args->的lambda表达式,并且之后参数中没有args
Lambda是什么?
Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使java的语言表达能力得到了提升
Lambda只需要一个参数时,参数的小括号可以省略
CommandLineRunner是一个接口(函数式接口),我们返回的是一个函数,这个函数有一个参数args,并且这个args是一个String [] 因为