目录
1.进入Spring MVC的准备工作
2.什么是Spring MVC
3.学习Spring MVC的三个要点
一.进入Spring MVC的准备工作
前言:

在前面的博客里面,我们写了一个简单的controller,我们在浏览器里面输入网址:http://127.0.0.1:8080/sayHi之后,就会看到一个hello,spring的返回,这就是一个简单的前后端的交互,那我们还有好多问题要问:为什么浏览器能够访问我们的Java程序,8080是谁在监听,我们为什么要写8080这个端口,以及后续我们要传一些数据,类似name,age这些,后端又如何进行接收,在进入Spring MVC之前,我们好需要学习一些基础的知识
Tomcat
在我们之前写的慢方法中,我们不会有浏览器的交互,因为没有东西帮助我们监听网络端口,等待浏览器连接,解析http请求以及返回响应,而这些都是我们现在要介绍的这个Tomcat所干的活,可以理解为Tomcat 是一个能够运行 Java Web 应用的 Servlet 容器,同时能够提供 HTTP 服务。并且Tomcat就是负责监听8080端口的
整个流程可以理解为这样
Spring Boot--------启动内嵌 Tomcat-----------Tomcat 监听 8080-----------等待客户端请求
Servlet
这个是一套Java web开发规范,规定程序怎么接收请求,怎么处理请求以及产生响应,而tomcat就是实现了servlet规范,所以又称Tomcat这类的为Servlet容器,但是Tomcat只是实现了说请求的接收,可以调用Servlet,这里的Servlet并不是规范了,而是一个接口,提供了一些必要的方法,当然我们可以通过Tomcat来调用我们自己重写实现的Servlet类,但是这样很麻烦,这样我们需要自己在代码中处理读取请求参数,判断URL,处理JSON之类的,所以我们后面引入了今天的主角spring mvc
二、什么是 Spring MVC?
Spring MVC是什么
Spring MVC 是又在 Servlet 的基础上进行了进一步封装。
所以我们处理请求只需要写这样的方法,大量底层的读取判断构造都由这个框架做好了的
java
@GetMapping("/user")
public String getUser() {
return "hello";
}
所以我们结合一下刚刚说的Tomcat
**Tomcat:**主要负责接收 HTTP 请求、提供 Servlet 运行环境、发送 HTTP 响应。
**Spring MVC:**主要负责找到对应的 Controller 方法、接收和转换参数、处理返回结果。
Spring MVC不仅是一个web框架,也是mvc思想的一种巨像表现
什么是MVC
M:Model(负责数据和业务的相关处理)
V:View(负责和用户交互,展示数据)
C:Controller(负责接收请求,并连接model和view)
可以将view理解为是去饭店的顾客,controller是前台,model是后厨,MVC就是为了让每一步都更加的明确
那我们可能会说之前的spring boot框架我们还没怎么熟悉,怎么就又有一个新的框架了,其实我们早就解除了spring mvc,当我们创建spring boot项目的时候,我们就选择的是创建spring web项目,因为我们是网页的开发,当我们选择这个时候,spring web就把web开发需要的spring mvc能力带进来了,所以我们之前也是使用过的,只是没有系统的认识这个
三.学习Spring MVC的三个要点
spring mvc入门需要掌握建立连接,请求,以及响应这三点
准确来说就是怎么找到对应的Java方法,请求里的数据怎么进入Java,处理完的结果怎么返回客户端
路由映射(如何找到Java方法)
当我们在浏览器访问之前的那个网址,怎么就对应了说是这个sayHi方法,前面的127.0.0.1:8080是找到具体的网络服务,而后面的sayHi就是找到了具体的对应方法,所以显示了hello,spring,这里就引入了一个注解:**@RequestMapping,**这个后面填对应的路径,通过这个就可以用URL将请求对应到具体的Java方法上了
java
@RestController
@RequestMapping("/hi")
public class UserController {
@RequestMapping("/sayHi")
public String sayHi() {
return "hello,Spring";
}
}
这个可以写到类上,也可以写到方法上面,所以当我们这次要找这个方法的时候,我们就需要在URL里面添加一段,最后就是127.0.0.1:8080/hi/sayHi这样,我们也可以通过这个例子来了解一下,这样的话我们的方法就是一级一级的下去寻找
GET 和 POST 到这里终于真正开始使用
之前我们在学习http的时候,我们知道get以及post是http的请求方法,到了我们这里,我们就需要学习Java后端该如何处理这些请求,当我们在浏览器输入刚刚的网址的时候,我们通过抓包工具也可以看到,浏览器其实是帮我们构造了一个GET请求的

