SpringMVC概述
- 定义
- SpringMVC是一种基于Java实现MVC设计模型的轻量级Web框架
- MVC设计模型:即将应用程序分为三个主要组件:模型(Model)、视图(View)和控制器(Controller)。这种分离使开发人员可以更容易地管理和维护代码。
- 它属于SpringFrameWork的后续产品,已经融合在Spring Web Flow中
- 它拥有一套完善的注解机制,通过注解可以让一个简单的Java类成为处理请求的控制器,而无需实现任何接口。同时它还支持
RESTful
编程风格的请求
- SpringMVC是一种基于Java实现MVC设计模型的轻量级Web框架
- SpringMVC的三大组件:处理器映射器(HandlerMapping)、处理器适配器(HandlerAdapter)、视图解析器(ViewResolver)
- SpringMVC就是要求我们编写一个个Controller控制器来处理请求,然后将结果转换成JSON数据响应给客户端
SpringMVC快速入门
环境准备相同步骤
-
Step1: 导入Spring坐标
-
导入Spring基础坐标:spring-context
-
导入Spring提供的监听器
ContextLoaderListener
的相关坐标:spring-web -
导入Spring集成Web环境相关坐标:servlet、jsp
-
导入Spring注解相关坐标:Annotation
-
导入与AOP相关的坐标:aop、aspectj
-
AOP坐标会在导入spring-context坐标后系统自动导入,如图所示
-
-
导入事务相关坐标:spring-tx
-
导入数据库相关坐标:mysql、数据源坐标(druid、cp30)
-
导入Spring集成JUnit相关坐标:junit、spring-test
-
导入Spring集成MyBatis相关坐标:mybatis、spring-jdbc、mybatis-spring
-
SpringMVC的相关坐标:spring-webmvc (注意:必须为必须为5.2.x.RELEASE版本)
<project xmlns="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/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.example</groupId><artifactId>SpringMvcDemo</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>MvcClaDemo</artifactId><packaging>war</packaging><name>MvcClaDemo Maven Webapp</name><url>http://maven.apache.org</url><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><!--===================Spring基础坐标=======================--><!--spring坐标--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.1.6</version></dependency><!--===================Spring自带监听器ContextLoaderListener所需坐标=======================--><!--spring-web--><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.2.25.RELEASE</version></dependency><!--===================Spring集成Web环境相关坐标=======================--><!-- servlet--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency><!--jsp--><dependency><groupId>javax.servlet.jsp</groupId><artifactId>javax.servlet.jsp-api</artifactId><version>2.3.3</version><scope>provided</scope></dependency><!--===================Spring注解相关坐标=======================--><!--Annotation坐标--><dependency><groupId>javax.annotation</groupId><artifactId>javax.annotation-api</artifactId><version>1.3.2</version></dependency><!--=====================Spring集成AOP相关坐标=========================--><!--aspectj坐标--><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.22.1</version></dependency><!--spring-tx坐标--><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>6.1.15</version></dependency><!--=====================数据库相关坐标=========================--><!--mysql坐标--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><!--druid坐标--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.18</version></dependency><!--c3p0坐标--><dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.5.5</version></dependency><!--===================Spring集成junit相关坐标=======================--><!--junit坐标--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency><!--spring-test坐标--><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>6.1.6</version><scope>test</scope></dependency><!--=====================MyBatis相关坐标=========================--><!--MyBatis坐标--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.16</version></dependency><!--mybatis-spring--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>3.0.3</version></dependency><!--spring-jdbc--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>6.1.10</version></dependency><!--===================SpringMVC基础坐标=======================--><!--spring-webmvc--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.25.RELEASE</version></dependency></dependencies><build><finalName>MvcClaDemo</finalName><plugins><!-- Tomcat插件 --><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</version></plugin></plugins></build> </project>
-
-
Step2: 右键源代码配置文件目录(即资源文件
resources
)→New
→File
,创建properties配置文件,博主文件名为jdbc.properties
,该配置文件代码如下-
注意: properties配置文件中配置的各个属性前必须添加个
id.
(即id.属性
,比如:属性url
就设置为id.url
,博主设置的为jdbc.url
),以供Spring配置文件可以使用属性占位符${}
语法引用这些属性#driverClassName代表数据库驱动,后跟驱动全类名(在MySQL驱动jar包下的META-INF下的services文件夹下的java.sql.Driver文件内) jdbc.driverClassName=com.mysql.cj.jdbc.Driver # 数据库连接URL jdbc.url=jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai # 数据库用户名 jdbc.username=root # 数据库密码 jdbc.password=123456 # 初始化连接数量---即容器中初始的数据库连接数量 jdbc.initialSize=5 # 最大活跃连接数量---容器中初始为5个,但若5个用完了,此时可以在申请5个数据库连接数量 #也就是说容器中最多存放10个数据库连接 jdbc.maxActive=10 # 获取连接时的最大等待时间,单位:毫秒。---与数据库进行连接时若超过3s仍未连接成功,则会报错 jdbc.maxWait=3000 #最小空闲连接数量---minIdle=5 # 配置检测连接是否有效的SQL,可以是一个查询语句,如果不指定则默认为"SELECT 1"---validationQuery=SELECT 1 # 是否开启自动提交事务---defaultAutoCommit=true
-
-
Step3: 在web项目核心目录(即
webapp
)下创建视图页面success.jsp,代码如下<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html><head><title>Title</title></head><body><h1>...Success Running...</h1></body> </html>
SpringMVC XML代码实现
需求:客户端发起请求,服务端接受请求,执行逻辑并进行视图跳转
-
步骤
- 导入SpringMVC的相关坐标
- 配置SpringMVC的核心前端控制器
DispathcerServlet
- 它拦截所有传入的请求,并将它们分发到适当的控制器
Controller
进行处理。 - 它可通过配置
web.xml
文件或Spring Boot的自动配置以注册DispatcherServlet
。
- 它拦截所有传入的请求,并将它们分发到适当的控制器
- 编写
web/Controller
表现层 的Controller控制器- 创建Controller类和视图页面
- 使用注解
@Controller
将Controller控制器配置到Spring容器中,并利用注解@RequestMapping("/xxx")
来给控制器中的业务方法设置地址请求映射 - 配置SpringMVC的核心文件
spring-mvc.xml
- 在该文件中配置
web/Controller
表现层 注解的组件扫描
- 在该文件中配置
- 在web.xml文件中配置SpringMVC的全局初始化参数
- 注意:该全局初始化参数是在配置SpringMVC的核心前端控制器的
<Servlet>
标签体内配置的,因为SpringMVC的全局初始化参数主要是该核心前端控制器DispatcherServlet
使用的
- 注意:该全局初始化参数是在配置SpringMVC的核心前端控制器的
- 执行访问测试(即客户端发起请求测试)
-
注意:
- SpringMVC快速入门之前要先把Spring相关代码及配置工作完成,具体步骤可详见Spring完整知识点汇总中的Spring集成Web环境→Spring配置文件的形式
- 此时不在需要
web/Controller
表现层 包下的继承Servlet接口的类,因为SpringMVC的本质就是对Servlet的简化处理
-
Step1: 创建业务层service包、持久层dao包、表现层controller包,代码分别如下
-
在dao包下创建
UserDao
接口,代码如下package at.guigu.dao;public interface UserDao {public void save(); }
-
在service包下创建
UserService
类,代码如下package at.guigu.service;import at.guigu.dao.UserDao;public class UserService {private UserDao userDao;public void setUserDao(UserDao bookDao) {this.userDao = bookDao;}public void save() {System.out.println("BookService save...");userDao.save();} }
-
在controller包下创建UserController类,代码如下
package at.guigu.controller;public class Usercontroller {public String save() {System.out.println("Usercontroller save...");//跳转到指定的视图页面return "success.jsp";} }
-
-
Step2: 使用
@RequestMapping
注解配置Controller控制器对应类中业务方法的映射地址,Usercontroller
代码更改如下package at.guigu.controller;import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;//将Usercontroller放到Spring容器中 @Controller public class Usercontroller {//设置请求地址映射@RequestMapping("/quick")public String save() {System.out.println("Usercontroller save...");return "success.jsp";} }
-
Step3: 右键源代码配置文件目录(即资源文件
resources
)→New
→XML Configuration File
→Spring Config
,文件名为spring-mvc.xml
,然后配置Spring以及SpringMVC的核心文件applicationContext.xml
、spring-mvc.xml
,代码如下-
Step3-1: Spring的核心配置文件代码如下
- 使用
context
命名空间加载jdbc.properties
文件(前提:需引入context
命名空间和约束路径)context
命名空间:xmlns:context="http://www.springframework.org/schema/context"
context
约束路径:http://www.springframework.org/schema/context
、http://www.springframework.org/schema/context/spring-context.xsd
- 配置数据源对应的bean
- 配置MyBatis的SqlSessionFactory
- 配置数据源
- 配置MyBatis核心配置文件(注意:若有的配置必须通过MyBatis核心配置文件配置时,则需要该步)
- 配置别名
- 引入dao包下所有接口对应的SQL映射文件
- 此时Spring会进行持久层扫描,自动生成该层中对应接口的bean
<?xml version="1.0" encoding="UTF-8"?> <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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--使用`context`命名空间加载 `properties` 文件--><context:property-placeholder location="classpath:jdbc.properties"/><!--Druid对应的bean--><bean id="dataSourceDruid" class="com.alibaba.druid.pool.DruidDataSource"><!--使用属性占位符`${}`语法引用properties文件中的属性--><property name="driverClassName" value="${jdbc.driverClassName}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean><!--配置MyBatis的SqlSessionFactory--><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><!--配置数据源--><property name="dataSource" ref="dataSourceDruid"/><!--加载MyBatis的核心配置文件<property name="configLocation" value="classpath:mybatis-config.xml"/>--><!--配置别名--><property name="typeAliasesPackage" value="at.guigu.pojo"/></bean><!--引入dao包下所有接口对应的SQL映射文件即MyBatis 持久层扫描,会自动生成该层中对应接口的bean--><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="at.guigu.dao"/></bean><!--配置bookService bean--><bean id="bookService" class="at.guigu.service.UserService"><!--绑定依赖关系--><property name="userDao" ref="userDao"></property></bean></beans>
- 使用
-
Step3-2: SpringMVC的核心配置文件代码如下
-
配置注解的组件扫描 需要在SpringMVC的配置文件中引入context和mvc的命名空间、约束路径;然后使用context命名空间配置组件扫描即可。
- 命名空间:
xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc"
- 约束路径
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
- 配置组件扫描代码:
<context:component-scan base-package="at.guigu.controller"></context:component-scan>
base-package
:给定一个包,然后会自动扫描该包下的所有内容,以便可以识别使用注解配置的类、字段和方法
- 注意:
- 其它三层架构包的注解的组件扫描在Spring的配置文件中配置
- 引入mvc的命名空间和约束路径是为了配置mvc的注解驱动,其作用可详见 SpringMVC回写数据——返回对象或集合 部分的内容
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><!--mvc的注解驱动--><mvc:annotation-driven/><!--配置Controller层的注解的组件扫描--><context:component-scan base-package="at.guigu.controller"></context:component-scan><!--等同于<context:component-scan base-package="at.guigu">type指定要扫描的内容为注解,expression指定要扫描的对应注解的全限定名只扫描at.guigu包下有@Controller注解的类<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan> --> </beans>
-
-
-
Step4: 在web项目核心目录(即
webapp
)下的web.xml中进行全局配置。web.xml完整代码如下- 配置Spring相关的配置
- Spring的全局初始化参数、配置Spring所提供的
ContextLoaderListener
监听器、web配置
- Spring的全局初始化参数、配置Spring所提供的
- 配置SpringMVC的核心前端控制器
DispathcerServlet
- 配置SpringMVC的全局初始化参数,该全局初始化参数用于定义SpringMVC的配置文件供监听器使用
<!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd" ><web-app><display-name>Archetype Created Web Application</display-name><!--配置Spring的全局初始化参数--><context-param><!--定义参数的名称,必须是唯一的--><param-name>contextConfigLocation</param-name><!--定义参数的值--><param-value>classpath:applicationContext.xml</param-value></context-param><!--监听器--><!--配置Spring所提供的`ContextLoaderListener` 监听器--><listener><!--监听器类的全限定名--><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!--声明Servlet--><!--配置SpringMVC的前端控制器的Servlet--><servlet><servlet-name>DispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--配置SpringMVC的全局初始化参数--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-mvc.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><!--将URL模式映射到特定的Servlet上(即DispatcherServlet)--><servlet-mapping><!--指定的Servlet的类名--><servlet-name>DispatcherServlet</servlet-name><!--给指定的Servlet设置url,相当于@WebServlet("/")--><!--代表将所有请求都交给前端控制器处理--><url-pattern>/</url-pattern></servlet-mapping></web-app>
- 配置Spring相关的配置
-
客户端发起请求测试:Tomcat运行该Web项目后输入地址映射的url后会自动跳转到
success.jsp
页面 -
完整包结构如下
SpringMVC注解代码实现
-
Step1: 创建业务层service包、持久层dao包、表现层controller包,代码分别如下
-
在dao包下创建
UserDao
接口,代码如下:package at.guigu.dao; import org.apache.ibatis.annotations.Mapper;@Mapper public interface UserDao {public void save(); }
@Mapper
注解作用: 用于标记单个Mapper接口,让MyBatis生成它的实现类并注入到Spring容器中。也就是说此时不需要创建持久层的实现类,有IOC容器自动创建,其唯一标识id为对应接口名首字母大写(即userDao
)该注解也可以使用
@MapperScan(at.guigu.dao)
来代替,不过该注解需写在Spring的核心配置文件中,表示: 用于扫描指定包中的所有接口,将它们自动注册为Spring的Bean并作为Mapper以上两个注解在做项目时可根据实际情况选择
由于它们需要让MyBatis生成它的实现类并注入到Spring容器中,所以必须要有MyBatis的核心配置类,否则不会生效
-
在service包下创建
UserService
类,代码如下:package at.guigu.service;import at.guigu.dao.UserDao; import org.springframework.stereotype.Service;@Service("userService") public class UserService {private UserDao userDao;public void setUserDao(UserDao bookDao) {this.userDao = bookDao;}public void save() {System.out.println("BookService save...");userDao.save();} }
-
在controller包下创建
UserController
类,代码如下:package at.guigu.controller;import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;// 将Usercontroller放到Spring容器中 @Controller public class Usercontroller {// 设置请求地址映射@RequestMapping("/quick")public String save() {System.out.println("Usercontroller save...");// 跳转到指定的视图页面return "success.jsp";} }
-
-
Step2: 创建一个与三层架构包同级的
config
包,并在该包下创建拆分配置文件对应的数据源拆分类DataSourceConfiguration
,代码如下(以Druid为例)- Step2-1: 创建数据源bean
package at.guigu.config;import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.PropertySource; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager;import javax.sql.DataSource;// 分配置文件对应的类不用配置@Configuration以及@ComponentScan注解 // 加载properties配置文件<context:property-placeholder location="classpath:jdbc.properties"/> @PropertySource("classpath:jdbc.properties") public class DataSourceConfiguration {@Value("${jdbc.driverClassName}")private String driverClassName;@Value("${jdbc.url}")private String url;@Value("${jdbc.username}")private String username;@Value("${jdbc.password}")private String password;/*** Druid对应的bean* Spring会将当前方法的返回值以指定的id存储到Spring的IOC容器中* @return* @throws Exception*/@Bean("dataSourceDruid")public DataSource getDruidDataSource() throws Exception{// 创建数据源对象DruidDataSource dataSource = new DruidDataSource();// 设置数据源基本连接数据dataSource.setDriverClassName(driverClassName);dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);return dataSource;} }
-
Step3: 在config包下创建MyBatis的核心配置类
MyBatisConfiguration
,代码如下package at.guigu.config;import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.context.annotation.Bean;import javax.sql.DataSource;public class MyBatisConfiguration {@Beanpublic SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();// 相当于设置别名<package name="at.guigu.pojo"/>sqlSessionFactoryBean.setTypeAliasesPackage("at.guigu.pojo");// 相当于配置数据库连接信息sqlSessionFactoryBean.setDataSource(dataSource);return sqlSessionFactoryBean;}// 映射扫描配置类,相当于引入dao包下所有接口对应的SQL映射文件<package name="at.guigu.dao"/>@Beanpublic MapperScannerConfigurer mapperScannerConfigurer() {MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();mapperScannerConfigurer.setBasePackage("at.guigu.dao");return mapperScannerConfigurer;} }
-
Step4: 在config包下创建Spring主配置文件对应的主类
SpringConfiguration
,引入分配置文件对应的拆分类DataSourceConfiguration
以及MyBatisConfiguration
,代码如下:package at.guigu.config;import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import;// 该注解代表该类是Spring的核心配置类 @Configuration // 配置注解的组件扫描<context:component-scan base-package="at.guigu"></context:component-scan> @ComponentScan("at.guigu") @MapperScan("at.guigu.dao") // 引入拆分配置文件<import resource="applicationContext-xxx.xml"/> @Import({DataSourceConfiguration.class, MyBatisConfiguration.class}) public class SpringConfiguration { }
-
注意: 由于在配置注解的组件扫描时属性值为
at.gui
,所以此时Spring会扫描包括controller包下的注解,为避免该情况,则有两种解决方式-
将Spring加载的bean设定扫描范围为精准范围,比如:
@ComponentScan(basePackages = {"at.guigu.dao", "at.guigu.service"})
-
将Spring加载的bean设定扫描范围为
at.gui
后排除掉controller包内的bean,该注解改为如下形式@ComponentScan(value = "at.guigu", excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class))
-
-
改进后的Spring核心配置类代码如下
package at.guigu.config;import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.context.annotation.Import; import org.springframework.stereotype.Controller;// 该注解代表该类是Spring的核心配置类 @Configuration // 配置注解的组件扫描<context:component-scan base-package="at.guigu.dao, at.guigu.service"></context:component-scan> @ComponentScan(value = "at.guigu",excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class))@MapperScan("at.guigu.dao") // 引入拆分配置文件<import resource="applicationContext-xxx.xml"/> @Import({DataSourceConfiguration.class, MyBatisConfiguration.class}) public class SpringConfiguration { }
-
-
Step5: 在config包下创建SpringMVC核心配置类
SpringMvcConfiguration
,代码如下:package at.guigu.config;import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration;// 该注解代表该类是SpringMVC的核心配置类 @Configuration // 配置注解的组件扫描<context:component-scan base-package="at.guigu.controller"></context:component-scan> // 加载controller对应的bean @ComponentScan("at.guigu.controller") // 自动配置SpringMVC的各种配置 @EnableWebMvc public class SpringMvcConfiguration { }
-
Step6: 在web项目核心目录(即
webapp
)下的web.xml中进行全局配置。web.xml完整代码如下- 配置Spring相关的配置
- Spring的全局初始化参数、配置Spring所提供的
ContextLoaderListener
监听器、web配置
- Spring的全局初始化参数、配置Spring所提供的
- 配置SpringMVC的核心前端控制器
DispathcerServlet
- 配置SpringMVC的全局初始化参数,该全局初始化参数用于定义SpringMVC的配置类供监听器使用
<!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd" ><web-app><display-name>Archetype Created Web Application</display-name><!--配置Spring配置类的全局初始化参数--><context-param><param-name>contextClass</param-name><param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value></context-param><context-param><!--定义参数的名称,必须是唯一的--><param-name>contextConfigLocation</param-name><!--定义参数的值--><param-value>at.guigu.config.SpringConfiguration</param-value></context-param><!--监听器--><!--配置Spring所提供的`ContextLoaderListener` 监听器--><listener><!--监听器类的全限定名--><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!--配置SpringMVC的前端控制器的Servlet--><servlet><servlet-name>DispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 配置 Spring MVC 的核心配置类 --><init-param><param-name>contextClass</param-name><param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value></init-param><init-param><param-name>contextConfigLocation</param-name><!--写入SpringMVC核心配置类的全限定名--><param-value>at.guigu.config.SpringMvcConfiguration</param-value></init-param><load-on-startup>1</load-on-startup></servlet><!--将URL模式映射到特定的Servlet上(即DispatcherServlet)--><servlet-mapping><!--指定的Servlet的类名--><servlet-name>DispatcherServlet</servlet-name><!--给指定的Servlet设置url,相当于@WebServlet("/")--><url-pattern>/</url-pattern></servlet-mapping> </web-app>
- 配置Spring相关的配置
-
客户端发起请求测试:Tomcat运行该Web项目后输入地址映射的url后会自动跳转到
success.jsp
页面 -
完整包结构如下
替代web.xml文件方式一
AbstractDispatcherServletInitializer 类中的抽象方法 | 解释 |
---|---|
WebApplicationContext createServletApplicationContext() | 创建Servlet容器时来加载SpringMVC对应的bean并放入WebApplicationContext 对象范围中(作用范围为ServletContext范围,即整个web容器),即加载SpringMVC的配置 |
String[] getServletMappings() | 设置SpringMVC对应的请求映射路径,当为/ 时表示拦截所有请求,此时任意请求都将转入到SpringMVC中进行处理 |
AbstractDispatcherServletInitializer 父类AbstractContextLoaderInitializer 中的抽象方法 | 解释 |
WebApplicationContext createRootApplicationContext() | 用于加载非SpringMVC对应的bean,比如加载Spring配置。其使用方法与createServletApplicationContext() 相同 |
- 为实现完全注解形式,可创建一个继承
AbstractDispatcherServletInitializer
类的子类ServletContainerInitConfiguration
来替代web.xml文件,从而实现全注解形式的开发
快速入门
此处只进行web.xml配置文件对应的配置类的编写,其它步骤可详见SpringMVC注解代码实现
-
Step1: 在config包下创建web.xml配置文件对应的配置类,即继承
AbstractDispatcherServletInitializer
类的子类ServletContainerInitConfiguration
,并重写其中的三个方法原始代码如下:package at.guigu.config;import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;// 定义一个Servlet容器启动的配置类,来加载Spring的配置 public class ServletContainerInitConfiguration extends AbstractDispatcherServletInitializer {// 加载SpringMVC的配置@Overrideprotected WebApplicationContext createServletApplicationContext() {return null;}// 设置哪些请求归SpringMVC处理@Overrideprotected String[] getServletMappings() {return new String[0];}// 加载非SringMVC的配置,比如:加载Spring的配置@Overrideprotected WebApplicationContext createRootApplicationContext() {return null;} }
-
Step2: 在
createServletApplicationContext()
方法中加载SpringMVC配置,并在getServletMappings()
方法中设置SpringMVC对应的请求映射路径,代码如下:package at.guigu.config;import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;// 定义一个Servlet容器启动的配置类,来加载Spring的配置 public class ServletContainerInitConfiguration extends AbstractDispatcherServletInitializer {// 加载SpringMVC的配置@Overrideprotected WebApplicationContext createServletApplicationContext() {AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();context.register(ServletContainerInitConfiguration.class);return context;}// 设置哪些请求归SpringMVC处理@Overrideprotected String[] getServletMappings() {// 代表将所有请求都交给前端控制器处理return new String[]{"/"};}// 加载非SringMVC的配置,比如:加载Spring的配置@Overrideprotected WebApplicationContext createRootApplicationContext() {return null;} }
-
Step3: 在
createRootApplicationContext()
方法中加载Spring配置,代码如下:package at.guigu.config;import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;// 定义一个Servlet容器启动的配置类,来加载Spring的配置 public class ServletContainerInitConfiguration extends AbstractDispatcherServletInitializer {// 加载SpringMVC的配置@Overrideprotected WebApplicationContext createServletApplicationContext() {AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();context.register(SpringMvcConfiguration.class);return context;}// 设置哪些请求归SpringMVC处理@Overrideprotected String[] getServletMappings() {// 代表将所有请求都交给前端控制器处理return new String[]{"/"};}// 加载非SringMVC的配置,比如:加载Spring的配置@Overrideprotected WebApplicationContext createRootApplicationContext() {AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();context.register(SpringConfiguration.class);return context;} }
-
Step5: 删除web.xml文件
运行截图如下
完整包结构如下
替代web.xml文件方式二
AbstractAnnotationConfigDispatcherServletInitializer 类中的抽象方法 | 解释 |
---|---|
Class<?>[] getServletConfigClasses() | 加载SpringMVC的配置 |
Class<?>[] getRootConfigClasses() | 加载非SpringMVC对应的bean,比如加载Spring配置 |
AbstractAnnotationConfigDispatcherServletInitializer 父类AbstractDispatcherServletInitializer 中的抽象方法 | 解释 |
String[] getServletMappings() | 设置SpringMVC对应的请求映射路径,当为/ 时表示拦截所有请求,此时任意请求都将转入到SpringMVC中进行处理 |
快速入门
此处只进行web.xml配置文件对应的配置类的编写,其它步骤可详见SpringMVC注解代码实现
-
Step1: 在config包下创建web.xml配置文件对应的配置类,即继承
AbstractAnnotationConfigDispatcherServletInitializer
类的子类ServletContainerInitConfiguration
,并重写其中的三个方法,代码如下:package at.guigu.config;import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;// 定义一个Servlet容器启动的配置类,来加载Spring的配置 public class ServletContainerInitConfiguration extends AbstractAnnotationConfigDispatcherServletInitializer {// 加载SpringMVC的配置@Overrideprotected Class<?>[] getServletConfigClasses() {return new Class[]{SpringMvcConfiguration.class};}// 设置哪些请求归SpringMVC处理@Overrideprotected String[] getServletMappings() {return new String[]{"/"};}// 加载非SringMVC的配置,比如:加载Spring的配置@Overrideprotected Class<?>[] getRootConfigClasses() {return new Class[]{SpringConfiguration.class};} }
-
Step2: 删除web.xml文件
运行截图如下
完整包结构如下
SpringMVC的执行流程
-
执行流程图解释
- 用户发送请求到前端控制器DispatcherServlet
- 前端控制器DispatcherServlet收到请求后调用处理器映射器HandlerMapping
- 处理器映射器HandlerMapping找到具体的处理器(可通过xml配置、注解进行查找)后会生成处理器对象以及处理器拦截器,然后将其返回给前端控制器DispatcherServlet
- 前端控制器DispatcherServlet收到后将会调用处理器适配器Handler Adapter
- 处理器适配器HandlerAdapter经过适配会调用具体的==处理器Controller(即控制器,也叫作后端控制器)==来处理
- 处理器Controller(即控制器,也叫作后端控制器)执行完成后会返回ModelAndView(即模型和视图)
- 处理器适配器HandlerAdapter会将处理器Controller(即控制器,也叫作后端控制器)返回的ModelAndView(即模型和视图)返回给前端控制器DispatcherServlet
- 前端控制器DispatcherServlet会将ModelAndView(即模型和视图)传给视图解析器View Resolver
- 视图解析器ViewResolver解析后会返回给前端控制器DispatcherServlet具体的视图View
- 前端控制器DispatcherServlet会根据模型Model来渲染视图View(即将模型数据填充到视图中)
- 最终由前端控制器DispatcherServlet将完整的响应页面响应给用户
即:首先,会通过核心前端控制器DispatcherServlet获取到所有客户端发送的Http请求,然后通过处理器映射器HandlerMappingjia那个请求分别发送给对应的控制器进行处理,处理完后会返回一个ModelAndView对象,包含模型数据和视图。然后前端控制器DispatcherServlet会通过视图解析器将视图解析为实际的视图对象,然后将模型数据填充到视图中进行渲染,并将结果返回给客户端。
SpringMVC解析
SpringMVC组件解析
-
DispatcherServlet(前端控制器)
-
SpringMVC的核心组件,充当前端控制器(Front Controller)。
它拦截所有传入的请求,并将它们分发到适当的控制器进行处理。
配置
web.xml
文件或Spring Boot的自动配置以注册DispatcherServlet
。
-
-
Controller(处理器、控制器、后端控制器)
- 用于处理用户请求,并返回相应的模型和视图。
- 通过注解(如
@Controller
和@RequestMapping
)定义 @RequestMapping
用于映射URL到控制器的方法。
@Controller public class MyController {@RequestMapping("/hello")public String sayHello(Model model) {model.addAttribute("message", "Hello, SpringMVC!");return "hello"; // 返回视图名称} }
-
Model(模型)
- 用于存储数据和业务逻辑。
- 控制器将数据添加到模型中,然后传递给视图进行展示
-
View(视图):
- 负责显示模型中的数据。
- 常见的视图技术包括JSP、Thymeleaf、Freemarker等。
- 视图解析器(View Resolver)用于解析视图名称并渲染最终的视图。
-
View Resolver(视图解析器):
- 负责将控制器返回的视图名称解析为实际的视图对象。
- 可以配置不同的视图解析器,如
InternalResourceViewResolver
(用于JSP)、ThymeleafViewResolver
(用于Thymeleaf)等。
// @Bean使用在方法上,将方法的返回值存储到容器中 @Bean public InternalResourceViewResolver viewResolver() {InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix("/WEB-INF/views/");resolver.setSuffix(".jsp");return resolver; }
-
Handler Mapping(处理器映射器):
- 负责将传入的请求映射到对应的控制器。
- Spring提供了多种处理器映射,如
BeanNameUrlHandlerMapping
、RequestMappingHandlerMapping
等。
-
Handler Adapter(处理器适配器):
- 负责调用控制器中的方法。
- 不同类型的控制器需要不同的处理器适配器,如
HttpRequestHandlerAdapter
、SimpleControllerHandlerAdapter
等
-
Exception Handling(异常处理):
- 通过
@ExceptionHandler
注解处理控制器中的异常。 - 还可以配置全局异常处理器,如
@ControllerAdvice
。
@ControllerAdvice public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)public ModelAndView handleException(Exception ex) {ModelAndView model = new ModelAndView("error");model.addObject("message", ex.getMessage());return model;} }
- 通过
- 通过以上组件的协同工作,SpringMVC可以高效地处理Web请求,并实现清晰的代码分离,使得Web应用程序更加模块化和易于维护。
SpringMVC注解解析
注解 | 解释 |
---|---|
@RequestMapping | 用于建立请求URL和处理请求方法之间的对应关系。使用在类上: 请求URL的第一级访问目录。此处不写的话就相当于应用的根目录;使用在方法上: 请求URL的第二级访问目录,与类上使用该注解标注的一级目录一起构成虚拟路径 |
@EnableWebMvc | 用于启用 Spring MVC 的一系列配置功能的核心注解。它通常与 Java 配置类结合使用,来自动配置 Spring MVC 的各种特性 。 |
@ResponseBody | 设置当前控制器方法相应内容为当前返回值,无需解析。可详见SpringMVC回写数据部分内容 |
@RequestParam(value, required, defaultValue) | 用于 获取请求参数 的注解 |
@RequestBody | 将 HTTP 请求的 请求体(body)中包含的数据传递给请求参数,比如:JSON数据、XML、表单数据等 |
@DateTimeFormat(pattern) | 设置日期时间的数据格式,patter 为要设置的日期时间格式的字符串。可详见获取日期类型的代码示例 |
@PathVatiable | 用于Rest风格,绑定路劲参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应。可详见Rest风格部分示例 |
@RestController | 设置当前控制器类为Restful风格,等同于@Controller +@ResponseBody |
@GetMapping(value) | 设置当前控制器方法Get请求访问路径以及Restful风格的动作,等同于@RequestMapping(value, method=RequestMethod.Get) |
@PostMapping(value) | 设置当前控制器方法Post请求访问路径以及Restful风格的动作,等同于@RequestMapping(value, method=RequestMethod.Post) |
@PutMapping(value) | 设置当前控制器方法Put请求访问路径以及Restful风格的动作,等同于@RequestMapping(value, method=RequestMethod.Put) |
@DeleteMapping(value) | 设置当前控制器方法Delete请求访问路径以及Restful风格的动作,等同于@RequestMapping(value, method=RequestMethod.Delete) |
@RequestMapping 属性 | 解释 |
---|---|
value | 用于指定请求的URL。与path属性的作用一样 |
method | 用于指定请求的方式,默认为get请求方式 |
params | 用于指定限制请求参数的条件。它支持简单的表达式,要求请求参数的key和value必须与配置的一模一样 |
@EnableWebMvc
可用来自动配置 Spring MVC 的各种特性 ,比如- 类型转换器
- 它可根据类型自动匹配对应的类型转换器,比如时间格式的转换,可详见获取日期类型的代码示例
- 异常处理
- 视图解析器
- 默认的视图解析器会查找
/WEB-INF/views/
下的 JSP 文件
- 默认的视图解析器会查找
- 静态资源处理
- 验证支持
- Spring表单标签支持
- 参数解析和绑定
- 跨域支持
- SpringMVC拦截器支持
- 资源绑定支持
- mvc的注解驱动
<mvc:annotation-driven/>
- 可代替配置处理器适配器
- 类型转换器
@RequestParam
与@RequestBody
的区别- 区别
@RequestParam
用于接收url地址传参,表单传参
@RequestBody
用于接收json数据 - 应用
后期开发中,发送json格式数据为主,@RequestBody
应用较广
如果发送非json格式数据,选用@RequestParam
接收请求参数
- 区别
@RequestMapping
-
@RequestMapping
-
在快速入门中该注解应用在方法上,并未应用在类上,所以URL为:
http://localhost:8080/quick
, -
若该注解既应用在类上也应用在方法上则URL为:
http://localhost:8080/xxx/quick
,代码如下所示- 当加在类上时,其参数值一般按照不同的功能模块进行分类书写,如下代码所示由于是User模块,所以设置为
@RequestMapping("user")
,URL此时即为http://localhost:8080/user/quick
package at.guigu.controller;import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;//将Usercontroller放到Spring容器中 @Controller @RequestMapping("/user") public class Usercontroller {//设置请求地址映射@RequestMapping("/quick")public String save() {System.out.println("Usercontroller save...");return "success.jsp";} }
- 当加在类上时,其参数值一般按照不同的功能模块进行分类书写,如下代码所示由于是User模块,所以设置为
-
-
@RequestMapping
与返回值的关系-
当
@RequestMapping
只应用在类或方法上- 返回值为
return "success.jsp"
:此时系统会自动在Web项目核心目录(即webapp)下找success.jsp
文件 - 返回值为
return "/success.jsp"
:系统会自动在Web项目核心目录(即webapp)下找success.jsp
文件 - 返回值为
return "/jsp/success.jsp"
:系统会自动在Web项目核心目录(即webapp)下的jsp目录下找success.jsp
文件
- 返回值为
-
当
@RequestMapping
同时应用在类和方法上-
返回值为
return "success.jsp"
:此时系统会自动在Web项目核心目录(即webapp)下的user目录下找success.jsp
文件- 若想让其直接在Web项目核心目录(即webapp)下找
success.jsp
文件则将返回值改为:return "/success.jsp"
- 若想让其直接在Web项目核心目录(即webapp)下找
-
返回值为
return "/success.jsp"
:系统会自动在Web项目核心目录(即webapp)下找success.jsp
文件 -
返回值为
return "/jsp/success.jsp"
:系统会自动在Web项目核心目录(即webapp)下的jsp目录下找success.jsp
文件
-
-
注意: 当配置了内部资源视图解析器后,此时
return "success"
返回的success.jsp
文件的地址与@RequestMapping
应用在哪里无关,只与内部资源视图解析器中配置的地址有关,以如下代码为例:此时只会去找webapp目录下的jsp目录下的success.jsp
文件// 配置视图解析器 @Bean public InternalResourceViewResolver viewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/jsp/"); // 设置视图文件路径前缀 resolver.setSuffix(".jsp"); // 设置视图文件后缀 return resolver; }
-
-
value
:用于指定请求的URL- 当
@RequestMapping
注解有多个属性时,该属性名称不可省略,如:@RequestMapping(value="/xxx", method=RequestMethod.GET)
- 当
@RequestMapping
注解只有这一个属性时,该属性名称可省略,如:@RequestMapping("/xxx")
- 当
-
method
:用于指定请求的方式。常用于Rest风格-
该属性值利用枚举类
RequestMethod
来调用,如图所示
-
-
params
:用于指定限制请求参数的条件-
它支持简单的表达式,要求请求参数的key和value必须与配置的一模一样
-
params={"accountName"}
:此时客户端的请求参数中必须有accountName -
params={"money!100"}
:此时客户端的请求参数必须有money
,且该参数值不能为100 -
代码示例如下
package at.guigu.controller;import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod;//将Usercontroller放到Spring容器中 @Controller @RequestMapping("/user") public class Usercontroller {//设置请求地址映射并限定请求参数的条件@RequestMapping(value = "/quick", params = {"username"})public String save() {System.out.println("Usercontroller save...");return "success.jsp";} }
Tomcat运行该Web项目后若不加限定的请求参数则会报错,如图一所示,加上后才会成功运行,如图二所示
-
SpringMVC 配置文件形式
SpringMVC 配置文件形式的组件扫描
-
在SpringMVC的核心文件
spring-mvc.xml
中配置组件扫描的步骤如下-
mvc命名空间引入
-
引入mvc命名空间:
xmlns:mvc="http://www.springframework.org/schema/mvc"
-
引入mvc的约束路径:
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/context/spring-mvc.xsd
-
-
context命名空间引入
-
引入context命名空间:
xmlns:context="http://www.springframework.org/schema/context"
-
引入context的约束路径:
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
-
-
配置组件扫描代码:
<context:component-scan base-package="at.guigu.controller"></context:component-scan>
-
SpringMVC是基于Spring容器的,所以在进行SpringMVC操作时就要利用
@Controller
注解将Controller存储到Spring容器中,若要使用@Controller
注解标注的话就需要用组件扫描代码进行组件扫描 -
配置组件扫描的代码有两个书写方法
<!--配置Controller层的注解的组件扫描,方法一--> <context:component-scan base-package="at.guigu.controller"></context:component-scan>
<!--配置Controller层的注解的组件扫描,方法二--> <context:component-scan base-package="at.guigu"><!--type指定要扫描的内容为注解,expression指定要扫描的对应注解@Controller的全限定名--><!--只扫描at.guigu包下有@Controller注解的类--><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
-
-
-
注意
- Spring和SpringMVC注解的组件扫描:要各自扫描各自的模块,互不干扰。所以在配置注解的组件扫描时:
- 若是Spring的:就在Spring的核心配置文件中进行注解的组件扫描
- 若是SpringMVC的:就在SpringMVC的核心配置文件中进行注解的组件扫描
- Spring和SpringMVC注解的组件扫描:要各自扫描各自的模块,互不干扰。所以在配置注解的组件扫描时:
SpringMVC配置文件形式的核心配置文件spring-mvc.xml解析
-
注意
-
SpringMVC有默认组件配置,默认组件都是在
DispatherServlet.properties
配置文件中配置的,该配置文件在External Libraries
下,如图所示
-
-
配置Controller层的注解的组件扫描
-
方式一:
<context:component-scan base-package="at.guigu.controller"></context:component-scan>
-
方式二:
<context:component-scan base-package="at.guigu"><!--type指定要扫描的内容为注解,expression指定要扫描的对应注解的全限定名--><!--只扫描at.guigu包下有@Controller注解的类--><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
-
注意:配置Controller层的注解的组件扫描时需要引入命名空间,可详见SpringMVC组件扫描
-
-
额外知识点
Controller包下Usercontroller代码如下
package at.guigu.controller;import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;//将Usercontroller放到Spring容器中 @Controller @RequestMapping("/user") public class Usercontroller {//设置请求地址映射@RequestMapping("/quick")public String save() {System.out.println("Usercontroller save...");return "/success.jsp";} }
-
Tomcat运行该Web项目后,运行截图如下,从截图中可看出我们输入完URL回车后显示了success.jsp页面的代码,在此过程中URL并没有改变。说明
return "/success.jsp"
默认使用的是 请求转发 的技术(可详见Web&Http&Servlet&Request&Response
)- 所以
return "/success.jsp"
相当于return "forward:/success.jsp"
- 所以
-
若我们将
return "/success.jsp"
改为return "redirect:/success.jsp"
,则此时运行Web项目后截图如下- 从截图中可知此时就变成了使用 重定向 技术(可详见
Web&Http&Servlet&Request&Response
)
- 从截图中可知此时就变成了使用 重定向 技术(可详见
-
-
配置内部资源视图解析器
InternalResourceViewResolver
-
当返回值为
return "/jsp/success.jsp"
时:系统会自动在Web项目核心目录(即webapp)下的jsp目录下找success.jsp
文件- 我们可以在SpringMVC的核心配置文件中配置内部资源视图解析器来将以上返回值简化为
return "success"
- 我们可以在SpringMVC的核心配置文件中配置内部资源视图解析器来将以上返回值简化为
-
配置步骤如下
<!--配置内部资源视图解析器--> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--将InternalResourceViewResolver类中的视图名称前缀属性prefix的值设为/jsp/--><property name="prefix" value="/jsp/"></property><!--将InternalResourceViewResolver类中的视图名称后缀属性suffix的值设为.jsp--><property name="suffix" value=".jsp"></property> </bean>
-
配置完成后,Tomcat运行该Web项目输入URL后,系统会将返回值
return "success"
中的success拿出来,然后自动与/jsp/
以及.jsp
进行拼接,拼接为/jsp/success.jsp
即return /jsp/success.jsp
。然后系统会自动在Web项目核心目录(即webapp)下的jsp目录下找success.jsp
文件,并将该jsp文件显示在客户端页面上,配置代码截图如下
-
SpringMVC注解形式
SpringMVC注解形式的组件扫描
-
在SpringMVC的核心类
SpringMvcConfiguration
中利用@ComponentScan
注解来配置组件扫描,如下代码所示package at.guigu.config;import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc;// 该注解代表该类是SpringMVC的核心配置类 @Configuration // 配置注解的组件扫描<context:component-scan base-package="at.guigu.controller"></context:component-scan> // 加载controller对应的bean @ComponentScan("at.guigu.controller") @EnableWebMvc public class SpringMvcConfiguration { }
-
需要注意的是在配置Spring核心配置类中的注解组件扫描时
@ComponentScan
属性值为at.gui
,所以此时Spring会扫描包括controller包下的注解,为避免该情况,则有两种解决方式-
将Spring加载的bean设定扫描范围为精准范围,比如:
@ComponentScan(basePackages = {"at.guigu.dao", "at.gui.service"})
-
将Spring加载的bean设定扫描范围为
at.gui
后排除掉controller包内的bean,该注解改为如下形式@ComponentScan(value = "at.guigu", excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class))
-
SpringMVC注解形式的核心配置类解析
SpringMVC有默认组件配置,默认组件都是在DispatherServlet.properties
配置文件中配置的,该配置文件在External Libraries
下,如图所示
-
在入门案例中使用了
@EnableWebMvc
注解来自动配置 SpringMVC 的各种特性,若想要修改则可以在SpringMVC的核心配置类中利用@Bean
注解来配置一个返回值为相应类的对象,此处以配置内部资源视图解析器为例 -
配置内部资源视图解析器
InternalResourceViewResolver
-
当返回值为
return "/jsp/success.jsp"
时:系统会自动在Web项目核心目录(即webapp)下的jsp目录下找success.jsp
文件- 我们可以在SpringMVC的核心配置文件中配置内部资源视图解析器来将以上返回值简化为
return "success"
- 我们可以在SpringMVC的核心配置文件中配置内部资源视图解析器来将以上返回值简化为
-
解决方式:在SpringMVC的核心配置类中配置内部资源视图解析器,代码如下
package at.guigu.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.view.InternalResourceViewResolver;// 该注解代表该类是SpringMVC的核心配置类 @Configuration // 配置注解的组件扫描<context:component-scan base-package="at.guigu.controller"></context:component-scan> // 加载controller对应的bean @ComponentScan("at.guigu.controller") // 自动配置 Spring MVC 的各种特性 @EnableWebMvc public class SpringMvcConfiguration {// 配置视图解析器@Beanpublic InternalResourceViewResolver viewResolver() {InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix("/jsp/"); // 设置视图文件路径前缀resolver.setSuffix(".jsp"); // 设置视图文件后缀return resolver;} }
-
SpringMVC数据响应
该部分示例项目
MvcRespXmlDemo
及MvcRespClaDemo
已上传至Gitee,可自行下载
- SpringMVC的数据响应方式
- 方式一:页面跳转
- 直接返回字符串
- 通过ModelAndView对象返回
- 方式二:回写数据
- 直接返回字符串
- 返回对象或集合
- 方式一:页面跳转
- 环境准备等工作可详见快速入门
SpringMVC页面跳转
SpringMVC页面跳转——直接返回字符串
- 在我们之前的示例中均是直接返回字符串的形式,比如
return "success.jsp"
return "/success.jsp"
return "/jsp/success.jsp"
- 此处不在对直接返回字符出串的形式做详细解释
- 注意:
- 若我们配置了内部资源视图解析器,此时我们直接返回的字符串会与视图解析器的前后缀拼接到一起后跳转(可详见SpringMVC的核心配置文件解析)
- 在一下示例中均默认已配置内部资源视图解析器,来完成示例操作
SpringMVC页面跳转——通过ModelAndView对象返回
-
通过ModelAndView对象返回有四种方式,代码示例如下
-
controller
包下的UserController类代码如下package at.guigu.controller;import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;//将Usercontroller放到Spring容器中 @Controller @RequestMapping("/user") public class Usercontroller {/*** SpringMVC页面跳转——直接返回字符串* @return*/@RequestMapping(value = "/quick1")public String save1() {System.out.println("Usercontroller save...");return "success";// 等同于return "/user/success.jsp";}/*** SpringMVC页面跳转——返回ModelAndView对象 方式一* @return*/@RequestMapping("/quick2")public ModelAndView save2() {/*Model:模型 用来封装数据View:视图 用来展示数据*/ModelAndView mv = new ModelAndView();// 设置模型数据mv.addObject("username", "zhangsan");// 设置视图名称mv.setViewName("success");return mv;}/*** SpringMVC页面跳转——返回ModelAndView对象 方式二* @return*/@RequestMapping("/quick3")public ModelAndView save3(ModelAndView mv) {/*Model:模型 用来封装数据View:视图 用来展示数据*/// 设置模型数据mv.addObject("username", "zhangsan");// 设置视图名称mv.setViewName("success");return mv;}/*** SpringMVC页面跳转——返回ModelAndView对象 方式三* @return*/@RequestMapping("/quick4")public String save4(Model model) {/*Model:模型 用来封装数据View:视图 用来展示数据*/// 设置模型数据model.addAttribute("username", "zhangsan");// 返回jsp视图文件return "success";}/*** SpringMVC页面跳转——返回ModelAndView对象 方式四* 方式四不常用,了解知道即可* @return*/@RequestMapping("/quick5")public String save5(HttpServletRequest request) {/*Model:模型 用来封装数据View:视图 用来展示数据*/// request代替model来设置模型数据request.setAttribute("username", "zhangsan");// 返回jsp视图文件return "success";} }
-
success.jsp代码如下
- 注意:jsp文件中使用EL表达式时要在JSP页面顶部
<%@...%>
标签体内加上isELIgnored="false"
,作用:防止Tomcat配置禁用EL表达式
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html><head><title>Title</title></head><body><h1>...Success Running...</h1><h2>${username}</h2></body> </html>
Tomcat运行该Web项目后截图如下所示
- 注意:jsp文件中使用EL表达式时要在JSP页面顶部
-
-
注意
public ModelAndView save3(ModelAndView mv)
是通过参数传入ModelAndView
对象以供使用,原理是: SpringMVC会自动根据方法的参数进行相应的注入,以该save3
为例,当SpringMVC检测到其参数为ModelAndView
,而这个类是SpringMVC所有的,此时SpringMVC框架就会自动为其提供一个ModelAndView
对象以供该方法使用public String save5(HttpServletRequest request)
的原理也是Spring会根据方法的参数进行相应的注入
SpringMVC回写数据
SpringMVC回写数据——直接返回字符串
-
在Web基础阶段,客户端访问服务器端,若想直接回写字符串作为响应体返回的话,只需要使用
response.getWriter("Hello World")
方法即可,而在Controller中若想直接返回字符串的方式如下:- 方式一: 通过SpringMVC框架注入
response
对象(即参数为response
对象),然后使用response
对象的getWriter().print("Hello World")
方法回写数据即可- 注意:此时不需要视图跳转,且业务方法返回值为
void
- 注意:此时不需要视图跳转,且业务方法返回值为
- 方式二: 将需要回写的字符串直接返回,但此时需要使用
@ResponseBody
注解告知SpringMVC框架,该方法返回的是字符串不是页面跳转(即它是直接在http响应体中返回的字符串)@ResponseBody
注解作用:标注该注解的方法的返回值会直接写入 HTTP 响应体中。该注解通常用于 RESTful Web 服务或 AJAX 请求处理,以便返回 JSON、XML 或其他格式的数据。- 总结:代表不进行页面跳转,直接回写数据
- 方式一: 通过SpringMVC框架注入
-
方式一的代码示例如下
-
在controller包下重现创建一个示例类
UserControllerTwo
,代码如下package at.guigu.controller;import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;import javax.servlet.http.HttpServletResponse; import java.io.IOException;/*** SpringMVC回写数据*/ //将Usercontroller放到Spring容器中 @Controller @RequestMapping("/userTwo") public class UserControllerTwo {/*** SpringMVC回写数据——直接返回字符串方式一* @param response* @throws IOException*/@RequestMapping(value = "/quick1")public void save(HttpServletResponse response) throws IOException {response.getWriter().print("Hello World!");} }
-
-
方式二的代码示例如下
package at.guigu.controller;import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletResponse; import java.io.IOException;/*** SpringMVC回写数据*/ //将Usercontroller放到Spring容器中 @Controller @RequestMapping("/userTwo") public class UserControllerTwo {/*** SpringMVC回写数据——直接返回字符串方式一* @param response* @throws IOException*/@RequestMapping(value = "/quick1")public void save(HttpServletResponse response) throws IOException {response.getWriter().print("Hello World!");}/*** SpringMVC回写数据——直接返回字符串方式二* @return*/@ResponseBody@RequestMapping(value = "/quick2")public String save2(){return "Hello World!";} }
-
方式二中我们一般会返回指定格式的字符串,比如JSON格式,代码步骤示例如下(以对象转为JSON格式为例)
-
注意:将对象转换为JSON格式进行输出时我们需要借助JSON的转换工具将对象转换为JSON格式的字符串,然后在返回
-
Step1: 在pom.xml文件中导入坐标
jackson-core
、jackson-databind
、jackson-annotations
<!--jackson-core--> <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.17.1</version> </dependency> <!--jackson-databind--> <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.17.1</version> </dependency> <!--jackson-annotations--> <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.17.1</version> </dependency>
-
Step2: 创建一个pojo包,在该包下创建一个User类,代码如下
package at.guigu.pojo;public class User {private String name;private int age;public User() {}public User(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';} }
-
Step3:
UserControllerTwo
类代码如下package at.guigu.controller;import at.guigu.pojo.User; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletResponse; import java.io.IOException;/*** SpringMVC回写数据*/ //将Usercontroller放到Spring容器中 @Controller @RequestMapping("/userTwo") public class UserControllerTwo {/*** SpringMVC回写数据——直接返回字符串方式一* @param response* @throws IOException*/@RequestMapping(value = "/quick1")public void save(HttpServletResponse response) throws IOException {response.getWriter().print("Hello World!");}/*** SpringMVC回写数据——直接返回字符串方式二:直接返回普通字符串数据* @return*/@ResponseBody@RequestMapping(value = "/quick2")public String save2(){return "Hello World!";}/*** SpringMVC回写数据——直接返回字符串方式二:返回JSON格式响应字符串数据* @return* @throws JsonProcessingException*/@ResponseBody@RequestMapping(value = "/quick3")public String save3() throws JsonProcessingException {User user = new User();user.setName("zhangsan");user.setAge(18);//使用JSON的转换工具将对象转换为JSON格式的字符串,然后在返回ObjectMapper mapper = new ObjectMapper();String json = mapper.writeValueAsString(user);return json;} }
-
-
注意:我们可以利用
@RestController
注解来代替@Controller
和@ResponseBody
这两个注解-
原因:在类级别使用
@RestController
注解,就不需要在每个方法上单独使用@ResponseBody
注解。@RestController
本质上是@Controller
和@ResponseBody
的组合。 -
此时
UserControllerTwo
类中方式二的代码可更改如下package at.guigu.controller;import at.guigu.pojo.User; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletResponse; import java.io.IOException;/*** SpringMVC回写数据*/ //将Usercontroller放到Spring容器中 @RestController @RequestMapping("/userTwo") public class UserControllerTwo {/*** SpringMVC回写数据——直接返回字符串方式二:直接返回普通字符串数据* @return*/@RequestMapping(value = "/quick2")public String save2(){return "Hello World!";}/*** SpringMVC回写数据——直接返回字符串方式二:返回JSON格式响应字符串数据* @return* @throws JsonProcessingException*/@RequestMapping(value = "/quick3")public String save3() throws JsonProcessingException {User user = new User();user.setName("zhangsan");user.setAge(18);//使用JSON的转换工具将对象转换为JSON格式的字符串,然后在返回ObjectMapper mapper = new ObjectMapper();String json = mapper.writeValueAsString(user);return json;} }
-
SpringMVC回写数据——返回对象或集合
-
在 SpringMVC回写数据——直接返回字符串 的示例中
使用JSON的转换工具将对象转换为JSON格式的字符串,然后在返回
这种方式每次都需要如下两句代码ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(user);
这样就造成了代码冗余,为避免冗余我们可对其进行优化,已便于达到如下目的:SpringMVC自动将对象或集合转为JSON格式的字符串
-
原理:找到SpringMVC默认组件配置的配置文件
DispatherServlet.properties
(可详见SpringMVC核心配置文件解析),然后找到处理器适配器HandlerAdapter
接口下的RequestMappingHandlerAdapter
类,该类下有一个public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters)
方法可用来设置一个JSON转换的转换器- 该类的作用:处理使用
@RequestMapping
注解的控制器方法。它是HandlerAdapter
接口的一个具体实现,负责调用带有@RequestMapping
注解的方法来处理 HTTP 请求。 - 可通过SpringMVC的核心配置文件来更改(配置代码及步骤可详见SpringMVC核心配置文件解析)
- 该类的作用:处理使用
-
-
优化步骤如下
-
Step1: SpringMVC核心配置文件代码如下
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><!--配置Controller层的注解的组件扫描--><context:component-scan base-package="at.guigu.controller"></context:component-scan><!--等同于<context:component-scan base-package="at.guigu">type指定要扫描的内容为注解,expression指定要扫描的对应注解的全限定名只扫描at.guigu包下有@Controller注解的类<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan>--><!--配置内部资源视图解析器--><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--将InternalResourceViewResolver类中的前缀属性prefix的值设为/jsp/--><property name="prefix" value="/user/"></property><!--将InternalResourceViewResolver类中的前缀属性suffix的值设为.jsp--><property name="suffix" value=".jsp"></property></bean><!--配置处理器适配器--><bean id="handlerAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"><property name="messageConverters"><list><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/></list></property></bean> </beans>
配置内部资源视图解析器以及处理器适配器都用到了setter方法注入,只是说一个是普通数据类型注入,一个是集合注入。具体注入方法解释可详见Spring完整知识点汇总一中的依赖注入
-
Step2: 直接返回字符串方式二:返回JSON格式响应字符串数据的代码更改如下
package at.guigu.controller;import at.guigu.pojo.User; import com.fasterxml.jackson.core.JsonProcessingException; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;//将Usercontroller放到Spring容器中 @Controller @RequestMapping("/userTwo") public class UserControllerFour {/*** SpringMVC回写数据——直接返回字符串方式二:返回JSON格式响应字符串数据* @return* @throws JsonProcessingException*/@ResponseBody@RequestMapping(value = "/quick3")public User save3() throws JsonProcessingException {User user = new User();user.setName("zhangsan");user.setAge(18);return user;} }
-
除此之外还可返回集合数据,代码如下:
package at.guigu.controller;import at.guigu.pojo.User; import com.fasterxml.jackson.core.JsonProcessingException; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;import java.util.ArrayList; import java.util.List;/*** 将Usercontroller放到Spring容器中* 测试:经配置后,SpringMVC自动将对象或集合转为JSON格式的字符串*/ @Controller @RequestMapping("/userFour") public class UserControllerFour {/*** SpringMVC回写数据——直接返回字符串方式二:返回JSON格式响应字符串数据* @return* @throws JsonProcessingException*/@ResponseBody@RequestMapping(value = "/quick3")public User save3() throws JsonProcessingException {User user = new User();user.setName("zhangsan");user.setAge(18);return user;}/*** SpringMVC回写数据——直接返回字符串方式二:返回JSON格式响应集合数据* @return* @throws JsonProcessingException*/@ResponseBody@RequestMapping(value = "/quick4")public List<User> save4() throws JsonProcessingException {User user1 = new User();user1.setName("zhangsan");user1.setAge(15);User user2 = new User();user2.setName("lisi");user2.setAge(12);List<User> userList = new ArrayList<User>();userList.add(user1);userList.add(user2);return userList;}}
-
-
在SpringMVC核心配置文件中进行处理器适配器的配置还稍显麻烦,我们可以在SpringMVC核心配置文件中使用mvc的注解驱动来代替对处理器适配器进行的配置
-
mvc的注解驱动代码:
<mvc:annotation-driven/>
- 它能够自动加载处理器映射器
RequestMappingHandlerMapping
和处理器适配器RequestMappingHandlerAdapter
,并且它的底层会继承jackson进行对象或集合的JSON格式字符串的转换
- 它能够自动加载处理器映射器
-
此时SpringMVC的核心配置文件代码如下
注意:mvc的注解驱动代码需要引入mvc的命名空间以及约束路径(可详见Spring快速入门代码实现)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><!--配置Controller层的注解的组件扫描--><context:component-scan base-package="at.guigu.controller"></context:component-scan><!--等同于<context:component-scan base-package="at.guigu">type指定要扫描的内容为注解,expression指定要扫描的对应注解的全限定名只扫描at.guigu包下有@Controller注解的类<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan>--><!--配置内部资源视图解析器--><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--将InternalResourceViewResolver类中的前缀属性prefix的值设为/jsp/--><property name="prefix" value="/user/"></property><!--将InternalResourceViewResolver类中的前缀属性suffix的值设为.jsp--><property name="suffix" value=".jsp"></property></bean><!--mvc的注解驱动--><mvc:annotation-driven/><!--等同于配置处理器适配器--><!--<bean id="handlerAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"><property name="messageConverters"><list><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/></list></property></bean>--> </beans>
-
SpringMVC的核心配置文件对应的SpringMVC核心配置类代码如下
package at.guigu.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.view.InternalResourceViewResolver;// 该注解代表该类是SpringMVC的核心配置类 @Configuration // 配置注解的组件扫描<context:component-scan base-package="at.guigu.controller"></context:component-scan> // 加载controller对应的bean @ComponentScan("at.guigu.controller") // 自动配置 Spring MVC 的各种特性,比如mvc的注解驱动<mvc:annotation-driven/> @EnableWebMvc public class SpringMvcConfiguration {// 配置视图解析器@Beanpublic InternalResourceViewResolver viewResolver() {InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix("/user/"); // 设置视图文件路径前缀resolver.setSuffix(".jsp"); // 设置视图文件后缀return resolver;} }
-