【SSM】SSM之SpringMVC框架:SpringMVC一个请求执行过程

一个简单的SpringMVC程序:

我们先通过创建一个简单的动态的JavaWeb项目“springmvc01”来认识一下SpringMVC,这样方便我们对其进行分析。

1、拷贝jar包:

对于所有框架而言,这一步都是必不可少的,我们需要在web工程的“WEB-INF”的目录下的lib文件夹中拷贝下列jar包,由于SpringMVC是spring家族的,使用它就必不可少的要拷贝spring框架的jar包:

  • a.Spring框架的jar包:
    在这里插入图片描述
  • b.Spring框架的依赖包:
    在这里插入图片描述
  • c.SpringMVC框架的jar包:
    在这里插入图片描述
  • d.SpringMVC框架的依赖包:
    在这里插入图片描述
2、创建一个JSP视图:

在“WEB-INF”目录下新建一个文件夹“jsp”用于存放JSP视图,在此目录下的视图非常安全,只能通过请求转发的方式访问。我们在此创建一个视图“hello.jsp”,该视图用于在浏览器客户端响应给用户。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Hello</title>
	</head>
	<body>
		Hello SpringMVC
	</body>
</html>
3、定义一个控制器Controller:

这一步是SpringMVC框架的集中体现,之前众多Servlet现在都可以写在一个类(控制器)中,大大的简化了代码。我们在src目录下新建一个包“cn.jingpengchong.hello.controller”,在该包中新建一个类HelloController:

package cn.jingpengchong.hello.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HelloController {

	@RequestMapping("hello")
	public String hello() {
		return "hello";
	}
}
  • @Controller:添加该注解后该类可以被Spring扫描器到,并且告诉Spring该类是一个控制器;
  • @RequestMapping():该注解用于使处理器映射器将其value属性值与请求地址进行匹配,以确定应该执行的方法;
4、配置spring的xml核心配置文件:

在spring的xml核心配置文件中配置一个扫描器,用于将自定义的处理器HelloController交给Spring来管理;除此之外还需要配置一个视图解析器InternalResourceViewResolver,用来将请求匹配到的处理器返回的字符串解析成真正的请求路径:

<?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"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">

	<!-- 配置controller包扫描 -->
	<context:component-scan base-package="cn.jingpengchong.hello"></context:component-scan>
	<!-- 配置视图解析器:这个配置可以简化控制器中返回的请求路径 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<!-- 将接受的url路径片段字符串拼接上前缀 -->
		<property name="prefix" value="/WEB-INF/jsp/"/>
		<!-- 将接受的url路径片段字符串拼接上后缀 -->
		<property name="suffix" value=".jsp"/>
	</bean>
</beans>
5、配置web.xml核心配置文件:

要发挥控制器的作用,在这里需要配置核心控制器(或称前端控制器),并且设置哪些请求路径会被匹配到并进行处理:

<?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">
  <display-name>springmvc01</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  
  <!--  核心控制器的配置 -->
	<servlet>
		<servlet-name>springmvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!-- DispatcherServlet继承了父类FrameworkServlet的contextConfigLocation属性,因此这里可以给个初始值 -->
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:springmvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>springmvc</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
</web-app>
6、测试:

将此项目添加进tomcat服务器并启动tomcat服务器,打开浏览器,并在地址栏输入“http://127.0.0.1/springmvc01/hello.do”后回车,结果如下:
在这里插入图片描述

请求的执行过程:
1、从在地址栏输入“http://127.0.0.1/springmvc01/hello.do”并回车,发送请求;

在这里插入图片描述

2、首先找到web.xml文件:

用于该请求以“.do”结尾,所以被url-pattern标签匹配到,然后根据servlet-name标签找到核心处理器“DispatcherServlet”。
在这里插入图片描述

3、然后找到springmvc.xml文件:

为核心处理器“DispatcherServlet”初始化contextConfigLocation属性时找到springmvc.xml文件。
在这里插入图片描述