介绍几个相关的注解
@GetMapping:只有向对应方法发送GET请求的时候,方法才会执行
@PostMapping:只有向对应方法发送POST请求的时候,方法才会执行
当我们没有指定一定要哪种的时候,就是@RequestMapping,这个可以默认匹配多种请求方法
Postman
这个之前我们也介绍过,这是一款构造请求的工具,当然我之前介绍的好像是apifox,不过两款软件都可以模拟前端构造请求给后端,就不需要我们再写一个前端的页面了

我们学习这一块的知识就可以配合着postman以及fiddler抓包工具来学习
简单来介绍一下这个软件的使用,先介绍里面的传参位置
**Params:**当我们需要用户端返回一个数据的时候,就可以在这里面构造
java
@RequestMapping("/r1")
public String r1(String name,Integer age) {
return name+age+"岁";
}

当我们把方法改成post之后,我们就可以在Body 的raw 里面写JSON了

接收请求参数(请求里的数据怎么进入Java)
1,常见的接收方式
这张表格是我们接下来学习接收参数需要一直围绕的一张表格!!!
| 参数来源 | 接收方式 |
|---|---|
URL 查询参数 ?name=Tom |
@RequestParam |
URL 路径 /user/10 |
@PathVariable |
| JSON 请求体 | @RequestBody |
| 请求头 | @RequestHeader |
| Cookie | @CookieValue |
| 表单数据 | 普通参数 / JavaBean |
| 上传的文件 | MultipartFile |
当我们已经会如何找到对应的方法之后,我们就要进入一个重头戏,就是接收请求来的参数了,我们需要根据用户传来的数据,通过Spring MVC里面的解析以及类型转换,将对应的数据对应到Java方法的参数,当然这个过程是Spring MVC自己会做的
java
@RequestMapping("/r1")
public String r1(String name,Integer age) {
return name+age+"岁";
}
我们通过postman构造的请求中有age以及name,spring会根据对应的参数名去进行匹配,我哪一个参数写在前面都没事,主要是age以及name相对应(参数名相对应),
推荐包装类型
因为如果当我们写的是public String r1(int age)的时候,我们传入的参数不能为空,也就是说我们必须传入参数,要不然就会出现报错,所以稳妥的时候尽量使用包装类
2,多参数的时候定义类
当我们的参数很多的时候,我们最好是可以定义一个类来保存这些,也就是比如我们像上面一样我们需要对象传入一个个人信息,我们有两种写法
第一种:
java
@RequestMapping("/r2")
public String r2(String name,Integer age,Integer userid,String email) {
return name+age+userid+email;
}

第二种:
java
public class User {
private Integer userid;
private String name;
private String email;
private Integer age;
public Integer getUserid() {
return userid;
}
public void setUserid(Integer userid) {
this.userid = userid;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
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 "User{" +
"userid=" + userid +
", name='" + name + '\'' +
", email='" + email + '\'' +
", age=" + age +
'}';
}
}
java
@RequestMapping("/r3")
public String r3(User user){
return user.toString();
}

这样如果参数更加多的时候,我们最好就是将所有的参数定义到统一的一个类里面,这样也方便我们管理,当然定义了User类,我们在postman里面构造的时候也需要跟前面一样,一个参数一个参数拆开来构造
3,@RequestParam(URL 查询参数 ?name=zahngsan)
它主要负责:从 HTTP 请求参数中获取数据,并将其绑定到 Controller 方法的形参上。
两个重要的作用1:改变参数名,2:获取对应的参数并绑定到方法中
1:改变参数名
当我们前端传来的参数名字叫username的时候,但是我们后端又想使用name这个参数名进行存储,这个时候就可以使用到这个了
java
@RequestMapping("/r4")
public String r4(@RequestParam("username") String name){
return name;
}

