一、RestTemplate是什么
RestTemplate是spring-web-xxx.jar包中提供的Http协议实现类。也就是说导入spring-boot-starter-web的项目可以直接使用RestTemplate类,就是基于模板方法设计模式的,封装了所有需要使用的API
在该类中主要针对6类请求方式封装的方法。
HTTP method | RestTemplate methods |
DELETE | delete |
GET | getForObject |
- | getForEntity |
HEAD | headForHeaders |
OPTIONS | optionsForAllow |
POSR | postForLocation |
- | psotForObject |
PUT | put |
any | exchange |
- | execute |
1.1 说明
get方式提供了两个方法:
两个方法都是发送get请求并处理响应。区别:
getForObject:把响应体直接转换为对象。该方法返回值为特定类类型。舍弃了Response Header的东西,但是用起来比getForEntity方便。如果只需要获取响应体中内容(调用控制器方法的返回值)使用此方法。
getForEntity:返回值包含响应头和响应体。用起来比getForObject稍微麻烦一些。
二、 get方式
1.1 项目导入spring-boot-starter-web依赖即可
注意:
如果方法返回值是String或基本数据类型时,建议给定produces设置响应结果类型,否则使用浏览器测试和使用RestTemplate获取的ContentType类型可能不一致。
@RestController
public class ServerController {
@RequestMapping(value = "/demo1",produces = "text/html;charset=utf-8")
public String demo1(){
return "demo1";
}
}
2.1 getForObject 无参数
使用Spring脚手架又创建了一个项目resttemplate。
在测试类中添加测试方法
@Test
void testGetForObject() {
RestTemplate restTemplate = new RestTemplate();
// 第二个参数是请求控制器响应内容类型。决定getForObject方法返回值类型。
String result = restTemplate.getForObject("http://localhost:8080/demo1", String.class);
System.out.println(result);
}
2.2 getForEntity无参数测试
在测试类中直接添加方法进行测试。
getForEntity和getForObject的区别就是返回值是ResponseEntity。里面不仅仅可以取出响应体内容,还可以取出响应头信息或请求状态码等。
注意:getForEntity和getForObject除了返回值不一样以外,其他用法完全相同。
@Test
void testGetForEntity(){
RestTemplate restTemplate = new RestTemplate();
// getForEntity第二个参数类型决定了ResponseEntity泛型类型,表示相应体中内容类型。
ResponseEntity<String> result = restTemplate.getForEntity("http://localhost:8080/demo1", String.class);
// 取出相应体内容。
System.out.println(result.getBody());
// 取出请求状态码。
System.out.println(result.getStatusCode());
// 通过getHeaders()取出响应头中想要的信息,以ContentType举例。
System.out.println(result.getHeaders().getContentType());
}
2.3 getForObject 使用不定项参数
在项目中添加了一个控制器方法
@RequestMapping("/demo2")
public String demo2(String name,int age){
return "name:"+name+",age:"+age;
}
添加测试方法
getForObject第一个参数URL中使用URL重写方式包含请求参数。参数后面使用{序号}格式进行占位,序号从1开始。
注意:getForObject第三个开始的参数顺序要和序号严格对应。
@Test
void testGetForObjectWithParam(){
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject("http://localhost:8080/demo2?age={1}&name={2}", String.class, 123, "张三");
System.out.println(result);
}
2.4 getForObject 使用Map传参
考虑使用不定项参数方式设置参数必须严格按照顺序进行设置,可能当参数过多时,比较难对应。
所以还提供了一种使用Map进行设置参数。根据占位符{key}进行对应,占位符中key的内容就是Map中key对应的Value
@Test
void testGetForObjectWithMapParam(){
RestTemplate restTemplate = new RestTemplate();
Map<String,Object> map = new HashMap<>();
map.put("age",15);
map.put("name","map传参");
String result = restTemplate.getForObject("http://localhost:8080/demo2?age={age}&name={name}", String.class, map);
System.out.println(result);
}
2.5 getForObject 使用restful传值
前提控制必须支持restful方式。在resttemplateserver项目中添加控制器方法
@RequestMapping("/demo3/{name}/{age}")
public String demo3(@PathVariable String name,@PathVariable int age){
return "restfule:name:"+name+",age:"+age;
}
在测试类中使用restful方式进行传参
@Test
void testGetForObjectRestful() {
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject("http://localhost:8080/demo3/张三/12", String.class);
System.out.println(result);
}
2.6 使用固定值或字符串拼接方式传参
固定方式值
很少在实际项目中URL参数是固定值。一般参数的值都是变量的值
@Test
void testGetForObjectWithParamFi() {
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject("http://localhost:8080/demo2?age=12&name=李四", String.class);
System.out.println(result);
}
字符串拼接
由于使用字符串拼接方式可能拼接错误,建议使用上面的几种方式。
@Test
void testGetForObjectWithParamFi2() {
RestTemplate restTemplate = new RestTemplate();
People peo = new People(3,"Lisi");
String result = restTemplate.getForObject("http://localhost:8080/demo2?age="+peo.getId()+"&name="+peo.getName(), String.class);
System.out.println(result);
}
三、post方式
3.1 传递表单数据
传参数语法与get相同(只是多了一个参数),虽然看起来是url重写(get方式)但实际上用post请求。也支持{序号}或{map的key}两种方式。
post也支持postForObject和postForEntity两种方式,每种方式提供三种方法重载,与get相同。
注意:
post相关方法比get相关方法多了一个参数,这个参数在参数列表中第二个。如果传递的是普通参数,第二个参数设置为null即可。如果希望向请求体中设置流数据,设置到第二个参数中,Application Service通过@RequestBody接收。第二个参数多用在直接传递对象等数据的情况。
post里面多了postForLocation() 返回值为URI获取到结果URI,使用较少。
@Test
void testPost(){
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.postForObject("http://localhost:8080/demo2?age=15&name=lisi", null, String.class);
System.out.println(result);
}
3.2传递请求体数据
postForObject 第二个参数为请求体数据。当设置第二个参数后,控制器方必须要使用@RequestBody接收此参数。
在控制器中添加方法。
其中方法参数map接收的就是postForObject第二个参数数据。
@RequestMapping("/demo4")
public String demo4(String name, int age, @RequestBody Map<String,Object> map){
return "name:"+name+",age:"+age+",map:"+map.get("a")+","+map.get("b");
}
``
在resttemplate项目的测试类中添加`
```java
@Test
void testPostWithBody(){
Map<String,Object> map = new HashMap<>();
map.put("a","a1");
map.put("b","b2");
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.postForObject("http://localhost:8080/demo4?age=15&name=lisi", map, String.class);
System.out.println(result);
}
四、exchange
当请求的控制器返回值类型为List、Set等带有泛型类型的类型时,就不能使用getForObject、getForEntity、postForObject等,因为它们都是只能设置返回值类型,而不能设置类型的泛型。这时就需要使用exchange方法。
除此以外,如果需要设置请求头参数情况也需要使用exchange方法。
4.1设置响应类型的泛型,不包含请求参数
在resttemplateserver中添加实体类和控制器方法,要求控制器方法返回值带有泛型
@Data
@AllArgsConstructor
@NoArgsConstructor
public class People {
private int id;
private String name;
}
@RequestMapping("/demo5")
public List<People> selectAll(){
List<People> list = new ArrayList<>();
list.add(new People(1,"张三"));
list.add(new People(2,"李四"));
return list;
}
在测试类中添加测试方法
@Test
void testList(){
// 泛型为请求体类型
// 构造方法参数是请求体数据
HttpEntity<String> httpEntity = new HttpEntity<>("");
// 泛型为调用控制器方法返回值类型,此处可以设置泛型
// 最后的大括号是因为ParameterizedTypeReference是abstract,但没有抽象方法
ParameterizedTypeReference<List<People>> py = new ParameterizedTypeReference<List<People>>() {};
RestTemplate restTemplate = new RestTemplate();
// HttpMethod 枚举,设置请求类型
ResponseEntity<List<People>> response = restTemplate.exchange("http://localhost:8080/demo5", HttpMethod.GET, httpEntity, py);
List<People> list = response.getBody();
for(People people : list){
System.out.println(people);
}
}
4.2 请求时包含普通表单参数
用法和之前讲解的getForObject两种参数相同支持{序号}和{map的key}
以{序号}举例:
ResponseEntity<List<People>> response = restTemplate.exchange("http://localhost:8080/demo5?id={1}&name={2}", HttpMethod.GET, httpEntity, py,123,"smallming");
五、HttpClient
pom依赖
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.11</version>
</dependency>
这里工具类封装
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
public class HttpClientUtil {
public static String doGet(String url, Map<String, String> param) {
// 创建Httpclient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
String resultString = "";
CloseableHttpResponse response = null;
try {
// 创建uri
URIBuilder builder = new URIBuilder(url);
if (param != null) {
for (String key : param.keySet()) {
builder.addParameter(key, param.get(key));
}
}
URI uri = builder.build();
// 创建http GET请求
HttpGet httpGet = new HttpGet(uri);
// 执行请求
response = httpclient.execute(httpGet);
// 判断返回状态是否为200
if (response.getStatusLine().getStatusCode() == 200) {
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (response != null) {
response.close();
}
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
public static String doGet(String url) {
return doGet(url, null);
}
public static String doPost(String url, Map<String, String> param) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
// 创建参数列表
if (param != null) {
List<NameValuePair> paramList = new ArrayList<>();
for (String key : param.keySet()) {
paramList.add(new BasicNameValuePair(key, param.get(key)));
}
// 模拟表单
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList,"utf-8");
httpPost.setEntity(entity);
}
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return resultString;
}
public static String doPost(String url) {
return doPost(url, null);
}
public static String doPostJson(String url, String json) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
// 创建请求内容
StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
httpPost.setEntity(entity);
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return resultString;
}
}
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.stereotype.Component;
@Component
public class RestClient {
//1. Get 请求方法
public CloseableHttpResponse get(String url) throws ClientProtocolException, IOException {
//创建一个可关闭的HttpClient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
//创建一个HttpGet的请求对象
HttpGet httpget = new HttpGet(url);
//执行请求,相当于postman上点击发送按钮,然后赋值给HttpResponse对象接收
CloseableHttpResponse httpResponse = httpclient.execute(httpget);
return httpResponse;
}
//2. Get 请求方法(带请求头信息)
public CloseableHttpResponse get(String url, HashMap<String, String> headermap) throws ClientProtocolException, IOException {
//创建一个可关闭的HttpClient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
//创建一个HttpGet的请求对象
HttpGet httpget = new HttpGet(url);
//加载请求头到httpget对象
for (Map.Entry<String, String> entry : headermap.entrySet()) {
httpget.addHeader(entry.getKey(), entry.getValue());
}
//执行请求,相当于postman上点击发送按钮,然后赋值给HttpResponse对象接收
CloseableHttpResponse httpResponse = httpclient.execute(httpget);
return httpResponse;
}
//3. POST方法
public CloseableHttpResponse post(String url, String entityString, HashMap<String, String> headermap) throws ClientProtocolException, IOException {
//创建一个可关闭的HttpClient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
//创建一个HttpPost的请求对象
HttpPost httppost = new HttpPost(url);
//设置payload
httppost.setEntity(new StringEntity(entityString));
//加载请求头到httppost对象
for (Map.Entry<String, String> entry : headermap.entrySet()) {
httppost.addHeader(entry.getKey(), entry.getValue());
}
//发送post请求
CloseableHttpResponse httpResponse = httpclient.execute(httppost);
return httpResponse;
}
//4. Put方法
public CloseableHttpResponse put(String url, String entityString, HashMap<String, String> headerMap) throws ClientProtocolException, IOException {
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpPut httpput = new HttpPut(url);
httpput.setEntity(new StringEntity(entityString));
for (Map.Entry<String, String> entry : headerMap.entrySet()) {
httpput.addHeader(entry.getKey(), entry.getValue());
}
//发送put请求
CloseableHttpResponse httpResponse = httpclient.execute(httpput);
return httpResponse;
}
//5. Delete方法
public CloseableHttpResponse delete(String url) throws ClientProtocolException, IOException {
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpDelete httpdel = new HttpDelete(url);
//发送put请求
CloseableHttpResponse httpResponse = httpclient.execute(httpdel);
return httpResponse;
}
}
json的工具类
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
import java.util.Map;
public class JsonUtils {
// 定义jackson对象
private static final ObjectMapper MAPPER = new ObjectMapper();
/**
* 将对象转换成json字符串。
* <p>Title: pojoToJson</p>
* <p>Description: </p>
* @param data
* @return
*/
public static String objectToJson(Object data) {
try {
String string = MAPPER.writeValueAsString(data);
return string;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
/**
* 将json结果集转化为对象
*
* @param jsonData json数据
* @param beanType 对象中的object类型
* @return
*/
public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
try {
T t = MAPPER.readValue(jsonData, beanType);
return t;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 将json数据转换成pojo对象list
* <p>Title: jsonToList</p>
* <p>Description: </p>
* @param jsonData
* @param beanType
* @return
*/
public static <T>List<T> jsonToList(String jsonData, Class<T> beanType) {
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
try {
List<T> list = MAPPER.readValue(jsonData, javaType);
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 把json转换为Map工具方法
* @param jsonData
* @param keyType
* @param valueType
* @param <K>
* @param <V>
* @return
*/
public static <K,V> Map<K,V> jsonToMap(String jsonData, Class<K> keyType,Class<V> valueType){
JavaType javaType = MAPPER.getTypeFactory().constructMapType(Map.class,keyType,valueType);
try {
Map<K,V> map = MAPPER.readValue(jsonData,javaType);
return map;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}