zl程序教程

您现在的位置是:首页 >  后端

当前栏目

Spring MVC 总结

SpringMVC 总结
2023-09-14 09:14:50 时间

Spring MVC 概述

为 WEB 项目提供的 MVC 分层框架

在这里插入图片描述

水平角度: Spring MVC 是 Spring 生态圈中的一个功能模块。两者是包含与被包含的关系;
垂直角度: Spring MVC 是建立在 Spring 核心基础功能之上的一个实用性的 WEB MVC 框架,是 Spring 的延伸和扩展。

MVC 的分离思想:

把整个应用程序中和用户进行交互的功能代码归纳在一起,这部分代码整体称为 V (View 或叫视图层)

把专门用来进行数据传递或数据逻辑处理的功能代码归纳在一起,称其为 M(Model 或叫l模型层)

C (控制器)就是 V 和 M 之间的桥梁

两个上下文对象

2 个 WebApplicationContext 对象:

  • WebApplicationContext 对象用来创建 Spring MVC 相关的组件,称其为 Web 上下文对象
  • RootApplicationContext 创建程序中其它的具体功能组件(如逻辑组件、数据层访问组件…),称其为 Root (根)上下文对象

一个支持事务,另一个不支持

在这里插入图片描述

DispatcherServlet 为中央控制器或前端控制器

在整个项目运作之前先让 DispatcherServlet 组件开始工作,DispatcherServlet 除了充当门神外,还会创建一个与自己有关联的 WebApplicationContext 工厂对象,即 Web 上下文对象

Spring 另提供有名为 ContextLoaderListener 的监听器组件,它可以监听程序的启动过程,并在程序启动时创建另一个 WebApplicationContext 工厂对象,即 Root 上下文对象

AbstractAnnotationConfigDispatcherServletInitializer : 基于注解的初始化 DispatcherServlet 的抽象组件,简单说就是一个 WEB 初始化组件,用来替代 web.xml 的功能

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{

	@Override
	protected Class<?>[] getRootConfigClasses() {	
		return new Class[] { RootConfig.class};
	}
	
	@Override
	protected Class<?>[] getServletConfigClasses() {
	return new Class[] { WebConfig.class};
	}
	
	//接受所有请求
	@Override
	protected String[] getServletMappings() {
		return new String[] {"/"};
	}
}
//web 上下文对象的配置类
@Configuration
@ComponentScan(basePackages = { "com.cpucode.web" }, excludeFilters = {
		@Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class) })
public class RootConfig {
}
// Root 上下文对象的配置类
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.cpucode.web.action" })
public class WebConfig {
}
  • @Configuration 注解:说明这个类是配置类;配置类用来替代 XML 配置文件
  • @EnableWebMvc 注解: 启动 Spring MVC 相关功能
  • @ComponentScan 注解: 指定上下文对象各自负责的组件所在包

核心组件

  • 前端控制器: 类似于超市的入口
  • 用户控制器: 类似于不同类型的货品架,为用户提供具体的商品买卖
  • 映射器: 类似于超市里的导购员。请问,我要的这个牌子的辣椒酱在哪里,哦,在这里
  • 适配器: 统一控制器,让其有一致对外的接口
  • 视图解析器: 找到视图,并负责渲染视图

前端控制器

  • 中央控制器 ( 前端控制器 ) : 由 Spring MVC 框架提供,对所有请求进行分流;
  • 用户控制器 ( 响应控制器 ) : 由开发者实现,用来响应用户的具体请求。如登录请求、注册请求

前端控制器(DispatcherServlet)是 Spring MVC 中最核心的组件,相当于整个程序中的行政、调度中心。其它的组件都是它的附庸,为前端控制器提供相关的服务

DispatcherServlet 必须在 Spring MVC 项目启动时被创建

请求分流

所有请求都会汇流给 DispatcherServlet 组件。再由 DispatcherServlet 分流到具体的用户控制器

  • 安全性: 前台可以对来访人员的身份进行初步认定和筛选。确保只能通过一个入口进入程序

  • 标准化: 每一个请求都会以相同的方式进行分流处理。统一协调,标准化项目,可以高度简化处理流程

