什么是 RestTemplate ?
传统情况下在 java 代码里访问 restful 服务,一般使用 Apache 的 HttpClient。不过此种方法使用起来太过繁琐。Spring 提供了一种简单便捷的模板类来进行操作,这就是 RestTemplate。
内置发送 get post delete 等请求的方法,在 SpringBoot 中只要导入 spring-boot-starter-web 的依赖可以直接使用。
为什么说是简单便捷呢?我们来看以下两种实现方式:
/** * @param url * @param param * @param headers * @param connectTimeout milliseconds * @param readTimeout milliseconds * @return */public static String get(String url, String param, Map<String, String> headers, int connectTimeout, int readTimeout) { BufferedReader in = null; StringBuilder builder = new StringBuilder(); try { String urlNameString = url; if (param != null) { urlNameString += "?" + param; } URL realUrl = new URL(urlNameString); // 打开和URL之间的连接 HttpURLConnection conn = (HttpURLConnection)realUrl.openConnection(); // 设置通用的请求属性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("user-agent", USER_AGENT);
if (connectTimeout > 0) { conn.setConnectTimeout(connectTimeout); } if (readTimeout > 0) { conn.setReadTimeout(readTimeout); } if (headers != null) { for (Entry<String, String> entry: headers.entrySet()) { conn.setRequestProperty(entry.getKey(), entry.getValue()); } } conn.connect(); if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { // 定义 BufferedReader输入流来读取URL的响应 in = new BufferedReader(new InputStreamReader( conn.getInputStream(), DEFAULT_CHARSET)); String line; while ((line = in.readLine()) != null) { builder.append(line).append("\n"); } } } catch (Exception e) { LOGGER.error("HttpUtil.get error.", e); } // 使用finally块来关闭输入流 finally { try { if (in != null) { in.close(); } } catch (Exception e2) { LOGGER.error("HttpUtil.get finally error.", e2); } } return builder.toString();}
复制代码
使用 RestTempalte
String result = restTemplate.getForObject(url,String.class);
复制代码
快速开始
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency>
复制代码
第一步:配置 RestTemplate
/** * RestTemplate配置 */@Configurationpublic class RestTemplateConfig {
@Bean public RestTemplate restTemplate(ClientHttpRequestFactory factory) { return new RestTemplate(factory); }
@Bean public ClientHttpRequestFactory simpleClientHttpRequestFactory() { SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); //超时设置 factory.setReadTimeout(6000); factory.setConnectTimeout(10000); return factory; }}
复制代码
第二步:使用 RestTemplate 的 Api 发送请求
/** * 测试get请求 */@Testpublic void test1(){ /** * getForObject * * 参数1 要请求的地址的url 必填项 * 参数2 响应数据的类型 是String 还是 Map等 必填项 * 参数3 请求携带参数 选填 * * getForObject 方法的返回值就是 被调用接口响应的数据 */ String result = restTemplate.getForObject("http://apis.juhe.cn/mobile/get?phone=13429667914&key=1cca71876dc0669109ed3f9501a85e8a",String.class); System.out.println(result);}
复制代码
Get 请求的 API
getForObject API:参数 1 url 地址,参数 2 响应数据类型 参数 3 请求携带参数 返回值类型为 String。
getForEntity API:参数 1 url 地址,参数 2 响应数据类型 参数 3 请求携带参数 返回值类型为 ResponseEntity。
Get 请求传递参数可以是以占位符的方式,或者是通过 map 传参。
/** * 测试get请求 */@Testpublic void test2(){
String result = restTemplate.getForObject("http://apis.juhe.cn/mobile/get?phone=13429667914&key=1cca71876dc0669109ed3f9501a85e8a", String.class);
System.out.println("getForObject返回值:"+result);
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://apis.juhe.cn/mobile/get?phone=13429667914&key=1cca71876dc0669109ed3f9501a85e8a", String.class);
System.out.println("通过ResponseEntity获取的响应状态码:"+responseEntity.getStatusCode());
System.out.println("通过ResponseEntity获取的响应数据:"+responseEntity.getBody());
/** * 通过Map传参 */ Map map= new HashMap(); map.put("phone","13429667914"); map.put("key","1cca71876dc0669109ed3f9501a85e8a"); String resultId = restTemplate.getForObject("http://apis.juhe.cn/mobile/get?phone={phone}&key={key}", String.class,map); System.out.println("map传参" + resultId);
}
复制代码
可以看到如下效果:
getForObject返回值:{"resultcode":"200","reason":"Return Successd!","result":{"province":"浙江","city":"杭州","areacode":"0571","zip":"310000","company":"移动","card":""},"error_code":0}通过ResponseEntity获取的响应状态码:200 OK通过ResponseEntity获取的响应数据:{"resultcode":"200","reason":"Return Successd!","result":{"province":"浙江","city":"杭州","areacode":"0571","zip":"310000","company":"移动","card":""},"error_code":0}map传参{"resultcode":"200","reason":"Return Successd!","result":{"province":"浙江","city":"杭州","areacode":"0571","zip":"310000","company":"移动","card":""},"error_code":0}
复制代码
Post 请求的 API
postForObject API:
参数 1 url 地址
参数 2 通过 LinkedMultiValueMap 对象封装请求参数
参数 3 响应数据类型返回值类型为 String
postForLocation API:
参数 1 url 地址
参数 2 通过 LinkedMultiValueMap 对象封装请求参数
响应值:获取返回的 URI
postForLocation 使用场景:在登录或注册完成,跳转到别的页面时,并获取要跳转的 URI。
**注意:**postForLocation 方法返回的 URI 实际上是指响应头的 Location 字段,所以,请求的接口的响应头必须要有 Location 字段(即请求的接口实际上是一个重定向的接口),否则返回值为 null。
package com.example.restdemo.controller;
import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;
@Controller@RequestMapping("/test")public class HelloController { /** * 测试 postForLocation */ @PostMapping("/postLocation") public String testPostForLocation(String username,String password){ System.out.println(username); return "redirect:/index.html"; }}
复制代码
测试 Post 请求
/** * 测试Post请求 */@Testpublic void test3(){ LinkedMultiValueMap<String, String> request = new LinkedMultiValueMap<>(); request.set("key","9363eb48d9bd745e7627322e2ae78099"); request.set("date","2021-10-22");
String result = restTemplate.postForObject("http://v.juhe.cn/laohuangli/d",request,String.class); System.out.println("通过LinkedMultiValueMap对象封装请求参数"); System.out.println(result);
Map map = new HashMap(); map.put("key","9363eb48d9bd745e7627322e2ae78099"); map.put("date","2021-10-22");
String result2 = restTemplate.postForObject("http://v.juhe.cn/laohuangli/d?key={key}&date={date}",request, String.class,map); System.out.println("通过参数拼接的方式:"); System.out.println(result2);
LinkedMultiValueMap<String, String> req = new LinkedMultiValueMap<>(); req.set("username","小明"); req.set("password","decs3465523"); URI uri = restTemplate.postForLocation("http://localhost:8085/test/postLocation", req); System.out.println("postForLocation请求到的地址为:"+uri);}
复制代码
执行效果如下:
通过LinkedMultiValueMap对象封装请求参数{"reason":"successed","result":{"id":"4190","yangli":"2021-10-22","yinli":"辛丑(牛)年九月十七","wuxing":"杨柳木 收执位","chongsha":"冲牛(丁丑)煞西","baiji":"癸不词讼理弱敌强 未不服药毒气入肠","jishen":"天恩 母仓 四相 不将 玉宇","yi":"祭祀 作灶 纳财 捕捉 畋猎 馀事勿取","xiongshen":"河魁 月刑 五虚 朱雀 触水龙","ji":"动土 破土 开市 安葬"},"error_code":0}通过参数拼接的方式:{"reason":"successed","result":{"id":"4190","yangli":"2021-10-22","yinli":"辛丑(牛)年九月十七","wuxing":"杨柳木 收执位","chongsha":"冲牛(丁丑)煞西","baiji":"癸不词讼理弱敌强 未不服药毒气入肠","jishen":"天恩 母仓 四相 不将 玉宇","yi":"祭祀 作灶 纳财 捕捉 畋猎 馀事勿取","xiongshen":"河魁 月刑 五虚 朱雀 触水龙","ji":"动土 破土 开市 安葬"},"error_code":0}postForLocation请求到的地址为:http://localhost:8085/index.html
复制代码
总结
本文主要向大家介绍了 RestTemplate 这样一个 HTTP 请求工具类的常见用法,并没有涉及到源码,其实内部源码很多很深,包括和解析 url 模板,绑定参数的 UriBuilderFactory UriTemplateHandler 等等,建议跟踪源码跑一遍会更加理解 restTemplate。这里就简单提下。
更多学习资料戳下方!!!
https://qrcode.ceba.ceshiren.com/link?name=article&project_id=qrcode&from=infoQ×tamp=1662366626&author=xueqi
评论