前言
在某种情况下,后台服务可能需要访问另一台服务器的REST接口。以前估计不少人用的都是HttpRequest类来着,结合Paser解析JSON格式的Body。现在Spring Boot的Web Starter就自带了RestTemplate,直接用它的就好了。最好不要再往项目里导新的依赖。这里做了点整理,分享出来。发
简单的请求
一、GET请求
案例如下:
RestTemplate restTemplate = new RestTemplate(); ResponseEntityresponseEntity = restTemplate.getForEntity(url, CustomClass.class);
CustomClass response = responseEntity.getBody();
(1)getForEntity 顾名思义就是发送GET请求,并得到一个对象
(2)这里的URL应该是完整的,即应该是这样的格式:"http://域名:端口/xxx/yyy"
(3)CustomClass是你自己定义的类,tempalte会将请求响应的JSON格式的body解析成CustomClass。
(4)ResponseEntity是请求响应的结果,可以获取响应码,以及最重要的响应Body
注意:由于RestTemplate是使用Jackson来进行映射的,而Jackson本质上是用setter/getter来实现的。其中JSON字符串转对象需要setter,对象转JSON字符串需要getter。这里是字符转对象,所以你定义的类必须有setter。
二、POST请求
案例如下:
... restTemplate.postForEntity(url, ParamObject, Response.class); ...
基本操作同上,不过postForEntity的第二个参数是请求对象,底层会将其转为JSON字符存入请求Body中
传输form/data
一、普通的表单请求
//用MultiValueMap存储表单数据 MultiValueMapparam = new LinkedMultiValueMap<>(); param.add("param1","1232"); param.add("param2","12312"); //用HttpEntity进行包装 HttpEntity > httpEntity = new HttpEntity<>(param); //发送请求 ResponseEntity responseEntity = restTemplate.postForEntity(url, httpEntity, Response.class);
这就相对于提交了一个普通的表单
二、带文件的表单请求
有时候我们需要把本地文件通过Post请求发送给另一个应用,可以这么做。而对方接收的时候就用@RequestParam("file") MultipartFile来接收。
MultiValueMapparam = new LinkedMultiValueMap<>(); //FileSystemResource是一个包装类,好统一处理 param.add("file", new FileSystemResource(new File(filePath))); ...
(1)网页上通过表单上传文件,默认标识符就是"file"
(2)经过FileSystemResource包装后,RestTemplate会利用File对象的InputStream从磁盘中读入文件内容,并写入HTTP请求body中。
三、带文件的表单请求——文件从客户端而来(MultipartFile)
//file由客户端上传过来,直接转发,不经过磁盘 @PostMapping("/some-url") public SomeResponse function(@RequestParam("file") MultipartFile file, ...) { ... MultiValueMapparam = new LinkedMultiValueMap(); param.add("file", new MultipartFileResource(file)); ... }
MultipartFileResource类似FileSystemResource
四、带文件的表单请求——本地没有文件,只有文件的文本内容
可能存在这种情况,即你本地保存的是文本文件的内容,(如保存在数据库中,用text存储。因为这样比较方便管理)而另一个服务器需要以文件的形式接收你的文本内容。即它会用一个MultipartFile来接收。这时候首先你从数据库中把文本内容读出来,传统数据库存储位置就在磁盘,这已经是不小的开销了,难道你还要把文本以文件的形式写到磁盘再传输吗?这种操作是非常愚蠢的。既然我们已经知道请求本质上传递的是字节数组,那何不就仿造FileSystemResource写一个适配类呢?
//该类与FileSystemResouce同父类 public class TextFeignFileResource extends AbstractResource { //文本的字节信息 private byte[] bytes; //当前读到的位置 private int index = 0; //文件名 private String filename; //构造函数需要两个参数,一个是文件名,随便取 //另一个就是文本内容,String类型足够存文本的 public TextFeignECLFileResource(String filename, String content) { this.filename = filename; this.bytes = content.getBytes(); } @Override public String getDescription() { return null; } @Override public InputStream getInputStream() throws IOException { return new InputStream() { //注意这里的返回值int是一个八位的字节的数值表示 //并不是读取到的字节个数 @Override public int read() throws IOException { if (index >= bytes.length) return -1; //返回-1是标准,表示读取结束 return bytes[index++]; } }; } @Override public boolean exists() { return true; } @Override public boolean isFile() { return true; } @Override public boolean isReadable() { return true; } @Override public long contentLength() throws IOException { return bytes.length; } @Override public String getFilename() { return filename; } }
使用方式:
MultiValueMapparam = new LinkedMultiValueMap<>(); param.add("file", new TextFeignFileResource("test.txt", "hello world"));
注意:这里之所以能这么做是因为普通的文本文件没有文件头等额外的描述信息
19-05-16补充
使用Jodd的Http API会更方便一点。