在这里插入图片描述

调度中心

一次请求、响应的完成,需要多个组件通力合作。如何协调各个组件的工作,保证请求、响应过程有条不紊的进行,则需要一个指挥者或说一个核心灵魂组件

DispatcherServlet就是每一次请求、响应过程中的组织者、调度者

DispatcherServlet 本质就是一个和 Spring MVC 程序一起启动的 Servlet

用户控制器

用户控制处理器(用户控制器 \ 控制器 \ 处理器)提供具体的响应用户请求的逻辑。用户控制器虽然由用户自定义编写,但也需要直接或间接遵循 Spring MVC 的控制器编写规范

编写控制器

public class HelloAction implements org.springframework.web.servlet.mvc.Controller {
   	@Override
   	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
   		System.out.println("Bean URL ");
   		return null;
   	}
}

映射控制器

原生 Servlet 开发中,需要在 web.xml 中注册、映射 Servlet 后浏览器才能请求到

在类前面 @Controller 注解 : 通知 Spring MVC 的上下文对象(WebApplicationContext), 控制器的创建交给你

@Controller
public class HelloAction  {
    //省略……
}

控制器的方法前面添加 @RequestMapping 注解。使用此注解可提供一个逻辑名向用户映射此方法

@RequestMapping("/hello")
public String hello() {
	System.out.pirntln("hello");
	return "hello";
}

映射器

检查用户的请求路径中是否存在对应的控制器组件

在这里插入图片描述

开发者没有显示配置映射器,Spring MVC 会启动默认的映射器组件

DispatcherServlet 所在包的根目录下有名为 DispatcherServlet.properties 的文件,已经配置了很多默认组件信息

@Bean 注解映射: 打开项目中的 WebConfig 配置类

@Bean(name = "/hello")
public HelloAction hello() {
 	return new HelloAction();
 }

“hello” 前面一定要加上 “/”

使用 @Bean 注解的方式映射控制器,则用户控制器需要实现 org.springframework.web.servlet.mvc.Controller 接口, 意味着必须是一个标准的控制器
@Bean 的作用就是告诉 Spring MVC:你要创建它,其名字被当成一个访问控制器的 URL

BeanNameUrlHandlerMapping 映射器的功能就是查找有没有哪一个 Bean 的名字用户请求的路径相匹配

RequestMappingHandlerMapping 映射器就是查找由 @RequestMapping 注解映射的控制器

适配器

适配器组件,其本质就是运用适配器设计模式,匹配不兼容的接口规范

在这里插入图片描述

  • SimpleControllerHandlerAdapter: 简单的控制器处理器适配器,支持实现了 Controller 接口的控制器

  • HttpRequestHandlerAdapter:http 请求处理器适配器,要求编写的控制器时实现 HttpRequestHandler 接口。此类控制器可以很方便的获取请求包中的相关信息

  • RequestMappingHandlerAdapter: 注解处理器适配器,适配使用了注解的用户控制器

在这里插入图片描述

视图解析器

视图解析器的功能

视图解析器,则会把这个字符串当成一个视图的逻辑名,并映射到真正的物理视图

视图解析器和映射器的有相似之处 :

  • 映射器入口时根据请求控制器逻辑名找到物理控制器

  • 视图解析器出口时根据视图逻辑名找到物理视图

InternalResourceViewResolver 作为视图解析器, 提供对 JSP 视图的支持

默认提供的、还是开发者自行定义的视图解析器,都必须实现 ViewResolver 接口

public interface ViewResolver {
    @Nullable
    View resolveViewName(String viewName, Locale locale) throws Exception;
}

在这里插入图片描述

配置视图解析器

WebConfig 配置类 :

