简介

简单的来说,就是一个在表述层负责和前端数据进行交互的框架
帮我们简化了许多从前端获取数据的步骤
springmvc基本流程

用户在原本的没有框架的时候请求会直接调用到controller这个类,但是其步骤非常繁琐
所以我们就使用springmvc进行简化
当用户发送请求时,首先到达的是Servlet,解析用户的请求,然后去mapping类寻找用户请求的是类中的哪一个方法
接着寻找到是哪个类之后,在发送request到Adapter去,此时adapter会拆解request然后将其中有用的参数发送给handler执行对应的逻辑
接着handler执行完毕后再发送adapter处理JSON串给servlet一个respone报文,返回给前端做出数据响应
核心组件
-
DispatcherServlet : SpringMVC提供,我们需要使用web.xml配置使其生效,它是整个流程处理的核心,所有请求都经过它的处理和分发![ CEO ]
-
HandlerMapping : SpringMVC提供,我们需要进行IoC配置使其加入IoC容器方可生效,它内部缓存handler(controller方法)和handler访问路径数据,被DispatcherServlet调用,用于查找路径对应的handler![秘书]
-
HandlerAdapter : SpringMVC提供,我们需要进行IoC配置使其加入IoC容器方可生效,它可以处理请求参数和处理响应数据数据,每次DispatcherServlet都是通过handlerAdapter间接调用handler,他是handler和DispatcherServlet之间的适配器![经理]
-
Handler : handler又称处理器,他是Controller类内部的方法简称,是由我们自己定义,用来接收参数,向后调用业务,最终返回响应结果![打工人]
-
ViewResovler : SpringMVC提供,我们需要进行IoC配置使其加入IoC容器方可生效!视图解析器主要作用简化模版视图页面查找的,但是需要注意,前后端分离项目,后端只返回JSON数据,不返回页面,那就不需要视图解析器!所以,视图解析器,相对其他的组件不是必须的![财务]
springmvc运用大致流程
首先声明一下controller
通过requestMapping指定该类的访问路径
java
package com.atguigu.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HelloController {
// 对外访问的地址,到handlerMapping注册的注册
@RequestMapping("springmvc/hello")
@ResponseBody//直接返回字符串给前端不需要找视图
public String Hello()
{
System.out.println("hello");
return "springMvc Hello";
}
}
接着我们声明一个配置类,将各种springmvc需要的类放入ioc容器当中
通过Bean组件放入ioc容器
java
//TODO: 导入handlerMapping和handlerAdapter的三种方式
//1.自动导入handlerMapping和handlerAdapter [推荐]
//2.可以不添加,springmvc会检查是否配置handlerMapping和handlerAdapter,没有配置默认加载
//3.使用@Bean方式配置handlerMapper和handlerAdapter
@EnableWebMvc
@Configuration
@ComponentScan(basePackages = "com.atguigu.controller") //TODO: 进行controller扫
//WebMvcConfigurer springMvc进行组件配置的规范,配置组件,提供各种方法! 前期可以实现
public class MvcConfig implements WebMvcConfigurer {
@Bean
public HandlerMapping handlerMapping(){
return new RequestMappingHandlerMapping();
}
@Bean
public HandlerAdapter handlerAdapter(){
return new RequestMappingHandlerAdapter();
}
}
那么我们知道spring中将类放入ioc容器中是需要读取一些配置文件的
那么将springmvc需要的各种工具类放入ioc容器中依靠的是如下的接口
AbstractAnnotationConfigDispatcherServletInitializer
java
package com.atguigu.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
//该类可以被web项目加载,会初始化ioc容器,会设置dispatcherServlet的地址
public class SpringMvcInit extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
// 设置我们项目的配置类
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{MvcConfig.class};
}
// 配置springmvc内部自带的servlet的访问地址
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
// 单个斜杠就代表着处理所有的用户请求的意思
}
}
那么上述的方法是如何实现将类放入ioc容器中呢?
我们先介绍一个接口
这个接口里面有一个onStartUp函数,其中这个函数会在web项目启动的时候调用

web容器初始化讲解
我们来找寻
AbstractAnnotationConfigDispatcherServletInitializer
的继承关系然后找出web容器初始化的原理

当我们点进去它的父类之后,我们再进去它的父类观察