也就是可以理解为说,找到名字叫username这个参数的数据,传过来对应到我后端自己的name中
2:获取对应的参数并绑定到方法中
java
@RequestMapping("/r5")
public String r5(@RequestParam("like")List<String> list){
return list.toString();
}

因为List是一个接口,我们想要传入参数的时候,必须要是实现这个接口的类创建的对象,比如Arraylist,但是当我们传入几个like也同样可以被接受到,这是为什么,因为
Spring MVC 会自动完成:
-
根据
@RequestParam("tag")找到请求中的三个值。 -
根据
List<String>判断需要转换为字符串集合。 -
通过类型转换机制得到一个实现了 List 接口的集合对象。
-
将这个对象传递给
r1()方法
也就是说相当于它帮我们创建了一个Arraylist对象,找到对应的like数据,然后add进去了,并且我们在postman中使用的时候,使用一个个like传可以,使用,分割一次性传进去也可以,
4,JSON
我们现在很多的项目并不是像我刚刚那么传输数据的,就类似于说?name=zhangsan&age=18这样,而是通过JSON这样的数据格式进行传输的,JSON是脱离编程语言的一种数据传输格式,也就是说我在C语言里面可以使用跟Java中同样的一份JSON文件,并且JSON还很轻量化
java
键值对使用 :
多个数据使用 ,
对象使用 {}
数组使用 []
5,Jackson
当我们的JSON数据传过来的时候,我们就需要有人讲JSON数据转为Java对象,这样的工作就是Jackson来干的,JSON转为Java对象叫做反序列化,反过来就叫序列化
6,@RequestBody(JSON请求体)
JSON一般传输给后端都是写在http请求的body里面的,所以我们在后端中要使用一个注解进行提示
java
@PostMapping("/r6")
public String add(@RequestBody User user) {
return user.toString();
}

7,一些方法的约定
前面你肯定也听说了说这些get,post方法有一些规定,但是程序员是可以不按照这些规定来的,那这到底是什么意思呢:
比如说GET一般是规定获取数据的,然后DELETE是删除数据,但是这只是一个规定,并不是强制的执行,所以我们可以有两种代码的写法
java
@DeleteMapping("/user/{id}")
public String deleteUser(@PathVariable Integer id) {
// 删除用户
return "删除成功";
}
java
@GetMapping("/deleteUser")
public String deleteUser(@RequestParam Integer id) {
// 删除用户
return "删除成功";
}
这两种方式都是正确的,下面这种方式只需要让问GET/deleteUser?id=1001也就是可以删除的,但是这样是违反了语义安全,所以还是不是很建议你们写下面这种,一般就是一种方法对应一类问题
8,@PathVariable(URL 路径 /user/10)
当我们的数据是写在URL里面的时候,我们就需要使用到这个参数,这里的{id}是一个路径占位符,也就是说这个位置是可以接收不同的值的
你可能会想那什么情况会写在路径里面,毕竟我们刚刚写的基本上都是在Query里面,那通常我们定义一个商品的id,一个文章的id的时候一般就会写在路径里面,可以让 URL 能够清晰地标识一个具体的资源。就例如:GET /article/10这种,就很好的标识了文章10
java
@RequestMapping("/r7/{id}")
public String getUser(
@PathVariable Integer id) {
return "id=" + id;
}

9,@RequestHeader(接收请求头)

再回顾一下http请求的内容,我圈出来的部分都是header的部分,那我们后端将如何获得呢(两种方式,上面获得请求都是有两种方式的,一种是使用HttpServletRequest这个类,还有一种就是可能会提供的注解)
java
@RequestMapping("/getHeader")
public String getHeader(HttpServletRequest request){
String UserAgent=request.getHeader("User-Agent");
return "UserAgent:"+UserAgent;
}
@RequestMapping("/getHeader2")
public String getHeader2(@RequestHeader("User-Agent")String UserAgent){
return "UserAgent:"+UserAgent;
}


