上节课我们学习了关于Spring Boot的相关知识,了解关于spring boot项目的创建,初级使用,配置文件的介绍,还有关于快速查找和定位问题的日志介绍,接下来我们学习Spring MVC相关知识
首先我们看下官方对Sping 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 MVC实际上是基于Servlet API的框架,说明他是兼容Servlet的,在我们之前学的Servlet来写博客系统,在这里创建Spring MVC也是同样适用.
其次,它本身是包含在Spring 框架的,说明他也是基于sping框架的,说到这里大家还记得当时spring boot的时候是如何介绍spring boot和sping的关系吗?
当时是这样说的,spring boot就是spring框架的脚手架,为了快捷开发spring
而生的框架,而在这里的Spring MVC实际上就是spring框架中的web模块
然⽽要真正的理解什么是 Spring MVC?我们⾸先要搞清楚什么是 MVC?
MVC 是 Model View Controller 的缩写,它是软件⼯程中的⼀种软件架构模式,它把软件系统分 为模型、视图和控制器三个基本部分

实际上MVC就是这样一种架构模型
用户最开始在游览器上输入一串URL后,通过HTTP/HTTPS协议将请求传递给了Controller控制器,然后Controller会去验证客户端发来的请求,确认无误之后,再将这个发送到Model模型中进行数据的处理(调用数据库)并且把响应信息发送回来,但是这个时候并不是把这个响应直接就返回给客户端了,而是先去交给View进行数据的处理显示部分
这里仔细说下View的作用,可能很多人不太懂,为啥响应不直接发送给客户端,而是还要经历View这一层呢???
因为Model返回的响应只是数据部分,不能直接去给用户看,用户看不懂格式,假设返回的是json格式,用户就会很懵逼,这个时候需要View层进行渲染,将原来的数据与服务器的渲染模板进行结合在一起,组成一个最终可读性都很高的页面给客户端,这个才是一次完整的交互…
上面说了MVC其实就是一种架构模型,是一种思想,而Spring MVC就是对这种思想的实现
就像我们之前讲Spring的时候,IOC就是一种思想,而DI就是基于IOC上去实现注入对象
总结来说,Spring MVC 是⼀个实现了 MVC 模式,并继承了 Servlet API 的 Web 框架。既然是 Web 框 架,那么当⽤户在浏览器中输⼊了 url 之后,我们的 Spring MVC 项⽬就可以感知到⽤户的请求
现在绝⼤部分的 Java 项⽬都是基于 Spring(或 Spring Boot)的,⽽ Spring 的核⼼就是 Spring MVC。也就是说 Spring MVC 是 Spring 框架的核⼼模块,⽽ Spring Boot 是 Spring 的脚⼿架,因此我 们可以推断出,现在市⾯上绝⼤部分的 Java 项⽬约等于 Spring MVC 项⽬,这是我们要学 Spring MVC 的原因
在创建 Spring Boot 项⽬时,我们勾选的 Spring Web 框架其实就是 Spring MVC 框架

在创建Spring Boot项目的时候,如果你不加上 Spring Web 它就不是Spring MVC项目,加上之后就是了
你可以理解 当初我们创建Servlet项目的时候,创建的还是maven项目,只有你最后导入Servlet的依赖之后,才从maven -> Spring MVC
简单来说,咱们之所以要学习 Spring MVC 是因为它是⼀切项⽬的基础,我们以后创建的所有 Spring、 Spring Boot 项⽬基本都是基于 Spring MVC 的。
1.连接的功能:将⽤户(浏览器)和 Java 程序连接起来,也就是访问⼀个地址能够调⽤到我们的 Spring 程序。
2 获取参数的功能:⽤户访问的时候会带⼀些参数,在程序中要想办法获取到参数
3 输出数据的功能:执⾏了业务逻辑之后,要把程序执⾏的结果返回给⽤户。

