RestTemplate使用详解

文章目录

  • 简介
  • 基本操作
  • uri参数
  • 传递json参数与header参数设置
  • form-data
  • exchange复杂类型处理
  • 上传文件
  • 下载文件

简介

对于http请求之前一直用apache的httpclient,已经习惯了,特别是使用fluent之后,更加方便了。

所以一直没有怎么太过关注RestTemplate,最近才发现在Spring环境中使用RestTemplate还是很方便。

特别是处理带有多重泛型的复杂类型时,httpclient需要一层一层的自己处理,RestTemplate只需要指定类型参数ParameterizedTypeReference就能完美解决。

RestTemplate默认的参数和文件名编码也很方便,基本不用额外处理,就不会有乱码问题。

另外,RestTemplate默认配置就能解决绝大部分场景,所以使用直接new就可以,没有过多配置。

所以,当你下一次在Spring环境中需要使用http请求时,可以考虑一下使用RestTemplate。

基本操作

  1. xxxForObject与xxxForEntity的区别:xxxForObject得到的结果是HTTP返回的body部分,xxxForEntity是整个HTTP返回部分,包含状态码等信息
  2. getForXXX与postForXXX:get请求没有body部分,post请求可以设置body部分
  3. responseType指定的是返回body部分的数据类型,对于复杂类型还需要指定泛型参数

服务端接口:

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/rt-template")
public class RestTemplateController {@RequestMapping("/base")public String base() {return "base执行";}@PostMapping("/param")public String param(@RequestParam("id") Long id,@RequestParam("name") String name) {System.out.println("获取到参数id:" + id + " name:" + name);return id + "_" + name;}
}

RestTemplate请求:

 @Test
public void base() {RestTemplate restTemplate = new RestTemplate();String url = "http://localhost:8087/rt-template/base";String result = restTemplate.getForObject(url, String.class);System.out.println(result);result = restTemplate.postForObject(url, null, String.class);System.out.println(result);ResponseEntity<String> entity = restTemplate.getForEntity(url, String.class);System.out.println(entity.getStatusCode() + " " + entity.getBody());entity = restTemplate.postForEntity(url, null, String.class);System.out.println(entity.getStatusCode() + " " + entity.getBody());
}

uri参数

RestTemplate有个map参数可以设置url的参数

例如:http://localhost:8087/rt-template/base?id=123&name=tim

id和name参数可以通过占位符设置,RestTemplate提供了2种方式:

  1. map,根据名字替换
  2. 可变参数object,根据顺序替换

url参数主要是针对get请求的传参,不过在RestTemplate中post请求也可以使用该方式。

@Test
public void paramMap() {RestTemplate restTemplate = new RestTemplate();String url = "http://localhost:8087/rt-template/base?id={id}&name={name}";Map<String, Object> uriVariables = new HashMap<>();uriVariables.put("id", "123456");uriVariables.put("name", "tim");String result = restTemplate.getForObject(url, String.class, uriVariables);
//        String result = restTemplate.postForObject(url, null,String.class, uriVariables);System.out.println(result);
}@Test
public void paramObject() {RestTemplate restTemplate = new RestTemplate();String url = "http://localhost:8087/rt-template/base?id={id}&name={name}";String result = restTemplate.getForObject(url, String.class, 123456, "tim");
//        String result = restTemplate.postForObject(url, null, String.class, 123456, "tim");System.out.println(result);
}

传递json参数与header参数设置

在接口中我们使用最多的还是json参数,例如后端使用@RequestBody。

@RequestMapping("/request-body")
public String requestBody(@RequestBody UserTO user){System.out.println(user);return user.toString();
}
@Test
public void postJson() {String url = "http://localhost:8087/rt-template/request-body";RestTemplate restTemplate = new RestTemplate();HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);String json = "{\"name\":\"tim\"}";HttpEntity<String> request = new HttpEntity<>(json, headers);restTemplate.postForEntity(url, request, String.class);
}

对于@RequestBody有几点需要说明:

  1. 请求必须是post的json数据
  2. @RequestBody可以和@RequestParam一起使用,请求使用post,body为json,@RequestParam获取uri中的参数

@RequestBody从参数可以非常灵活,只要请求是post的json都能正常解析:

  1. @RequestBody String uid
  2. @RequestBody String[] ids
  3. @RequestBody List<String> ids
  4. List<Map<String,Object>> list
  5. @RequestBody User user
  6. @RequestBody List<User> userList

对于 @RequestBody请求不是json时,最常见的错误是:
Content-Type ‘application/x-www-form-urlencoded;charset=UTF-8’ is not supported

