一、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());
    }

resttemplate get请求传json resttemplate getforobject_apache

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;
    }

}