文章目录
请求
初识restTemplate
怎么用?
SpringBoot项目
SpringBoot项目中,只需要引入spring-boot-starter-web依赖就可以了,其实spring-boot-starter-web依赖也是SpringBoot项目必备的一个依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
设置超时时间
引入依赖之后,就来开始使用吧,任何一个Http的Api我们都可以设置请求的连接超时时间,请求超时时间,如果不设置的话,就可能会导致连接得不到释放,造成内存溢出。这个是我们需要重点注意的点,下面就来看看RestTemplate如何来设置超时时间呢?我们可以在SimpleClientHttpRequestFactory类中设置这两个时间,然后将factory传给RestTemplate实例,设置如下:
@Configuration
public class RestTemplateConfig {
/**
* 服务器返回数据(response)的时间
*/
private static final Integer READ_TIME_OUT = 6000;
/**
* 连接上服务器(握手成功)的时间
*/
private static final Integer CONNECT_TIME_OUT = 6000;
@Bean
public RestTemplate restTemplate(){
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient());
return new RestTemplate(requestFactory);
}
@Bean
public HttpClient httpClient(){
//默认证书有效
SSLConnectionSocketFactory sslConnectionSocketFactory = SSLConnectionSocketFactory.getSocketFactory();
SSLContext sslContext = null;
try {
//信任所有的SSL证书
sslContext = SSLContextBuilder.create().setProtocol(SSLConnectionSocketFactory.SSL)
.loadTrustMaterial((x, y) -> true).build();
} catch (Exception e) {
e.printStackTrace();
}
if (sslContext != null) {
sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext);
}
// 支持HTTP、HTTPS
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslConnectionSocketFactory)
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
connectionManager.setMaxTotal(200);
connectionManager.setDefaultMaxPerRoute(100);
connectionManager.setValidateAfterInactivity(2000);
RequestConfig requestConfig = RequestConfig.custom()
// 服务器返回数据(response)的时间,超时抛出read timeout
.setSocketTimeout(READ_TIME_OUT)
// 连接上服务器(握手成功)的时间,超时抛出connect timeout
.setConnectTimeout(CONNECT_TIME_OUT)
// 从连接池中获取连接的超时时间,超时抛出ConnectionPoolTimeoutException
.setConnectionRequestTimeout(1000)
.build();
return HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).setConnectionManager(connectionManager).build();
}
}
GET请求
getForObject方法的重载方法有如下三个
/**
方法一,直接将参数添加到url上面。
* Retrieve a representation by doing a GET on the specified URL.
* The response (if any) is converted and returned.
* <p>URI Template variables are expanded using the given URI variables, if any.
* @param url the URL 请求地址
* @param responseType the type of the return value 响应体的类型
* @param uriVariables the variables to expand the template 传入的参数
* @return the converted object
*/
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
RequestCallback requestCallback = this.acceptHeaderRequestCallback(responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = this.responseEntityExtractor(responseType);
return (ResponseEntity)nonNull(this.execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));
}
/**
方法二,通过Map来提交参数。
* Retrieve a representation by doing a GET on the URI template.
* The response (if any) is converted and returned.
* <p>URI Template variables are expanded using the given map.
* @param url the URL
* @param responseType the type of the return value
* @param uriVariables the map containing variables for the URI template
* @return the converted object
*/
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
RequestCallback requestCallback = this.acceptHeaderRequestCallback(responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = this.responseEntityExtractor(responseType);
return (ResponseEntity)nonNull(this.execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));
}
/**
方法三,用URI来请求。
* Retrieve a representation by doing a GET on the URL .
* The response (if any) is converted and returned.
* @param url the URL
* @param responseType the type of the return value
* @return the converted object
*/
public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException {
RequestCallback requestCallback = this.acceptHeaderRequestCallback(responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = this.responseEntityExtractor(responseType);
return (ResponseEntity)nonNull(this.execute(url, HttpMethod.GET, requestCallback, responseExtractor));
}
测试
这是我们的Controller
@Controller
public class UserController {
/**
*
* @return
*/
@GetMapping("/getUser")
@ResponseBody
public user getUser(@ProbeParam("username") String username,
@ProbeParam("age") Integer age) {
return new user(username,age);
}
@PostMapping("/postUser")
@ResponseBody
public user postUser(@RequestBody user user) {
return user;
}
}
测试类
@Test
void contextLoads() {
user u = new user("小王", 19);
String url = "http://localhost:8080/getUser?username={username}&age={age}";
user user = restTemplate.getForObject(url, user.class,u.getName(),u.getAge());
System.out.println(user);
}
需要注意的是:
1.传参替换使用{?}来表示坑位,根据实际的传参顺序来填充,如下:
url = baseUrl+"?userName={?}&userId={?}";
resultData = restTemplate.getForObject(url, ResultData.class, "张三2",2);
2.使用{xx}来传递参数时,这个xx对应的就是map中的key
url = baseUrl + "?userName={userName}&userId={userId}";
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("userName", "张三1");
paramMap.put("userId",1);
3.当响应头是application/json;charset=UTF-8格式的时候,返回的数据类型可以直接写String.class,如下
String url ="http://localhost:8081/testRestTemplateApp/getUser.do?userName=张三1&userId=1";
String resultData = restTemplate.getForObject(url, String.class);
4.不推荐直接使用方法三传入URI
原因主要有如下两点: 1. 传入的参数包含中文时必须要转码,直接传中文会报400的错误,2. 响应的结果必须要跟接口的返回值保持一致,不然回报406的错误。
//userName不能直接传入张三1,不然会报400的错误
URI uri = URI.create(baseUrl+"?userName=%E5%BC%A0%E4%B8%891&userId=1");
//responseType不能传入String.class,不然会报406的错误
ResultData resultData1 = restTemplate.getForObject(uri, ResultData.class);
POST 请求
说完了get请求相关的方法之后,接下来我们来看看post请求相关的方法,首先还是来看postForObject的三个重载方法。
/**
* @param url the URL 请求地址
* @param request the Object to be POSTed (may be {@code null}) 请求体,可以传入一个Bean对象,也可以传入HttpEntity对象,包装请求头
* @param responseType the type of the return value 响应对象的类型
* @param uriVariables the variables to expand the template 传入的参数
* @return the converted object
* @see HttpEntity
*/
@Nullable
<T > T postForObject(String url, @Nullable Object request, Class < T > responseType,
Object...uriVariables) throws RestClientException;
/**
* @param url the URL 请求地址
* @param request the Object to be POSTed (may be {@code null}) 请求体,可以传入一个Bean对象,也可以传入HttpEntity对象,包装请求头
* @param responseType the type of the return value 响应对象的类型
* @param uriVariables the variables to expand the template 传入的map
* @return the converted object
* @see HttpEntity
*/
@Nullable
<T > T postForObject(String url, @Nullable Object request, Class < T > responseType,
Map < String, ?>uriVariables) throws RestClientException;
/**
* @param url the URL
* @param request the Object to be POSTed (may be {@code null})
* @param responseType the type of the return value
* @return the converted object
* @see HttpEntity
*/
@Nullable
<T > T postForObject(URI url, @Nullable Object request, Class < T > responseType) throws RestClientException;
还是利用上面的Controller
@Controller
public class UserController {
/**
*
* @return
*/
@GetMapping("/getUser")
@ResponseBody
public user getUser(@ProbeParam("username") String username,
@ProbeParam("age") Integer age) {
return new user(username,age);
}
@PostMapping("/postUser")
@ResponseBody
public user postUser(@RequestBody user user) {
return user;
}
}
测试类
@Test
void contextLoads1() {
user u = new user("小王", 19);
String url = "http://localhost:8080/postUser";
ResponseEntity<user> user = restTemplate.postForEntity(url,u,user.class);
System.out.println(user.getBody());
}
分析
一般我们请求的数据大多是json数据
这里我们用到了
谷歌的gson模块
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
那么如何使用呢非常简单
这是我们的json数据
{ "code": 0, "count": 1, "data": [ { "url": "https://bimg.bemfa.com/2e828657ec4eee3f32898b5dd8fc2d09-cc2e0e66e0a113667f2ca251d9087955-1637594745.jpg", "time": "2021-11-22 23:25:45" } ] }
先通过这个网站转化为javabean类
在线JSON字符串转Java实体类(JavaBean、Entity)-BeJSON.com
@lombok.Data
public class BafaCloudBean {
private int code;
private int count;
private List<Data> data;
}
@lombok.Data
public class Data {
private String url;
private Date time;
}
Service类
@Service
public class BafaCloud {
RestTemplate restTemplate = new RestTemplate();
public String getUrl() {
ResponseEntity<String> forEntity = restTemplate.getForEntity("https://images.bemfa.com/cloud/v1/get/?uid=60163f906afb4a6098d54db6452daaf8&topic=lz6644", String.class);
String body = forEntity.getBody();
Gson gson = new Gson();
BafaCloudBean bafaCloudBean = gson.fromJson(body, BafaCloudBean.class);
Data data = bafaCloudBean.getData().get(0);
String url = data.getUrl();
return url;
}
}
通过这个我们就可以获得https://bimg.bemfa.com/2e828657ec4eee3f32898b5dd8fc2d09-cc2e0e66e0a113667f2ca251d9087955-1637594745.jpg这个url
案例
下载图片
@Service
public class JPG {
@Autowired
BafaCloud bafaCloud;
public void downloadImage() throws IOException {
// String url = "https://bimg.bemfa.com//f2b45e980c04dfab837bc1ec06884eb9-b51a41f124ba4adb21abe6ff17f94f13-1642745065.jpg";
String url = bafaCloud.getUrl();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<byte[]> forEntity = restTemplate.getForEntity(url, byte[].class);
Files.write(Paths.get("C:\\Users\\86157\\Desktop\\htmltest\\3.jpg"), Objects.requireNonNull(forEntity.getBody(), "未获取到下载文件"));
}
}
分析百度AI
@Service
public class BaiduAi {
public static String body_analysis() {
// 请求url
String url = "https://aip.baidubce.com/rest/2.0/image-classify/v1/body_analysis";
try {
// 本地文件路径
String filePath = "C:\\Users\\86157\\Desktop\\htmltest\\1.jpg";
// String filePath = "abc\\5.jpg";
byte[] imgData = FileUtil.readFileByBytes(filePath);
String imgStr = Base64Util.encode(imgData);
String imgParam = URLEncoder.encode(imgStr, "UTF-8");
String param = "image=" + imgParam;
// 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。
String accessToken = "24.bff5411920269c821c4cccbafefcf523.2592000.1648000967.282335-25537608";
String result = HttpUtil.post(url, accessToken, param);
System.out.println(result);
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public boolean get(){
String json = BaiduAi.body_analysis();
Gson gson = new Gson();
JsonRootBean jsonRootBean = gson.fromJson(json, JsonRootBean.class);
List<Person_Info> person_info = jsonRootBean.getPerson_info();
// System.out.println(person_info.size());
Person_Info person_info1 = person_info.get(0);
body_parts body_parts = person_info1.getBody_parts();
Double scoreLeft = body_parts.getLeft_knee().getScore();
Double scoreRight = body_parts.getRight_knee().getScore();
if((scoreLeft - scoreRight) > 0.1 || (scoreLeft - scoreRight) < -0.1){
return false;
}
return true;
}
}
总结
本文主要介绍了restTemplate类的使用,首先介绍了需要引入的依赖,然后介绍了如何设置超时时间,接着就是介绍了restTemplate中get请求相关的方法和post请求相关的方法,以及这些方法如何调用。最后就是对常用的请求方法做了一个封装。希望对读者朋友们有所帮助。