使用到的工具:Interlij IDEA、Postman
一、SpringMVC
在使用spring-cloud的过程中,server端提供 api接口的时候 接受的请求类型有(POST、GET、PUT 等)
1、关于提交参数的 http Cotent-Type:
application/x-www-form-urlencoded: 表单提交,浏览器url等 都是通过这种方式
application/json:ajax 提交,指定Content-Type
2、参数注解的使用
SpringMVC中常用的请求参数注解有(@RequestParam, @RequestBody, @PathVariable)等。
2.1 @RequestParam
@RestController
public class TestController {
@RequestMapping(value = "/hello") // <1>
public String hello (String name) { // <2>
return "hello " + name;
}
}
name 被默认当做 @RequestParam。 形参String name
由框架使用字节码技术获取name这个名称,自动检测请求参数中key值为name的参数,也可以使用@RequestParam(“name”)覆盖变量本身的名称。当我们在url中携带name参数或者form表单中携带name参数时,会被获取到。
2.2 @PathVariable
@RestController
public class BookController {
@RequestMapping(value = "/hello/{name}") // <1>
public String hello(@PathVariable("name") String name) { // <2>
return "hello " + name;
}
}
name 参数被指定在url 的 /hello/{name} 后边,随着请求。@PathVariable 会获取到这个参数。
以上方式,在url 中都能直接指定参数,在 controller中能获取到参数。这两种方式比较适用于单个参数或者少量的参数提交,如果参数较多 建议使用对象封装。
2.3 @RequestBody
@RestController
public class BookController {
@RequestMapping(value = "/hello") // <1>
public String hello(@RequestBody String name) { // <2>
return "hello " + name;
}
}
这种方式,请求时需要将参数放在请求的body中,在 headers中指定 Content-Type:application/json
body 中的参数必须符合 json格式,Controller 才能获取到
二、Feign 中的接口写法
在 FeignClient 的接口中,如果入参不指定参数注解(@RequestParam,@RequestBody,@PathVariable)其中一种。Feign会默认为 @RequestBody 且 Content-Type为:application/json
当参数注解为 @RequestBody 时,Feign 会将参数封装到请求的body中 类似于上图。
body中存在参数,这时候会通过 post 提交,无论你在RequestMapping 指定的为何种提交方式。
如果不加默认的注解,Feign则会对参数默认加上@RequestBody注解,而RequestBody一定是包含在请求体中的,GET方式无法包含。所以上述两个现象得到了解释。Feign在GET请求包含RequestBody时强制转成了POST请求,而不是报错
而在controller的方法上 如果不用 @RequestBody 注解入参,将获取不到参数。
指定请求参数的类型与请求方式,上述问题的出现实际上是由于在没有理清楚Feign内部机制的前提下想当然的和SpringMVC进行了类比。同样,在使用对象作为参数时,也需要注意这样的问题。
对于这样的接口
@FeignClient("book")
public interface BookApi {
@RequestMapping(value = "/book",method = RequestMethod.POST)
Book book(@RequestBody Book book); // <1>
@RequestMapping(value = "/book",method = RequestMethod.POST)
Book book(@RequestParam("id") String id,@RequestParam("name") String name); // <2>
@RequestMapping(value = "/book",method = RequestMethod.POST)
Book book(@RequestParam Map map); // <3>
// 错误的写法
@RequestMapping(value = "/book",method = RequestMethod.POST)
Book book(@RequestParam Book book); // <4>
}
<1> 使用@RequestBody传递对象是最常用的方式。
<2> 如果参数并不是很多,可以平铺开使用@RequestParam
<3> 使用Map,这也是完全可以的,但不太符合面向对象的思想,不能从代码立刻看出该接口需要什么样的参数。
<4> 错误的用法,Feign没有提供这样的机制自动转换实体为Map。