0


SpringMVC基础详解

文章目录

一、SpringMVC简介

1、什么是MVC

  • MVC是一种软件架构模式(是一种软件架构设计思想,不止Java开发中用到,其它语言也需要用到),它将应用分为三块:- M:Model(模型),负责业务处理及数据的收集- V:View(视图),负责数据的展示- C:Controller(控制器),负责调度。它是一个调度中心,它来决定什么时候调用Model来处理业务,什么时候调用View视图来展示数据

在这里插入图片描述

MVC架构模式的描述:前端浏览器发送请求给web服务器,web服务器中的Controller接收到用户的请求,Controller负责将前端提交的数据进行封装,然后Controller调用Model来处理业务,当Model处理完业务后会返回处理之后的数据给Controller,Controller再调用View来完成数据的展示,最终将结果响应给浏览器,浏览器进行渲染展示页面。

2、MVC架构模式与三层模型的区别

什么是三层模型

  • 三层模型就是由Controller控制器和View视图组成的表现层,将Model数据模型拆封为业务层和与数据库交互的持久层

image.png

MVC架构模式与三层模型的区别?

  • MVC和三层模型都采用了分层结构来设计应用程序,都是降低耦合度,提高扩展力,提高组件复用性
  • 区别在于他们的关注点不同- 三层模型更加关注业务逻辑组件的划分- MVC架构模式关注的是整个应用程序的层次关系和分离思想
  • 现代的开发方式大部分都是MVC架构模式结合三层模型一起用

3、什么是SpringMVC

  • SpringMVC是一个实现了MVC架构模式的Web框架,底层基于Servlet实现
  • SpringMVC已经将MVC架构模式实现了,因此只要我们是基于SpringMVC框架写代码
  • Spring框架中有一个子项目叫做Spring Web,Spring Web子项目当中包含很多模块- Spring MVC- Spring WebFlux- Spring Web Services- Spring Web Flow- Spring WebSocket- Spring Web Services Client
  • Spring架构图如下,其中Web中的servlet指的就是Spring MVC

在这里插入图片描述

二、HelloWorld程序

1、pom文件

  1. <?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.xc</groupId><artifactId>springmvc-xml</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><dependencies><!--springmvc--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.1</version></dependency><!--servletAPI--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><!--spring5和thymeleaf整合--><dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf-spring5</artifactId><version>3.0.11.RELEASE</version></dependency></dependencies><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties></project>

2、springmvc.xml

  • 组件扫描。spring扫描这个包中的类,将这个包中的类实例化并纳入IoC容器的管理
  • 视图解析器。视图解析器(View Resolver)的作用主要是将Controller方法返回的逻辑视图名称解析成实际的视图对象。视图解析器将解析出的视图对象返回给DispatcherServlet,并最终由DispatcherServlet将该视图对象转化为响应结果,呈现给用户
  1. <?xml version="1.0" encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!--组件扫描--><context:component-scanbase-package="com.xc.controller"/><!--视图解析器--><beanid="thymeleafViewResolver"class="org.thymeleaf.spring5.view.ThymeleafViewResolver"><!--作用于视图渲染的过程中,可以设置视图渲染后输出时采用的编码字符集--><propertyname="characterEncoding"value="UTF-8"/><!--如果配置多个视图解析器,它来决定优先使用哪个视图解析器,它的值越小优先级越高--><propertyname="order"value="1"/><!--当 ThymeleafViewResolver 渲染模板时,会使用该模板引擎来解析、编译和渲染模板--><propertyname="templateEngine"><beanclass="org.thymeleaf.spring5.SpringTemplateEngine"><!--用于指定 Thymeleaf 模板引擎使用的模板解析器。模板解析器负责根据模板位置、模板资源名称、文件编码等信息,加载模板并对其进行解析--><propertyname="templateResolver"><beanclass="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver"><!--设置模板文件的位置(前缀)--><propertyname="prefix"value="/WEB-INF/templates/"/><!--设置模板文件后缀(后缀),Thymeleaf文件扩展名不一定是html,也可以是其他,例如txt,大部分都是html--><propertyname="suffix"value=".html"/><!--设置模板类型,例如:HTML,TEXT,JAVASCRIPT,CSS等--><propertyname="templateMode"value="HTML"/><!--用于模板文件在读取和解析过程中采用的编码字符集--><propertyname="characterEncoding"value="UTF-8"/></bean></property></bean></property></bean></beans>

