21、GET/POST请求使用案例及注意事项

前言

在之前,我们分析了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 请求时就会报错。

&nbsp;
而且注解中的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 自动将集合类型的参数进行了解析拼接。
&nbsp;

5. 单个对象参数

当Get 请求参数超过三个时,就需要进行查询参数封装为对象。

上面说到当参数没有注解时,就会放入到请求体中,但是@RequestParam不支持直接传递对象类,这时就需要使用@SpringQueryMap注解,它可以将对象属性及值,转为键值对拼接在URL 后面。

    @GetMapping("/get")
    public Order getOrder(@SpringQueryMap Order order);

日志如下:
&nbsp;

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 会解析这个注解,标记为上传文件请求,还需要指定consumesMULTIPART_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);
    }