对于 Spring MVC 来说,掌握了以上 3 个功能就相当于掌握了 Spring MVC
在 Spring MVC 中使⽤ @RequestMapping 来实现 URL 路由映射,也就是浏览器连接程序的作⽤
这里是写了两个注解: 其实@RequestMapping注解就是实现URL路由的,如果你想设计两级路径的话,你可以在类上再加上该注解,否则的话一级路径就能搞定
第二个注解就是@RequestBody,它的作用之前也是说过,就是去返回一个非静态页面,加上该注解后,返回的是数据,否则会去查找是否存在你好 世界的名字的一个页面,不存在就会报错,那么他加到方法是就是针对这个方法进行了处理,如果加到类上,该类的每个方法返回的都是本身数据而不是静态页面


@RequestMapping 是 Spring Web 应⽤程序中最常被⽤到的注解之⼀,它是⽤来注册接⼝的路 由映射的。
@RequestMapping 注解介绍 路由映射:所谓的路由映射指的是,当⽤户访问⼀个 url 时,将⽤户的请求对应到程序中某个类 的某个⽅法的过程就叫路由映射。
@RequestMapping 即可修饰类,也可以修饰⽅法,当修饰类和⽅法时,访问的地址是类 + ⽅ 法。

实际上在之前的版本,RequestMapping默认是支持Get请求,现在优化了,默认情况下Get和Post请求都支持的
但是有些公司就为了便于管理,打算统一用Get或者Post请求,这个时候你就需要去指定了具体的哪种请求了



上面那种又比较麻烦,所以换成直接指定的注释

在Spring MVC中可以直接用方法中的参数来实现传参
我们在控制台看到了在前端传过来的参数,并且在控制台打印出来了


关于传参数,是有很多说法的
1.假设前端传参数是分两种情况

,我们可以看到,在方法里是没有设置格式,而Spring MVC对针对传出的数据,会自动给设置类型
针对对象或者HashMap参数,他就会给返回一个json格式的数据,要是字符串呢,他就会转换成text格式
所以他是很智能的去识别并且判断出转换成什么格式…


传入对象参数的好处就是你不需要在前端传入多个参数,只需去传入id或者姓名等等主键字段,就可以去数据库中找到唯一对象,返回对象的信息

假设前端传入id是空,根据上面的代码即使传入的参数是Integer id也会报错,仔细一看是在setId那一行,因为传入的id是Integer类型,但是实参的id是int类型,所以设置id的时候,因为传入的是null,这里int就会发生冲突

这里你就可以去做个非空的效验,如果你本身形参的类型是int 报错就是传入参数那一行,这样的话就没问题了




仔细理解这句话,为所以形参的顺序和实参的顺序不需要一一对应是因为,从前端传入的参数,他也不是傻傻的按着顺序去赋值的,而是先去根据字段名对比,对应上了就进行赋值

某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不⼀致,⽐如前端传递了⼀个 time 给后端,⽽后端⼜是有 createtime 字段来接收的,这样就会出现参数接收不到的情况,如果出现 这种情况,我们就可以使⽤ @RequestParam 来重命名前后端的参数值
这里通过@RequestParam 注解来进行重命名,匹配上前端的参数
接下来就是改变参数的值,来验证是否是否有效
当把参数设置为true的时候,这个参数你是你是传递不可,而且必须是重命名后的time参数,否则就会报错.你最好是设置为false,这样当没有传递参数,也不至于会报错.
上面我们讲了后端参数的重命名,接下来继续讲关于参数的传递
注意后端处理的这边的语法形式,加了@RequestBody就说明返回的这个对象是以json格式返回的


注意这里是获取URL中的参数,不是URL参数的参数,为什么这样说呢???
之前我们知道很多URL地址中包含一些通过?来分割开的参数
比方 https://xxx?zzz 这里zzz就是URL的参数部分,而我们这里指的不是这一部分,而是在?前面的URL地址部分的参数