再父类里面我们发现有一个
registerDispatcherServlet
方法,这个方法就是将web容器放入ioc容器当中的方法,我们点进去观察

点进去这个方法之后,我们发现有一个名为
createServletApplicationContext();
的方法,我们再点进去观察

我们在这里发现,有一个
AnnotationConfigWebApplicationContext();
类,这个类再spring中是用于读取配置类和配置文件将类导入ioc容器中的类
紧接着我们发现,在这个类中,我们发现了一个
getServletConfigClasses();
这个方法。是不是很熟悉?
我们回到最开始的地方观察

在最开始的继承了上述所有类的子类中,是不是有一个这样的方法
将配置类通过反射装入数组,然后再父类的函数中调用数组将其放入了ioc容器
如果对象数组不为空就将其配置类放入ioc容器进行注册

里面还有servletmapping的代码,用于将地址映射的类也装入ioc容器中

SpringMvc接收数据
1.访问路径设置
Java代码展示
该代码中和新注释就是@ResquestMapping
该注释能够使得这个controller响应一个user的网页路径请求
并且写在该类下的所有方法的请求路径都是
/user/方法上的request路径
其余的原理都写在了注释里
java
package com.atguigu.requestmapping;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("user")
public class UserController {
// handler->handlerMapping
@RequestMapping("login")
public String login() {
return "login";
}
// 可以通过一个字符数组装入注册的地址,可以响应多个请求地址,method用于指定前端发送什么请求类型才会响应
@RequestMapping(value = {"register","login"},method = RequestMethod.GET)
public String register()
{
return "register";
}
// 模糊匹配,*表示前面如果是/user,则后面不管是/user/dasdasdasd /user/ds都能匹配 不过多层不可匹配/user/a/a这样就不能匹配
// **表示前面如果是/user,则后面不管是/user/aa/aaaa/aaaa/,多少层都能够匹配
// @GetMapping表示该方法以get方式接收请求实际源码只不过是多加了一个method 指明了请求方式罢了
@GetMapping({"/user/*","/user/**"})
public String modifyPassword(){
return "modifyPassword";
}
}
2.接收参数
java
@RequestMapping("data")
@ResponseBody
// 形参列表,填写对应的名称参数即可! 请求参数名 = 形式参数名即可,这样会自动赋值
public String data(String name,int age)
{
System.out.println("name: "+name+" age: "+age);
return "name: "+name+" age: "+age;
}
通过指定requestMapping注释能够指定接收路径
通过ResponseBody能够指定该类直接返回给前端字符串进行接收
1.@Param注解

通过value指定传入参数时的key名字,就算是传入的key名字和参数名相同也会报错
required用于指定是否是必须被传入的参数,默认值是true代表必须传入,否则报错

2.一名多值
可以通过一个列表接收传入的多个值
但是注意,如果未使用requestParam那么就会报错
因为未使用requestParam就会代表着直接将一个字符串赋值给了一个列表报错

3.实体类接收参数
只需要将传入的参数名和实体类名保持一致即可


4.路径传参接收
要点:在路径标签中指定其路径的时候使用花括号将其括起来
然后再参数列表中声明一个与路径中花括号括起来的key值相同的名字即可
这样就可以获取到路径中的值,如下图结果所示
不过要注意,我们需要使用@PathVariable写在参数名前面,不然正常情况下默认规定其通过param方式获取数据
即便参数列表中参数名不相同依旧可以指定value的对应值与mapping注解中的key值传参


5.json数据接收
Java在没有导入对应的json转换依赖的时候是不能够获取到json数据的

我们导入一个json依赖

在配置类上方添加一个
@EnableWebMvc
注解就可以使得适配器转化json数据并发送给类进行接收

@EnableWebMvc解释
@EnableWebMvc注解效果等同于在 XML 配置中,可以使用 `<mvc:annotation-driven>` 元素!我们来解析`<mvc:annotation-driven>`对应的解析工作!
让我们来查看下`<mvc:annotation-driven>`具体的动作!
先查看标签最终对应解析的Java类

查看解析类中具体的动作即可
打开源码:org.springframework.web.servlet.config.MvcNamespaceHandler

打开源码:org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser
在对应的源码中,我们可以发现他将一个Adapter(经理)加入了ioc容器,并且在Adapter对象中加入了json字符串适配器能够解析json串


