首先我们需要知道MVC是什么
MVC 是⼀种架构设计模式, 也⼀种思想
MVC 是 Model View Controller 的缩写,它是软件⼯程中的⼀种软件架构设计模式,它把软件系统分为模型、视图和控制器三个基本部分
- View(视图) 指在应⽤程序中专⻔⽤来与浏览器进⾏交互,展⽰数据的资源.
- Model(模型) 是应⽤程序的主体部分,⽤来处理程序中数据逻辑的部分.
- Controller(控制器)可以理解为⼀个分发器,⽤ 来决定对于视图发来的请求,需要⽤哪⼀个模型来处理,以及处理完后需要跳回到哪⼀个视图。即 ⽤来连接视图和模型
⽐如去饭店吃饭 :
客⼾进店之后, 服务员来接待客⼾点餐, 客⼾点完餐之后, 把客⼾菜单交给前厅,
前厅根据客⼾菜单 给后厨下达命令.
后厨负责做饭, 做完之后, 再根据菜单告诉服务员, 这是X号餐桌客⼈的饭.
在这个过程中
服务员就是View(视图), 负责接待客⼾, 帮助客⼾点餐, 以及给顾客端饭
前厅就是Controller(控制器), 根据⽤⼾的点餐情况, 来选择给哪个后厨下达命令.
后厨就是Model(模型), 根据前厅的要求来完成客⼾的⽤餐需求
一、什么是Spring MVC
1、概念
MVC 是⼀种架构设计模式, 也⼀种思想, ⽽ Spring MVC 是对 MVC 思想的具体实现. 除此之外, Spring MVC还是⼀个Web框架. 总结来说,Spring MVC 是⼀个实现了 MVC 模式的 Web 框架.
在创建 Spring Boot 项⽬时,我们勾选的 Spring Web 框架 其实就是 Spring MVC 框架
2、SpringBoot与Spring MVC关系
我们会疑惑,创建的不是SpringBoot项⽬吗? 怎么⼜变成了Spring MVC项⽬? 他们 之间到底有着什么样的关系?
SpringBoot是2014年发布的, Spring 是2004年发布的, 在2014年发布之前, 就不能⽤Spring实现MVC 架构吗? 显然不是了. Spring Boot 只是实现Spring MVC的其中⼀种⽅式⽽已. Spring Boot 可以添加很多依赖, 借助这些依赖实现不同的功能. Spring Boot 通过添加Spring Web MVC框架, 来实现web功能.
⽐如: 厨房可以⽤来做饭, 但真实实现做饭功能的是⽕以及各种做饭相关的⻝材和⼯具. 厨房就好⽐是SpringBoot, 厨房可以装柜⼦, 实现收纳功能, 装燃⽓灶等, 实现做饭功能. 做饭这个事, 就是MVC, 在⼏千年前, 有⽕有⻝材就可以实现做饭
3、图理解Spring MVC
学习Spring MVC重点学习如何通过浏览器和用户程序进行交互
二、学习Spring MVC
既然是 Web 框架, 那么当⽤⼾在浏览器中输⼊了 url 之后,我们的 Spring MVC 项⽬就可以感知到⽤⼾ 的请求, 并给予响应.
1、如何交互
1. 建⽴连接:
将⽤⼾(浏览器)和 Java 程序连接起来,也就是访问⼀个地址能够调⽤到我们的 Spring 程序。
2. 请求:
⽤⼾请求的时候会带⼀些参数,在程序中要想办法获取到参数, 所以请求这块主要是 获取参数 的功能.
3. 响应:
执⾏了业务逻辑之后,要把程序执⾏的结果返回给⽤⼾, 也就是响应.
三、建立连接
创建项目, Spring MVC 项⽬创建和 Spring Boot 创建项⽬相同,在创建的时候选择 Spring Web 就相当于创建了 Spring MVC 的项⽬.具体可参考http://t.csdnimg.cn/Echbk
1、@RequestMapping :实现 URL 路由映射 ,也就是浏览器连接程序的作⽤
直接看代码
package com.example.demo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("user")
@RestController
public class HelloController {
@RequestMapping("/sayHi")
public String sayHi(){
return "hello,Spring MVC";
}
接下来访问: http://127.0.0.1:8080/user/sayHi, 就可以看到程序返回的数据了
1、@RequestMapping 是 Spring Web MVC 应⽤程序中最常被⽤到的注解之⼀,它是⽤来注册接⼝的 路由映射的. 表⽰服务收到请求时, 路径为 /sayHi 的请求就会调⽤ sayHi 这个⽅法的代码.
路由映射: 当⽤⼾访问⼀个 URL 时, 将⽤⼾的请求对应到程序中某个类的某个⽅法的过程就叫路由映射.
注意:如果 @RestController 去掉
⼀个项⽬中, 会有很多类, 每个类可能有很多的⽅法, Spring程序怎么知道要执⾏哪个⽅法呢? Spring会对所有的类进⾏扫描, 如果类加了注解@RestController, Spring才会去看这个类⾥⾯的⽅法 有没有加 @RequestMapping 这个注解
2、@RequestMapping 使⽤
@RequestMapping 即可修饰类,也可以修饰⽅法 ,当修饰类和⽅法时,访问的地址是类路径 + ⽅ 法路径.
@RequestMapping标识⼀个类:设置映射请求的请求路径的初始信息
@RequestMapping标识⼀个⽅法:设置映射请求请求路径的具体信息
@RequestMapping("user")
public class HelloController {
@RequestMapping("/sayHi")
public String sayHi(){
return "hello,Spring MVC";
}
注意: @RequestMapping 的URL 路径最前⾯加不加 / (斜杠)都可以, Spring程序启动时, 会进⾏判断, 如果 前⾯没有加 / , Spring会拼接上⼀个 /
3、@RequestMapping 是 GET 还是 POST 请求?
1、GET请求:
浏览器发送的请求类型都是get, 通过以上案例, 可以看出来 @RequestMapping ⽀持get请求.
- 我们可以通过fiddler抓包得出它是GET请求
2、Post请求
使用postman测试是否为post请求
由上图结果可以得出它也为post请求
postman使用:
下载链接:Download Postman | Get Started for Free
3、 指定GET/POST⽅法类型
看代码:这里指定POST方法类型
@RequestMapping("user")
@RestController
public class HelloController {
@RequestMapping(value = "/getRequest",method= RequestMethod.POST)
public String sayHi(){
return "hello,Spring MVC";
}
所以在浏览器中访问就会报405
用Postman报错
psot请求才会出现正确结果
四、请求
访问不同的路径, 就是发送不同的请求.
在发送请求时, 可能会带⼀些参数, 所以学习Spring的请求, 主要 是学习如何传递参数到后端以及后端如何接收
后端开发⼈员⽆需过度关注如何传递参数, 了解即可, 实际开发中以Postman测试为主.
⽐如餐厅的厨师, 不关注⽤⼾是在店⾥下单, 还是外卖平台下单, 或者⼩程序下单, 只需要知道如何接 收订单, 根据订单做出对应的菜肴就可以了
1、传递单个参数
@RequestMapping("/helloCN")
public String method1(String name){
return "接收到参数name:"+ name;
}
通过Fiddler观察请求和响应 :HTTP响应状态码为200, Content-Type 为 text/html
2、传递多个参数
@RequestMapping("/m2")
public Object method2(String name, String password) {
return "接收到参数name:" + name + ", password:" + password;
}
Postman查看结果:
3、传递对象
如果参数⽐较多时, ⽅法声明就需要有很多形参. 并且后续每次新增⼀个参数, 也需要修改⽅法声明. 我们不妨把这些参数封装为⼀个对象. Spring MVC 也可以⾃动实现对象参数的赋值,⽐如 Person 对象:
package com.example.demo;
public class UserInfo {
private Integer id;
private String name;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "UserInfo{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
传递对象代码实现
@RequestMapping("/r1")
public String r1(UserInfo user) {
return user.toString();
}
4、后端参数重命名(后端参数映射)
某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不⼀致,⽐如前端传递了⼀个 time 给后端,⽽后端是使⽤ createtime 字段来接收的,这样就会出现参数接收不到的情况,如果出现 这种情况,我们就可以使⽤ @RequestParam 来重命名前后端的参数值
@RequestMapping("/m4")
public Object method_4(@RequestParam("time") String createtime) {
return "接收到参数createtime:" + createtime;
}
注意:
1. 使⽤ @RequestParam 进⾏参数重命名时, 请求参数只能和 @RequestParam 声明的名称⼀ 致, 才能进⾏参数绑定和赋值.
2. 使⽤ @RequestParam 进⾏参数重命名时, 参数就变成了必传参数
⾮必传参数设置
如果我们的实际业务前端的参数是⼀个⾮必传的参数, 针对上述问题, 如何解决呢? 先来了解下参数必传的原因, 我们查看 @RequestParam 注解的实现细节就可以发现端倪,注解 实现如下:
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
boolean required() default true;
String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n"
}
可以看到 required 的默认值为true, 表⽰含义就是: 该注解修饰的参数默认为必传 既然如此, 我们可以通过设置 @RequestParam 中的 required=false 来避免不传递时报错, 具体实现如下:
@RequestMapping("/m4")
public Object method_4(@RequestParam(value = "time", required = false) String createtime) {
return "接收到参数createtime:" + createtime;
}
可以看到, 添加required=false之后, time前⾯也加了key, 变成了 value = "time" 注解属性赋值时, 没有指明key的话, 默认为value属性. 如果需要有多个属性进⾏赋值时, 需要写上key
5、传递数组
Spring MVC 可以⾃动绑定数组参数的赋值
@RequestMapping("/m5")
public String method5(String[] arrayParam) {
return Arrays.toString(arrayParam);
}
6、传递集合
集合参数:和数组类似, 同⼀个请求参数名有为多个, 且需要使⽤ @RequestParam 绑定参数关系
默认情况下,请求中参数名相同的多个值,是封装到数组. 如果要封装到集合,要使⽤ @RequestParam 绑定参数关系
@RequestMapping("/m6")
public String method6(@RequestParam List<String> listParam){
return "size:"+listParam.size() + ",listParam:"+listParam;
}