3、配置web.xml文件

  • Spring MVC是一个web框架,在javaweb中谁来负责接收请求,处理请求,以及响应呢?当然是Servlet
  • 在SpringMVC框架中已经为我们写好了一个Servlet,它的名字叫做:DispatcherServlet,我们称其为前端控制器
  • 既然是Servlet,那么它就需要在web.xml文件中进行配置:
  1. <?xml version="1.0" encoding="UTF-8"?><web-appxmlns="https://jakarta.ee/xml/ns/jakartaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"version="5.0"><!--配置前端控制器--><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--手动设置springmvc配置文件的路径及名字--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param><!--为了提高用户的第一次访问效率,建议在web服务器启动时初始化前端控制器--><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><!-- /* 表示任何一个请求都交给DispatcherServlet来处理 --><!-- / 表示当请求不是xx.jsp的时候,DispatcherServlet来负责处理本次请求--><!-- jsp本质就是Servlet,因此如果请求是jsp的话,应该走它自己的Servlet,而不应该走DispatcherServlet --><!-- 因此我们的 url-pattern 使用 / --><url-pattern>/</url-pattern></servlet-mapping></web-app>

**DispatcherServlet是SpringMVC框架为我们提供的最核心的类,它是整个SpringMVC框架的前端控制器,负责接收HTTP请求、

  1. 将请求路由到处理程序

  1. 处理响应信息

,最终将响应返回给客户端。**

  1. 接收客户端的HTTP请求:DispatcherServlet监听来自Web浏览器的HTTP请求,Tomcat已经将请求数据解析为Request对象
  2. 处理请求的URL:DispatcherServlet将请求的URL与处理程序进行匹配,确定要调用哪个控制器(Controller)来处理此请求
  3. 调用相应的控制器:DispatcherServlet将请求发送给找到的控制器处理,控制器将执行业务逻辑,然后返回一个模型对象(Model)
  4. 渲染视图:DispatcherServlet将调用视图引擎,将模型对象呈现为用户可以查看的HTML页面
  5. 返回响应给客户端:DispatcherServlet将为用户生成的响应发送回浏览器,响应可以包括表单、JSON、XML、HTML以及其它类型的数据

4、html文件

  1. <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>Title</title></head><body>
  2. hello world
  3. </body></html>

5、执行Controller

  1. @ControllerpublicclassHelloController{@RequestMapping("/test")publicStringtest(){return"success";}}

配置Tomcat

在这里插入图片描述

启动tomcat,调用test

在这里插入图片描述

三、RequestMapping注解

**

  1. @RequestMapping

注解是 Spring MVC 框架中的一个

  1. 控制器映射注解

,用于将请求映射到相应的处理方法上。具体来说,它可以将指定 URL 的请求绑定到一个特定的方法或类上,从而实现对请求的处理和响应。**

RequestMapping的出现位置

  • 通过源码可以看到RequestMapping注解只能出现在类上或者方法上
  • 当然类上和方法上也可以同时出现,类上是公共的,方法上是独有的

在这里插入图片描述

1、value属性

1.1、基础使用

  • value属性是该注解最核心的属性,value属性填写的是请求路径,也就是说通过该请求路径与对应的控制器的方法绑定在一起
  • value属性是一个字符串数组,表示可以提供多个路径,也就是说,多个不同的请求路径可以映射同一个控制器的同一个方法
  • value属性和path属性互为别名,两个属性一样

在这里插入图片描述

举例

  1. @Controller@RequestMapping("/hello")publicclassRequestMappingController{@RequestMapping(value ={"/test1","test2"})publicStringtest(){return"success";}}

1.2、Ant风格(模糊匹配路径)

  • value是可以用来匹配路径的,路径支持模糊匹配,我们把这种模糊匹配称之为Ant风格- ?:表示任意的单个字符- *:表示任意的0个或多个字符- **:表示任意的一层或多层目录(只能使用xxx/**的方式)

匹配?例子

  1. @RequestMapping("/x?z/testValueAnt")publicStringtestValueAnt(){return"success";}
  • 匹配成功,可以正常访问到以上控制器的方法上

在这里插入图片描述

  • 匹配失败,抛错404

在这里插入图片描述

匹配*例子

  1. @RequestMapping("/x*z/testValueAnt")publicStringtestValueAnt(){return"success";}
  • 匹配成功,可以正常访问到以上控制器的方法上

在这里插入图片描述

  • 匹配失败,抛错404

在这里插入图片描述

匹配例子**

  • spring6中**通配符只能出现在路径的末尾,否则抛错,spring5可以不用在末尾
  1. @RequestMapping("/testValueAnt/**")publicStringtestValueAnt(){return"success";}
  • 匹配成功,可以正常访问到以上控制器的方法上

在这里插入图片描述

1.3、路径占位符(@PathVariable)

普通的请求路径:http://localhost:8080/springmvc/login?username=admin&password=123&age=20

restful风格的请求路径:http://localhost:8080/springmvc/login/admin/123/20

如果使用restful风格的请求路径,在控制器中应该如何获取请求中的数据呢?

  • 不加@PathVariable路径变量注解会抛500异常
  1. @RequestMapping(value ="/testRestful/{id}/{username}/{age}")publicStringtestRestful(@PathVariable("id")int id,@PathVariable("username")String username,@PathVariable("age")int age){System.out.println(id +","+ username +","+ age);return"success";}

2、method属性

2.1、基础使用

  • 如果前端发送请求的方式和后端的处理方式不一致时,会出现405错误
  • HTTP状态码405,这种机制的作用是:限制客户端的请求方式,以保证服务器中数据的安全
  • SpringMVC使用RequestMapping注解method属性来实现限制请求方式

在这里插入图片描述

  • 通过RequestMapping源码可以看到,method属性也是一个数组
  • 数组中的每个元素是RequestMethod,而RequestMethod是一个枚举类型的数据

在这里插入图片描述

举例

  • 只允许get和post请求方式,否则报错405
  1. @RequestMapping(value="/login", method ={RequestMethod.GET,RequestMethod.POST})publicStringtestMethod(){return"success";}

2.2、衍生xxxMapping注解

  • SpringMVC提供了另外一些注解,使用更加的方便- GetMapping:要求前端必须发送get请求- PutMapping:要求前端必须发送put请求- DeleteMapping:要求前端必须发送delete请求- PatchMapping:要求前端必须发送patch请求

举例

  • 两种方式效果一样,对比衍生注解更加简洁
  1. //@RequestMapping(value="/login", method = RequestMethod.POST)@PostMapping("/login")publicStringtestMethod(){return"success";}

2.3、web的请求方式

前端向服务器发送请求的方式包括哪些?共9种

  • GET:获取资源,只允许读取数据,不影响数据的状态和功能- 使用URL中传递参数或者在HTTP请求的头部使用参数,服务器返回请求的资源
  • POST:向服务器提交资源,可能还会改变数据的状态和功能- 通过表单等方式提交请求体,服务器接收请求体后,进行数据处理
  • PUT:更新资源,用于更新指定的资源上所有可编辑内容- 通过请求体发送需要被更新的全部内容,服务器接收数据后,将被更新的资源进行替换或修改
  • DELETE:删除资源,用于删除指定的资源- 将要被删除的资源标识符放在URL中或请求体
  • HEAD:请求服务器返回资源的头部- 与 GET 命令类似,但是所有返回的信息都是头部信息,不能包含数据体- 主要用于资源检测和缓存控制
  • OPTIONS:请求获得服务器支持的请求方法类型,以及支持的请求头标志- OPTIONS则返回支持全部方法类型的服务器标志- 主要用于跨域检查
  • PATCH:部分更改请求- 当被请求的资源是可被更改的资源时,请求服务器对该资源进行部分更新,即每次更新一部分
  • TRACE:服务器响应输出客户端的 HTTP 请求,主要用于调试和测试
  • CONNECT:建立网络连接,通常用于加密 SSL/TLS 连接

⚠️注意

  • 使用超链接以及原生的form表单只能提交get和post请求
  • put、delete、head请求可以使用发送ajax请求的方式来实现

GET和POST的区别

  • get请求比较适合从服务器端获取数据
  • post请求比较适合向服务器端传送数据
  • get请求支持缓存。 也就是说当第二次发送get请求时,会走浏览器上次的缓存结果,不再真正的请求服务器
  • post请求不支持缓存。每一次发送post请求都会真正的走服务器

3、params属性

  • 对于RequestMapping注解来说:- value属性是一个数组,只要满足数组中的任意一个路径,就能映射成功- method属性也是一个数组,只要满足数组中任意一个请求方式,就能映射成功- params属性也是一个数组,不过要求请求参数必须和params数组中要求的所有参数完全一致后,才能映射成功

在这里插入图片描述

params属性的4种用法

  1. @RequestMapping(value="/login", params={"username", "password"}) - 请求参数中必须包含username 和 password,才能与当前标注的方法进行映射
  2. @RequestMapping(value="/login", params={"!username", "password"})- 请求参数中不能包含username参数,但必须包含password参数,才能与当前标注的方法进行映射
  3. @RequestMapping(value="/login", params={"username=admin", "password"})- 请求参数中必须包含username参数,并且参数的值必须是admin,另外也必须包含password参数,才能与当前标注的方法进行映射
  4. @RequestMapping(value="/login", params={"username!=admin", "password"})- 请求参数中必须包含username参数,但参数的值不能是admin,另外也必须包含password参数,才能与当前标注的方法进行映射

4、headers属性

  • headers和params原理相同,用法也相同
  • 当前端提交的请求头信息和后端要求的请求头信息一致时,才能映射成功

headers属性的4种用法

  1. @RequestMapping(value="/login", headers={"Referer", "Host"}) - 请求头信息中必须包含Referer和Host,才能与当前标注的方法进行映射
  2. @RequestMapping(value="/login", headers={"!Referer", "Host"})- 请求头信息中不能包含Referer参数,但必须包含Host参数,才能与当前标注的方法进行映射
  3. @RequestMapping(value="/login", headers={"Referer=xxx", "Host"})- 请求头信息中必须包含Referer参数,并且参数的值必须是xxx,另外也必须包含Host参数,才能与当前标注的方法进行映射
  4. @RequestMapping(value="/login", headers={"Referer!=xxx", "Host"})- 请求头信息中必须包含Referer参数,但参数的值不能是xxx,另外也必须包含Host参数,才能与当前标注的方法进行映射

四、获取请求参数

1、原生Servlet API

前端表单提交数据

在这里插入图片描述
F12查询提交数据方式

在这里插入图片描述

后端控制器获取数据

  1. @PostMapping(value="/register")publicStringregister(HttpServletRequest request){// 通过当前请求对象获取提交的数据String username = request.getParameter("username");String password = request.getParameter("password");String sex = request.getParameter("sex");String[] hobbies = request.getParameterValues("hobby");String intro = request.getParameter("intro");System.out.println(username +","+ password +","+ sex +","+Arrays.toString(hobbies)+","+ intro);return"success";}

**这样通过Servlet原生的API获取到提交的数据。但是这种方式

  1. 不建议使用

,因为方法的参数

  1. HttpServletRequest

依赖Servlet原生API,Controller的测试将不能单独测试,必须依赖

  1. web服务器

才能测试。**

2、RequestParam注解

2.1、value属性

  • RequestParam注解作用:将请求参数与方法上的形参映射
  1. @PostMapping(value ="/register")publicStringregister(@RequestParam(value ="username")String a,@RequestParam(value ="password")String b,@RequestParam(value ="sex")String c,@RequestParam(value ="hobby")String[] d,@RequestParam(name ="intro")String e
  2. ){System.out.println(a);System.out.println(b);System.out.println(c);System.out.println(Arrays.toString(d));System.out.println(e);return"success";}
  • @RequestParam注解的两个属性valuename,互为别名,作用相同

在这里插入图片描述

  • 发送请求时提交的数据是:name1=value1&name2=value2,则这个注解应该这样写:@RequestParam(value="name1")@RequestParam(value="name2")

2.2、required属性

  • required属性用来设置该方法参数是否为必须
  • 默认情况下,这个参数为 true,表示方法参数是必需的。如果请求中缺少对应的参数,则会抛出异常
  • 可以将其设置为false,false表示不是必须的,如果请求中缺少对应的参数,则方法的参数为null在这里插入图片描述

举例

  • 添加了一个 age 形参,没有指定 required 属性时,默认是true,表示必需的

在这里插入图片描述

  • 但前端表单中没有年龄age,报错如下

在这里插入图片描述

2.2、defaultValue属性

  • defaultValue属性用来设置形参的默认值
  • 没有提供对应的请求参数或者请求参数的值是空字符串""的时候,方法的形参会采用默认值

举例

  • age属性设置为非必须,当前端不传值时候,默认年龄为18岁

在这里插入图片描述

3、根据形参名获取

  • 如果方法形参的名字和提交数据时的name相同,则@RequestParam可以省略
  1. @PostMapping(value="/register")publicStringregister(String username,String password,String sex,String[] hobby,String intro){System.out.println(username +","+ password +","+ sex +","+Arrays.toString(hobby)+","+ intro);return"success";}

4、根据实体类接收

  • 在SpringMVC中也可以使用POJO类/JavaBean实体类来接收请求参数
  • 不过有一个非常重要的要求:实体类的属性名必须和请求参数的参数名保持一致
  1. @PostMapping("/register")publicStringregister(User user){System.out.println(user);return"success";}
  • 底层的实现原理:反射机制- 先获取User对象实例,没有则反射实例化- 然后获取请求参数的名字,通过请求参数名字拼接出set属性名的方法名- 最后User实例和set属性方法反射给属性赋值
  • 请求参数是否可以赋值到JavaBean对应的属性上,不是取决于属性名,而是setter方法名

5、RequestHeader注解

  • 该注解的作用是:将请求头信息映射到方法的形参上
  • 对于RequestHeader注解来说,也有三个属性:value、required、defaultValue,和RequestParam一样
  1. @PostMapping("/register")publicStringregister(User user,@RequestHeader(value="Referer", required =false, defaultValue ="")String referer){System.out.println(user);System.out.println(referer);return"success";}

6、CookieValue注解

  • 该注解的作用是:将请求提交的Cookie数据映射到方法的形参上
  • 对于CookieValue注解来说,也有三个属性:value、required、defaultValue,和RequestParam一样
  1. @GetMapping("/register")publicStringregister(User user,@CookieValue(value="id", required =false, defaultValue ="110")String id){System.out.println(user);System.out.println(id);return"success";}

7、请求的中文乱码问题

7.1、get请求乱码

  • get请求数据在URI后面提交,这个乱码问题怎么解决呢?
  • 解决办法是找到 CATALINA_HOME/config/server.xml文件,找到其中配置端口号的标签<Connector>,在该标签中添加URIEncoding="UTF-8

在这里插入图片描述

  • 但是对于高版本的Tomcat服务器来说,是不需要设置的,例如Tomcat10Tomcat9,有如下的默认配置,在默认情况下URIEncoding使用的就是UTF-8的编码方式

在这里插入图片描述

  • 但对于低版本的Tomcat服务器,例如:Tomcat8,URIEncoding的默认配置是ISO-8859-1

在这里插入图片描述

7.2、post请求乱码

  • post请求是解决请求体的中文乱码问题
  1. request.setCharacterEncoding("UTF-8");
  • 同样,对于高版本的Tomcat10服务器来说,针对请求体中的字符编码也是配置好的,默认也是采用了UTF-8,web.xml配置如下

在这里插入图片描述

  • 一定要注意:Tomcat9以及之前的版本,以上的配置是没有的
  • 解决方法:web.xml中配置mvc自带的乱码过滤器
  1. <!--配置SpringMVC自带的乱码过滤器--><filter><filter-name>encoding</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param><!--
  2. 设置forceEncoding为true,就是强制设置编码的意思
  3. forceEncoding为true就会设置forceRequestEncoding和forceResponseEncoding为true
  4. 这样,如下源码的两个if条件成立,就会设置utf-8编码了
  5. --><init-param><param-name>forceEncoding</param-name><param-value>true</param-value></init-param></filter><filter-mapping><filter-name>encoding</filter-name><url-pattern>/*</url-pattern></filter-mapping>
  • 源码解析

在这里插入图片描述

在这里插入图片描述

五、Servlet的三个域对象

  • 请求域:request、会话域:session、应用域:application
  • 三个域都有以下三个方法:
  1. // 向域中存储数据voidsetAttribute(String name,Object obj);// 从域中读取数据ObjectgetAttribute(String name);// 删除域中的数据voidremoveAttribute(String name);
  • 主要是通过:setAttribute + getAttribute方法来完成在域中数据的传递和共享

1、request域对象

  • request对象代表了一次请求,一次请求一个request
  • 使用请求域的业务场景- 在A资源中通过转发的方式跳转到B资源- 因为是转发,所以从A到B是一次请求- 如果想让A资源和B资源共享同一个数据,可以将数据存储到request域中
  • 在request域中共享数据有以下几种方式- 使用原生Servlet API方式- 使用Model接口- 使用Map接口- 使用ModelMap类- 使用ModelAndView类

使用原生Servlet API方式

  1. @RequestMapping("/testServletAPI")publicStringtestServletAPI(HttpServletRequest request){// 向request域中存储数据
  2. request.setAttribute("testRequestScope","在SpringMVC中使用原生Servlet API实现request域数据共享");return"view";}

使用Model接口

  1. @RequestMapping("/testModel")publicStringtestModel(Model model){// 向request域中存储数据
  2. model.addAttribute("testRequestScope","在SpringMVC中使用Model接口实现request域数据共享");return"view";}

使用Map接口

  1. @RequestMapping("/testMap")publicStringtestMap(Map<String,Object> map){// 向request域中存储数据
  2. map.put("testRequestScope","在SpringMVC中使用Map接口实现request域数据共享");return"view";}

使用ModelMap类

  1. @RequestMapping("/testModelMap")publicStringtestModelMap(ModelMap modelMap){// 向request域中存储数据
  2. modelMap.addAttribute("testRequestScope","在SpringMVC中使用ModelMap实现request域数据共享");return"view";}

Model、Map、ModelMap的关系?

  • 输出打印Model、Map、ModelMap的Class,底层实例化的对象都是:BindingAwareModelMap
  • BindingAwareModelMap的继承结构

在这里插入图片描述

  • BindingAwareModelMap继承ModelMap实现Model,而ModelMap又实现了Map接口

在这里插入图片描述

使用ModelAndView类

  • 为了更好的体现MVC架构模式,提供了一个类:ModelAndView。这个类的实例封装了ModelView
  • 也就是说这个类既封装业务处理之后的数据,也体现了跳转到哪个视图
  • 使用它也可以完成request域数据共享
  1. @RequestMapping("/testModelAndView")publicModelAndViewtestModelAndView(){// 创建“模型与视图对象”ModelAndView modelAndView =newModelAndView();// 绑定数据
  2. modelAndView.addObject("testRequestScope","在SpringMVC中使用ModelAndView实现request域数据共享");// 绑定视图
  3. modelAndView.setViewName("view");// 返回return modelAndView;}

注意:

  1. 方法的返回值类型不是String,而是ModelAndView对象
  2. ModelAndView不是出现在方法的参数位置,而是在方法体中new的
  3. 需要调用addObject向域中存储数据
  4. 需要调用setViewName设置视图的名字

**以上我们通过了五种方式完成了request域数据共享,这几种方式在底层DispatcherServlet调用我们的Controller之后,返回的对象都是

  1. ModelAndView

。**

在这里插入图片描述

2、session域对象

  • session对象代表了一次会话- 从打开浏览器开始访问,到最终浏览器关闭,这是一次完整的会话- 每个会话session对象都对应一个JSESSIONID,而JSESSIONID生成后以cookie的方式存储在浏览器客户端- 浏览器关闭,JSESSIONID失效,会话结束
  • 使用会话域的业务场景- 登录成功后保存用户的登录状态

使用原生Servlet API方式

  1. @RequestMapping("/testSessionScope1")publicStringtestServletAPI(HttpSession session){// 向会话域中存储数据
  2. session.setAttribute("testSessionScope1","使用原生Servlet API实现session域共享数据");return"view";}

3、application域对象

  • application对象代表了整个web应用- 服务器启动时创建,服务器关闭时销毁- 对于一个web应用来说,application对象只有一个
  • 使用应用域的业务场景- 记录网站的在线人数

使用原生Servlet API方式

  1. @RequestMapping("/testApplicationScope")publicStringtestApplicationScope(HttpServletRequest request){// 获取ServletContext对象ServletContext application = request.getServletContext();// 向应用域中存储数据
  2. application.setAttribute("applicationScope","我是应用域当中的一条数据");return"view";}

六、HttpMessageConverter消息转换器

  • HttpMessageConverter是Spring MVC中非常重要的一个接口
  • 翻译为:HTTP消息转换器。该接口下提供了很多实现类,不同的实现类有不同的转换方式

在这里插入图片描述

  • 转换器是HTTP协议Java程序中的对象之间的互相转换

在这里插入图片描述

1、Form表单转换器和默认转换器

Form表单转换器

**请求体中的数据是如何转换成user对象的,底层实际上使用了

  1. HttpMessageConverter

接口的其中一个实现类

  1. FormHttpMessageConverter

。**

在这里插入图片描述

**通过上图可以看出

  1. FormHttpMessageConverter

是负责将

  1. 请求协议

转换为

  1. Java对象

的。**

默认转换器

**Controller返回值看做逻辑视图名称,视图解析器将其转换成物理视图名称,生成视图对象,

  1. StringHttpMessageConverter

负责将视图对象中的HTML字符串写入到HTTP协议的响应体中。最终完成响应。**

在这里插入图片描述

**通过上图可以看出

  1. StringHttpMessageConverter

是负责将

  1. Java对象

转换为

  1. 响应协议

的。**

2、@ResponseBody

首页面AJAX请求获取数据,非跳转页面Controller

2.1、Servlet原生API方式

  1. // 有返回值@RequestMapping(value ="/hello1")publicStringhello1(HttpServletResponse response)throwsIOException{
  2. response.getWriter().print("hello");returnnull;}// 无返回值@RequestMapping(value ="/hello2")publicvoidhello2(HttpServletResponse response)throwsIOException{
  3. response.getWriter().print("hello");}

页面展示

在这里插入图片描述

注意:如果采用这种方式响应,则和 springmvc.xml 文件中配置的视图解析器没有关系,不走视图解析器了

2.2、@ResponseBody注解方式

  • 这里的"hello"不是逻辑视图名了,而是作为响应体的内容进行响应。直接输出到浏览器客户端
  • 程序中使用的消息转换器是:StringHttpMessageConverter,为什么会启用这个消息转换器呢?- 因为你添加@ResponseBody这个注解
  1. @ControllerpublicclassHelloController{@RequestMapping(value ="/hello")@ResponseBodypublicStringhello(){// 由于你使用了 @ResponseBody 注解// 以下的return语句返回的字符串则不再是“逻辑视图名”了// 而是作为响应协议的响应体进行响应。return"hello";}}
  • 通常AJAX请求需要服务器给返回一段JSON格式的字符串,可以返回JSON格式的字符串吗?当然可以,代码如下:
  1. @ControllerpublicclassHelloController{@RequestMapping(value ="/hello")@ResponseBodypublicStringhello(){return"{\"username\":\"zhangsan\",\"password\":\"1234\"}";}}

页面展示

在这里插入图片描述

  • 此时底层使用的消息转换器还是:StringHttpMessageConverter
  • 那如果在程序中是一个POJO对象,怎么将POJO对象以JSON格式的字符串响应给浏览器呢?- 方式一:自己写代码将POJO对象转换成JSON格式的字符串,用上面的方式直接return即可- 方式二:启用MappingJackson2HttpMessageConverter消息转换器

2.3、MappingJackson2HttpMessageConverter(JSON转换器)

启动JSON消息转换器需要两个步骤

  • 第一步:引入jackson依赖,可以将java对象转换为json格式字符串
  1. <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.17.0</version></dependency>
  • 第二步:开启注解驱动,会自动装配一个消息转换器:MappingJackson2HttpMessageConverter
  1. <mvc:annotation-driven/>

@ResponseBody最经典用法如下:

  1. @RequestMapping(value ="/hello")@ResponseBodypublicUserhello(){User user =newUser("zhangsan","18");return user;}
  • 将POJO对象转换成JSON格式的字符串,响应给前端

在这里插入图片描述

3、@RestController

  • 为了方便,Spring MVC中提供了一个注解@RestController。这一个注解代表了:@Controller + @ResponseBody
  • @RestController标注在类上即可。被它标注的Controller中所有的方法上都会自动标注@ResponseBody
  1. @RestControllerpublicclassHelloController{@RequestMapping(value ="/hello")publicUserhello(){User user =newUser("zhangsan","18");return user;}}

4、@RequestBody

  • 作用是直接将请求体传递给Java程序

4.1、&拼接参数

在没有使用这个注解的时候:

  1. @RequestMapping("/save")publicStringsave(User user){// 执行保存的业务逻辑
  2. userDao.save(user);// 保存成功跳转到成功页面return"success";}

**当

  1. 请求体

提交的数据是:**

  1. username=zhangsan&password=1234&email=zhangsan@powernode.com

**那么Spring MVC会自动使用

  1. FormHttpMessageConverter

消息转换器,将请求体转换成user对象**

**当使用这个注解的时候:这个注解只能出现在

  1. 方法的参数上

**

  1. @RequestMapping("/save")publicStringsave(@RequestBodyString requestBodyStr){System.out.println("请求体:"+ requestBodyStr);return"success";}

**Spring MVC仍然会使用

  1. FormHttpMessageConverter

消息转换器,将请求体直接以字符串形式传递给requestBodyStr变量**

4.2、JSON格式参数

  • 如果请求体JSON格式字符串,可以将其转化为POJO对象
  • 此时必须使用@RequestBody注解来完成
  • 底层使用的消息转换器是:MappingJackson2HttpMessageConverter
  • 启动步骤与@ResponseBody一样,引入jackson依赖、开启注解驱动
  1. @RequestMapping("/send")@ResponseBodypublicStringsend(@RequestBodyUser user){System.out.println(user);System.out.println(user.getUsername());System.out.println(user.getPassword());return"success";}

5、RequestEntity

  • 这个类的实例封装了整个请求协议:包括请求行请求头请求体所有信息
  1. @RequestMapping("/send")@ResponseBodypublicStringsend(RequestEntity<User> requestEntity){System.out.println("请求方式:"+ requestEntity.getMethod());System.out.println("请求URL:"+ requestEntity.getUrl());HttpHeaders headers = requestEntity.getHeaders();System.out.println("请求的内容类型:"+ headers.getContentType());System.out.println("请求头:"+ headers);User user = requestEntity.getBody();System.out.println(user);System.out.println(user.getUsername());System.out.println(user.getPassword());return"success";}

执行结果:

在这里插入图片描述

6、ResponseEntity

  • 用该类的实例可以封装响应协议,包括:状态行响应头响应体
  • 如果你想定制属于自己的响应协议,可以使用该类
  1. @ControllerpublicclassUserController{@GetMapping("/users/{id}")publicResponseEntity<User>getUserById(@PathVariableLong id){User user = userService.getUserById(id);if(user ==null){returnResponseEntity.status(HttpStatus.NOT_FOUND).body(null);}else{returnResponseEntity.ok(user);}}}

七、异常处理器

1、默认异常处理器

  • 方法执行过程中出现了异常,跳转到对应的视图,在视图上展示友好信息

**默认处理器

  1. DefaultHandlerExceptionResolver

核心方法:**

在这里插入图片描述

**当请求方式和处理方式

  1. 不同

时,DefaultHandlerExceptionResolver的默认处理态度是:**

在这里插入图片描述

2、自定义异常处理器

2.1、跳转错误页面

  1. @ControllerAdvicepublicclassExceptionController{@ExceptionHandlerpublicStringexceptionHandler(Exception e,Model model){
  2. model.addAttribute("e", e);return"error";}}
  1. <!DOCTYPEhtml><htmllang="en"xmlns:th="http://www.thymeleaf.org"><head><metacharset="UTF-8"><title>出错了</title></head><body><h1>出错了,请联系管理员!</h1><divth:text="${e}"></div></body></html>

在这里插入图片描述

2.2、返回错误响应对象

  1. @ControllerAdvicepublicclassExceptionController{@ExceptionHandler(value ={Exception.class})@ResponseBodypublicResponseEntity<String>exceptionHandler(Exception e,Model model){// 这里先判断拦截到的Exceptiion是不是我们自定义的异常类型if(e instanceofMyException){MyException myException =(MyException) e;returnResponseEntity.status(500).body(myException.getMeg());}else{// 如果拦截的异常不是我们自定义的异常(例如:数据库主键冲突)returnResponseEntity.status(500).body("服务器端异常");}}}

八、拦截器

1、拦截器概述

  • 拦截器作用是在请求到达控制器之前或之后进行拦截,可以对请求和响应进行一些特定的处理
  • 拦截器可以用于很多场景下- 登录验证:对于需要登录才能访问的网址,使用拦截器可以判断用户是否已登录,如果未登录则跳转到登录页面- 权限校验:根据用户权限对部分网址进行访问控制,拒绝未经授权的用户访问- 请求日志:记录请求信息,例如请求地址、请求参数、请求时间等,用于排查问题和性能优化- 更改响应:可以对响应的内容进行修改,例如添加头信息、调整响应内容格式等

2、拦截器和过滤器的区别

  • 过滤器更注重在请求和响应的流程中进行处理,可以修改请求和响应的内容,例如设置编码和字符集、请求头、状态码等
  • 拦截器则更加侧重于对控制器进行前置或后置处理,在请求到达控制器之前或之后进行特定的操作,例如打印日志、权限验证等

Filter、Servlet、Interceptor、Controller的执行顺序:

在这里插入图片描述

3、拦截器的创建与基本配置

定义拦截器

  • 实现org.springframework.web.servlet.HandlerInterceptor 接口,共有三个方法可以进行选择性的实现- preHandle:处理器方法调用之前执行(返回true放行,false拦截)- postHandle:处理器方法调用之后执行- afterCompletion:渲染完成后执行
  1. @ComponentpublicclassMyInterceptorimplementsHandlerInterceptor{@OverridepublicbooleanpreHandle(HttpServletRequest request,HttpServletResponse response,Object handler)throwsException{System.out.println("处理器方法前调用");returntrue;}@OverridepublicvoidpostHandle(HttpServletRequest request,HttpServletResponse response,Object handler,ModelAndView modelAndView)throwsException{System.out.println("处理器方法后调用");}@OverridepublicvoidafterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex)throwsException{System.out.println("渲染完成后调用");}}

基本配置

springmvc.xml配置如下

  1. <mvc:interceptors><beanclass="com.xc.interceptors.MyInterceptor"/></mvc:interceptors><!-- 或者 --><mvc:interceptors><refbean="myInterceptor"/></mvc:interceptors>

添加组件扫描

在这里插入图片描述

注意:对于这种基本配置来说,拦截器是拦截所有请求的

4、多个拦截器执行顺序

如果所有拦截器preHandle都返回true

**按照springmvc.xml文件中配置的顺序,

  1. 自上而下

调用 preHandle**

  1. <mvc:interceptors><refbean="interceptor1"/><refbean="interceptor2"/></mvc:interceptors>

执行顺序:

在这里插入图片描述

如果其中一个拦截器preHandle返回false

  1. <mvc:interceptors><refbean="interceptor1"/><refbean="interceptor2"/></mvc:interceptors>

**如果

  1. interceptor2

的preHandle返回false,执行顺序:**

在这里插入图片描述
**规则:只要有一个拦截器

  1. preHandle

返回false,所有

  1. postHandle

都不执行。但返回false的拦截器的前面的拦截器按照逆序执行

  1. afterCompletion

。**

标签: java spring mvc

本文转载自: https://blog.csdn.net/qq_35512802/article/details/139730755
版权归原作者 冬天vs不冷 所有, 如有侵权,请联系我们删除。

“SpringMVC基础详解”的评论:

还没有评论