4、然后找到HelloController.java文件:

由于springmvc.xml文件中配置了Spring扫描器,扫描器会去“cn.jingpengchong.hello”包下逐一查找添加了特定注解的类,由于类HelloController添加了@Controller注解,所以便被扫描到,并且根据该注解断定该类是一个处理器。
在这里插入图片描述
在这里插入图片描述

5、DispatcherServlet内部代码流程:

我们知道一个请求被servlet捕获后必定会调用service方法,由service方法根据请求类别再调用doGet或doPost方法,对于DispatcherServlet也是一样。而由于DispatcherServlet没有重写其父类FrameworkServlet的service方法,因此请求必定会执行FrameworkServlet中的service():
在这里插入图片描述
由于“HttpMethod.PATCH == httpMethod || httpMethod == null”的返回值时false,所以调用了父类的service()方法,在其父类的service()方法中,发现其又执行了doGet()方法:
在这里插入图片描述
由于FrameworkService类中重写了doGet()方法,所以执行到了FrameworkService类中的doGet()方法:
在这里插入图片描述
在该方法中又执行了processRequest()方法,在processRequest()方法中又执行了doService()方法:
在这里插入图片描述
我们发现doService()方法发现其是一个抽象方法,既然是一个抽象方法,那么该类的子类必定有实现该方法的,恰巧DispatcherServlet类就是FrameworkServlet类的子类,我们点开该方法的实现,发现DispatcherServlet确实实现了该方法,那么当执行doService()方法时必定是执行DispatcherServlet类中的doService()方法了,向下执行,发现确实执行到了DispatcherServlet类中的doService()方法,并且在该方法中执行了doDispatch()方法:
在这里插入图片描述
在doDispatch()方法中,发现里面通过getHandler()方法获得了一个处理器映射器,该映射器获得了将要被执行的HelloController类中的hello()方法:
在这里插入图片描述
接着向下走,发现其又获得了一个处理器适配器,并且将处理器映射器获得的hello()方法交给该处理器适配器执行:
在这里插入图片描述
接着向下执行,到了processDispatchResult()方法:
在这里插入图片描述
在processDispatchResult()方法中又执行了render()方法:
在这里插入图片描述
在render()方法中又获得了一个View类的实例化对象,并调用了该对象的render()方法:
在这里插入图片描述
接着向下执行,发现View的render()方法其实是View的子类AbstractView中实现的方法:
在这里插入图片描述
在该方法中又执行了renderMergedOutputModel()方法:
在这里插入图片描述
接着向下执行,发现renderMergedOutputModel()方法其实是AbstractView的子类InternalResourceView中的方法:
在这里插入图片描述
在renderMergedOutputModel()方法中获得了一个RequestDispatcher类对象:
在这里插入图片描述
接着向下执行,发现在方法的最后调用了该对象的forward()方法,此时RequestDispatcher的实例化对象rd中已经有了响应的完整路径:
在这里插入图片描述
我们在学习Servlet时就知道了“request.getRequestDispatcher(“路径”).forward(request, response);”是一个请求转发,可见在SpringMVC中,控制器处理请求后默认是用请求转发来响应页面给用户的!为了进一步验证我们的观点,我们不妨对HelloController类中的hello()方法做一些改造,直接让它以请求转发的方式响应给用户:

@RequestMapping("hello")
public String hello() {
	return "forward:/WEB-INF/jsp/hello.jsp";
}

再次发送同样的请求,我们发现,效果真实一样的!
在这里插入图片描述
那么用重定向的方式可以响应吗?我们试一下:

@RequestMapping("hello")
public String hello() {
	return "redirect:/WEB-INF/jsp/hello.jsp";
}

在这里插入图片描述
从上面的图中可以发现,重定向是不可以的,这也是为什么在WEB-INF目录下的jsp页面是安全的了,因为在该目录下的资源只能通过请求转发的方式访问!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值