--- title: 使用 Maven 创建 Spring MVC 项目 date: 2020-11-11 15:52:52 tags: - Spring - Spring MVC - Maven categories: - Spring --- > Maven 可以用来创建 Java 项目,并管理依赖,创建出来的项目不依赖于特定的 IDE,可以用 Eclipse、IDEA 社区版、IDEA 旗舰版,甚至 VSCode 来开发。_(具体 VSCode 怎么配置 Java 开发环境,这里不再赘述)_ > Maven 创建项目时,需要从国外的服务器上下载项目的依赖、插件等,速度会很慢,甚至导致创建项目失败,具体如何配置,请参考我的另一篇博客 [Maven 的相关配置](http://zhouxy.xyz/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/Maven-%E7%9A%84%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE/)。 ## 一、创建 Java Web 项目 ### 1. 使用 maven 创建 Java Web 项目 启动开发环境,用 Maven 创建项目,从原型中选择“maven-archetype-webapp”,再依次指定 groupId、artifactId 等信息,不同的 IDE 创建 Maven 项目的过程略有不同,但大同小异。 ### 2. 完善目录结构 在 `main` 文件夹中创建 `java` 和 `resources` 两个文件夹;在 `src` 文件夹中创建 `test` 文件夹,并中其中也创建 `java` 和 `resources` 两个文件夹。 - ${basedir}/src/main/java 文件夹中创建 Java 包和类; - ${basedir}/src/main/resources 文件夹中存放静态文件; - ${basedir}/src/test/java 文件夹中创建项目的测试类,比如说 Junit 代码; - ${basedir}/src/test/resources 存放测试用的资源。 > 在 IDEA 中新建目录时,会有几个提示,因为 IDEA 通过 pom.xml 文件知道这是个 maven 项目,猜测并帮助你创建标准的 maven 项目骨架。这时候按住 shift 键,并按住下方向键,可将其全部选中,再按回车,即可一次性创建好所有文件夹并标记好,这样就不用一个一个创建并标记了。在 VSCode 中,并不会对项目中的文件夹进行标记(VSCode 的一些图标可能会根据文件名进行猜测),所以一个一个创建文件夹就完事了。 初始的项目路径如下: ![初始项目结构](http://zhouxy.xyz/img/163635_48fc6498_6543055.png) 我们需要完善其目录结构: ![完善后的目录结构](http://zhouxy.xyz/img/164009_81ccdf56_6543055.png) ### 3. 添加 Servlet 和 JSP 的依赖包 在 pom.xml 文件中的 `dependencies` 标签中添加 Servlet 和 JSP 的依赖: ```xml javax.servlet javax.servlet-api 4.0.1 javax.servlet.jsp javax.servlet.jsp-api 2.3.3 jstl jstl 1.2 ``` 这样,一个 Java Web 项目就创建好了。 ## 二、配置 Spring MVC ### 1. 导入 Spring、Spring MVC 的依赖 在 pom.xml 文件中的 `dependencies` 标签中添加如下依赖: ```xml org.springframework spring-webmvc 5.2.8.RELEASE ``` > 导入 spring-webmvc 好像就会自动导入 spring-aop、spring-beans、spring-context、spring-core、spring-expression、spring-web 这些个依赖。 ### 2. 配置并启用 Spring MVC 以前(包括现在很多人)配置 Spring MVC 都是通过 web.xml 配置的,随着 Java 和 Spring 的发展,现在完全可以不使用 xml 配置并启用 Spring MVC。 下面的配置适用于 Spring 3.2 及以上版本(我写本文时,Spring 的版本已经是 5.2.9 了),且 Servlet 容器支持 Servlet 3.0(2009 年 12 月发布)。所以,你的开发环境大概率支持以下配置方法。 #### 2.1.1 创建 RootConfig 配置类 **RootConfig 类将用于非 web 部分的配置。** *本示例中重在与 Web 相关的配置,所以 `RootConfig` 相对简单,实际项目中将会有很多非 Web 的配置来充实完善 RootConfig。* ```java package xyz.zhouxy.chapter01.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @Configuration @ComponentScan(basePackages = "xyz.zhouxy.chapter01", excludeFilters = { @Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class)}) public class RootConfig { } ``` #### 2.1.2 创建 WebConfig 配置类 WebConfig 将用于 DispatcherServlet 应用程序上下文配置。 ```java package xyz.zhouxy.chapter01.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.view.InternalResourceViewResolver; @Configuration @EnableWebMvc @ComponentScan("xyz.zhouxy.chapter01.web") public class WebConfig implements WebMvcConfigurer { @Bean public ViewResolver viewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); resolver.setExposeContextBeansAsAttributes(true); return resolver; } @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } } ``` - `@EnableWebMvc` 注解启动 Spring MVC; - `@ComponentScan` 启用组件扫描;所指定的包中的所有带有 `@Controller` 注解的类都会成为 Spring bean。 - `viewResolver` 方法配置 JSP 视图解析器,将 `InternalResourceViewResolver` 类的实例声明为 bean; - 重写的 `configureDefaultServletHandling` 方法,通过调用 `DefaultServletHandlerConfigurer` 的 `enable()`,要求 `DispatcherServlet` 将对静态资源的请求转发到 Servlet 容器中默认的 Servlet 上,而不是使用 `DispatcherServlet` 本身来处理此类请求。 > 《Spring 实战(第4版)》中,WebConfig 是继承自 `WebMvcConfigurerAdapter` 类,但当前的版本,该类已经过时,`WebConfig` 类实现 `WebMvcConfigurer` 接口即可。 #### 2.1.3 创建 WebAppInitializer 类 当我们创建了 `RootConfig` 和 `WebConfig` 配置类之后,怎么让它们应用于我们的项目呢?答案是通过写一个 `WebAppInitializer`。 `WebAppInitializer` 类继承自 `AbstractAnnotationConfigDispatcherServletInitializer`,所以它会自动地配置 `DispatcherServlet` 和 Spring 应用上下文,Spring 应用上下文会位于应用程序的 Servlet 上下文中。 ```java package xyz.zhouxy.chapter01.config; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class WebAppInitializer 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[] { "/" }; } } ``` > **更多细节:** > 在 Servlet 3.0 环境中,容器会在类路径中查找 `javax.servlet.ServletContainerInitializer` 接口的实现类,找到的话,就用它来配置 Servlet 容器。Spring 的 `SpringServletContainerInitializer` 类即为该接口的实现类,`SpringServletContainerInitializer` 又会查找实现 `WebApplicationInitializer` 的类并将配置的任务交给它们来完成。 > > Spring 3.2 中引入了一个便利的 `WebApplicationInitializer` 基础实现,也就是 `AbstractAnnotationConfigDispatcherServletInitializer`。 > > 因为我们的 `WebAppInitializer` 继承自 `AbstractAnnotationConfigDispatcherServletInitializer`(同时也就实现了 `WebApplicationInitializer` 接口),因此当部署到 Servlet 3.0 容器中的时候,容器会自动发现它,并用它来配置 Servlet 上下文。 ## 三、使用 Spring MVC 前面我们已经配置好了 Spring MVC,接下来我们编写一个 Controller 来测试一下吧。 ### 1. 创建页面 在 ${basedir}/src/main/webapp/WEB-INF/ 文件夹中新建一个 `views` 文件夹,再在 `views` 文件夹中新建 `test.jsp` 文件: ```html <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> Test

Test Page

``` ### 2. 创建 TestController ```java package xyz.zhouxy.chapter01.web; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller public class TestController { @GetMapping("/test") public String toTestPage() { return "test"; } } ``` ### 3. 部署项目 将项目部署到 Tomcat,应用上下文为 `chapter01`。 > 不同 IDE 配置 Tomcat 部署项目具体细节找时间再写吧。 在浏览器输入 http://localhost:8080/chapter01/test ,由于上面的映射,`toTestPage()` 方法将被执行,它返回字符串“test”,被视作视图的名称,由 `WebConfig` 类中配置的视图解析器解析为具体的视图 `/WEB-INF/views/test.jsp`。 ![运行结果](http://zhouxy.xyz/img/233117_0a37d814_6543055.png "屏幕截图.png")