文章目录
SpringMVC入门
1. SpringMVC简介
在之前,我们曾学过基于MVC思想的struts2框架,而Spring本身对于Web开发也提供了一个非常强大的解决方案。SpringMVC基于模型-视图-控制器(Model-View-Controller,MVC)模式实现,它能够帮助我们构建更为灵活和松耦合的Web应用程序。
SpringMVC得益于自身两大核心技术DI和AOP的运用,使得我们可以在Web项目中以更优雅和更健壮的方式引入、整合各类资源。目前,SpringMVC在Web框架的市场份额上,已经遥遥领先于struts2等传统Web框架。
2. 搭建SpringMVC
2.1 引入类库
要使用SpringMVC,需要首先新建基于“war”的maven项目,在pom.xml中引入spring-webmvc模块:
<modelVersion>4.0.0</modelVersion>
<groupId>com.turing</groupId>
<artifactId>spring-06</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.19.RELEASE</version>
</dependency>
</dependencies>
打开pom的树状依赖视图
我们可以看到spring-webmvc模块把我们需要用到的spring其它相关模块(数据访问类模块除外)都引入进来了。
2.2 配置DispatcherServlet
类似于struts2的配置,我们同样需要在web应用中注册SpringMVC的前端控制器。与struts2不同的是,SpringMVC的前端控制器不是基于Filter的,而是基于Servlet(DispatcherServlet
)的。
我们可以像struts2一样,在web.xml中对SpringMVC的前端控制器进行配置,但为了结合Servlet3.0+
的新特性,同时为了更便利的使用Spring后续的新功能,我们将使用基于Java的配置来对SpringMVC的前端控制器进行注册。在编写这些配置之前,让我们先来了解一下Servlet3.0+
以及SpringMVC中与Servlet配置有关的一些新特点:
在Servlet3.0+
环境中,容器会在类路径中查找实现了javax.servlet.ServletContainerInitializer
接口的类,如果能发现的话,就会用它来配置Servlet。
而Spring提供了这个接口的实现,名为SpringServletContainerInitializer
,这个类会反过来查找实现了WebApplicationInitializer
的类并将配置的任务交给它们来完成。为了更简便的实现WebApplicationInitializer
接口,Spring提供了一个抽象类,我们只需要继承这个抽象类,就能完成对DispatcherServlet
的注册。
public class SpringWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override // 获得根配置类
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class };
}
@Override // 获得web配置类
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
@Override // 配置servlet-mapping
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
忽略getRootConfigClasses()
和getServletConfigClasses()
,以上配置和web.xml中的这段配置,效果是等价的:
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
接下来,让我们再来看看接下来的两个方法做了什么。
2.3 应用上下文配置
2.3.1 DispatcherServlet上下文
当DispatcherServlet加载以后,它会创建Spring应用上下文,并加载配置文件或者配置类中所声明的bean。让我们看看WebConfig这个配置类到底做了哪些工作:
@Configuration
@EnableWebMvc // 启用SpringMVC
@ComponentScan("com.turing.web")
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
// 设置视图前缀
resolver.setPrefix("/");
// 设置视图后缀
resolver.setSuffix(".jsp");
// 让上下文的bean在请求的属性中也可以访问
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
// 配置静态资源的处理
configurer.enable();
}
}
- 首先通过
@EnableWebMvc
启动SpringMVC @ComponentScan("com.turing.web")
用来配置DispatcherServlet
所启动的上下文中所应包含的bean,这些bean主要是Controller(类似struts2中的action)、用户自定义的servlet、filter、listener以及视图解析器等。- viewResolver()主要用来生成视图解析器,SpringMVC的controller中的用来处理请求的方法和struts2类似,也是返回String类型的结果,我们只需要给InternalResourceViewResolver设置相应的前缀和后缀。例如,如果处理请求的方法返回的是“success”,那spring根据视图解析器找到的页面路径将会是“/success.jsp”。
- 最后,我们通过重写configureDefaultServletHandling()方法,使得图片、样式等静态资源不经由
DispatcherServlet
处理。
2.3.2 ContextLoaderListener上下文
在Spring Web应用中,通常还会有另外也给上下文。这个上下文是由ContextLoaderListener创建的。这个上下文主要用来加载应用中除开web组件以外其他的bean,比如service、dao等。
@Configuration
@ComponentScan(basePackages = { "com.turing" }, excludeFilters = {
@Filter(type = FilterType.ANNOTATION, value = { EnableWebMvc.class, Controller.class }) })
public class RootConfig {
}
在excludeFilters
中,我们对类上标记了@EnableWebMvc
和@Controller
的类不进行扫描,以面重复装载Bean到Spring容器中。
为了便于更好的理解两个上下文之间的关系,我们来看一下项目的包结构:
2.4 编写控制器
@Controller
public class HelloController {
private final Logger logger = LogManager.getLogger(HelloController.class);
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello(Model model) {
model.addAttribute("username", "jack");
logger.debug("HelloController:hello()");
return "success";
}
}
@Controller
该注解用来声明spring的控制器,本身与@Component
没有区别,只不过是用来表示控制器的身份而已,让开发者看起来更清晰。@RequestMapping
用来声明访问路径与处理方法/类的映射关系
3. SpringMVC的请求处理流程
通过上面这个简单的hello案例,我们一起来回顾一下SpringMVC的执行流程:
- 当我们输入“
/hello
”时,请求的第一站是DispatcherServlet
这个前端控制器,它的任务是根据处理器映射来选择合适的controller。 - controller中我们已经将路径与处理方法的对应关系,通过
@RequestMapping
注册到了上下文中的处理器映射中。 - 通过查询处理器映射,
DispatcherServlet
会将请求派发给HelloController.hello(),并等候处理结果 - hello方法处理完成后,会将模型数据打包(model),并标识出要展示的视图逻辑名称(“success”)
- 前端控制器
DispatcherServlet
通过我们之前配置的视图解析器InternalResourceViewResolver,给视图名添加对应的前缀和后缀,最终得到完整的视图路径(”/success.jsp“)。 - 结合处理请求得到的模型数据model和动态页面”/success.jsp“,渲染输出好视图。
- 最终将这个视图页面以html格式返回给前端。
4.使用log4j2记录日志
在SpringMVC中使用log4j2记录日志也是非常方便的,不过与mybatis不同的是,除开引入Log4j的类库外,还需要额外引入Log4j JCL的库:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.11.1</version>
</dependency>
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%-5p [%C{2}] (%F:%L) - %m%n" />
</Console>
</Appenders>
<Loggers>
<!-- <Logger name="org.springframework.beans.factory" level="DEBUG" /> -->
<Root level="debug">
<AppenderRef ref="STDOUT" />
</Root>
</Loggers>
</Configuration>
</Appenders>
<Loggers>
<!-- <Logger name="org.springframework.beans.factory" level="DEBUG" /> -->
<Root level="debug">
<AppenderRef ref="STDOUT" />
</Root>
</Loggers>
```