这一部分是关于SpringMVC的内容
看一个事物的定义,我们首先应看一下官方对他的定义
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”
所以我们提炼提炼下上面的话,可以得出两个知识点:
1.SpringMVC是一个Web框架
2.SpringMVC基于Servlet构建
所以我们大致的了解了什么是SpringMVC,那:什么是MVC?
MVC 是 Model View Controller 的缩写,它是软件工程中的一种软件架构模式,它把软件系统分为模型、视图和控制器三个基本部分。
我们一个一个来说
Model(模型)
:是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。
View(视图)
:是应用程序中处理数据显示的部分,通常视图依据模型数据创建
Controller(控制器)
:是应用程序中处理用户交互的部分。通常控制器从视图读取数据,然后控制用户输入,并且向模型发送数据。
所以我们总结一下,具体的流程如下:
<1>`控制器(Controller)`接收HTTP请求
<2>把请求数据转换为`模型(Model)`
<3>经过一些业务逻辑处理,如根据请求数据进行不同的逻辑业务操作(数据库的CRUD操作)
<4>返回一些数据给客户端
<5> 这些数据最终可能包装为一个`视图(View)`:比如说网页(html),数据(json),文件(Controller的返回方法决定)
设计模式有很多,所谓的MVC只是其中一种的
其实你可以发现,我们上面的MVC就是一种具体的处理流程,它属于一种思想,但是Spring MVC更加的具体,也就是说而Spring MVC 是对 MVC 思想的具体实现。
那么再次更新定义Spring MVC定义: Spring MVC 是一个实现了 MVC 模式,并继承了 Servlet API 的 Web 框架
。
现在绝大部分的 Java 项目都是基于 Spring(或 Spring Boot)的,而 Spring 的核心就是 Spring MVC。
也就是说 Spring MVC 是 Spring 框架的核心模块,而 Spring Boot 是 Spring 的脚手架,因此我们可以推断出,现在市面上绝大部分的 Java 项目约等于 Spring MVC 项目,这是我们要学 Spring MVC 的原因。
所以一句话总结:Spring MVC是一切项目的基础,我们以后创建的Spring,Spring Boot都是基于Spring MVC的。
Spring MVC就是MVC的具体实现,所以根据上面的流程,我们可以分出以下三个学习目标
1. 连接的功能:将用户(浏览器)和 Java 程序连接起来,也就是访问一个地址能够调用到我们的Spring 程序。
2. 获取参数的功能:用户访问的时候会带一些参数,在程序中要想办法获取到参数。
3. 输出数据的功能:执行了业务逻辑之后,要把程序执行的结果返回给用户。
其实也很简单,就是创建一个SpringBoot项目,这个Spring Web项目是第一次开发SpringBoot项目时候就会勾选上
但是这里笔者提一句,如果说此时你的网络特别的慢,创建一个项目要花费的时间,又要从网上去下载一些资源,你怎么办呢?
是不是有宝子们很疑惑?这是个啥创建方式?没事,往下看
1.建立我们之前SpringBoot项目中的这两个文件,注意我们的启动类的路径一定要对,还有就是要建立一个static包,我这里没有框出来
是不是很好奇,为什么可以这么搞?因为前面我们的SpringBoot项目当中,我们仅仅需要MVC的部分,所以我们可以直接从之间建立好的项目中去复制我们需要的部分
1.依赖 2.启动类 3.static文件夹用来返回视图(新建另外的文件都可以,我也是这样操作的,一定是要有的)
@RequestMapping 是 Spring Web 应用程序中最常被用到的注解之一,它是用来注册接口的路由映射的
。
这里我们写一个类用来准备演示接下里的所有操作
@Controller //第一步:加注解,表示注册到容器中作为(bean对象),注册为控制器
public class TestController {
}
肯定先要给我们的类加一个Controller注解,要让Spring可以扫描到,让当前类可以作为一个bean对象被容器装载
然后我们就要定义一个方法来处理我们的http响应和请求
,之前Servlet中是怎么处理的呢?是不是根据请求的路径和方法来匹配我们里面的某一个类
?所以这里其实还是一样的思路,但是没有之前那么多的代码量了
@Controller //第一步:加注解,表示注册到容器中作为(bean对象),注册为控制器
public class TestController {
@RequestMapping("/t1")
public Object t1(){
return null;
}
}
//这里我要特别对@RequestMapping("/t1")进行说明
@RequestMapping("/t1")就是定义服务资源的注解,可以配置我们的服务路径和服务方法
然后开始我们正式的访问之路
首先运行启动类,然后在浏览器中输入我们的url路径:
127.0.0.1:8080/t1
,这里就不用带项目路径了
然后发现报错了,但是具体啥原因,我们也不知道呀,加调试信息
呗,让他打印报错信息咋们看看
然后看报错信息
那就给他返回一个视图呗,就看他还报不报错
这里我们再次进入引用探讨模式
首先,我们在url中的queryString中携带两个数据:
127.0.0.1:8080/t1?a=1&b=xxx
,这就是一个很简单的URL携带数据,然后我们在后端接收并且打印一下
@RequestMapping("/t1")
public Object t1(Integer a,String b){
//然后这里使用日志框架进行打印
log.debug("a={},b={}",a,b);
return "/test.html";
}
然后访问一下看看(这里没有报错,我们就可以关闭DeBug了,不然打印太长,不好看)
首先可以看到,是发送并且响应成功了的
然后设置级别,并且在当前的类上加上日志框架的注释@Slf4j//这是日志框架
这个时候问题就来了,你是怎么识别数据并且到我们的model里面的呢?你咋知道怎么对应的?所以我们改一个参数名,然后再看看
这里我们把a改成 abc看看
queryString里面是存的是键值对,所以这里根据我们上面的实验可以看到它其实是通过键名来进行数据转化的
这里我们一个一个来
先来看一下表单格式
很神奇不是嘛?我们通过postman发送http请求,携带表单格式,明明一切正常,接收和请求每一点问题,响应状态码也是200,但是后端没有数据打印出来?问题在哪里呢?
我们再看看一下postman,仔细看看,是不是有不对的地方?没错
虽然说get方法和post方式都可以在body里面包含数据,但是你表单数据通过get方法去递交数据,响应是响应成功了,但是我们后端不支持这种格式,也就是说它不符合规范,所以我们要换成post方法
然后看一下form-data格式
还有queryString也可以,我们上面演示了,这里就不演示了,但是这里对postman有一点需要我特别说一下的
这里我们有两个参数a和b不是?一个是Integer。一个是String,所以这里我们构造一个类,然后用该类的对象接收参数
@Data //作用就是生成get setter toString equals/hashcode等
public class Test {
private Integer a;
private String b;
}
其实这里它还少了一个构造方法,我们可以通过一些特别的方法看到它
然后正式开始我们传递对象的内容
可以看到,本来应该会返回的html,但是这里没有,仔细看看我们的postman,发现是方法忘了修改
,应该是get方法的
然后此时就响应成功了,如果此时不放心,我们还可以打印一下对象的属性
所以这里就有问题啦,那我简单类型我能接受你的请求,我对象里面设置属性我也可以接收你的请求,那使用场景是什么呢?
这里就看你请求数据键值对的个数了吧?少的话就简单类型就行,省点资源,多的话就对象,减少操作。
这是个啥意思?什么叫做参数必传
?实际场景来说一下
还是我们上面的代码,给a加一个注释
注意看此时的报错信息,然后我此时不传a,咋们再看报错信息
这就是参数必传
的意思
此时的b传了就显示b的内容,没传就是null,对b没有影响。那么就有同学要问了,我不想去掉参数必传注释但是又想让该字段传或者不传,那我怎么搞?
说来惭愧,博客都发布了突然想起来还有这个内容,所以来加上,这一部分就是来接收我们的消息体的,然后之前写的时候总觉得这里内容有点突兀,一直没想起来缺了啥,现在补上,就是我们有json格式的消息体的时候,我们要加上这个注解,然后就可以对json格式的数据进行解析
然后这里注意和上面区分一下,一个是@RequestBody接收所有类型请求题,一个是@RequestParam参数必传
这里接着我们上面的代码写,如果此时我们想要接收一个文件,怎么办呢?
毕竟form-data是可以携带文件
的(不能太大嗷!)
然后这里的话就要用MultipartFile来进行我们的接收
这是不是可以更近一步的说明我们的数据转化是通过键名来的?
然后这里你还可以给它设置参数必传,比如说
这里我们说了,Controller控制器注释是为了保证当前的Bean对象可以被注册到容器当中,所以类上要加。而@ResquestMapping
是提供了服务的路径。这里我们的类和方法都是可以加的,具体情况如下
加了之后,我们访问的路径就要稍微做一点小改变了,比如此时我们运行启动类,然后用postman去访问
所以可以这里小小总结一下
然后可以看到,我们上面返回的其实基本都是基础类型,还有些返回了网页,问题就出在网页这里,一般来说,我们返回的不是网页内容,那么默认的服务方法(全部都是支持的)
但是如果返回的是网页呢?这个时候我们就需要配置了。如下:
但是这种方式就有点麻烦,我们能不能有其他的方式呢?有,那就是我们的组合注释
@GetMapping和@PostMapping
为了我们上面代码的简单化,就有了这两个组合注解,当然,spring里面组合注解有很多,不是只有这两种,这里我就是只演示了这两种,还有其他的比如@RestController = @Controller + @ResponseBody
,这是题外话,接下里我演示一下这个组合注解的用法。
(1)这里我们接收的时候,可以使用简单类型来接收,也可以使用对象来接收,
这个看我们自己的选择。如果说参数少,就简单类型接收就好,多了的话就对象
接收提高效率。
(2)你可以选择加注解或者不加注解,这里注解我们就讲了一个@RequestParam
参数必传,其他的有需要的时候我们再说。参数必传你可以给赋值,然后让它和达
成和没有时候一样的效果
(3)接收JSON数据的时候:你要给用来接收的对象或者简单类型前面加上注释@requestBody
(4)文件接收也很简单,就是用一个MultipartFile类型参数来接收
(5)然后就是我们的组合注解,这里使用也很明了,具体的根据实际情况来判断
复习一下我们的URL格式
协议名://域名:port(端口号)/带层次的文件路径?queryString
然后,这里如果说我想要拿到你这个路径名称呢?就是文件路径的名称,这里就不写格式了,直接看具体实现
这里啥意思呢?
@PostMapping("/m6/{name}/{password}")
这里的name和password就是我们之后方法的变量名,同时方法的参数前面就上@PathVariable
这样就可以获取到我们的方法路径
这里说白了就是获取我们的sessionID,所以这里不对此会话机制做过多的讲解
还是给我们的方法参数前面加上了一个注解@CookieValue
我们上面说了什么呢?Spring MVC是基于继承了Servlet的API,所以当然可以通过Servlet的方式获取啦
这是一种很有意思的方式,来看看下面这个,没有什么特别的语法,机制就很有意思
然后我们打印出来之后可以看到打印成功没什么问题
那么如果我们去掉seesionID呢?
然后发现他还会继续打印,这里我实验了好几次,每次删掉sessionID之后,他还是会打印,然后我没删sessionID后发送了几次请求才发现他是这么搞的
这一部分的话就是session存在的时候才可以获取到,看下面
先看一下通用的格式
@RequestMapping("/header")
@ResponseBody
public String header(@RequestHeader("User-Agent") String userAgent) {
return "userAgent:"+userAgent;
}
这里就是在你的方法参数前面加上一个@RequestHeader("请求头中的键名")
,然后直接获取就好,但是这里特别注意一下,你的请求头当中一定要有该键值对,没有就会报错
其实这部分是在我博客快写完的时候发现漏了这个玩意的,文件处理部分没有讲,这里稍微说一下,后续用到的时候再提。
这里的c对象,是MultipartFile c
如果说是保存文件:
1.c.getByte() 返回byte[]
2.c.getInputStream 返回输入流,自行读取获取数据
3.c.tranferTo(new File(...))保存
如果说是获取文件名
log.debug("filename = {}",c.getOriginalFilename());
先说一说什么是转发和重定向。
forward:请求转发,请求服务端后端代码,后端直接把响应正文网页放在响应体
当中,一次请求路径不变。
redirect:请求重定向,后端返回状态码301/302/307,响应头location=xxx(重定向路径)
然后客户端浏览器自动的发起第二次请求:以location中的路径,也就是说,两次
请求路径会变
其实我们之前就是一直是转发,也就是返回html网页
但是我们之前的是省略写法,这里写全大家看一下
然后在postman当中查看我们的响应体
然后这里再来看一看我们的重定向
这里你看不出个啥,然后这里就要用到我们的抓包工具了
前面我们在返回null的时候有时候会报错,可是加了@Response
就不会报错了,为什么呢?
@Response:该注解通过请求映射方法,把返回值序列化为JSON字符串,设置为
响应正文Body
所以这里这一点是对我们之前的一个使用说明
注意我这里的Test对象里面就两个属性,一个Integetr,一个是String
然后关于数据结构这里,我们这里使用map和List进行演示
这里作为一个了解小拓展内容
甚至你还可以自己随意发挥
然后这里还有一点补充是关于@ResponseBody的,就是你可以直接把该注解加到类上,就不用和我一样在这里写一个方法加一个方法了。
这一篇博客呢,就是关于Sping MVC的基础学习,我们主要学到了
什么是MVC?MVC和Spring的关系
最最重要的是,作为MVC具体实现的Spring MVC它是怎么在后端处理业务的。
- 连接的功能:将用户(浏览器)和 Java 程序连接起来,也就是访问一个地址能够调用到我们的Spring 程序。
- 获取参数的功能:用户访问的时候会带一些参数,在程序中要想办法获取到参数。
- 输出数据的功能:执行了业务逻辑之后,要把程序执行的结果返回给用户。