SpringBoot避坑指南(三)——构建Web服务

一、RESTful API

Spring Boot 2 中引入的一批新注解中,除了 @GetMapping ,还有 @PutMapping、@PostMapping、@DeleteMapping 等注解,这些注解极大方便了开发人员显式指定 HTTP 的请求方法。当然,你也可以继续使用原先的 @RequestMapping 实现同样的效果。

业务操作 非RESTful RESTful API
获取用户账号 /account/query/1 /accounts/1 GET
新增用户账号 /account/add /accounts POST
更新用户账号 /account/edit /accounts PUT
删除用户账号 /account/delete accounts DELETE

二、使用 RestTemplate 访问 HTTP 端点

RestTemplate 是 Spring 提供的用于访问 RESTful 服务的客户端的模板工具类,它位于 org.springframework.web.client 包下。

在设计上,RestTemplate 完全可以满足 RESTful 架构风格的设计原则。相较传统 Apache 中的 HttpClient 客户端工具类,RestTemplate 在编码的简便性以及异常的处理等方面都做了很多改进。

接下来,我们先来看一下如何创建一个 RestTemplate 对象,并通过该对象所提供的大量工具方法实现对远程 HTTP 端点的高效访问。

创建 RestTemplate

如果我们想创建一个 RestTemplate 对象,最简单且最常见的方法是直接 new 一个该类的实例,如下代码所示:

@Bean
public RestTemplate restTemplate(){
    
    
    return new RestTemplate();
}

这里我们创建了一个 RestTemplate 实例,并通过 @Bean 注解将其注入 Spring 容器中。

通常,我们会把上述代码放在 Spring Boot 的 Bootstrap 类中,使得我们在代码工程的其他地方也可以引用这个实例。

下面我们查看下 RestTemplate 的无参构造函数,看看创建它的实例时,RestTemplate 都做了哪些事情,如下代码所示:

public RestTemplate() {
    
    
        this.messageConverters.add(new ByteArrayHttpMessageConverter());
        this.messageConverters.add(new StringHttpMessageConverter());
        this.messageConverters.add(new ResourceHttpMessageConverter(false));
        this.messageConverters.add(new SourceHttpMessageConverter<>());
        this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
 
        //省略其他添加 HttpMessageConverter 的代码
}

可以看到 RestTemplate 的无参构造函数只做了一件事情,添加了一批用于实现消息转换的 HttpMessageConverter 对象。

我们知道通过 RestTemplate 发送的请求和获取的响应都是以 JSON 作为序列化方式,而我们调用后续将要介绍的 getForObject、exchange 等方法时所传入的参数及获取的结果都是普通的 Java 对象,我们就是通过使用 RestTemplate 中的 HttpMessageConverter 自动帮我们做了这一层转换操作。

这里请注意,其实 RestTemplate 还有另外一个更强大的有参构造函数,如下代码所示:

public RestTemplate(ClientHttpRequestFactory requestFactory) {
    
    
        this();
        setRequestFactory(requestFactory);
}

从以上代码中,我们可以看到这个构造函数一方面调用了前面的无参构造函数,另一方面可以设置一个 ClientHttpRequestFactory 接口。而基于这个 ClientHttpRequestFactory 接口的各种实现类,我们可以对 RestTemplate 中的行为进行精细化控制。

这方面典型的应用场景是设置 HTTP 请求的超时时间等属性,如下代码所示:

@Bean
public RestTemplate customRestTemplate(){
    
    
        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        httpRequestFactory.setConnectionRequestTimeout(3000);
        httpRequestFactory.setConnectTimeout(3000);
        httpRequestFactory.setReadTimeout(3000);
 
        return new RestTemplate(httpRequestFactory);
}

这里我们创建了一个 HttpComponentsClientHttpRequestFactory 工厂类,它是 ClientHttpRequestFactory 接口的一个实现类。通过设置连接请求超时时间 ConnectionRequestTimeout、连接超时时间 ConnectTimeout 等属性,我们对 RestTemplate 的默认行为进行了定制化处理。

除了实现常规的 HTTP 请求,RestTemplate 还有一些高级用法可供我们进行使用,如指定消息转换器、设置拦截器和处理异常等。

指定消息转换器

在 RestTemplate 中,实际上还存在第三个构造函数,如下代码所示:

public RestTemplate(List<HttpMessageConverter<?>> messageConverters) {
    
    
        Assert.notEmpty(messageConverters, "At least one HttpMessageConverter required");
        this.messageConverters.addAll(messageConverters);
}

从以上代码中不难看出,我们可以通过传入一组 HttpMessageConverter 来初始化 RestTemplate,这也为消息转换器的定制提供了途径。
假如,我们希望把支持 Gson 的 GsonHttpMessageConverter 加载到 RestTemplate 中,就可以使用如下所示的代码。

@Bean
public RestTemplate restTemplate() {
    
    
        List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
        messageConverters.add(new GsonHttpMessageConverter());
        RestTemplate restTemplate = new RestTemplate(messageConverters);
        return restTemplate;
}

原则上,我们可以根据需要实现各种自定义的 HttpMessageConverter ,并通过以上方法完成对 RestTemplate 的初始化。

设置拦截器

如果我们想对请求做一些通用拦截设置,那么我们可以使用拦截器。不过,使用拦截器之前,首先我们需要实现 ClientHttpRequestInterceptor 接口。

这方面最典型的应用场景是在 Spring Cloud 中通过 @LoadBalanced 注解为 RestTemplate 添加负载均衡机制。我们可以在 LoadBalanceAutoConfiguration 自动配置类中找到如下代码。

@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
            final LoadBalancerInterceptor loadBalancerInterceptor) {
    
    
        return restTemplate -> {
    
    
            List<ClientHttpRequestInterceptor> list = new ArrayList<>(
                    restTemplate.getInterceptors());
            list.add(loadBalancerInterceptor);
            restTemplate.setInterceptors(list);
        };
}

在上面代码中,我们可以看到这里出现了一个 LoadBalancerInterceptor 类,该类实现了 ClientHttpRequestInterceptor 接口,然后我们通过调用 setInterceptors 方法将这个自定义的 LoadBalancerInterceptor 注入 RestTemplate 的拦截器列表中。

处理异常

请求状态码不是返回 200 时,RestTemplate 在默认情况下会抛出异常,并中断接下来的操作,如果我们不想采用这个处理过程,那么就需要覆盖默认的 ResponseErrorHandler。示例代码结构如下所示:

RestTemplate restTemplate = new RestTemplate();
 
ResponseErrorHandler responseErrorHandler = new ResponseErrorHandler() {
    
    
        @Override
        public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException {
    
    
            return true;
        }
 
        @Override
        public void handleError(ClientHttpResponse clientHttpResponse) throws IOException {
    
    
            //添加定制化的异常处理代码
        }
};
 
restTemplate.setErrorHandler(responseErrorHandler);

在上述的 handleError 方法中,我们可以实现任何自己想控制的异常处理代码。

猜你喜欢

转载自blog.csdn.net/luomo0203/article/details/120051040