10,cookie和session
我们再来回顾一下之前学习的cookie以及session的相关知识点,就是当我们登录一个网页,在短时间内,我们重新登录这个网页的时候,他就相当于是会记住我们,就是我们不需要再次重复登录也可以正常访问到刚刚的内容,这是怎么做到的呢,明明我们的http是无状态的,这意味着http协议本身不会自动记住两次请求之间的用户关系,这时候cookie以及session就派上用场了,整个流程就是浏览器登录的时候,发送用户名以及密码,后端验证用户信息没错之后创建或者获取session,来保存用户信息,然后服务端通过http响应的set-cookie,返回一个sessionid,客户端就会存储这个sessionid在cookie里面,后续我们访问的时候就会带着这个sessionid给后端,后端就根据这个来验证我们的信息就好了,我们真实在后端写设置session的时候,不会来一个用户设置一个,而是编写统一的登录逻辑。自动根据不同的用户创建不同的session,session一般就是我们后端来管理,前端一般是访问不到的,毕竟存储了用户的一些密码啥的,cookie一般存储的就是sessionid以及一些主题,语言之类的,而session一般存储的是id,登录信息以及权限,我们可以通过f12的方式来看我们客户端存储的cookie

1,设置和获取cookie
cookie由于是在客户端的,所以我们可以自己手动添加一些信息,你想写什么写什么,但是你在百度的网站下面写的话他们的后端是不会去认可识别的
java
@RequestMapping("/getcookie")
public String getcookie(HttpServletRequest request){
Cookie[] cookies=request.getCookies();
if (cookies!=null){
for (Cookie cookie:cookies){
System.out.println(cookie.getName()+"="+cookie.getValue());
}
}
return "获取cookie成功";
}
@RequestMapping("/getcookie2")
public String getcookie2(@CookieValue("username") String username){
return "获取cookie成功,username:"+username;
}
@RequestMapping("/setcookie")
public String setcookie(HttpServletResponse response) {
// 1. 创建 Cookie 对象
Cookie cookie = new Cookie("username", "zhangsan");
// 2. 设置 Cookie 的有效期(单位:秒)
cookie.setMaxAge(60 * 60);
// 3. 设置 Cookie 的路径
cookie.setPath("/");
// 4. 将 Cookie 添加到 HTTP 响应中
response.addCookie(cookie);
return "添加Cookie成功";
}


2,设置和获取session
java
@RequestMapping("/setsession")
public String setsession(HttpServletRequest request){
//先获取session对象,没有的话会先创建一个
HttpSession session = request.getSession();
session.setAttribute("username","zhangsan");
session.setAttribute("userid","1234");
return "设置session成功";
}
@RequestMapping("/getsession")
public String getsession(HttpServletRequest request){
//先获取session对象,没有的话会先创建一个
HttpSession session = request.getSession();
System.out.println(session.getAttribute("username"));
System.out.println(session.getAttribute("userid"));
return "获取session成功";
}
@RequestMapping("/getsession2")
public String getsession2(@SessionAttribute("username")String username){
return "获取session成功,name:"+username;
}
@RequestMapping("/getsession3")
public String getsession3(HttpSession session){
return "获取session成功,name:"+session.getAttribute("username");
}

响应(处理完的结果怎么返回客户端)
1,返回静态HTML页面(利用网址/利用代码)

我们先在这个目录底下创建一个html文件,然后在浏览器里面输入网址就可以访问到网页了
http://localhost:8080/index.html
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Spring MVC 测试</title>
</head>
<body>
<h1>欢迎学习 Spring MVC!</h1>
<p>这是 Spring Boot 提供的静态页面。</p>
<button onclick="alert('点击成功')">
点击我
</button>
</body>
</html>