@Bean
public InternalResourceViewResolver viewResolver() {	
	InternalResourceViewResolver inResolver=new InternalResourceViewResolver();	
	inResolver.setPrefix("/WEB-INF/jsp/");
	inResolver.setSuffix(".jsp");
	return inResolver;
}
  • @Bean 注解表示此对象由 Spring 容器创建
  • inResolver.setPrefix ("/WEB-INF/jsp/") 表示 JSP 页面视图所在物理位置
  • inResolver.setSuffix (".jsp") 表示 JSP 视图的后缀

静态资源

WebConfig 配置类,让其实现 WebMvcConfigurer 接口

public class WebConfig implements WebMvcConfigurer{ 

}

重写 configureDefaultServletHandling() 方法,启动 Servlet 的 default Servlet 来处理静态资源

public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
	configurer.enable();
}

总结

在这里插入图片描述

  1. 浏览器的请求到达前端控制器(DispatcherServlet)

  2. 前端控制器解析出请求路径后询问映射器,咱们是否提供的有用户需要的用户控制器,映射器把查询结果返回给前端控制器

  3. 适配器的作用就是统一不同类型的用户控制器(也体现了 Spring MVC 中用户控制器的多样性和灵活性)

  4. 用户控制器开始工作(具体的响应逻辑)

  5. 用户控制器返回视图逻辑名和视图中所需要的数据(ModelAndView)

  6. 前端控制器询问视图解析器,你能够根据逻辑名找到物理视图吗?视图解析器开始工作并找到物理视图

  7. 前端控制器渲染物理视图和数据,生成浏览器能够识别的数据格式

  8. 响应浏览器,并在浏览器中显示最终请求结果

映射与数据解析

地址请求映射

请求地址映射 : 每一次请求都会交给用户控制器响应。为了保证用户能请求到用户控制器,则需要 Spring MVC 向外提供用户控制器对外的请求接口

在这里插入图片描述

@RequestMapping 注解的作用:把用户控制器以 URL 逻辑名的方式向外映射,用于由外向内的请求调用。

解析请求包中的信息,查找是否存在相匹配的控制器,这个工作由映射器组件完成。

@RequestMapping 的位置

放置在类前面也可以放在方法前面

@Controller              
@RequestMapping("/user") 
public class UserController {
	 @RequestMapping(value = "/register") 
	 public String register() {
	           return “user/register”; 
	 }
}

使用表达式限定请求

映射描述具有多样性:

  • 支持标准的 URL 格式
  • 支持 Ant 风格

Ant 风格指在 URL 中支持 通配符的语法结构描述

  • ?: 匹配任何单字符
  • * : 匹配 0 个或者任意数量的字符
  • ** : 匹配 0 个或者更多的目录
  • {xxx} 占位符的 URL

限定请求的方法

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {	
	String name() default "";
	@AliasFor("path")
	String[] value() default {};
	@AliasFor("value")
	String[] path() default {};
	RequestMethod[] method() default {};
	String[] params() default {};
	String[] consumes() default {};
	String[] produces() default {};
}
  • method():可限定请求的方法;
  • params():可以限定请求的参数

常用的请求方法 :

  • GET: 一般用于查询请求,具有幂等性,多次相同的请求会返回相同的结果,所以可以使用浏览器缓存。不会影响系统的整体性能
  • POST: 一般用于数据保存请求。不具有幂等性,多次操作会产生新的资源
  • DELETE: 一般用于删除资源请求,可以多次删除
  • PUT: 一般用于更新数据请求,也具有幂等性,无论更新多次性,结果都一样
@RequestMapping(value="/test",method=RequestMethod.POST) 
public String test(){
    return "user/test1";   
}

RequestMethod 是一个枚举类型

public enum RequestMethod {
	GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
}

限定请求参数

限定请求参数,Spring MVC 会检查请求包中是否包含符合要求的请求参数

@RequestMapping(value="/test", params="userId") 
public String test(){
    //...   
}
  • params=“userId”: 指挥响应请求包中包含有名为 userId 参数的请求
  • params="!userId" : 如果请求包中有名为 userId 的请求参数,则不响应,否则响应
  • params=“userId!=1”: 对响应的请求有更多的要求,除了请求包中必须包含 userId 参数外,其值必须是 1
  • params={“userId=1”,“userName”}: 响应的条件是,请求包中必须包含名为 userId 和 userName 这两个参数,且 userId 参数的值必须为 1

