一次性说清楚restTemplate如何使用1
一 、使用RestTemple分以下几步走:
**GET 请求** 1. header ===> HttpHeaders headers = new HttpHeaders(); 2. 请求参数 ===> 拼接到url后面(http://a.xxx/read?param1=参数1的值¶m2=参数2的值)**POST 请求** 3. header ==> HttpHeaders headers = new HttpHeaders(); 4. 请求参数queryparam ==> 拼接形式和get请求一样,也可以代码赋值/UriComponentsBuilder.fromHttpUrl 5. 请求体body的格式 3.1 json ===> 推荐用LinkedMultiValueMap 3.2 form表单 ===> 推荐用MultiValueMap==>MultiValueMap<String, String> formParams = new LinkedMultiValueMap<>(); (MultiValueMap 的泛型是 MultiValueMap<K, V>,底层存储结构是 Map<K, List<V>>,每个 key 对应一个值列表)总结:
- 确定请求是什么请求: post / get / put / delete
- 确定访问的api路径:
- 请求路径是否有请求参数需要拼接。
- 参数拼接是在末尾( http://localhost:8080/api/login?version=1.0) 还是在中间替换(http://localhost:8080/api/{version}/login) - 是否需要请求头,组装请求头
privatestaticStringtoken="ssdagfdsersdgh"//根据业务来定//请求头格式固定HttpHeadersheaders=newHttpHeaders();headers.add("apiKey","k0j9h7da6uhf4nd23s5l2gj");headers.add("Authorization","Bearer"+token);//请求头的特殊情况//post请求需要指定请求格式是json还是form,二者选一,get请求不需要指定//1.jsonheaders.setContentType(MediaType.APPLICATION_JSON);//2.formheaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);- 根据请求参数格式,组装参数。
//1.get请求拼接参数//1.1尾部拼接参数请求Stringurl="http://a.xxx/read?id=452&type=33";//多个参数//1.2动态拼接参数请求===> 使用restTemplate.exchange(),使用占位符 ===>构建响应体部分Stringurl="http://a.xxx/read?id=452&version={version}&type=33";//1.3 提前构建Stringurl=UriComponentsBuilder.fromHttpUrl("http://a.xxx/read").queryParam("id",452).queryParam("version",version)// 自动编码特殊字符.queryParam("type",33).toUriString();//2.post 请求拼接参数//2.1 post请求有请求参数,在请求体外部,类似get 请求构建Stringurl=UriComponentsBuilder.fromHttpUrl("http://a.xxx/read").queryParam("id",452).queryParam("version",version)// 自动编码特殊字符.queryParam("type",33).toUriString();//2.2 post请求体,格式json 必须搭配header headers.setContentType(MediaType.APPLICATION_JSON); 以下4种方式,四选一//2.2.1 使用实体类 构建JSON请求体(实体类)UserCreateDTOrequestBody=newUserCreateDTO();requestBody.setUsername("张三");requestBody.setAge(25);requestBody.setEmail("zhangsan@xxx.com");//2.2.2 使用JsonObject 初始化Jackson核心类ObjectMapperobjectMapper=newObjectMapper();ObjectNoderootNode=objectMapper.createObjectNode();rootNode.put("username","李四");// 简单字段rootNode.put("age",30);// 嵌套JSON对象ObjectNodeaddressNode=rootNode.putObject("address");addressNode.put("city","上海");addressNode.put("street","YY路");rootNode.put("email","lisi@xxx.com");//2.2.3 直接定义JSON字符串(可来自文件/配置/接口文档)StringjsonBody="{\n"+" \"username\": \"王五\",\n"+" \"age\": 28,\n"+" \"address\": {\n"+" \"city\": \"广州\",\n"+" \"street\": \"ZZ路\"\n"+" }\n"+"}";//2.2.4 使用万能map组装结构//2.3 post请求体,格式form表单 必须搭配header headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);以下3种方式,三选一//表单信息,需要放在MultiValueMap中,MultiValueMap相当于Map<String,List<String>>, 构建Form表单请求体(必须用LinkedMultiValueMap)// Form 表单的 MultiValueMap 唯一合法泛型是 MultiValueMap<String, String>,//其他泛型(如 <ParamDto>、<String, Object>)都会导致 RestTemplate 序列化失败。//2.3.1 使用MultiValueMap, LinkedMultiValueMapMultiValueMap<String,String>formData=newLinkedMultiValueMap<>();formData.add("username","zhangsan");// 单值参数formData.add("password","123456");formData.add("hobby","read");// 单Key多Value(复选框)formData.add("hobby","sports");//2.3.2 使用map 或者List<Map<String,String>Map<String,String>formData=newHashMap<>();formData.put("username","zhangsan");// 单值参数formData.put("password","123456");formData.put("hobby","read");//2.3.3 手动拼接Form表单字符串(键值对,&分隔,多值字段用同一Key重复)StringformBody="username=wangwu&password=111111&hobby=read&hobby=sports";//2.3.4 特殊情况:文件/图片等MultiValueMap<String,Object>body=newLinkedMultiValueMap<>();//调用add方法放入表单元素(表单名称:值)//②:文件对应的类型,需要是org.springframework.core.io.Resource类型的,常见的有[InputStreamResource,ByteArrayResource]body.add("file1",newFileSystemResource(filePath));//2.4请求体外部动态拼接参数请求===> 使用restTemplate.exchange() 使用占位符 ===>构建响应体部分- 构建一个完整的、可发送的 HTTP POST / GET请求实体
/* *一 基础封装 HttpEntity「请求体 + 请求头」的基础封装, *构建请求体,其中body的数据类型 和 HttpEntity<Map<String,Object>>中的一致,此处body的数据类型是Map<String,Object> *///1.请求体+请求头HttpEntity<Map<String,Object>>requestEntity=newHttpEntity<>(body,headers);// 2.可以只有请求头HttpEntity<Map<String,List<Map<String,Object>>>>rr=newHttpEntity<>(headers);/* *二 复杂封装 RequestEntity 「全量请求信息(体 + 头 + 方法 + URL)」的完整封装 ,用于exchange 方法四个参数全部生效, 2. 当用于(postForEntity/getForEntity || postForObject/getForObject时,method和封装的url将被忽略) *///1.全量封装,其中 URI.create("http://localhost:8080/api/batch")动态参数将无法修改到url,仅适合固定urlRequestEntity<Map<String,List<Map<String,Object>>>>requestEntity=newRequestEntity<>(body,// 请求体headers,// 请求头HttpMethod.POST,// 请求方法URI.create("http://localhost:8080/api/batch")// 请求URL);/* *三 使用实体类,组装参数body格式,HttpEntity与RequestEntity皆可以使用实体类声明,且更灵活 *///举例://实体类定义@DatapublicclassreqDto{privateStringid;privateStringobject;privateLongcreated;privateStringmodel;}//方法内部 HttpEntity<reqDto> 与RequestEntity<reqDto> 二选一reqDto requestBody=newreqDto();requestBody.setId("2");requestBody.setObject("25");HttpEntity<reqDto>ree=newHttpEntity<>(requestBody,headers);//同理RequestEntity<reqDto>requestEntity=newRequestEntity<>(requestBody,// 请求体headers,// 请求头HttpMethod.POST,// 请求方法URI.create("http://localhost:8080/api/batch")// 请求URL);- 构建响应体,发送请求
//1 基础封装下构建 (postForEntity / postForObject / GetForEntity / GetForObject)ResponseEntity<String>response=restTemplate.postForEntity("http://localhost:8080/api/login",requestEntity,String.class);//2 复杂封装下构建 ,其中Map<String, Object> 与 new ParameterizedTypeReference<Map<String, Object>>() 对应ResponseEntity<Map<String,Object>>responseEntity=restTemplate.exchange(requestEntity,newParameterizedTypeReference<Map<String,Object>>(){});Map<String,Object>result=responseEntity.getBody();2.1关于newParameterizedTypeReference<Map<String,Object>>(){}说明 标准写法:newParameterizedTypeReference<Map<String,Object>>(){}→ 大括号内空,无需填任何内容; 核心原因:ParameterizedTypeReference是抽象类但无抽象方法,空匿名内部类即可保留泛型信息;//2.2 推荐使用实体类 解析复杂响应(强类型,无需强制转换)ResponseEntity<UserResponse>response=restTemplate.exchange(requestEntity,newParameterizedTypeReference<UserResponse>(){}// 或直接传 UserResponse.class);// 取值:类型安全,无强制转换Integercode=response.getBody().getCode();StringuserName=response.getBody().getData().getUser().getName();//3 url 占位符情况Stringurl1="http://a.xxx/read?id={id}&version={version}&type={type}";ResponseEntity<String>response=restTemplate.postForEntity(url1,requestEntity,String.class,452,// 第一个占位符{id}"v1",// 第二个占位符{version}33// 第三个占位符{type});- 处理返回值