在源码中由于已经将Adapter和Handler加入了ioc容器,我们就不需要在手动生成这两对象假如ioc容器中,只需要添加一个注解即可

6.接收cookie数据
先来介绍一下cookie是什么
Cookie,即"小甜饼"的意思,在计算机领域中,特指一种由服务器发送到用户浏览器并保存在用户计算机(客户端)上的小型文本文件。它满足RFC6265标准,通常用于辨别用户身份、跟踪用户活动、保存用户设置等。以下是对Cookie的详细解释:
一、Cookie的定义
Cookie是一种技术,允许网站服务器把少量数据储存到客户端的硬盘或内存,或是从客户端的硬盘读取数据。这些数据以"名/值"对(name-value pairs)的形式储存,通常经过了加密处理,因此一般用户看到的只是一些毫无意义的字母数字组合,只有服务器的CGI处理程序才知道它们真正的含义。
二、Cookie的作用
- 会话管理:Cookie最初也是最主要的作用就是用于会话管理。当用户登录一个网站时,服务器会生成一个包含会话ID的Cookie并发送给浏览器,浏览器将这个Cookie保存在本地。此后,每次用户发送请求时,浏览器都会自动将这个Cookie发送给服务器,服务器通过会话ID识别用户身份,从而保持用户的登录状态。
- 个性化设置:Cookie还可以用来保存用户的个性化设置,如主题、语言、字体大小等。这样,当用户再次访问网站时,网站可以根据Cookie中的信息为用户提供更加个性化的体验。
- 购物车功能:在电子商务网站中,Cookie经常被用来实现购物车功能。当用户将商品添加到购物车时,这些信息会被保存在Cookie中。这样,即使用户关闭了浏览器或换了一台电脑,只要Cookie还在,购物车中的商品信息就不会丢失。
- 跟踪用户行为:网站可以使用Cookie跟踪用户在网站上的行为,如访问了哪些页面、停留了多长时间、点击了哪些链接等。这有助于网站分析用户行为,优化网站设计和内容。
- 广告定向:除了网站自己设置的Cookie外,还有一些第三方Cookie,它们通常由广告商或数据分析公司设置。这些Cookie可以用来跟踪用户在多个网站上的行为,从而为用户提供更加精准的广告定向服务。
三、Cookie的类型
- 会话Cookie(Session Cookies):这种类型的Cookie在浏览器关闭后就会被删除,主要用于保存用户的会话信息。
- 持久Cookie(Persistent Cookies):与会话Cookie不同,持久Cookie会在用户的计算机上长期保存,直到其过期时间到达或被用户手动删除。这种类型的Cookie常用于保存用户的登录状态、个性化设置等信息。
- 安全Cookie(Secure Cookies):安全Cookie只能通过HTTPS协议传输,不能通过未加密的HTTP协议传输。这增加了Cookie在传输过程中的安全性。
- HttpOnly Cookie:HttpOnly是一个标志属性,用于防止JavaScript代码访问特定的Cookie。当设置了HttpOnly属性的Cookie被创建后,它将无法通过客户端脚本(如JavaScript)进行访问。这有助于减少跨站脚本攻击(XSS)的风险。
四、Cookie的安全性问题及防范措施
虽然Cookie在许多方面都非常有用,但它们也存在一些潜在的安全风险,如XSS攻击、CSRF攻击、Cookie劫持和隐私泄露等。为了防范这些风险,网站可以采取以下措施:
- 设置HttpOnly属性、对输出进行编码等,以防止XSS攻击。
- 使用Token验证、检查请求的来源等,以防止CSRF攻击。
- 使用HTTPS协议对Cookie进行加密传输、设置SameSite属性等,以防止Cookie劫持。
- 遵循最小必要原则收集和使用用户数据,并采取加密、匿名化等安全措施,以保护用户隐私。
综上所述,Cookie作为一种重要的客户端技术,在互联网应用中发挥着举足轻重的作用。然而,在使用Cookie的过程中,我们也需要注意其潜在的安全风险,并采取相应的措施进行防范和保护。
那么我们如何接收cookie数据呢
我们在Java类中编写如下一个类,在参数中通过cookievalue指定cookiename的请求的参数名字

我们先用save通过响应报文存储一个cookie数据
可以通过图片看到存储成功了

接着我们通过cookiename这个key值从cookie中取出对应的value值显示在屏幕上