基本可以确定是请求端使用了默认的Content-Type,而不是json。

form-data

RestTemplate的post可以直接设置一个map来传递参数

@Test
public void formData() {String url = "http://localhost:8087/rt-template/request-body";RestTemplate restTemplate = new RestTemplate();MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();paramMap.add("name", "tim");String result = restTemplate.postForObject(url, paramMap, String.class);System.out.println(result);
}

上面这个请求默认的Content-Type 是’application/x-www-form-urlencoded;charset=UTF-8’

在服务端,可以使用@RequestParam(“name”),或者直接用一个对象来获取参数:

@RequestMapping("/param")
public String param(@RequestParam("name") String name) {System.out.println("获取到参数name:" + name);return name;
}@RequestMapping("/form-data")
public String normalUser(UserTO user){System.out.println(user);return user.toString();
}

当然,也可以把参数封装在HttpEntity中:

@Test
public void formDataEntity() {String url = "http://localhost:8087/rt-template/form-data";RestTemplate restTemplate = new RestTemplate();MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();paramMap.add("name", "tim");HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(paramMap, headers);String user = restTemplate.postForObject(url, httpEntity, String.class);System.out.println(user);
}

exchange复杂类型处理

其实,前面介绍的postxxx、getxxx、xxxForObject、xxxForEntity最终都是调用了exchange。

我们当然也可以直接调用exchange方法,不过我们很少直接调用,因为直接使用exchange稍微复杂一点。

我们什么时候需要exchange呢?

最常见的就是处理复杂类型泛型的时候,因为exchange行有一个ParameterizedTypeReference responseType参数。

前面我们已经感受到了RestTemplate最方便的地方就是能自动帮我们处理返回结果,包装为类。

当处理复杂类型的时候就需要ParameterizedTypeReference。

例如,像下面这个返回Result<List>:

@RequestMapping("/get-users")
public Result<List<UserTO>> getUsers(){LinkedList<UserTO> list = new LinkedList<>();list.add(UserTO.builder().id(1).name("tim").age(18).build());list.add(UserTO.builder().id(2).name("allen").age(20).build());return getSuccess(list);
}public static <T> Result<T> getSuccess(T data){return Result.<T>builder().success(true).data(data).message("执行成功").build();
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserTO {private Integer id;private String name;private Integer age;private Date birthday;}
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Result <T> {/*** 编码区分消息类型*/private Integer code;/*** 是否执行成功*/private Boolean success;/*** 执行结果消息*/private String message;/*** 数据*/private T data;
}

该我们ParameterizedTypeReference登场了

@Test
public void getUsers() {RestTemplate restTemplate = new RestTemplate();String url = "http://localhost:8087/rt-template/get-users";ParameterizedTypeReference<Result<List<UserTO>>> type = new ParameterizedTypeReference<>() {};HttpHeaders headers = new HttpHeaders();HttpEntity<?> httpEntity = new HttpEntity<>(headers);ResponseEntity<Result<List<UserTO>>> entity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, type);Result<List<UserTO>> result = entity.getBody();System.out.println(result);
}

重点:ParameterizedTypeReference<Result<List>> type = new ParameterizedTypeReference<>() {};

只需要把我们返回参数的泛型具化就可以了。

上传文件

@PostMapping("/upload")
public Result<?> upload(@RequestParam("file") MultipartFile uploadFile,@RequestParam("id") Long id) {String oldName = uploadFile.getOriginalFilename();try {Path dest = Paths.get("F:\\pic", String.valueOf(id), oldName);File file = dest.toFile();if (!file.exists()) {File parentFile = file.getParentFile();if (!parentFile.exists()) {if (!parentFile.mkdirs()) {ResultHelper.getFailResult("创建目录失败");}}if (!file.createNewFile()) {ResultHelper.getFailResult("创建文件失败");}}uploadFile.transferTo(dest);} catch (Exception e) {log.error(e.getMessage(), e);ResultHelper.getFailResult("上传文件失败");}return ResultHelper.getDefaultSuccess();
}

最重要的是设置content type为MULTIPART_FORM_DATA

@Test
public void upload() {String filePath = "F:\\index.html";String url = "http://localhost:8087/rt-template/upload";HttpHeaders headers = new HttpHeaders();// multipart/form-dataheaders.setContentType(MediaType.MULTIPART_FORM_DATA);headers.addIfAbsent("token","123");MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();param.add("file", new FileSystemResource(new File(filePath)));param.add("id", "123");HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(param, headers);RestTemplate restTemplate = new RestTemplate();Result<?> result = restTemplate.postForObject(url, request, Result.class);System.out.println(result);
}

