@RestController
@RestController 是由 @Controller 和 @ResponseBody 两个注解构成的。
Spring 启动的时候会扫描所有包含 @Controller 或者 @RestController 注解的类,创建出对外的接口,这样外界就可以从这里与服务器实现交互,如果没有这个注解, Spring 就不会 扫描该类,外界也就无法找到这个类了。
因为 Spring 项目包含的类很多,不仅仅有自定义的类,还有标准库第三方库的类,为了能快速启动 Spring 项目,所以 Spring 只会扫描所有包含 @Controller 或者 @RestController 注解的类,并创建其对外的接口
举个例子:下面的类即使使用了 @RequestMapping 注解,客户端在访问的时候得到却是 404 (页面不存在)的响应,就因为这个类没有使用 @Controller 或者 @RestController 注解
404 页面可以由程序员自行设定,例如 B站的 404 页面就很精美,Spring 的 404 页面有一个默认的页面,上面就是默认的 404 页面
@Controller 和 @ReponseBody的区别:
@Controller 是用来返回页面的,例如 html
@ResponseBody 是用来返回数据的。
如果你在类上面使用了 @Controller ,在类里的方法的返回值就是页面,例如下面所示:返回一个 html 页面,返回值的参数类型虽然是 String,但是Spring 会将返回值作为 html 来解析。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>我是一级标题</h1>
</body>
</html>
@RequestMapping("/RespController")
@Controller
public class ResponseController {
@RequestMapping("r1")
public String returnHTML() {
return "/index.html";
}
}
返回页面的时候,返回值填写的是 该页面相对于 static 这个包的路径
通过抓包我们可以看出响应的数据类型为 text/html
由于 @Controller 注解的类的方法一般返回的是页面,如果你想要返回数据的话,可以在方法上加上 注解 @ResponseBody
@ResponseBody
@RequestMapping("/r2")
public String returnText() {
return "/index.html";
}
注解源码解析
@RestController 源码解析:
Target 是指这个注解可以作用的位置,ElementType 里面包含很多枚举类型,其中 TYE 指类,说明 @RestController 是一个类注解,作用在类上。
Retention 指注解可以存活到哪个事时间段里:我们编写的Java 代码要运行的时候,首先是由源代码(SOURCE)编译为 .class 文件(CLASS),最后才进入运行阶段(RUNTIME)
@RestController 可以活到 RUNTIME,说明 @RestController 在代码运行阶段依旧存在
接着下面就是我们熟知的 @Controller 和 @ResponseBody 两个注解,这也说明了 @RestController 是 由 @Controller 和 @ResponseBody 两个注解构成的。
Controller 注解源码解析:
首先这是一个类注解,只能作用在类上,不能作用在方法上
其可以存活在代码运行阶段
@ResponseBody 注解源码解析:
即是一个类注解,也是一个方法注解
其可以存活在代码运行阶段
@ResquestMapping
@RequestMapping 是 用来注册接口的路由映射的。
简单来说,@RequestController 是用来开辟一个外界能找到的路径,@RestController 或者 @Controller 就是路径的大门,只有大门打开了,外界才能走这一条路。
在学习 http 的时候,我们知道发送请求的方法有好几种,其中包括 GET、POST、PUT、DELETE…
如果想要让客户端使用指定的请求方法的话,可以使用 @GetMapping、@PostMapping、@PutMapping 等
而 @RequestMapping 则是包含所有的请求方法,即客户端使用哪个请求方法都可以,这个注解我们经常使用
@RequestMapping 即是一个 类注解,也是一个方法注解,访问路径是 类路径 + 方法路径
如果要访问下面类的 r1 方法的话,url 为 http://127.0.0.1:8080/RequestController/r1?a=aaa
在写路径的时候,我们一般把路径名称定义为对应的类名或者方法名,可以不加 /,如果不加 Spring 会默认加上,一般我们都会加上 /
传递普通参数
使用基本类型传参的时候,参数为必传参数(除 boolean 之外),否则会报 500 错误
类型不匹配的时候,会报 400 错误
@RequestMapping("/ResController")
@RestController
public class RequestController {
@RequestMapping("r2")
public String r2(String a, int b) {
return "接收参数:" + a + b;
}
}
举个例子:
如果不传递 b 参数(int 类型),就会报错
IDEA 上也会报错:
如果你传递的类型不匹配,会报 400 的错误
IDEA 会提示 String 类型的参数无法传递给 int 类型里。
正常传递参数:
传递多个普通参数
在传递多个参数,只要参数的名称写对即可,不需要考虑顺序,Spring 会根据对应的 参数名区接收参数。
@RequestMapping("/ResController")
@RestController
public class RequestController {
@RequestMapping("/r6")
public String r6(String name, int gender, int age) {
return "接收到的参数:" + "name:" + name + " gender:" + gender + " age:" + age;
}
}
传递对象
如果参数比较多的时候,方法的声明就需要很多的形参,并且后续每增加一个新的参数,方法的参数列表也要进行增加,为了方便书写,我们会将这些参数封装成一个对象,Spring MVC 会自动实现对对象参数的赋值
例如我们要传递一个 UserInfo 对象:
public class UserInfo {
String name;
int gender;
int age;
public UserInfo() {
}
public UserInfo(String name, int gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getGender() {
return gender;
}
public void setGender(int gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "UserInfo{" +
"name='" + name + '\'' +
", gender=" + gender +
", age=" + age +
'}';
}
}
@RequestMapping("/ResController")
@RestController
public class RequestController {
@RequestMapping("/r7")
public String r7(UserInfo userInfo) {
return userInfo.toString();
}
}
如果参数没有写全的话:由于是对象的参数,这些参数有默认值,没有传递的参数,一律使用 默认值,这是 JavaSE 的知识了。
传递数组
@RequestMapping("/ResController")
@RestController
public class RequestController {
@RequestMapping("/r9")
public String r9(int[] arr) {
return Arrays.toString(arr);
}
}
在 postman 我们可以一个一个元素去传递
也可以一起传递过去
@RequestParam(参数重命名)
当前端传递的参数和我们后端自己写的参数不符合的时候,我们可以使用 @RequestParam 这个注解来重命名参数,例如:我们方法定义的参数为 name,但是前端想用 a 来进行传递,我们可以将 name 重命名为 a
@RequestMapping("/ResController")
@RestController
public class RequestController {
@RequestMapping("/r8")
public String r8(@RequestParam(value = "a") String name) {
return "接收参数:" + name;
}
}
参数进行重命名之后,外界只能使用重命名后的参数名称来传递数值,不可以使用 后端定义的参数名!!!
否则会报 400 的客户端错误
源码解析
@RequsetParam 作用在参数上(PARAMETER)
其中 重命名设置既可以使用 value = “新参数名”,也可以使用 name = “新参数名”
required 是指这个参数是 必传的还是非必传的,@RequestParam 默认是必传参数,如果要设置非必传参数需要单独设置 required = false
必传参数与非必传参数
如果有写参数是可以不用传递的话,我们可以设置为非必传参数,这样没有传递参数也不会发生报错,没有传递参数会默认赋值为 默认值,所以基本类型的参数即使设置为 非必传参数也没用,基本类型的参数一定的必传的参数,否则就会发生报错。
非必传参数设置为 required = false
@RequestMapping("/ResController")
@RestController
public class RequestController {
@RequestMapping("/r11")
public String r11(@RequestParam(value = "s", required = false) String str) {
return str + " test";
}
@RequestMapping("/r12")
public int r12(@RequestParam(value = "a", required = false) int aaaa) {
return aaaa;
}
}
设置为非必传参数,在没有传递参数的话,会设置为默认值。
基本类型的参数就算设置为非必传参数也没用,没有传递依旧报错
传递集合
在参数传递的形式上,集合参数的传递和上面数组参数传递是一样的。
但是需要 使用 @RequestParam 注解来绑定参数关系
默认情况下,请求中参数名称相同的多个值是封装到数组里的,如果要封装到集合中,需要使用 @RequestParam 绑定参数关系
@RequestMapping("/ResController")
@RestController
public class RequestController {
@RequestMapping("/r10")
public String r10(@RequestParam List<Integer> list) {
return list.toString();
}
}
JSON
JSON 介绍
JSON 和 JS 没有关系,只是语法相似。
JSON 本质上就是一个字符串,通过文本来存储和描述数据
Spring MVC 有 JSON 转换工具,我们可以直接使用,以此来完成JSON 和 Java对象的互传,当然网络上也有很多 JSON 转换工具,我们都可以直接拿来使用。
JSON 语法:
使用键值对(key,value)保存数据
数据与数据之间使用 , 分割
对象使用 { } 表示
数组使用 [ ] 表示
数值可以为对象,也可以为数组,数组中可以包含多个对象。
举例:下面的格式化的 JSON 数据:
{
"squadName": "Super hero squad",
"homeTown": "Metro City",
"formed": 2016,
"secretBase": "Super tower",
"active": true,
"members": [{
"name": "Molecule Man",
"age": 29,
"secretIdentity": "Dan Jukes",
"powers": ["Radiation resistance", "Turning tiny", "Radiationblast "]
},
{
"name": "Madame Uppercut",
"age": 39,
"secretIdentity": "Jane Wilson",
"powers": ["Million tonne punch", "Damage resistance", "Superhumanreflexes "]
},
{
"name": "Eternal Flame",
"age": 1000000,
"secretIdentity": "Unknown",
"powers": ["Immortality", "Heat Immunity", "Inferno",
"Teleportation", "Interdimensional travel"
]
}
]
}
也可以进行压缩然后表示:
{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiationblast "]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhumanreflexes "]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}
JSON 传递 (@RequestBody)
使用 @RequestBody 来绑定参数,RequestBody 是 作用在请求正文的数据绑定,请求参数必须写在请求正文中.
我们将 UserInfo 这个对象使用 JSON 格式的数据进行传递
public class UserInfo {
String name;
int gender;
int age;
public UserInfo() {
}
public UserInfo(String name, int gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getGender() {
return gender;
}
public void setGender(int gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "UserInfo{" +
"name='" + name + '\'' +
", gender=" + gender +
", age=" + age +
'}';
}
}
@RequestMapping("/ResController")
@RestController
public class RequestController {
@RequestMapping("/r13")
public String r13(@RequestBody UserInfo userInfo) {
return userInfo.toString();
}
}
在 postman 中选择 raw ,选择 JSON ,然后填写你要传递的 JSON 数据
在传递对象的参数使用 JSON 时,如果缺少默写参数,会使用参数的默认值进行填充,和之前我们提到的是一样的。
从 URL 获取参数 @PathVariable
如果方法参数名和需要绑定的URL中的变量名称一致时,可以不进行重命名
如果方法参数名和需要绑定的URL中的变量名称不一致的时候,需要进行重命名
将你要从URL获取的参数使用 { } 包裹起来,需要重命名的参数直接在 @PathVariable 里面填写即可。
@RequestMapping("/ResController")
@RestController
public class RequestController {
@RequestMapping("/r14/{id}/{name}")
public String r14(@PathVariable Integer id, @PathVariable("name") String userName) {
return "id = " + id + " name = " + userName;
}
}
上传文件 @RequestPart
@RequestMapping("/r15")
public String getFile(@RequestPart("file1") MultipartFile file) throws IOException {
System.out.println(file.getOriginalFilename());
//文件上传
file.transferTo(new File("D:\\图\\" + file.getOriginalFilename()));
return "文件上传成功!";
}
查看电脑对应的路径,发现文件成功接收并下载到对应的路径里。