SpringMVC
SpringMVC的基本流程:
浏览器发送请求,如请求地址符合前端控制器的url-pattern,该请求就会被前端控制器DispatcherServlet进行处理,前端控制器会读取SpringMVC的核心配置文件,通过扫描组件的方式找到控制器,将请求地址和控制器中的@RequestMapping(请求映射)的value属性值进行匹配,如果匹配成功,该注解所标识的控制器方法就是处理请求的方法,处理请求的方法需要放回一个字符串类型的视图名称,视图名称通过被视图解析器进行解析,加上前缀和后缀之后组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发的视图所对应的页面。
Dispatcher翻译为调度
@RequestMapping注解
翻译为请求映射,作用是将请求和处理请求的处理器进行联系起来,建立映射关系
SpringMVC接收到指定的请求,就会来找到映射关系中对应的控制器中的方法进行处理这个请求
同一个路径只能有一个@RequestMapping进行映射
@RequestMapping注解可以使用的范围:类和方法上
作用的类上面:设置映射请求的请求路径的初始信息
例如:
@Controller
@RequestMapping(“Hello”)
Public class Controller{
@ReuqestMapping(“/”)
Public String test(){
Return “test”;
}
}
就需要使用 http://ip:port/工程路径/Hello/ 这个请求才能被test方法进行处理,需要先处理初始信息,在处理具体信息
作用在方法上面:设置映射请求请求的具体信息
@RequestMapping中的属性值:
其中value属性的值必须进行设置
@RequestMapping中的Method属性值的含义:通过请求方式进行映射,如POST和GET请求等
如果没有进行设置method中的属性值,表示只要当地址匹配(也就是和value的属性值相匹配,就可以访问,不管是通过那种请求方式进行访问)
示例代码如下:
控制器中的代码
Index.html中的代码:
运行结果:
通过Get请求进行访问的时候,截图如下:
成功
通过POST请求进行访问的时候:
Method中的属性值不相匹配,所以不能访问。
@RequestMapping的派生类注解:
@GetMapping:就相当于将@Reuqestmapping的Method属性值设置为Get请求
@PostMapping:就相当于在@RequestMapping中的method中的属性值设置为Post请求
@PutMapping:就相当于将@ReuqestMapping中的Method中的属性值设置为Put请求
等。。。
@RequestMapping注解中的params属性值:
表示通过请求参数的方式进行匹配,只有当参数完全匹配的时候,才能进行访问页面
实例代码如下:
通过form表单进行提交,请求类型为get
Controller中的代码如下:
通过表单进行访问的结果是:
成功
通过超链接进行访问(请求参数中没有username)
(提示:通过thymeleaf进行添加参数的方法)
th:href="@{/test.html(username='xiaowang',password=123456)}"
SpringMVC中的ant风格:
一个?表示任意的单个字符
一个*表示任意的0个或者多个字符
两个**表示任意的一层或者多层目录
@RequestParam注解的属性和作用:
属性:
1、value属性:作用:将请求参数中的哪一项和controller中的形参进行创建映射关系
2、Required属性:作用:默认是true,表示只有当这个请求参数存在的时候才会继续,如果不存在切没有设置defaultvalue就会报错
3、Defaultvalue属性:作用:设置默认值,当请求为null和空字符串的时候进行使用。
@RequestHeader注解的作用和属性:
作用:用于获取请求头中的信息
属性:
1、value属性:需要的请求头中的信息键值对中的key
2、Required属性:设置这个需要的请求头信息是否是必须的存在
3、Defaultvalue属性:设置默认值,当请求头中没有对应value中的key时,就会使用默认值
@CookieValue注解的作用和属性:
作用:获取value属性中对应的cookie的值
属性:
1、value属性:cookie对象的key部分
2、Required属性:设置是否是必须含有的cookie
3、Defaultvalue属性:设置默认值,设置当value属性对象的cookie属性不存在时使用的值。
SpringMVC中将请求参数中的信息封装成一个Bean对象的代码实现:
注意:StringMVC中通过请求参数创建相应的Bean对象的时候,请求中的参数的name需要和Bean中的属性名相对应(和将数据库中的数据进行取出在创建对象注意事项相同)
这是在表单中的代码:
这是在controller控制器中的代码
这是Bean对象中的代码
在StringMVC中解决中文编码问题:
可以通过过滤器将请求先设置编码集,再由dispatcherServlet进行获取请求。
代码如下:
注意:因为SpringMVC中没有使用JSP,所以没有page域对象,只有三个域对象,分别是:request域对象、session域对象、application域对象。
通过SpringMVC将数据共享到request域对象中:
第一种方式:
通过Servlet原生的API进行共享
代码如下:
Controller类中的方法的参数为HttpServletRequest类型的话,会将这个请求自动进行赋值。
第二种方式:
通过ModelAndView将数据共享到request域对象中
代码如下:
ModelAndView的作用:可以将这个类名进行分解,分为两个:
Model:
作用:将数据进行共享,通过addObject()方法进行添加数据。
View:
作用:设置请求转发的视图名称(什么是视图名称,也就是将一个页面的路径和后缀进行删除后单纯页面的名称)
需要注意的是:
如果是通过ModelAndView进行共享数据,就必须将ModelAndView这个类型作为这个方法的返回值
原因:因为是将数据保存在request域对象中,只有通过请求转发的方式才能获取到当前request域对象中的数据,由于在ModelAndView对象中进行设置了视图的名称,因此可以通过ModelAndView进行请求的转发(也就是说Thymeleaf视图解析器可以将ModelAndView中的视图名称进行解析获取页面),如果是直接返回一个视图名称的话,这个请求中的数据就不能在转发之后进行读取。
第三种方式:
通过Model的方式将数据共享到request域对象中
代码如下:
使用这种方法最后还是会使用到ModelAndView对象,大致是这样的流程,先自动化将参数model进行赋值,在通过addArrtibute方法进行保存数据,最后底层会创建一个ModelAndView对象,将这个方法的返回值String作为视图名称,将Modle作为ModelAndView中的Model,在将这个ModelAndView通过Thymeleaf视图解析器进行解析。
第四种方式:
通过Map进行共享数据
代码如下:
第五种方式:
通过ModelMap进行共享数据
代码如下:
Map和ModelMap和Model之间的关系:
如图
ModelMap继承了LinkedHashMap
LinkedHashMap实现了接口Map
如图可以看出Modle这个接口是通过Map进行存储数据的
因此,本质上Model和Map和ModelMap可以说是使用的同一个类进行操作的
通过反射机制中的getClass方法可以得出结论:
统一是通过
这个类进行操作的。
向session域对象中共享数据:
推荐使用Servlet原生API进行共享session域数据
代码如下:
将数据共享到session域对象中的方式推荐是用原生的ServletAPI的方式,添加参数HttpSession对象进行共享
向Application上下文对象中进行共享数据:
通过使用HttpServletRequest对象进行获取上下文对象进行保存数据或者通过HttpSession对象进行获取上下文对象进行保存数据,
代码如下:
通过Thymeleaf从域对象中进行取出数据的方法:
总结:
向域对象中进行共享数据的方法:
向request域对象中进行共享数据:
1、通过使用Servlet原生的API进行共享,使用HttpServletRequest对象进行共享
2、通过使用Spring中的ModelAndView,将数据保存到Model中,在设置视图名称,返回类型必须是ModelAndView
3、通过Model进行保存:传入Model参数,保存数据,返回视图名称(String)
4、通过Map进行共享数据:传入Map参数,保存数据,返回视图名称(String)
5、通过ModelMap进行共享数据:传入ModelMap参数,保存数据,返回参数名称(String)
上述的3、4、5种方法底层都是使用的同一个类进行操作的(BindingAWareModelMap这个类)
向session域对象中进行共享数据:
通过使用Servlet原生API进行共享数据:传入参数HttpSession,保存数据,返回视图名称(String)
向Application域对象中进行共享数据:
通过使用Servlet原生的API进行共享数据:传入request对象(HttpServletRequest)或者Session(HttpSession)对象进行获取ServletContext上下文对象,在进行保存数据,返回视图名称(String)
什么时候视图会被ThymeleafViewResolver进行解析成为要给ThymeleafView视图:
只有当视图名成没有任何前缀的时候,就会被ThymeleafViewReSolver视图解析器进行解析成为一个ThymeleafView视图。(通过ThymeleafViewResolver解析器进行解析后的视图,最终获取到的页面会通过转发的方式进行跳转)
如果有前缀:
前缀为:forward:表示转发视图(叫做internalResourceView)
前缀为:redirect:表示重定向视图(叫做RedirectView)
示例代码:
使用转发视图和重定向视图都需要进行两次解析:
第一次解析:将前缀进行去掉,在将去掉后的请求进行相应的操作(如果是请求转发,就是将请求进行再次转发,如果是重定向视图就将请求进行重定向)。
第二次解析:在将请求和控制器中的请求映射进行匹配,如果匹配成功,执行控制器中的方法,将返回的视图名称通过thymeleaf视图解析器进行解析,最后返回页面。
SpringMVC中的视图控制器:
什么时候使用:
当一个控制器中的方式不用处理请求,只需要设置一个视图名称的时候就可以使用,例如首页就是一个简单的例子。
通过xml中的视图控制器将映射和页面进行设置:
注意:如果添加了一个视图控制器之后,在控制器中所有的映射关系都会消失。
如何解决:需要开启mvc中的注解驱动
创建一个jsp视图解析器只能创建两种视图类型:(internalResourceView视图类型和rediaectView视图类型)
什么时候创建internalResourceView视图类型:当添加了前缀为forward:或者没有任何前缀(因为没有添加前缀会被我们创建的InternalResourceViewResolver解析器进行解析)的时候创建的视图类型为internalReourceView类型
什么时候创建redizectView视图类型:当添加了前缀为redizect:的时候创建的视图类型为redizectView类型
如何发送put请求和delete请求:
需要创建一个过滤器(HiddenHttpMethodFilter)
从源码中可以看出,如果想要发送的请求类型为put和delete请求需要满足两个条件:
第一个条件:必须是post请求
第二个条件:需要有一个参数的name属性为_method,它的值必须是put、delete、patch请求
请求为put和delete类型的代码如下:
需要注意:因为HiddenHttpMethodFilter中将请求中的_method这个参数进行获取了,如果将处理编码的过滤器放在他的后面就没有任何的作用,需要将处理编码的过滤器放在处理请求的过滤器之前
通过Thymeleaf语法将域对象中的集合进行遍历:
语法如下:
通过th:each=” 每一个元素的引用 ” :集合 (语法和foreach类似)
通过Thymeleaf将请求参数拼接到地址中的方法:
Thymeleaf中@{}是用来解析地址的
注意:不是直接创建的标签,如果需要进行绑定事件,需要使用on进行绑定:
实例代码:
如图:上面的id为deleteHref的标签就是通过Thymeleaf语法进行遍历间接创建的标签,如果需要进行绑定单机事件,就需要使用on的方式进行绑定事件,如果使用原来的方式进行绑定事件,事件不会生效。
如何处理静态资源:
首先,静态资源是在我们后面进行添加的,需要重新进行在maven中打war包,其次,在重新进行打包之后,因为Dispatcher前端控制器的映射和tomcat服务器中的web.Xml文件中的DefalutServlet程序冲突,就近原则,就会选择Dispatcher进行处理所有的请求,结果就导致不能将静态资源进行加载,需要在Spring.xml文件中将DefaultServlet程序进行开启,开启的方法:(<mvc:default-servlet-handler/>)注意,如果进行开启之后,需要再加上注解驱动,如果不加上注解驱动,之前的映射关系会全部失效,并且所有的请求都会通过defaultServlet程序进行处理,结果就是什么都不能使用,只能加载静态资源。注解驱动的代码(<mvc:annotation-driven)
Dispatcher前端控制器和DefaultServlet程序处理的先后顺序:
先通过Dispatcher前端控制器进行处理,如果不能进行处理,在通过DefaultServlet程序进行处理
HttpMessageConverter(报文信息转化器):
作用:将java对象转化成相应报文,将请求报文转化成java对象
HttpMessageConverter中的两个注解和两个类型:
两个注解:@RequestBody @ResponseBody
两个类型:RequestEntity ResponseEntity
@RequestBody注解的作用:
将请求报文转化为java对象
实例代码:
注意:如果是使用了@RequestBody注解,就必须要提交数据,否则不会得到访问。
实例:
如果这里没有使用form表单进行提交数据,那么就不会访问到上图中的控制器,达到success界面。反之,则能过进行访问,输出的数据为:
也就是进行提交的数据
RequestEntity的作用:
将请求报文进行封装,在使用的时候需要进行传入该类型的参数,会自动将这个请求中的请求报文进行赋值。(请求报文中包含有请求体和请求头,请求体中的数据只有是通过post请求进行提交的才会有数据,否则为null)
示例代码:
注意:如果是通过上面这个图的方式进行提交信息,请求体中不会存在数据,结果就是null,当通过一个form表单(提交方式为post请求)进行提交数据的时候,请求体中才会存在数据。
@ResponseBody注解的作用:
通过这个注解我们可以很容易的将一个java对象自动转化成为一个json对象
将java对象转化为响应体报文
实例代码:
注意:如果添加了@ResponseBody注解之后,返回的就不再是一个视图名称了,而是一个响应体。例如这个的success,如果没有添加注解@ResponseBody,返回的就是一个视图名称,这个视图名称会被Thymeleaf视图解析器进行解析,如果添加了@ResponseBody注解之后,就表示相应体中的数据为success这个字符串
注意:不能直接将一个对象放到响应体中相应给浏览器,需要将这个对象进行转化成JSON字符串类型对象之后,在页面再将JSON字符串类型转化成JSON对象类型进行取出。![](https://img2022.cnblogs.com/blog/3042455/202211/3042455-20221125200013863-1371715498.png)
如果直接将对象进行相应,就会出错。
在SpringMVC中,不用我们手动的将对象转化成json字符串的形式,可以通过jackson进行自动转化。
通过jackson将java对象转化成一个json字符串形式的具体操作:
1、通过maven将依赖进行引入
2、需要在springMVC的核心配置文件中开启注解驱动(<mvc:annotation-driven/>)
3、处理器的方法上需要使用@ResponseBody注解的方式进行表示
4、直接将java对象作为返回值
满足以上给四点之后,就可以讲返回的java对象自动转化成一个json字符串形式
通过springMVC处理ajax请求:
实例代码如下:
Ajax请求的作用是不刷新页面,进行局部的更新,,其中回调函数中的参数,就代表了响应体中的内容。(如实例中的response参数)
ResponseEntity的作用:
ResponseEntity用于控制方法的返回值类型,该控制器方法的返回值就是响应到浏览器的响应报文。
作用一:(通过ResponseEntity实现文件下载功能)
示例代码:
设置请求头中的信息是固定的,只有文件的名称可以进行自定义。
创建一个ResponseEntity对象(响应报文)需要三个参数:请求体、请求头、请求响应码
作用二:(通过ResponseEntity实现文件的上传)
如果要实现上传功能,需要进行以下操作:
第一:需要添加依赖commons-fileupload这个jar
第二:需要在SpringMVC的核心配置文件中进行添加一个上传解析器,将上传的文件解析成为MultipartFile对象(在创建这个bean的时候,只能通过id进行获取,并且id值的属性需要进行固定,multipartResolver,不能通过类型进行获取),便于通过Spring进行自动赋值获取。
第三:必须是通过post请求进行提交
实例代码:
photo文件夹在target中
文件上传需要注意,如果当两个文件的文件名相同的时候,IO中默认使用的是不进行追加,结果就是会将原先文件中的内容进行覆盖。
如何解决文件内容发生覆盖的问题:
可以通过给每一个文件添加一个无法重复的名称进行解决,这里通过使用java中util中的UUID进行解决
示例代码:
@RestController注解的作用:
他的作用主要是两个:(他是一个类的注解,类似于@Controller注解)
第一个作用:使用这个注解之后,该类中的每一个方法都会默认添加@ResponseBody注解
第二个作用:他是一个控制器,有和@Controller注解同样的作用
解释:@RestController注解是SpringMVC中提供的一个符合注解,表示在控制器的类上,就相当于给类添加了@Controller注解,同时,在这个类中的每一个方法上都添加了@ResponseBody注解。
SpringMVC中的拦截器(interceptor):
拦截器是对控制器中的方法进行拦截,分为preHandle、postHandle、afterCompletion。
PreHandle拦截器是对控制器方法执行之前进行作用(有拦截作用,返回false为拦截,返回true表示放行)
PostHandle拦截器是对控制器方法执行之后进行作用
AfterCompletion拦截器是对视图渲染结束之后进行作用
如何创建一个拦截器:
1、编写一个类实现接口HandleInterceptor,重写相应的方法
2、在SpringMVC的配置文件中进行配置拦截器
配置拦截器的三种方式:
第一种方式:直接在拦截器中进行添加一个拦截器(注意:使用这种方法由于我们没有设置拦截路径,因此所有的请求都会被拦截)
第二种方式:将编写的拦截器类交给Spring进行管理,本质上和上面一种没有区别(同样,由于没有设置拦截路径,所有的请求都会被拦截)
第三种方式:通过<mvc:interceptor>进行配置拦截器,使用这种方式可以设置拦截路径以及不拦截的路径等
在设置拦截路径的时候,如果使用的是 /* 表示的是任意一层目录下的文件(如 /a ,/b下的文件),如果需要设置为任意层,则使用 /**
第一种方式和第二种方式都是直接设置的拦截器,没有设置拦截路径,所以他会将DispatcherServlet进行处理的所有请求进行拦截(通过DispatcherSevlet进行处理的请求就会被控制器进行处理),第三种方式可以设置拦截路径和不进行拦截的路径。
多个拦截器的执行顺序:
如果每一个拦截器的PreHandle都是返回true
此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件中的编写顺序有关,Prehandle的执行顺序和在配置文件中的编写顺序相同,但是Posthandle和afterComplation的执行顺序和在配置文件中的编写顺序相反
如果有一个拦截器的PreHandle返回了false
当前返回false和之前的PreHandle会执行(包含返回false的拦截器),PostHandle都不会执行,返回false之前的afterComplation会执行(不包括返回false的拦截器)。
异常处理器:
第一种方式:基于配置的异常处理
实例代码如下:
第二种方式:通过注解的方式处理异常
实例代码如下:
通过注解的方式配置SpringMVC:
使用配置类和注解代替web.xml文件和SpringMVC的核心配置文件的功能
实例代码:
替换web.xml文件的类:
替换SpringMVC的配置文件的类:
设置视图解析器的时候可以借鉴在SpringMVC通过xml文件进行创建的方式进行创建。
替换Spring文件的类:
SpringMVC的常用组件:
1、DispatcherServlet:前端控制器,不需要工程师开发,有框架进行提供
作用:统一处理请求和响应,整个流程的控制中心,由他调用其他的组件进行处理用户的请求。
2、HandlerMapping:处理器映射器,不需要工程师开发,有框架提供
作用:根据请求的url、method方式等信息匹配对应的控制器,即控制器方法
3、Handler:处理器,需要工程师开发
作用:在DispatcherServlert的控制下Handler对具体的用户请求进行处理
4、HandlerAdapter:处理器适配器,不需要工程师进行开发,有框架提供
作用:同构HandlerAdapter对处理器(控制器中的方法)进行执行
5、ViewResolver:视图解析器,不需要工程师开发,有框架进行提供
作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、RedirectView
6、View:视图
作用:将模型数据通过页面展示给用户