下载文件

@GetMapping("/download/{id}/{name}")
public void download(@PathVariable(value = "id") Long id,@PathVariable(value = "name") String name,HttpServletRequest request,HttpServletResponse response) throws Exception {Path path = Paths.get("F:\\pic", String.valueOf(id), name);File file = path.toFile();if (file.exists()) {FileInputStream fis = new FileInputStream(file);response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);response.setHeader("content-disposition","attachment;fileName=" + URLEncoder.encode(name, StandardCharsets.UTF_8));OutputStream os = response.getOutputStream();FileCopyUtils.copy(fis, os);}
}

指定body类型为byte数组就可以:

@Test
public void downloadFile() throws IOException {Long id = 123L;String fileName = "index.html";String url = "http://localhost:8087/rt-template/download/{1}/{2}";ResponseEntity<byte[]> entity = restTemplate.getForEntity(url, byte[].class, id, fileName);if (entity.getStatusCode().is2xxSuccessful()) {byte[] body = entity.getBody();if (body == null || body.length == 0) {throw new RuntimeException("文件内容为空");}FileCopyUtils.copy(body, new FileOutputStream("F:\\tmp\\" + fileName));} else {System.out.println("请求异常:" + entity.getStatusCode());}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/19249.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C 语言实例 - 表格形式输出数据

将 1~100 的数据以 10x10 矩阵格式输出。 #include <stdio.h>int main() {int i, j, count;for(i 1; i < 10; i) {for(j i; j <100; j 10 )printf(" %3d", j);printf("\n");}return 0; }运行结果&#xff1a; 1 11 21 31 41 51 61 …

数据库内核-基础知识

常用索引&#xff1a; 介绍&#xff1a; 哈希表&#xff1a;数组加链表&#xff0c;取字段Hash值做Key,B树&#xff1a; 树形结构&#xff0c;排序后N分查找B树&#xff1a; 树形结构&#xff0c;仅叶子结点存放数据跳表索引&#xff1a;链表链表&#xff0c;相当于一级链…

【YashanDB知识库】kettle从DM8的number类型同步到YashanDB的varchar类型,存入是科学计数法形式的数据

【标题】kettle从DM8的number类型同步到YashanDB的varchar类型&#xff0c;存入是科学计数法形式的数据 【问题分类】数据导入导出 【关键字】数据同步&#xff0c;number类型&#xff0c;科学计数法 【问题描述】客户查询不到准确数据&#xff0c;只看到科学计数法展示的字…

【FISCO BCOS 3.0】一、新版本搭链介绍

目录 一、区块链种类的变化 二、搭链演示 1.单群组区块链&#xff08;Air版本&#xff09; 2.多群组区块链&#xff08;Pro版本&#xff09; 3.可扩展区块链&#xff08;Max版本&#xff09; FISCO BCOS的发展速度如日中天&#xff0c;对于稳定的2.0版本而言&#xff0c;偶…

058.最后一个单词的长度

题意 给你一个字符串 s&#xff0c;由若干单词组成&#xff0c;单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。 难度 简单 示例 1&#xff1a; 输入&#xff1a;s "Hello World" 输…

Linux通过 SSH 使用 rsync 进行文件传输

目录 目的整体思路ssh建立连接A服务器上的操作输入 ssh-keygen 生成密钥对查看公钥 B服务器上的操作设置公钥认证 A服务器上的操作使用SSH登录进行测试 同步数据知识拓展SSH&#xff08;Secure Shell&#xff09;rsync&#xff08;Remote Sync&#xff09; 目的 使用SSH&#…

JavaWeb基础(一)-IO操作

Java I/O工作机制&#xff1a; 注&#xff1a;简要笔记&#xff0c;示例代码可能较少&#xff0c;甚至没有。 1、Java 的 I/O 类库的基本架构。 ​ Java 的 I/O 操作类在包 java.io 下&#xff0c;大概有将近80个类&#xff0c;这些类大概可以分为如下四组。 基于字节操作的…

UE5中绘制饼状图

饼状图 使用UE绘制前提完整的创建过程123456678 附录代码.h代码.c代码 使用UE绘制前提 EPIC Game使用的版本是Unreal Engine 5.0.3。 没有使用其他额外的插件&#xff0c;使用的是C和Ui共同绘制。 C编译器使用的是VS2019。 完整的创建过程 1 首先在UE中随意一种项目的白色。…

服务器端请求伪造--SSRF

SSRF 简介 ##SSRF定义 SSRF(Server-Side Request Forgery:服务器端请求伪造)是一种由 攻击者构造形成&#xff0c;由服务端发起请求 的一个安全漏洞。一般情况下&#xff0c;SSRF攻击的目标是从 外网无法访问的内部系统&#xff08;正是因为它是由服务端发起的&#xff0c;所…

一个小技巧轻松提升量化精度!IntactKV:保持关键词元无损的大语言模型量化方法

目录 摘要关键词元&#xff08;Pivot Tokens&#xff09;方法概述实验验证1. 权重量化2. KV Cache 量化3. 权重和激活值量化 参考文献 本文介绍我们针对大语言模型量化的工作 IntactKV&#xff0c;可以作为插件有效提升 GPTQ、AWQ、QuaRot 等现有主流量化方法效果。论文作者来自…

海外社媒账号如何运营安全稳定?

由于设备与网络原因&#xff0c;通常一个海外社媒账号尤其是多账号的稳定性都有一定限制&#xff0c;错误的操作或者网络都可能使得账号被封&#xff0c;前功尽弃。本文将为大家讲解如何通过IP代理来维持账号稳定与安全&#xff0c;助力海外社媒矩阵的搭建。 一、社媒账号关联…

C++ ─── string的完整模拟实现

本博客实现了string的常见接口实现 下面是用到的一些函数&#xff0c;供大家回顾复习 string.h #define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include<iostream> #include<assert.h> using namespace std;namespace bit {class string{public:typedef char*…

深入理解计算机系统 家庭作业4.52

练习题4.3 p.254 \sim\seq\seq-full.hcl文件内已经说的很清楚了哪些不能更改,哪些是题目要求更改的控制逻辑块. 依据家庭作业4.51的答案,在seq-full.hcl文件内更改对应的HCL描述即可 以下答案注释了#changed的就是更改部分 #/* $begin seq-all-hcl */ ######################…

Redis 中 Set 数据结构详解

用法 Redis 中的 Set 是一个无序&#xff0c;不重复集合&#xff08;里面的元素为字符串&#xff09;&#xff0c;支持常用的集合操作。 常见命令 1. 增 添加一个或多个元素到 set 中 SADD key member [ member ... ] 返回值&#xff1a; 添加成功的元素个数 将一个元素移到…

数据结构(1):线性表

1 线性表的顺序实现 创建的新项目是cpp类型哦&#xff01; 1.1 初始化 1.1.1 静态分配 #define _CRT_SECURE_NO_WARNINGS#include <stdio.h> #define MaxSize 10 //定义顺序表的长度 typedef struct {int data[MaxSize];//用静态的数组存放元素&#xff01;int lengt…

在Java中实现多线程之间的通信

一、技术难点 在Java中实现多线程之间的通信是一个复杂但重要的任务&#xff0c;它涉及到线程同步、数据共享和线程间协作等多个方面。以下是实现多线程通信时可能遇到的一些技术难点&#xff1a; 线程同步&#xff1a;多线程环境下&#xff0c;多个线程可能同时访问和修改共享…

【UE5.1 角色练习】08-物体抬升、抛出技能 - part2

目录 前言 效果 步骤 一、让物体缓慢的飞向手掌 二、向着鼠标方向发射物体 前言 在上一篇&#xff08;【UE5.1 角色练习】08-物体抬升、抛出技能 - part1&#xff09;的基础上继续完成角色将物体吸向手掌&#xff0c;然后通过鼠标点击的方向来发射物体的功能。 效果 步骤…

STEP 7-MicroWIN SMART

“STEP 7-MicroWIN SMART”是西门子公司为其S7-200 SMART系列PLC&#xff08;可编程逻辑控制器&#xff09;设计的编程软件。这款软件以其直观的操作界面和强大的功能&#xff0c;在工业自动化领域被广泛应用&#xff0c;特别是在小型自动化系统的开发和控制中表现出色。以下是…

滑动窗口模板(Java)

题目描述 有一个长为 &#x1d45b; 的序列 &#x1d44e;&#xff0c;以及一个大小为 &#x1d458; 的窗口。现在这个从左边开始向右滑动&#xff0c;每次滑动一个单位&#xff0c;求出每次滑动后窗口中的最大值和最小值。 例如&#xff0c;对于序列 [1,3,−1,−3,5,3,6,7] …

【Linux 网络编程】网络的基础知识详解!

文章目录 1. 计算机网络背景2. 认识 "协议" 1. 计算机网络背景 网络互联: 多台计算机连接在一起, 完成数据共享; &#x1f34e;局域网&#xff08;LAN----Local Area Network&#xff09;: 计算机数量更多了, 通过交换机和路由器连接。 &#x1f34e; 广域网WAN: 将…