很多人看到这里会有点懵逼,其实也是有这种写法的,在URL地址中存在参数作为路径的,那么在实际上的前端中传入的参数就是后端要接收的参数
接下来一个代码示例就很清楚了




上面的上传图片就比较简略,写死的目录和文件后缀名,接下来就要对这些问题进行处理一下
在这之前,有个扩展知识可以了解一下

在实际的开发项目的过程中,我们可以创建三个配置文件,一个dev(开发过程中)一个prod(上线过程中)一个是控制究竟是开发还是上线的配置文件,这样的可以简化我们的开发,有的时开发和上线的配置项不一样,如果只执行一个改来改去就很麻烦,在开发过程中配置开发的那个yml,在上线过程中配置另一个yml,然后在运行的时候你可以再去指定究竟是哪个…

那么在写上传文件这个接口的时候,也就体现了方便性,你可以分别在两个配置文件中写这两个平台的路径进行存储图片(开发在windows,上线在linux上)
然后你只需去设置配置文件的运行平台即可


获取Cooike实际上有两种方式,一个是通过Servlet,另一个就是通过@CookieValue注解来实现

显示通过Cooike数组来写的话,比较繁琐,所以通过注解的方式就来获取到某一个具体的cooike对象
这两种都模拟了一遍,你可以自己去游览器控制台添加cookie并且在控制台打印

获取header也是很简单的两种方式,有的时候获取header,因为header里面有客户端的设备信息和型号,那我们可以去通过这个型号进行统计,那些产品用的更多之类的

Session 存储和 Servlet 类似,是使⽤ HttpServletRequest 中获取的


在获取session的时候是有两种方式,但是在判断的时候需要进行双重判断,不仅仅要判断会话不为空还要判断会话里面的某个cookieName不为空,否则就不能获取该会话里某个CookieValue,这个处理方法在Servlet是是需要去考虑的,当然你也可以通过注解的方式去设置参数的值来保证不会报错

实际上 session是服务器的存储机制,cookie是客户端的存储机制,
当第一个cookie出现后,我们就需要在服务器第一次创建会话来存储该cookie的name和value,并且将生成的token/sessionID返回客户端,客户端记录下这个sessionID,下次再去访问相关页面就会带上这个sessionID来直接识别用户身份,这都是之前Servlet里面的内容
通过上⾯的学习我们知道,默认请求下⽆论是 Spring MVC 或者是 Spring Boot 返回的是视图 (xxx.html),⽽现在都是前后端分离的,后端只需要返给给前端数据即可,这个时候我们就需要使⽤ @ResponseBody 注解了。

咱们先去处理后端接口

然后再去处理前端,这里前端通过form表单形式来提交,就很简单

这里可以直接通过hashMap来直接返回,因为hashMap本身就是键值对格式


@RequestMapping("/login2")
public HashMap<String, Object> login2(String username, String password) {
HashMap<String, Object> result = new HashMap<String, Object>();
int state = 200;
int data = -1; // 等于 1,登录成功,否则登录失败
String msg = "未知错误";
if(StringUtils.hasLength(username) && StringUtils.hasLength(password)) {
if (username.equals("admin") && password.equals("admin")) {
data = 1;
msg = "";
}else{
msg = "用户名或密码错误!";
}
}else{ // 参数为空
msg = "非法参数";
}
result.put("state", state);
result.put("data", data);
result.put("msg", msg);
return result;
}

后端逻辑中我们最后返回给前端的数据就是result,result本身就是一个hashmap里面的键值对形式的数据,如果我们在前端不做处理,返回的格式就是类似于这种

咱们先去把前端代码展示一下


然后接下来 将后端传的两个参数直接改成传对象试一下
由此可见,后端这里实际上是不需要修改啥的,但是前端那里有几个点需要注意,不然的话不容易出来你想要的内容



上面几个点我都指了出来,因为这里面格式的问题要注意的特别多
forward VS redirect

具体内容可以参考这篇大牛文章,说的肯定比我讲的好
请求转发和重定向的区别