这是我们不写controller,也可以直接访问到网页的,并且当你的网址不写后面的/index.html也是可以正常访问到相同的界面的,因为我们的Spring Boot会默认自动去处理static下的index页面,所以这个取名也是比较关键的
那如果我们想要用户不直接输入网页名称的后缀名index.html也可以访问到网页的话就需要写controller来跳转了
java
@Controller
public class PageController {
@GetMapping("/html")
public String html() {
return "/index.html";
}
}
2,@Controller 和 @RestController 有什么区别?
因为我们前面写的代码前面有一个注解叫RestController,那我们现在写的这个Controller又是什么呢,他们有什么区别,最大的区别就是RestController主要用途是返回数据,所以如果当我们在刚刚的代码前面也写这个的话,返回的就不是网页了,而是一个字符串,但是Controller主要的用途是返回网页以及视图,所以我们这么写就会去找前面我们写的html代码了,然后返回网页
3,@ResponseBody(返回数据)
因为我们前面讲到的@RestController也是返回数据,这个也是返回数据,你会发现,当你要返回一个数据的时候,写这两个哪一个都是一样的结果,那怎么理解这两个注解呢:
这两个的主要区别是适应范围和方式:
| 对比 | @ResponseBody |
@RestController |
|---|---|---|
| 注解位置 | 方法上或类上 | 类上 |
| 核心作用 | 将返回值写入响应体 | 声明控制器,并默认将返回值写入响应体 |
| 是否能返回 HTML 代码 | 可以 | 可以 |
| 是否能返回 JSON | 可以 | 可以 |
我写两个代码,这两个代码可以很很好的理解这个
java
@Controller
public class TestController {
@ResponseBody
@GetMapping("/hello")
public String hello() {
return "Hello Java";
}
@GetMapping("/home")
public String home() {
return "forward:/index.html";
}
}
这个正常返回网页
java
@RestController
public class TestController {
@GetMapping("/hello")
public String hello() {
return "Hello Java";
}
@GetMapping("/home")
public String home() {
return "forward:/index.html";
}
}
这个不会返回网页,而是返回forward:/index.html,如果 @RestController也访问网页的话只能在方法里面直接书写html代码,并且设置一个响应类型为网页
返回带有 CSS 样式的 HTML
java
@RestController
public class HtmlController {
@RequestMapping("/htmlh1")
public String html() {
return "<h1>你好,一级标题</h1>";
}
}

这里spring会自动识别出来我们这是一个以及标题
Content-Type
这个决定了我们后端返回的参数的类型是什么,是html还是JSON等等
常见的类型
| Content-Type | 代表类型 | 常见用途 |
|---|---|---|
text/plain |
普通文本 | 返回字符串 |
text/html |
HTML | 返回网页内容 |
application/json |
JSON | 前后端传输数据 |
application/xml |
XML | 传输 XML 数据 |
application/x-www-form-urlencoded |
表单编码 | 提交普通表单 |
multipart/form-data |
多部分表单数据 | 上传文件、表单 |
application/octet-stream |
二进制数据 | 通用文件传输 |
image/png |
PNG 图片 | 返回 PNG 图片 |
application/pdf |
PDF 文档 | 返回 PDF 文件 |
如何设置类型
通过produce来设置
java
@RestController
public class TestController {
@RequestMapping(
value = "/user",
method = RequestMethod.GET,
//这里设置类型,我现在转为JSON类型
produces = "application/json"
)
public Map<String, Object> getUser() {
Map<String, Object> user = new HashMap<>();
user.put("name", "张三");
user.put("age", 20);
user.put("major", "计算机科学与技术");
return user;
}
}
响应JSON
以下Java类可以自动转化为JSON格式

java
@ResponseBody
@RequestMapping("/returnJson")
public User returnJson() {
return new User("zhangsan", 20,123,"123qq.com");
}


状态码更改
HTTP 状态码不是根据服务器想表达什么随便修改,而应该遵循 HTTP 标准含义。4xx 表示客户端请求问题,5xx 表示服务器处理问题。后端根据实际情况返回合适的状态码,前端根据状态码或者业务状态码决定展示什么页面或提示。
java
@ResponseBody
@RequestMapping("/setType")
public String setType(HttpServletResponse response) {
response.setStatus(400);
return "设置状态成功";
}
到此Spring MVC三要素大致的内容已经讲解完毕,接下来的一篇文章会介绍一下相关的小练习