7.接收请求头数据

通过RequestHeader标签写在参数上,就能够通过参数获取到对应请求头的中的key值为Host的数据
8.获取原生api对象

SpringMVC接收数据总结

SpringMVC响应数据(输出数据)
两种开发模式介绍
1.前后端不分离介绍
整体调用流程
1.浏览器通过向服务端发送请求进行一些数据交互和页面跳转请求
2.controller层接收后通过三层架构一步步发送到mapper层(Dao层)
3.dao层通过和数据库交互获取数据返回到controller进行数据封装处理
4.在前后端不分离项目中,controller会将数据放入共享域中,并且找到需要跳转的html页面
5.然后前端页面会从共享域中拿取数据,并且将模板页面发送给controller层
6.接着将controller层中返回到的html页面发送给浏览器
7.主要用于小型的管理系统的开发

开发流程
我们首先在webapp下面的web-inf的文件中声明一个.jsp文件这是一个网页
接着我们创建一个配置类,让他继承WebMvcConfigurer
继承这个类之后我们就可以将视图解析器装入ioc容器中了(该类还封装了很多mvc容器需要的类,视图解析器的作用是将.jsp文件进行解析)
我们在重写的方法中,通过registry将文件的index.jsp的文件进行前后缀注册,以便能够定位到视图的位置

接着我们创建一个jspcontroller能够将视图返回给前端
其注意要点图里面就有
其中setAttribute是将数据放入共享数据域的

观察jsp文件,在共享数据区域获取数据

这是返回的结果

转发与重定向实现
转发指的是访问项目内的文件,范围只能是项目内
重定向指可以是向内也可以是向外
其在springMVC中的实现如下
先观察一下资源文件的访问路径是/jsp/index

转发
在转发中,我们先指定转发的访问路径将其设置为forward
然后我们在方法内返回视图文件的访问路径即可,但是要注意
在访问路径前面需要加一个forward编译器才能判定他是在进行转发
否则会直接识别为这是资源文件的位置进行解析,就如开发流程那里所说的一眼

通过转发的方式我们也到达了forward的文件的位置

重定向
其注意要点如图所示
这是向内重定向

同样也有向外重定向

2.前后端分离模式
主要通过json和前端进行数据交互
前端都是调用的一个后端接口获取数据
一般用于大型商业部署项目开发,多端部署

返回json串
其原理如下图所示
核心的注解是一个@ResponeseBody
通过responesebody能够告知adapter我们即将返回的是一个json串
然后让adapater进行处理,将Java类对象转化为一个json串发送给前端
通过使用responseBody能够使得返回视图和转发重定向的语法全部生效


具体controller类的编写如下
通过controller添加到ioc容器
通过requestmapping指定访问路径
接着在需要返回json串的类/方法上添加@ResponseBody即可返回一个json串
也可以是返回一个list对象

这两个方法的返回结果如下图所示


RestController注解

可以观察源码,同时包含了controller和responsebody注解
能够使用这一个注解替代controller和responsebody注解
返回静态资源
我们现在文件目录下面放入一个静态图片资源

我们在平常的客户端请求文件的路径时是访问不到的
因为默认情况下当服务端接收请求之后,回去handlerMapping()中寻找有没有对应的handler请求路径
此时会发现没有对应的请求路径,那么就会发生错误

那么我们如何解决这种情况呢
在配置类中重写一个如红圈所示的接口就可以实现找到静态资源

那么其原理是什么呢
我们点进去接口里面进行观察,如红箭头所指的类是返回静态资源得以成功的方法

接着点进去那个添加Servlet进行观察
我们可以发现,他添加了一个handler对静态资源进行处理

那么这个handler是如何对静态资源进行处理的呢
在这个handler是这样处理的,假如我们没有找到路径,那么就会对图片资源的路径进行内部转发
通过转发去寻找请求地址所需要的资源

原理图
Servlet接收到一个请求,先去handlerMapping寻找有没有对应的controller类查找数据
发现没有,那么handlerMapping就会找DefaultServletHandler去转发图片的路径寻找资源

结果如下

RESTFul风格
一种基于http协议的规范编码风格

其请求路径的设计如下图所示

全局异常处理机制
什么是声明式异常和编程式异常?
编程式:在代码内部有详细的异常捕捉
声明式:在外部使用一个配置文件对需要进行异常捕获的文件进行包裹,有异常时就会调用外部异常处理代码进行处理

