Spring MVC(一)

@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 来解析。

java 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>我是一级标题</h1>
</body>
</html>
java 复制代码
@RequestMapping("/RespController")
@Controller
public class ResponseController {

    @RequestMapping("r1")
    public String returnHTML() {
        return "/index.html";
    }
}

返回页面的时候,返回值填写的是 该页面相对于 static 这个包的路径

通过抓包我们可以看出响应的数据类型为 text/html


由于 @Controller 注解的类的方法一般返回的是页面,如果你想要返回数据的话,可以在方法上加上 注解 @ResponseBody

java 复制代码
    @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 错误

java 复制代码
@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 会根据对应的 参数名区接收参数。

java 复制代码
@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 对象:

java 复制代码
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 +
                '}';
    }
}
java 复制代码
@RequestMapping("/ResController")
@RestController
public class RequestController {
    @RequestMapping("/r7")
    public String r7(UserInfo userInfo) {
        return userInfo.toString();
    }
}

如果参数没有写全的话:由于是对象的参数,这些参数有默认值,没有传递的参数,一律使用 默认值,这是 JavaSE 的知识了。

传递数组

java 复制代码
@RequestMapping("/ResController")
@RestController
public class RequestController {
    @RequestMapping("/r9")
    public String r9(int[] arr) {
        return Arrays.toString(arr);
    }
}

在 postman 我们可以一个一个元素去传递


也可以一起传递过去

@RequestParam(参数重命名)

当前端传递的参数和我们后端自己写的参数不符合的时候,我们可以使用 @RequestParam 这个注解来重命名参数,例如:我们方法定义的参数为 name,但是前端想用 a 来进行传递,我们可以将 name 重命名为 a

java 复制代码
@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

java 复制代码
@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 绑定参数关系

java 复制代码
@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 数据:

java 复制代码
{
	"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"
			]
		}
	]
}

也可以进行压缩然后表示:

java 复制代码
{"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 格式的数据进行传递

java 复制代码
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 +
                '}';
    }
}
java 复制代码
@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 里面填写即可。

java 复制代码
@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

java 复制代码
    @RequestMapping("/r15")
    public String getFile(@RequestPart("file1") MultipartFile file) throws IOException {
        System.out.println(file.getOriginalFilename());
        //文件上传
        file.transferTo(new File("D:\\图\\" + file.getOriginalFilename()));
        return "文件上传成功!";
    }


查看电脑对应的路径,发现文件成功接收并下载到对应的路径里。

相关推荐
ekskef_sef13 分钟前
Nginx—Rewrite
java·数据库·nginx
星迹日19 分钟前
数据结构:二叉树
java·数据结构·经验分享·二叉树·
Mr.Demo.21 分钟前
[Spring] Eureka & SpringCloud LoadBalance
spring·spring cloud·eureka
道剑剑非道26 分钟前
QT开发技术 【基于TinyXml2的对类进行序列化和反序列化】 二
java·数据库·qt
码上艺术家37 分钟前
手摸手系列之 Java 通过 PDF 模板生成 PDF 功能
java·开发语言·spring boot·后端·pdf·docker compose
试行1 小时前
C++连接使用 MySQL Connector/C++ 库报错bad allocation
java·c++·mysql
内心如初2 小时前
JAVA-Exploit编写(7)--http-request库文件上传使用续篇
java·网络安全·exploit
计算机-秋大田2 小时前
基于SSM的自助购药小程序设计与实现(LW+源码+讲解)
java·后端·微信小程序·小程序·课程设计
神秘的t2 小时前
javaEE初阶————多线程初阶(2)
java·开发语言
好的吖。2 小时前
JavaEE
java·java-ee