限定头信息

限定头信息,指 Spring MVC 可以通过 HTTP 请求包中的消息头信息进行过滤

@RequestMapping(value="/test", headers="content-type=text/*")
public String test(){
     //...   
}

test() 方法只会响应请求包中的内容类型为 text/* 的请求

绑定请求包中的数据

注解解析请求包中的数据 :

  • @RequestParam
  • @CookieValue
  • @RequestHeader
  • @PathVariable

HTTP 协议的一种数据格式包 :
在这里插入图片描述

  • 请求行: 包括请求方法、请求的资源地址(URL) 、HTTP 协议版本号;
  • 消息头: 消息头是传送给服务器的信息,以 key:value 的格式描述;
  • 实体部分或报文体: 以 key=value 的数据格式保存客户端传递给应用程序的数据。

@RequestParam

自动绑定请求包中的请求参数中的值

请求参数在请求包中的 2 个位置:

  • 用 ? 的方式附加在 URL 后面。如 http://:/saveUser?name=abc 。name 就是请求参数,abc 是值
  • name=abc 的方式存储在请求包的报文体中(实体部分)

POST 方法请求时,数据将存储在实体部分

@RequestMapping(value="/saveUser")
public String save(@RequestParam("userName") String userName,
				   @RequestParam("password")  password){
}

@RequestParam(“参数名”) 中的 “参数名” 和请求包中的参数名命名相同

@RequestParam 注解中有 3 个常用的属性:

  • value() : 指定要解析的请求包中的参数名

  • required() : 表示请求包中是否必须存在由 value() 指定的参数名,默认值是 true。如果没有此参数则会抛出异常

  • defaultValue() : 表示如果不能正确获取到指定参数的值时,则提供一个默认值。设置该参数时,自动将 required 设为 false

@RequestMapping(value="/saveUser")
public String save(@RequestParam(value = "userName",
					defaultValue="mk",
					required = false) String userName,){
}

@CookieValue

@CookieValue 用来自动绑定请求包中的 Cookie 值

Cookie 所能保存的数据量有限且只能是字符类型

@RequestMapping(value="/sessionId")
public String getSessionId(@CookieValue("JSESSIONID") String sessionId){
}

注入 Cookie 中所携带的 JSESSIONID 的值

@RequestHeader

请求包中有很多消息头信息,都是以 key:value 的格式存在

@RequestMapping(value="/header")
public String getHeader(@RequestHeader("Accept-Language") String accpetLanguage){
  //...
}

accpetLanguage 参数会被注入请求包中 key 名为 Accept-Language 的消息头值

@RequestHeader 注解中的方法 :

@AliasFor("name")
String value() default "";
String name() default "";
boolean required() default true;
String defaultValue() default ValueConstants.DEFAULT_NONE;

@PathVariable

获取 URL 中变量的值

{userId} 就是变量占位符

@RequestMapping("/user/{userId}")
public String getUserById(@PathVariable("userId") String userId){

}

required 属性,表示是否强制 URL 中有变量的存在

boolean required() default true;

总结

  • @RequestParam :请求参数中的值
  • @CookieValue: Cookie 的值
  • @RequestHeader 请求头的值
  • @PathVariable :请求变量的值

绑定表单数据

对象 / 表单

表单的方式提交数据有一个优点,可以把逻辑上具有内在联系的多个数据同时发送给服务器

提交数据最终会交给服务器端的用户控制器完成

控制器中的处理流程应该分 3 步走:

  • 请求包中解析出客户端提交过来的注册数据
  • 处理注册数据。核心业务逻辑就是添加数据到数据库中
  • 根据处理结果进行页面跳转

OOP 方式绑定数据

public class User {
	private String userName;
   	private String userPassword;
    //……
}
@RequestMapping("/register",method = RequestMethod.POST)
public String register(User user) {
	System.out.println(user);
	return null;
}

表单中数据以 key=value&key=value 的方式提交,此处的 key 实质是表单控件的名称

Spring MVC 能自动解析这个数据,然后自动注入到对象的同名属性中

在这里插入图片描述

对象级联

OOP 代码中经常会出现类似于 A 对象引用 B 对象,B 对象引用 C 对象的现象

Spring MVC 支持对象级联自动数据绑定 , 多层级的对象级联

在这里插入图片描述

表单验证

JSR : 数据验证是对数据进行逻辑处理之前需要进行的一个很重要环节,如果不合要求的数据进入逻辑处理环节后,会导致程序的崩溃

在这里插入图片描述

验证用户提交的表单数据的合法性 :

  • 客户端验证: 表单提交之前,通过客户端的 JS 脚本对表单中预提交的数据进行验证
  • 服务器端验证: 数据提交到服务器后,由服务器端的的代码进行验证

Bean 类型的属性前面 :

  • @Null: 被注解的属性的值必须为空

  • @NotNull: 被注解的属性的值可以不为空

  • @Min(value): 注解数字类型的属性,其值大于等于指定的值

  • @Max(value): 注解数字类型的属性,其值小于等于指定值

  • @Size(max, min): 注解的属性值的大小必须是在给定的范围内(包括边界数字)

  • @Past: 注解日期类型属性,必须是一个过去的日期

  • @Future: 注解日期类型属性,必须是一个将来的日期

  • @Pattern(regexp): 使用正则表达式验证属性的值

  • @Length(min, max): 属性值的长度在给定的范围之内(包括边界数字)

public class Teacher {
	@NotNull(message = "姓名不能为空")
	private String name;
	   
	@Min(value = 22,message = "年龄不能小于 22 岁")
	private Integer age;
	
	//...
}

@Valid 注解表示在绑定数据之后对数据进行验证

BindingResult 组件用来保存验证过程中的错误信息

@Controller
@RequestMapping("/teacher")
public class TeacherAction {
   	@RequestMapping(value = "/save",method = RequestMethod.POST)
   	public String register(@Valid Teacher teacher,BindingResult result) {
   		if (result.hasErrors()) {
   			return "fail"; 
   		}
   		return "success";
   	}
}

原生 Servlet

HttpServletRequest: 用来处理请求包
HttpServletResponse: 用来处理响应包
HttpSession: 会话对象
ServletConfig: 配置对象
ServletContext: Servlet 上下文对象

在这里插入图片描述

Servlet API 代理类

Spring MVC 在它的 org.springframework.web.context.request 包中提供的有 WebRequest 接口,此接口可以用来代理原生 HttpServletRequest 的功能

使用 IO 流

WEB 程序整体上是 B / S 结构,本质上是基于底层网络的程序,是 C / S 结构体系的升级

网络编程的几个基本要素:

  • 服务器端建立监听端口
  • 客户端向监听端口发起网络连接
  • 连接成功后建立起双向的网络流传输通道
  • 彼此之间通过网络流通道进行数据交流

Spring MVC 既可以把原生的 Servlet API 对象注入到控制器的方法中,也可以把更底层的 IO 流对象注入到控制器方法中

在这里插入图片描述

注入 InputStream

@RequestMapping(value = "/testApi04",method = RequestMethod.POST)
public void hello(InputStream inputStream) throws IOException {
    byte[] buff=new byte[128];
	int read= inputStream.read(buff);
	System.out.println(new String(buff,0,read));
}

控制器方法的映射机制有只接受 POST 方法的限制,如果是 GET 方法的请求包,直接使用 InputStream 对象无法获取到请求包中的数据。

GET 方法的请求数据是附加在 URL 上的,InputStream 只能读取实体部分的数据

注入 OutputStream

OutputStream 对象读取指定文件中的内容后直接响应给浏览器

@RequestMapping(value = "/testApi05")
public void hello(OutputStream outputStream) throws IOException {
	Resource res = new ClassPathResource("/test.txt");
	FileCopyUtils.copy(res.getInputStream(), outputStream);
}

XML 方式

2 个上下文对象分别依赖于 DispatcherServlet 和 ContextLoaderListener 组件完成创建。

  • DispatcherServlet : 整个程序的调度中心(本质就是一个 Servlet),Spring MVC 程序启动时必须要初始化完成对 DispatcherServlet 组件的创建。此组件还会创建一个与自己有关联的 WebApplication 工厂对象,即 Web 上下文对象

  • ContextLoaderListener : 由 Spring 提供的监听器组件,它可以监听程序的启动过程,并在程序启动时创建另一个 WebApplication 工厂对象,即 Root 上下文对象

在这里插入图片描述

  • web.xml: 理论上,在新建 Spring MVC WEB 项目时, WEB-INF 目录中会自动创建这个文件。如果不存在,就需要创建一个
  • spring-mvc.xml: 由开发者新建,一般放在项目的 src/main/resources 目录下面
  • application.xml: 由开发者新建,放在项目的 src/main/resources 目录下面

web.xml

在 web.xml 中配置 DispatcherServlet 组件相关的信息

 <!-- 配置 Spring MVC 的核心组件 DispatcherServlet -->
<servlet>
	<servlet-name>springMVC</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring-mvc.xml</param-value>
	</init-param>
	<load-on-startup>0</load-on-startup>
</servlet>

<servlet-mapping>
	<servlet-name>springMVC</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>

contextConfigLocation 是 DispatcherServlet 的属性,用于指定与 DispatcherServlet 创建的上下文对象有关的配置文件的位置。此处为 spring-mvc.xml 文件位置

在 web.xml 中配置 ContextLoaderListener 监听器组件相关信息

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>classpath:application.xml</param-value>
</context-param>
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

配置临听器时,也需要为临听器创建的上下文对象指定配置文件的位置,此处指 application.xml 文件的位置

spring-mvc.xml

spring-mvc.xml 用来配置与 Spring MVC 相关的组件信息,用来提供给 web 上下文对象进行组件维护

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
	<!-- 启动注解支持 -->
	<mvc:annotation-driven/>
    <!--静态资源交给 tomcat default servelt 处理-->
	<mvc:default-servlet-handler />
    <!--扫描组件位置-->
	<context:component-scan
		base-package="com.cpucode.web.action"></context:component-scan>
   <!-- 视图解析器 -->
	<mvc:view-resolvers>
		<bean
			class="org.springframework.web.servlet.view.InternalResourceViewResolver">
			<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> 
			<property name="prefix" value="/WEB-INF/jsp"></property>
			<property name="suffix" value=".jsp"></property>
		</bean>
	</mvc:view-resolvers>
</beans>
  • mvc:annotation-driven: 启动注解支持,完全使用 XML 进行 Spring MVC 项目维护,并不是很方便。即使在使用 XML 时,建议还是结合注解一起使用,这也是 Spring MVC 官方建议的

  • context:component-scan: 指定哪些组件由 Spring MVC 的上下文对象负责。除了 Spring MVC 内部组件外,再就是用户控制器

  • mvc:view-resolvers: 配置具体的视图解析器

application.xml

application.xml 是 Spring 上下文容器所关联的配置文件,可称其为全局上下文对象的关联配置文件

<beans xmlns="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-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
	<context:annotation-config></context:annotation-config>
	<context:component-scan
		base-package="com.cpucode.web">
		<context:exclude-filter type="annotation"
			expression="org.springframework.stereotype.Controller" />
	</context:component-scan>
</beans>
  • context:annotation-config: 启动注解支持,建议需要全局上下文对象创建、维护的对象使用注解的方式
  • context:component-scan: 扫描位置,需要排除开 Spring MVC 容器对象扫描的位置

数据模型

数据模型 : Spring MVC 提供的在特定作用域内封装数据的组件

请求作用域

WEB 程序的应用层使用的是 HTTP 协议,HTTP 协议有一个特点,无状态

无状态指上一次请求与下一次请求之间是隔离的,没有内在的联系

原生 Servlet 提供了 3 个作用域 :

  • 请求作用域: 使用 HttpServletRequest 组件存储的数据可以在每一次的请求周期内存在。 请求结束,数据也将消失

  • 会话作用域: 使用 HttpSession 组件保存的数据能在整个会话生命周期内存在。如购物车就可以保存在会话作用域中

  • 应用程序作用域: 使用 ServletContext 组件保存的数据在整个应用程序生命周期之内存在

Spring MVC 中,把数据保存在请求作用域 , 方案 :

  • 直接使用 HttpServletRequest 组件
  • 使用 Spriing MVC 提供的高级数据模型组件

原生 HttpServletRequest

@RequestMapping("/login")
public String login(User user,HttpServletRequest request) {
   	if("cpucode".equals(user.getUserName()) && "123".equals(user.getUserPassword())) {
   		//请求作用域	
	    request.setAttribute("loginUser", user);
	   	return "index";
   	}
   	return "fail";
}
  • user 参数: 以 OOP 的方式绑定请求包中传过来的数据;
  • request 参数: 注入原生 HttpServletRequest 组件。登录者的信息保存在 HttpServletRequest 对象中

HttpServletRequest 组件具有服务器端数据存储功能,本质是内部维护有一个 map 对象。HttpServletRequest 的生命周期较短,从请求开始到请求结束。所以,其保存的数据也只能在整个请求范围内有效

Spring MVC 模型组件

只要 Spring MVC 引用出 HttpServletRequest 内置的 map 对象

在这里插入图片描述

@RequestMapping(value="/login",method=RequestMethod.POST)
public String login(User user,Map map) {
   	if("mk".equals(user.getUserName()) && "123".equals(user.getUserPassword())) {
   		map.put("loginUser", user);
   		return "index";
   	}
   	return "fail";
}

map 参数 : 通知 Spring MVC ,把某个作用域中的 map 对象引用出来

Spring MVC 引用出来的是请求作用域也就是 HttpServletRequest 的内置 map 对象

数据模型

Spring MVC 中的数据模型组件 :

  • Model
  • ModelMap
  • ModelAndView

数据模型应该有 2 层含义:

  • WEB 程序中封装数据的组件
  • 此模型对象会有自己特定作用域

请求作用域 : 间接使用 HttpServletRequest 对象
会话作用域 : 间接使用 HttpSession 对象

Model

Model 是一个接口类型,Model 接口中提供了标准的保存数据的方法

将 Model 设为控制器方法的参数便可 , Model 是一个接口类型,Spring MVC 注入一个具体的实例对象

@RequestMapping(value="/login",method=RequestMethod.POST)
public String login01(User user,Model map) {
	if("cpucode".equals(user.getUserName()) && "123".equals(user.getUserPassword())) {
		map.addAttribute("loginUser", user);
		return "index";
	}
	return "fail";
}

ModelMap

用 Map 存储数据的模型 , 一个链表实现的 Map

public class ModelMap extends LinkedHashMap<String, Object> {
}
@RequestMapping(value="/login",method=RequestMethod.POST)
public String login01(User user,ModelMap map) {	
	if("cpucode".equals(user.getUserName()) && "123".equals(user.getUserPassword())) {
		map.addAttribute("loginUser", user);
		return "index";
	}
	return "fail";
}

ModelAndView

ModelAndView 其实就是封装了 ModelMap 外加一个用来保存视图相关信息的 view 对象 , 把数据模型视图拼在了一起,便于一次性交给前端控制器处理

public class ModelAndView {
	@Nullable
	private Object view;
	@Nullable
	private ModelMap model;
	//……
}

在这里插入图片描述

用法 :

@RequestMapping(value="/login",method=RequestMethod.POST)
public ModelAndView login01(User user) {
	ModelAndView mv=new ModelAndView();
	if("cpucode".equals(user.getUserName()) && "123".equals(user.getUserPassword())) {
		mv.addObject("loginUser", user);
		mv.setViewName("index");
		return mv;
	}
	mv.setViewName("fail");
	return mv;
}

会话作用域

Map、Model 、ModelMap、ModelAndView ,默认情况下,保存的数据都是请求作用域级别的

@Controller
@RequestMapping("/user")
@SessionAttributes("loginUser")
public class UserAction {
	@RequestMapping(value = "/login", method=RequestMethod.POST)
	public ModelAndView login01(User user) {
		ModelAndView mv = new ModelAndView();
		
		if("cpucode".equals(user.getUserName()) && "123".equals(user.getUserPassword())) {
			mv.addObject("loginUser", user);
			mv.setViewName("index");
			return mv;
		}
		
		mv.setViewName("fail");
		return mv;
	}
}

@SessionAttributes(“loginUser”) 中的属性名 loginUser 必须保持 和 mv.addObject(“loginUser”, user) 中的 loginUser 名一样

Spring MVC 即把数据保存到请求作用域中、也保存到会话作用域

总结

  • 使用 Map 做数据模型时, Spring MVC 注入的是一个 LinkedHashMap 实例
  • ModelMap 是 LinkedHashMap 的子类,本质还是 LinkedHashMap,只是封装了 put 方法,让其显得高级一点
  • Model 是接口,Spring MVC 注入的也是 LinkedHashMap 实例

视图技术

JSON 序列化

@ResponseBody

前后端分离结构 : 把一部分数据逻辑交给前端处理

后端一般选择以 JSON 的格式向前端进行数据传递

返回字符串

@Controller
@RequestMapping("/json")
public class JsonAction {
	@RequestMapping("/test01")
	@ResponseBody
	public String testJson() {
		return "Hello";
	}
}
  • 没有 @ResponseBody 注解:Spring MVC 会把返回值 “hello” 理解为视图逻辑名,通过视图解析器找到视图物理位置

  • @ResponseBody 注解: Spring MVC 会把返回值直接写入响应包后交给浏览器。意味着不需要视图解析器的参与

返回对象

@RequestMapping("/test02")
@ResponseBody
public User testJson01() {
	return new User("cpucode", "123");
}

Spring MVC 和 JSON

WebConfig 类文件

@Bean
public MappingJackson2HttpMessageConverter mappConverter() {
	MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter=new MappingJackson2HttpMessageConverter();
	return mappingJackson2HttpMessageConverter;
}

MappingJackson2HttpMessageConverter 就是一个消息转换器,其作用就是把数据映射成 JSON 格式

jackson 插件完成具体的 JSON 格式序列化

<dependency>
   	<groupId>com.fasterxml.jackson.core</groupId>
   	<artifactId>jackson-databind</artifactId>
   	<version>2.10.0</version>
</dependency>

视图技术

视图技术:

  • 模板
  • 模板解析引擎

模板

动态页面模板 :

  • HTML、CSS 等 : 为模板中的数据提供版式和样式
  • 强逻辑性语言: 提供数据逻辑能力,可以自动更新模板中的数据

模板解析引擎

动态页面模板需要被渲染成纯 HTML 静态页面后才能发送给浏览器,这个渲染过程就是依靠模板解析引擎实现

在这里插入图片描述

主流视图技术

主流视图技术 :

  • Jsp: Jsp 模板是 J2EE 官方指定的,所以其模板引擎可由遵循 J2EE 规范的服务器实现,如 tomcat
  • Freemarker: Freemarker 因 Struts MVC 风靡一时。其模板需要自己提供的模板引擎解析
  • Thymeleaf: Thymeleaf 应该算是后起之秀,更适应现代化开发理念和习惯

Spring MVC 视图解析器

Spring MVC 执行流程

@Controller 和 @RequestMapping 注解

Spring MVC 传递参数

Spring MVC 重定向和转发

@Autowired 和 @Service 注解

@ModelAttribute 注解

Spring MVC 拦截器

Spring MVC 异常处理

Spring MVC REST 风格

了解 Restful 相关的内容

Spring MVC 文件上传

Spring MVC 文件下载

常规应用

中文乱码问题

中文乱码的解决方式可以自定义过滤器,也可以使用 Spring MVC 自带的过滤器

整合