前言
在之前,我们分析了Feign 的基本原理及相关源码,实际在使用时还是需要额外注意Feign 调用接口的编写,需要安排其规定的格式,不然那很容易出错,下面就总结一下常用的GET/POST请求时需要注意的问题。
HTTP 请求方式
GET和POST是HTTP请求的两种基本方法,最直观的区别就是GET把参数包含在URL中,POST通过request body
传递参数。
从使用角度来说,他们的主要区别是:
- GET - 从指定的资源请求数据
- POST - 向指定的资源提交要被处理的数据
关于他们的具体了解,可以查看文档:HTTP 方法:GET 对比 POST
GET请求案例
在向服务器获取资源时,一般使用GET请求,比如查询数据。
1. 没有参数
没有参数就很简单,只需要使用@GetMapping
标识好请求路径就可以了。
@GetMapping("/noParam}")
public List<Order> noParam();
2. 多个基础类型参数
Get请求多个参数时,需要使用@RequestParam
或者@PathVariable
注解,这是因为在加载方法元数据的时候,如果该形参没有注解,默认会直接将其放在请求体中,这样GET 请求时就会报错。
而且注解中的value
属性必须指定绑定的参数名,不然会报错RequestParam.value() was empty on parameter 0
。
案例:
@GetMapping("insert")
public List<Order> insertOrder(@RequestParam("accountId") Long accountId, @RequestParam("commodityCode") String commodityCode, @RequestParam("count") Long count, @RequestParam("money") Long money);
@GetMapping("id/{id}")
public List<Order> id(@PathVariable("id") String id);
4. 集合数据参数
在Spring MVC使用GET 请求传递集合参数时,需要这么写:
@GetMapping("/noParam")
public List<Order> noParam(@RequestParam(list) List<Long> list);
在请求时,URL 集合值使用逗号隔开:
http://localhost:9000/order/noParam?list=22,33,44
在使用Feign 调用时,直接调用就可以了,可以从日志看到,Feign 自动将集合类型的参数进行了解析拼接。
5. 单个对象参数
当Get 请求参数超过三个时,就需要进行查询参数封装为对象。
上面说到当参数没有注解时,就会放入到请求体中,但是@RequestParam
不支持直接传递对象类,这时就需要使用@SpringQueryMap
注解,它可以将对象属性及值,转为键值对拼接在URL 后面。
@GetMapping("/get")
public Order getOrder(@SpringQueryMap Order order);
日志如下:
6. 多个对象参数
多个对象参数时,只需要使用多个@SpringQueryMap
即可:
@GetMapping("/get")
public Order getOrder(@SpringQueryMap Order order,@SpringQueryMap Account account);
多个对象参数加基本类型参数时,只需要添加对应的注解即可,需要注意实体类中的属性和这个基础类型参数名不能相同,不然拼接到URL中,两个同名参数传递过去就会覆盖了。
@GetMapping("/get")
public Order getOrder(@SpringQueryMap Order order,@RequestParam("accountId") Long accountId);
7. 下载文件
下载文件需要注意的是,应该返回二进制数据,还有GET 请求时,需要对URL进行编码,不然会报错编码不符合规范
,其他没什么区别。
@GetMapping("/download")
public ResponseEntity<byte[]> download(@RequestParam("filePath") String filePath) ;
POST 请求案例
POST 请求一般用于数据提交到服务器,比如添加数据,上传文件等。
1. 传递单个对象参数
默认形参没有添加注解时,就会放入到请求体中,这个时候会使用编码器,将对象编码,并以Content-Type: application/json
形式发送请求,所以只要注意在服务提供者中,添加@RequestBody
注解,将请求体转为对象即可。
@PostMapping("addOrder")
public Order addOrder(@RequestBody Order order);
2. 传递多个对象参数
如果像下面这样使用两个@RequestBody
,是会报错的:
@PostMapping("addOrderAnd")
public Order addOrderAnd(@RequestBody Order order,@RequestBody Account account);
这时候需要将两个对象封装在一个对象中,变成单个对象进行请求传递:
@PostMapping("addOrderAnd")
public Order addOrderAnd(@RequestBody AccountAndOrder accountAndOrder);
3. 上传文件
上传文件时,需要注意的是需要使用@RequestPart
注解,Fiegn 会解析这个注解,标记为上传文件请求,还需要指定consumes
为MULTIPART_FORM_DATA_VALUE
,编码器会根据这个配置,将文件对象进行编码。
@PostMapping(value = "/spring/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE,produces =MediaType.APPLICATION_JSON_VALUE )
@ResponseBody
public Object springUpload(@RequestPart("file") MultipartFile file) ;
在调用方,上传文件时,则需要将文件对象转为MultipartFile
。
一般不采用Feign 去上传文件,这种方式请求链路比较长,性能很低,一般都是前端直接上传到文件服务器,然后再告诉后台上传了哪个文件。
@GetMapping("/insertOrder")
public Object insertOrder() {
File file = new File("E:\\javaPro\\prime-code-generator\\pom.xml");
MultipartFile multipartFile =fileToMultipartFile(file);
Object o = orderFeign.springUpload(multipartFile);
return o;
}
public static MultipartFile fileToMultipartFile(File file) {
String fieldName = "file";
FileItemFactory factory = new DiskFileItemFactory(16, null);
FileItem item = factory.createItem(fieldName, "multipart/form-data", true, file.getName());
int bytesRead = 0;
byte[] buffer = new byte[8192];
try {
FileInputStream fis = new FileInputStream(file);
OutputStream os = item.getOutputStream();
while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
return new CommonsMultipartFile(item);
}