Spring Web MVC是构建在Servlet API之上的Web框架,自诞生之时就被纳入了Spring框架中。其正式/官方名称为“Spring ?Web MVC”,源自其所属的模块(spring-webmvc),但通常被称为“Spring MVC”。
是一种软件设计典范,用一种将业务逻辑、数据、界面显示分离的方法组织代码
配置Spring MVC Web应用的方式有两种:xml配置与Java代码配置。
配置Spring MVC Web应用的过程如下:
在src/main/webapp/WEB-INF下创建三个配置文件:web.xml、applicationContext.xml、dispatcher-servlet.xml
首先要在web.xml中配置DispatcherServlet,它负责接受请求,并根据处理程序映射将请求委托给对应的处理器,也就是控制器。
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
除了DispatcherServlet外,我们还应在web.xml中配置servlet-mapping。它指定servlet映射,即指定什么请求会被什么servlet处理。
如我们前面所说的,DispatcherServlet,不是真正的用于处理请求的组件,它拦截要处理的请求,根据处理程序映射(HandlerMapping)将请求委托给对应的处理器,也就是控制器。
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<!-- 这里的/表示所有请求,但是.jsp的请求除外 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
?在web.xml文件中我们也可以注册监听器,使用的标签是<listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
ContextLoaderListener监听器的作用是监听程序的启动和关闭,监听到程序启动的时候,会加载spring的配置文件applicationContext.xml,并创建spring根容器。
使用<context-param>配置spring配置文件的位置,参数名是固定的,叫做contextConfigLocation
spring配置文件可以对应多个,多个可以使用逗号、空格、换行隔开,另外还可以使用*通配符
如果配置文件放到了src下,则需要添加classpath:前缀
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:config/spring-*.xml
</param-value>
</context-param>
spring mvc配置文件的默认名称是"servlet的名称-servlet.xml。当然,也可随意命名该文件,spring mvc配置文件中配置的组件主要给DispatcherServlet使用,所以需要通过DispatcherServlet的初始化参数contextConfigLocation来配置spring mvc配置文件的位置。
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/spring_mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
web.xml文件的完整内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- spring配置文件默认名称是applicationContext.xml -->
<!-- 当然,也可以随意命名,如果自己指定了该文件的名称,需要通过上下文参数来配置其位置 -->
<!-- spring配置文件中的组件是给整个程序用的 -->
<!-- 参数名是固定的,叫做contextConfigLocation -->
<!-- spring配置文件可以对应多个,多个可以使用逗号、空格、换行隔开 -->
<!-- 另外还可以使用*通配符 -->
<!-- 如果配置文件放到了src下,则需要添加classpath:前缀 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:config/spring-*.xml
</param-value>
</context-param>
<!-- listener用于注册监听器 -->
<!-- ContextLoaderListener监听器的作用是监听程序的启动和关闭 -->
<!-- 监听到程序启动的时候,会加载spring的配置文件applicationContext.xml,并创建spring根容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- spring mvc配置文件的默认名称是"servlet的名称-servlet.xml" -->
<!-- 当然,也可随意命名该文件,spring mvc配置文件中配置的组件主要给DispatcherServlet使用 -->
<!-- 所以需要通过DispatcherServlet的初始化参数contextConfigLocation来配置spring mvc配置文件的位置 -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/spring_mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- servlet-mapping指定servlet的映射
也就是指定什么样的请求会被该servlet处理
DispatcherServlet不是真正用于处理请求的组件,用于拦截要处理的请求
做一些事情后,再将请求分发/派发给真正处理请求的控制器
DispatcherServlet,我们叫做前端控制器
-->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<!-- 这里的/表示所有请求,但是.jsp的请求除外 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
在这个配置文件中配置Spring,配置全局性的bean,如Service、Dao等组件
<context:component-scan base-package="com.qdu.service" />
applicationContext.xml是spring配置文件的默认名称,一般会将applicationContext,xml的名称改成spring-config.xml。
spring-config.xml的完整内容如下:
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 该配置文件是spring配置文件,用于配置全局性的bean,如Service、Dao等组件 -->
<context:component-scan base-package="com.qdu.service" />
</beans>
注意:如果自己指定了该文件的名称,需要在web.xml中通过上下文参数来配置其位置?
在这个文件中配置Spring MVC处理请求时使用的各个组件(1.2)。
1. 配置Controller(控制器):开启对控制器包的扫描,使用@Controller修饰对应的控制器类
<context:component-scan base-package="com.qdu.controller" />
2. 配置ViewResolver(视图解析器):让DispatcherServlet可以将视图名称解析为视图的实际逻辑名称。
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
3.?启用注解驱动的编程模型,这样@RequestMapping等的配置会生效
?mvc:annotation-driven的标记使用会自动注册多个必须的bean,包括RequestMappingHandlerMapping
<mvc:annotation-driven />
4. 配置静态资源
我们配置servlet-mapping时,<url-pattern>写的是/,即拦截所有除了.jsp的请求,所以静态资源也会被拦截,需要针对静态资源单独处理。
可以用default-servlet-handler标记,其表示将静态资源交给web容器的默认servlet来处理
<mvc:default-servlet-handler />
可以使用mvc:resources标记使用单独的处理器处理静态资源
<!-- location:指定静态资源的位置,mapping用于指定访问静态资源的请求url模式 -->
<mvc:resources location="/" mapping="/index.html" />
<mvc:resources location="/css/" mapping="/css/**" />
<mvc:resources location="/js/" mapping="/js/**" />
<mvc:resources location="/img/" mapping="/img/**" />
如果只是希望能够跳转到WEB-INF/jsp目录下的某个jsp页面,并不做其他处理,可直接使用<mvc:view-controller>标记指定请求url和要跳转的视图的名称?
<mvc:view-controller path="/" view-name="index" />
<mvc:view-controller path="/aaa" view-name="index" />
<mvc:view-controller path="/toIndex" view-name="index" />
一般会将spring mvc配置文件的名称改成spring_mvc.xml。
spring_mvc.xml的完整内容如下:
<?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:p="http://www.springframework.org/schema/p"
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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启对控制器包的扫描,这样@Controller修饰的类会注册为spring管理的bean -->
<context:component-scan base-package="com.qdu.controller" />
<!-- 启用注解驱动的编程模型,这样@RequestMapping等的配置会生效 -->
<!-- mvc:annotation-driven的标记使用会自动注册多个必须的bean,包括RequestMappingHandlerMapping -->
<mvc:annotation-driven />
<!-- 配置视图解析器,让DispatcherServlet可以将视图名称解析为视图的实际逻辑名称 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- /拦截的是所有请求,包括静态资源,会导致静态资源的访问报404 -->
<!-- 需要针对静态资源单独处理 -->
<!-- 1. default-servlet-handler标记表示将静态资源交给web容器的默认servlet来处理 -->
<!-- <mvc:default-servlet-handler /> -->
<!-- 2. mvc:resources标记表示使用单独的处理器处理静态资源 -->
<!-- location:指定静态资源的位置,mapping用于指定访问静态资源的请求url模式 -->
<mvc:resources location="/" mapping="/index.html" />
<mvc:resources location="/css/" mapping="/css/**" />
<mvc:resources location="/js/" mapping="/js/**" />
<mvc:resources location="/img/" mapping="/img/**" />
<!-- 如果只是希望能够跳转到WEB-INF/jsp目录下的某个jsp页面 -->
<!-- 并不做其他处理,可直接使用<mvc:view-controller>标记指定请求url和要跳转的视图的名称 -->
<mvc:view-controller path="/" view-name="index" />
<mvc:view-controller path="/aaa" view-name="index" />
<mvc:view-controller path="/toIndex" view-name="index" />
</beans>
基于xml配置的项目结构图如下:
?可以发现,关于spring、spring mvc的配置文件统一放到src/main/resources/config下,web.xml放到src/main/webapp/WEB-INF下。
src/main/java/com/qdu主要放controller包和service包。
src/main/webapp下放网络的静态资源(src/main/webapp/static),src/main/webapp/WEB-INF放的除了web.xml还有jsp页面。
在src/main/java/com/qdu/config下创建三个配置类MyWebApplicationInitializer.class、SpringConfig.class、SpringMvcConfig.class
该类用于替换web.xml文件,用于初始化程序,在程序启动的时候被加载和使用。
如果spring+springmvc程序用的都是java类配置,那么可以直接让该类继承自
AbstractAnnotationConfigDispatcherServletInitializer类,以便简化写法?
让我们回忆一下我们在web.xml中都做了哪些事:
那么在该类中我们就应实现这三个功能:
1.?配置spring配置文件的位置:getRootConfigClasses()方法中指定spring配置类有哪些,可以有多个。加载spring配置类形成的是根容器
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] {SpringConfig.class,SpringTx.class};
}
2. 配置spring mvc配置文件的位置:getServletConfigClasses()方法用于指定spring mvc配置类有哪些,可以有多个。加载spring mvc配置类形成的是Servlet上下文容器
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] {SpringMvcConfig.class};
}
3. 配置DispatcherServlet:getServletMappings()方法用于指定DispatcherServlet的url映射,也就是DispatcherServlet能拦截的请求的url模式,可以是多个,用一个String[]表示
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
MyWebApplicationInitializer类完整内容如下:
package com.qdu.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
//该类用于替换web.xml文件,用于初始化程序,在程序启动的时候被加载和使用
//如果spring+springmvc程序用的都是java类配置,那么可以直接让该类继承自
//AbstractAnnotationConfigDispatcherServletInitializer类,以便简化写法
public class MyWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
//getRootConfigClasses()方法中指定spring配置类有哪些,可以有多个
//加载spring配置类形成的是根容器
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] {SpringConfig.class,SpringTx.class};
}
//getServletConfigClasses()方法用于指定spring mvc配置类有哪些,可以有多个
//加载spring mvc配置类形成的是Servlet上下文容器
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] {SpringMvcConfig.class};
}
// getServletMappings()方法用于指定DispatcherServlet的url映射
// 也就是DispatcherServlet能拦截的请求的url模式,可以是多个,用一个String[]表示
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
该类用于替换spring-config.xml文件
同spring-config.xml中所作的事情一样,开启对com.qdu.service(还可以有dao)的包扫描
package com.qdu.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration //说明该类是个配置类
@ComponentScan(basePackages= {"com.qdu.service"})
public class SpringConfig {
}
该类用于替换spring mvc的配置xml文件,Spring MVC的配置类需要实现WebMvcConfigurer接口,来实现各种mvc配置。
我们在spring_mvc.xml中共做了如下几件事:
1. 对于Controller,使用@ComponentScan开启对Controller包的扫描
@ComponentScan(basePackages = { "com.qdu.controller" })
2. 使用configureViewResolvers()方法中注册视图解析器组件
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
//调用jsp()方法指定前缀和后缀
registry.jsp("/WEB-INF/jsp/", ".jsp");
}
3.?@EnableWebMvc和在xml配置文件中使用<mvc:annotation-driven />等效
@EnableWebMvc
4. 使用addResourceHandlers()中添加对静态资源的处理,为指定的静态资源添加资源处理器,让静态资源能够正常显示。
?/static/**是访问静态资源的url模式,/static/是静态资源所在的位置
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// /static/**是访问静态资源的url模式,/static/是静态资源所在的位置
registry.addResourceHandler("/static/**").addResourceLocations("/static/");
}
addViewControllers()方法用于为一些请求添加简单的视图控制器,这样可以不用添加控制器方法实现简单的页面跳转
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/aaa").setViewName("index");
registry.addViewController("/toIndex").setViewName("index");
registry.addViewController("/toSecond").setViewName("second");
}
在这里详细解释一下这里的“添加控制器方法实现简单的页面跳转”:
WEB-INF/jsp目录下的页面是不能直接访问,需要经过控制器跳转,比如我们现在有一个index.jsp,我们要跳转到这个页面需要在com.qdu.controller包中写一个IndexController
package com.qdu.controller;
import org.springframework.stereotype.Controller;
@Controller
public class IndexController {
@RequestMapping({"/","/aaa","/toIndex"})
public String toIndex() {
return "index"; //返回的index是要跳转的页面的名称
}
}
这里的"/"这个url表示程序的上下文路径,意思是如果请求url是上下文路径,就跳转到index页面/视图,可以对应多个url。
如果需要添加方法处理请求,比如需要从数据库读取一些数据,再跳转到页面显示,可以在控制类中添加方法处理请求。
但是如果只是单纯希望跳转到一个jsp页面,不做其他处理,直接在springmvc配置文件中配置即可
?SpringMVCConfig类的内容如下:
package com.qdu.config;
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.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@ComponentScan(basePackages = { "com.qdu.controller" })
//Spring MVC的配置类需要实现WebMvcConfigurer接口,来实现各种mvc配置
//@EnableWebMvc和在xml配置文件中使用<mvc:annotation-driven />等效
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {
//addResourceHandlers()中添加对静态资源的处理
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 为指定的静态资源添加资源处理器,让静态资源能够正常显示
// /static/**是访问静态资源的url模式,/static/是静态资源所在的位置
registry.addResourceHandler("/static/**").addResourceLocations("/static/");
}
//addViewControllers()方法用于为一些请求添加简单的视图控制器
//这样可以不用添加控制器方法实现简单的页面跳转
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/aaa").setViewName("index");
registry.addViewController("/toIndex").setViewName("index");
registry.addViewController("/toSecond").setViewName("second");
}
//configureViewResolvers()方法中注册试图解析器组件
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
//调用jsp()方法指定前缀和后缀
registry.jsp("/WEB-INF/jsp/", ".jsp");
}
}