本篇博客给大家带来的是SpringBoot的知识点, 本篇是SpringBoot入门, 介绍Spring MVC相关知识.
🐎文章专栏: JavaEE初阶
🚀若有问题 评论区见
❤ 欢迎大家点赞 评论 收藏 分享
如果你不知道分享给谁,那就分享给薯条.
你们的支持是我不断创作的动力 .
王子,公主请阅🚀
要开心
要快乐
顺便进步
1. 什么是Spring Web MVC?
官方对于 Spring MVC 的描述是这样的:
Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, “Spring Web MVC”,comes from the name of its source module (spring-webmvc), but it is more commonly known as “Spring MVC”.
翻译为中文:
Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从一开始就包含在 Spring 框架中. 它的正式名称“Spring Web MVC”来自其源模块的名称(Spring-webmvc),但它通常被称为"Spring
MVC".
详细见: Spring官网
什么是Servlet 呢?
Servlet 是一种实现动态页面的技术. 准确来讲Servlet是一套 Java Web 开发的规范,或者说是一套Java Web 开发的技术标准. 只有规范并不能做任何事情,必须要有人去实现它. 所谓实现 Servlet 规范,就是真正编写代码去实现 Servlet 规范提到的各种功能,包括类、方法、属性等.
Servlet 规范是开放的,除了 Sun 公司,其它公司也可以实现 Servlet 规范,目前常见的实现了Servlet 规范的产品包括 Tomcat、Weblogic、Jetty、Jboss、WebSphere 等,它们都被称为"Servlet 容器". Servlet 容器用来管理程序员编写的 Servlet 类.
先来搞清楚MVC, 方便我们理解Spring MVC.
1.1 什么是MVC ?
MVC 是 Model View Controller 的缩写,它是软件工程中的一种软件架构设计模式,它把软件系统分为模型、视图和控制器三个基本部分
View(视图): 指在应用程序中专门用来与浏览器进行交互,展示数据的资源.
Model(模型): 是应用程序的主体部分,用来处理程序中数据逻辑的部分.
Controller(控制器 ): 可以理解为一个分发器,用来决定对于视图发来的请求,需要用哪一个模型来处理,以及处理完后需要跳回到哪一个视图。即用来连接视图和模型.
比如去公司面试 :
我们到了公司之后, HR会给我们安排会议室, 根据候选人去通知不同的部门来安排面试, 面试结束后, 由HR来告诉我们面试结果.
在这个过程中
HR就是View(视图), 负责接待候选人, 并告知候选人面试结果.
不同的部门, 就是Controller(控制器), HR根据候选人来选择对应的部门来进行面试.
面试官 就是Model层, 来处理面试这个事情.
1.2 什么是Spring MVC?
MVC 是一种架构设计模式, 也一种思想, 而 Spring MVC 是对 MVC 思想的具体实现. 除此之外, Spring MVC还是一个Web框架.
总结来说,Spring MVC 是一个实现了 MVC 模式的 Web 框架.
Spring MVC主要关注有两个点: MVC 和 Web 框架.
实际上, 我们在上篇文章已经用过Spring MVC了, 在创建Spring Boot 项目时, 我们 勾选的 Spring Web 框架其实就是 Spring MVC 框架:
前面创建的不是SpringBoot项目吗? 怎么又变成了Spring MVC项目? 它们之间到底有着什么样的关系?
Spring Boot 是实现Spring MVC的其中一种方式.
Spring Boot 可以添加很多依赖, 借助这些依赖实现不同的功能. Spring Boot 通过添加Spring Web MVC框架, 来实现web功能.
2. Spring MVC
既然是 Web 框架, 那么当用户在浏览器中输入了 url 之后,我们的 Spring MVC 项目就可以感知到用户的请求, 并给予响应. 学习Spring MVC, 重点也就是学习如何通过浏览器和用户程序进行交互.
分以下三个方面:
1. 建立连接: 将用户(浏览器)和 Java 程序连接起来,也就是访问一个地址能够调用到我们的 Spring 程序.
2. 请求: 用户请求的时候会带一些参数,在程序中要想办法获取到参数, 所以请求这块主要是 获取参数 的功能.
3. 响应: 执行了业务逻辑之后,要把程序执行的结果返回给用户, 也就是响应.
2.1 项目准备
Spring MVC 项目创建和 Spring Boot 创建项目相同,在创建的时候选择 Spring Web 就相当于创建了Spring MVC 的项目.
2.2 建立连接
在 Spring MVC 中使用 @RequestMapping 来实现 URL 路由映射 ,也就是浏览器连接程序的作用
我们先来看看代码怎么写.
创建一个 UserController 类,实现用户通过浏览器和程序的交互,具体实现代码如下:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/user")
@RestController
public class UserController {
@RequestMapping("/hello")
public String sayHello() {
return "hello, SpringMVC!";
}
}
启动程序, 浏览器访问: http://127.0.0.1:8080/user/hello .就可以看到程序返回的结果了.
2.2.1 @RequestMapping 注解介绍
@RequestMapping 是 Spring Web MVC 应用程序中最常被用到的注解之一,它是用来注册接口的路由映射的.
表示服务收到请求时, 路径为 /hello 的请求就会调用 hello 这个方法的代码.
路由映射: 当用户访问一个 URL 时, 将用户的请求对应到程序中某个类的某个方法的过程就叫路由映射.
既然 @RequestMapping 已经可以达到路由映射了, 我们为什么还要加 @RestController
呢?
我们把 @RestController 去掉, 再来访问一次:
可以看到, 程序报了404, 找不到该页面.
这就是 @RestController 起到的作用.
一个项目中, 会有很多类, 每个类可能有很多的方法, Spring程序怎么知道要执行哪个方法呢?
Spring会对所有的类进行扫描, 如果类加了注解@RestController , Spring才会去看这个类里面的方法
有没有加 @RequestMapping 这个注解, 当然他的作用不止这一点, 后面再详讲.
2.2.2 @RequestMapping 使用
@RequestMapping 即可修饰类,也可以修饰方法 ,当修饰类和方法时,访问的地址是类路径 + 方法路径.
@RequestMapping 标识一个类:设置映射请求的 路径初始信息.
@RequestMapping 标识一个方法:设置映射请求的 路径具体信息 .
@RequestMapping 的URL 路径最前面加不加 / (斜杠)都可以, Spring程序启动时, 会进行判断, 如果前面没有加 / , Spring会拼接上一个 / 。本文都要求加 /
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/user")//可以不加/, 但建议加
@RestController
public class UserController {
@RequestMapping("/hello")//可以不加/, 但建议加
public String sayHello() {
return "hello, SpringMVC!";
}
}
2.2.3 @RequestMapping 是 GET 还是 POST 请求?
Ⅰ GET请求
利用 Fiddler来查一下上面写的请求是GET 还是 POST.
可以看到是GET请求.
Ⅱ POST请求
测试一下 @RequestMapping 能否发送POST请求.
通过form 表单来构造请求: 在 resources/static 路径目录下创建test.html, 代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/user/hello" method="post">
<input type="submit" value="提交">
</form>
</body>
</html>
同样用Fiddler抓包,如下:
不难发现, @RequestMapping 既支持Get请求, 又支持POST请求.
Ⅲ 指定POST请求
既然 @RequestMapping 支持POST请求. 那要怎么设置某个请求为 POST请求呢?
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 UserController {
@RequestMapping(value="/hello",method= RequestMethod.POST)//可以不加/, 但建议加
public String sayHello() {
return "hello, SpringMVC!";
}
}
2.4 请求
访问不同的路径, 就是发送不同的请求. 在发送请求时, 可能会带一些参数, 所以学习Spring的请求, 主要是学习如何传递参数到后端以及后端如何接收.
传递参数, 咱们主要是使用浏览器和 Postman 来模拟. Postman下载链接
2.4.1 传递单个参数
接收单个参数, 在 Spring MVC 中直接用方法中的参数就可以,比如以下代码:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/req")
@RestController
public class RequestController {
@RequestMapping("/r1")
public String r1(String name) {
return "接到参数,name: " + name;
}
}
① 使用浏览器发送请求并传参
② 使用Postman 发送请求并传参.
Ⅲ 不传参的时候发送请求会怎么样?
请求还是发送成功了, name默认为 null.
注意事项 : 使用基本类型来接收参数时, 参数必须传(除boolean类型), 否则会报500错误.
@RequestMapping("/r2")
public String r2(int age) {
return "接到参数,age:"+age;
}
正常传参:
不传参:
总结:
对于包装类型, 如果不传对应参数,Spring 接收到的数据则为null。
所以实际开发中,对于参数可能为空的数据,建议使用包装类型.
2.4.2 传递多个参数
和接收单个参数一样, 直接使用方法的参数接收即可. 使用多个形参.
当有多个参数时,前后端进行参数匹配时,是以参数的名称进行匹配的,因此参数的位置是不影响后端获取参数的结果.
2.4.3 传递对象
如果参数比较多时, 方法声明就需要有很多形参. 并且后续每次新增一个参数, 也需要修改方法声明.
我们不妨把这些参数封装为一个对象.
Spring MVC 也可以自动实现对象参数的赋值,比如 Student 对象:
在当前目录下,创建一个新的类 Student 并写上一些属性.
package com.fhao.mvc;
public class Student {
private String name;
private Integer id;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
}
传递对象代码实现:
@RequestMapping("/r4")
public String r4(Student student) {
return student.toString();
}
使用Postman 发送请求并传参. 结果如下图所示:
前面说过, 基本数据类型必须传(boolean除外), 那么把Student 对象中的 age 改成 int 类型并且在发送请求的时候不给传参, 这种情况会发生什么?
可以看到请求发送成功, age默认为0.
总结:
Spring 会根据参数名称自动绑定到对象的各个属性上, 如果某个属性未传递, 则赋值为 null。
基本类型则赋值为默认初识值, 比如 int类型的属性, 会被赋值为0。
所以实际开发中, 也建议使用对象来传参.
2.4.4 后端参数重命名
某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不一致,比如前端传递了一个 time 给后端,而后端是使用 createtime 字段来接收的,这样就会出现参数接收不到的情况,如果出现这种情况,我们就可以使用 @RequestParam 来重命名前后端的参数值.
具体示例如下,后端实现代码:
@RequestMapping("/r5")
public String r5(@RequestParam("time") String createtime) {
return "接收参数createtime:"+createtime;
}
直接看截图结果:👇
可以看到, Spring可以正确的把客户端传递的参数 time 绑定到了后端参数 caretetime 参数上
此时, 如果浏览器使用 createtime 进行参数传递呢?
错误日志信息为: 请求参数 ‘time’ 不存在
可以得出结论:
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("/r5")
public String r5(@RequestParam(value = "time",required = false) String createtime) {
return "接收参数createtime:"+createtime;
}
2.4.5 传递数组
@RequestMapping("/r6")
public String r6(String[] array) {
return "接收数组array: "+Arrays.toString(array);
}
使用Postman发送请求并传参:
2.4.6 传递集合
集合参数:和数组类似, 同一个请求参数名有多个, 且需要使用 @RequestParam 绑定参数关系.
默认情况下,请求中参数名相同的多个值,是封装到数组. 如果要封装到集合,要使用 @RequestParam 绑定参数关系.
后端接收代码如下:
@RequestMapping("/r7")
public String r7(@RequestParam List<String> list) {
return "size:"+list.size()+" ,list:"+list;
}
Postman传参测试如下:
本篇博客到这里就结束啦, 感谢观看 ❤❤❤
🐎期待与你的下一次相遇😊😊😊