一、 什么是RestTemplate?
RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程 Http 服务的方法,能够大大提高客户端的编写效率。
调用 RestTemplate 的默认构造函数,RestTemplate 对象在底层通过使用java.net包下的实现创建 HTTP 请求,可以通过使用 ClientHttpRequestFactory 指定不同的HTTP请求方式。
ClientHttpRequestFactory 接口主要提供了两种实现方式
- 一种是 SimpleClientHttpRequestFactory,使用 J2SE 提供的方式(即java.net 包提供的方式)创建底层的 Http 请求连接
- 一种方式是使用 HttpComponentsClientHttpRequestFactory 方式,底层使用 HttpClient 访问远程的 Http 服务,使用 HttpClient 可以配置连接池和证书等信息。
二、 使用方法
- pom.xml添加依赖
<!--调用外部网络API使用 start-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5</version>
</dependency>
<!--调用外部网络API使用 end-->
<!--Rest请求start-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.8.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.8.8</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.28</version>
</dependency>
<!--rest请求end-->
- 基于jdk的spring的RestTemplate,配置Config中的bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
default-autowire="byName" default-lazy-init="true">
<!--方式一、使用jdk的实现-->
<bean id="ky.requestFactory" class="org.springframework.http.client.SimpleClientHttpRequestFactory">
<property name="readTimeout" value="10000"/>
<property name="connectTimeout" value="5000"/>
</bean>
<bean id="simpleRestTemplate" class="org.springframework.web.client.RestTemplate">
<constructor-arg ref="ky.requestFactory"/>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
</beans>
- 使用Httpclient连接池的方式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
default-autowire="byName" default-lazy-init="true">
<!--方式二、使用httpclient的实现,带连接池-->
<bean id="ky.pollingConnectionManager" class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager">
<!--整个连接池的并发-->
<property name="maxTotal" value="1000" />
<!--每个主机的并发-->
<property name="defaultMaxPerRoute" value="1000" />
</bean>
<bean id="ky.httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder" factory-method="create">
<property name="connectionManager" ref="ky.pollingConnectionManager" />
<!--开启重试-->
<property name="retryHandler">
<bean class="org.apache.http.impl.client.DefaultHttpRequestRetryHandler">
<constructor-arg value="2"/>
<constructor-arg value="true"/>
</bean>
</property>
<property name="defaultHeaders">
<list>
<bean class="org.apache.http.message.BasicHeader">
<constructor-arg value="User-Agent"/>
<constructor-arg value="Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"/>
</bean>
<bean class="org.apache.http.message.BasicHeader">
<constructor-arg value="Accept-Encoding"/>
<constructor-arg value="gzip,deflate"/>
</bean>
<bean class="org.apache.http.message.BasicHeader">
<constructor-arg value="Accept-Language"/>
<constructor-arg value="zh-CN"/>
</bean>
</list>
</property>
</bean>
<bean id="ky.httpClient" factory-bean="ky.httpClientBuilder" factory-method="build" />
<bean id="ky.clientHttpRequestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<constructor-arg ref="ky.httpClient"/>
<!--连接超时时间,毫秒-->
<property name="connectTimeout" value="5000"/>
<!--读写超时时间,毫秒-->
<property name="readTimeout" value="10000"/>
</bean>
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<constructor-arg ref="ky.clientHttpRequestFactory"/>
<property name="errorHandler">
<bean class="org.springframework.web.client.DefaultResponseErrorHandler"/>
</property>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
</beans>
- 编写controller,通过testGetAction 和 testPostAction 这两个API来模拟第三方的API
package com.sdu.controller;
import com.alibaba.fastjson.JSONObject;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
/**
* call API
*/
@RestController
public class SpringRestTemplateController
{
@Autowired
private RestTemplate restTemplate;
/***********HTTP GET method*************/
@RequestMapping(value = "/testGetAction",method = RequestMethod.GET)
public Object getJson()
{
JSONObject json = new JSONObject();
json.put("username", "tester");
json.put("pwd", "123456748");
return json;
}
@RequestMapping(value = "/getApi",method = RequestMethod.GET)
public String testGet()
{
String url = "http://localhost:8080/testGetAction";
JSONObject json = restTemplate.getForEntity(url, JSONObject.class).getBody();
return json.toJSONString();
}
/**********HTTP POST method**************/
@RequestMapping(value = "/testPostAction",method = RequestMethod.POST)
public Object postJson(@RequestBody JSONObject param)
{
System.out.println(param.toJSONString());
param.put("action", "post");
param.put("username", "tester");
param.put("pwd", "123456748");
return param;
}
@RequestMapping(value = "/postApi",method = RequestMethod.POST)
public Object testPost()
{
String url = "http://localhost:8080/testPostAction";
JSONObject postData = new JSONObject();
postData.put("descp", "request for post");
JSONObject json = restTemplate.postForEntity(url, postData, JSONObject.class).getBody();
return json.toJSONString();
}
然后在postman上调用getApi,然后查看结果
{“pwd”:“123456748”,“username”:“tester”}
在postman上post 请求 postApi,查看结果
{“action”:“post”,“pwd”:“123456748”,“descp”:“request for post”,“username”:“tester”}
到这里,我们已经完成了调用Spring API的模拟。
关于Postman的使用,请参考:
Postman 使用方法详解
使用Postman模拟发送get、post、delete、put请求
三、Flask启动服务
- 启动 Flask 的 serve
# -*- coding: UTF-8 -*-
# @File : server.py
import json
import time
from flask import Flask, jsonify
from flask import request
import logger
from Main import Main
logger = logger.logger
app = Flask(__name__, static_url_path="")
@app.route("/healthcheck", methods=['POST', 'GET'])
def test_hello():
# logger.info("health")
res = {"message": "hello world!"}
res_json = jsonify(res)
return res_json
@app.route("/test", methods=['POST', 'GET'])
def get_data():
if request.method == 'POST':
data = request.form.get("data", "")
logger.info("data: %s" % data)
try:
# your code here 对获取的数据进行操作
# res = function(data)
# return jsonify(res)
except Exception as e:
# logger.error(e)
# res = function(data)
# return jsonify(res)
if __name__ == "__main__":
my_model = Main()
app.run(host="127.0.0.1", port=9001, debug=True)
- 在 spring 中调用该接口
@RequestMapping(value = "/post_test2",method = RequestMethod.POST)
public Object post_test2()
{
// url
String url = "http://127.0.0.1:9001/test";
// headers
HttpHeaders headers = new HttpHeaders();
//根据 headers 的类型不同,ContentType 也不同
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// body
MultiValueMap<String, String> postData = new LinkedMultiValueMap<>();
postData.add("data", "I m fine.");
//String postData = "data=I m fine. Are you?";
HttpEntity<MultiValueMap<String, String>> entity
= new HttpEntity<>(postData, headers);
// 根据要求返回数据类型不同,选择 postForObject 或者 postForEntity方法
//String answer = restTemplate.postForObject(url, entity, String.class);
//postData.put("data", "I m fine. Are you?");
JSONObject json = restTemplate.postForEntity(url, postData, JSONObject.class).getBody();
return json.toJSONString();
//return answer;
}
四、参考链接
RestTemplate实践
spring使用RestTemplate来调用其他接口
Spring中使用RestTemplate调用第三方接口API
RestTemplate实践 - Trust_FreeDom
spring mvc - tutorial 1:实现简单的GET、POST接口并使用Postman测试
How to POST form data with Spring RestTemplate? - stackoverflow
POST request via RestTemplate in JSON - stackoverflow
how to get data from ‘ImmutableMultiDict’ in flask - stackoverflow