SpringMVC HelloWord

1. HelloWord 环境搭建

1.1. Tomcat服务环境

这里介绍一下IDAE Maven工程怎么关联本地Tomcat服务。

首先编辑pom.xml,将打包方式修改为war

1
<packaging>war</packaging>

创建webapp/WEB-INF目录,再添加web.xml

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">

</web-app>

Run->Edit Run Configurations->添加Tomcat Server Local

  • 点击右下角的Fix->选择带有exploded的选项

1.2. 依赖

Spring依赖

  • 4个核心容器模块
  • AOP(Spring注解依赖于AOP)
  • web和webmvc(webmvc就是SpringMVC)

根据依赖传递,只需要导入webmvc

1
2
3
4
5
6
7
8
9
10
11
12
<properties>
<spring.version>5.1.5.RELEASE</spring.version>
</properties>

<dependencies>
<!-- springmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>

1.3. 编辑web.xml,配置前端控制器 DispatcherServlet

配置前端控制器DispatcherServlet,从名称就可以看出是一个Servlet

不仅是针对DispatcherServlet,所有的Servlet在创建时都分以下3种情况

  • loadOnStartup < 0:即负数的情况下,web容器启动的时候不做实例化处理,servlet首次被调用时做实例化。这种情况和没有设置loadOnStartup是一样的
  • loadOnStartup > 0:web容器启动的时候做实例化处理,顺序是由小到大,正整数小的先被实例化
  • loadOnStartup = 0:web容器启动的时候做实例化处理,相当于是最大整数,因此web容器启动时,最后被实例化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- The front controller of this Spring Web application, responsible for 
handling all application requests (配置前端控制器,本质是一个Servlet,拦截所有请求并智能派发) -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<init-param>
<!-- contextConfigLocation指定springmvc配置文件的路径
默认值是/WEB-INF/<servlet-name>-servlet.xml -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- load-on-startup是可选配置,值越小,优先级越高
若值为1,则web应用在启动时就会加载该Servlet
如果<load-on-startup>未配置,则首次访问该Servlet时,才被加载 -->
<load-on-startup>1</load-on-startup>
</servlet>

<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

DispatcherServlet的URL映射拦截规则如下,/*的拦截范围比/更大,还会拦截到*.jsp请求,这样jsp页面就无法显示了

url-pattern 拦截请求 使用说明
/* 一切资源。包括js、css等 不建议使用。全部拦截后,JSP页面就无法显示了
/ 除了jsp之外的一切资源 强烈建议使用。多用于前台请求
*.action或*.do 指定后缀的请求 可以使用。多用于后台请求

1.4. 创建springmvc.xml

在类路径下创建springmvc.xml,就是Spring Bean Configuration File

  • Eclipse:用STS插件快速创建即可
  • IDEA:New->XML Configuration File->Spring Config

配置组件扫描

1
<context:component-scan base-package="demo.springmvc"/>

1.5. 创建JSP页面

创建/WEB-INF/jsp/index.jsp

1.6. 创建Controller

注意在SpringMVC中,@Controller不能与其它注解组件混用。如果改为@Component,则无法识别@RequestMapping等注解

1
2
3
4
5
6
7
8
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello() {
System.out.println("HelloWorld");
return "/WEB-INF/jsp/index.jsp";
}
}

1.7. 运行Tomcat测试

在Tomcat上运行,访问 /hello

2. 添加视图解析器

返回的jsp页面(视图)的前后缀总是/WEB-INF/jsp/.jsp,每次都要写,很麻烦,而且页面路径一改,所有地方都要修改。这时候我们可以使用视图解析器,它会自动给视图名拼接前后缀,得到完整的路径,简化开发

编辑springmvc.xml

1
2
3
4
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>

修改Controller

1
2
3
4
5
6
7
8
9
10
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello() {
System.out.println("hellowolrd");
// return "/WEB-INF/jsp/index.jsp";
// 去掉前后缀
return "index";
}
}

3. HelloWorld运行流程

  1. 客户端请求/hello
  2. 请求来到tomcat服务器;
  3. SpringMVC的前端控制器收到所有请求
  4. 前端控制器看一下请求地址和@RequestMapping标注的哪个匹配,来找到到底使用那个类的哪个方法来处理
  5. 前端控制器找到了目标处理器类和目标方法,直接利用返回执行目标方法;
  6. 方法执行完成以后会有一个返回值;SpringMVC认为这个返回值就是要去的页面地址
  7. 拿到方法返回值以后;用视图解析器进行拼串得到完整的页面地址;
  8. 拿到页面地址,前端控制器帮我们转发到页面;

4. DispatcherServlet尝试不指定bean配置文件的位置

尝试不指定bean配置文件的位置

1
2
3
4
5
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

运行tomcat,发现报错,说找不到Bean配置文件,默认会到/WEB-INF/下去找springDispatcherServlet-servlet.xml,这个配置文件的名称由你配置的<servlet-name>决定,默认文件名就是<servlet-name>-servlet.xml

1
2
Caused by: java.io.FileNotFoundException: 
Could not open ServletContext resource [/WEB-INF/springDispatcherServlet-servlet.xml]

5. DispatcherServlet的url-pattern分析

5.1. url-pattern为/的分析

打开tomcat服务器的全局web.xml,所有tomcat项目中的web.xml都继承该配置文件。可以看到有一个DefaultServlet,它是专用用来处理静态资源的请求的。仔细看,你会发现它的url-pattern就是/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!--
DefaultServlet会应用于所有的tomcat项目,用于处理静态资源请求。
哪些资源是静态资源呢?简单地讲,除了jsp/servlet(jsp本质还是servlet),其它的资源都是静态资源

DefaultServlet是如何处理静态资源的请求呢?以用户访问index.html为例
DefaultServlet会在服务器下找到index.html这个资源,并返回给用户
-->
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

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

如果我们给DispatcherServleturl-pattern也配置/,相当于禁用了DefaultServlet,静态资源也交给DispatcherServlet去处理。用户访问/index.htmlDispatcherServlet会去找哪个Controller的RequestMapping能够匹配/index.html,如果没有匹配,用户就无法访问/index.html

那为什么用户可以直接访问jsp页面呢?再查看tomcat服务器的全局web.xml,可以看到有一个名为jsp的servlet,它会拦截所有的jsp请求,渲染jsp页面返回给用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>

5.2. 修改

修改为/*

1
2
3
4
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>

访问Controller对应的/hello,输出以下警告,说

1
2
警告 [http-nio-8080-exec-6] 
org.springframework.web.servlet.DispatcherServlet.noHandlerFound No mapping for GET /WEB-INF/jsp/index.jsp

panchaoxin wechat
关注我的公众号
支持一下