全局异常处理注释
所有需要的异常都在图中写清楚了
详解再图片下方写


@ControllerAdvice和@RestControllerAdvice解析
ControllerAdvice:标识这是一个全局异常处理类,当全局异常发生时就会寻找该类进行处理,可以返回逻辑视图和转发重定向
RestControllerAdvice:点进去后其实可以发现源代码里面有controlleradvice和responsebody注解在里面
responseBody是告知这个类会返回一个json字符串

@ExceptionHandler
异常处理的类,在其后面的括号内的参数是用于指定该方法处理什么类型的异常
拦截器
类似于javaweb中的Filter(过滤器)
对一些特殊的请求进行拦截处理
拦截器 Springmvc VS 过滤器 javaWeb:
-
相似点
-
拦截:必须先把请求拦住,才能执行后续操作
-
过滤:拦截器或过滤器存在的意义就是对请求进行统一处理
-
放行:对请求执行了必要操作后,放请求过去,让它访问原本想要访问的资源
-
不同点
-
工作平台不同
-
过滤器工作在 Servlet 容器中
-
拦截器工作在 SpringMVC 的基础上
-
拦截的范围
-
过滤器:能够拦截到的最大范围是整个 Web 应用
-
拦截器:能够拦截到的最大范围是整个 SpringMVC 负责的请求
-
IOC 容器支持
-
过滤器:想得到 IOC 容器需要调用专门的工具方法,是间接的
-
拦截器:它自己就在 IOC 容器中,所以可以直接从 IOC 容器中装配组件,也就是可以直接得到 IOC 容器的支持
其作用范围如图所示
因为使用了springmvc框架,那么在程序内部是只有一个DispatcherServlet进行请求处理的
假如使用filter的话,只能在Servlet外部即整个springMVC框架外部进行拦截处理,一刀切,并不能在里面的各种资源调用的内部进一些业务逻辑的处理
那么使用拦截器就可以解决这一问题

拦截器作用的位置

拦截器如何使用
首先在配置类中注册一下拦截器(注意,图中的这种注册方式是拦截全部请求的,至于具体到方法的后续会讲解到)

拦截器类的书写,我们需要继承一个HanlerInterceptor类
其需要重写如下三个方法
preHandle
postHandle
afterCompletion

preHandle方法
其参数和注意事项如下
其中handler就是我们进行拦截的目标方法
preHandler是在目标方法执行前执行的代码

postHandle方法
其参数和主义的事项如下
其中modelAndView返回的是一个视图或者共享域对象
不需要时为空

afterCompletion方法
在前面两个方法执行完毕后调用
其中ex参数是当目标方法发生异常时传入,并进行输出

拦截器的指定拦截
链式调用
在将拦截器类进行注册后添加一个addpathPatterns就可以进行拦截

排除拦截
在前一个大的路径内,指定一个在大路径内的小路径就可以进行小路径的拦截

拦截的顺序
根据注册的先后进行拦截,其源码其实是所有的拦截类放入一个数组
然后prehandler是正序遍历数组进行方法调用,所以先进入的类会先执行
接着post和after方法是逆序遍历,也就是说,先进入的类后遍历

源码
通过mapping(秘书)对对应的拦截方法进行获取

观察下面的代码,下方红箭头所指通过handler获取拦截方法执行的目标方法

在红箭头的上方,有一个拦截方法,他会判断前置prehadler的返回结果,假如是一个false那么就进入方法执行return代表着剩下的目标方法的逻辑不执行,实现了拦截

参数校验
可以通过给实体类的变量上添加注解,不符合对应的要求的就会报错

在对应的实体类中添加对应的注解

接着我们需要在对应的接收前端数据的controller层接收对应实体类参数的方法中打的参数上添加
@Validdated注解!!!
如果不添加那自动校验就不会生效

以字符串不能为空举例当字符串为空时,会将报错信息默认的返回
但是我们发现这种方法前端不容易读懂,所以我们需要自定义的定义报错信息的返回

我们需要定义一个BindingResult类进行错误的接收
注意,该类一定要在参数列表中紧挨着需要校验的实体类
接着我们通过hasErrors判断是否报错
如果报错,我们定义一个集合将错误参数放入并返回

总结
调用流程,很关键
