SpringMVC内部工作流程
SpringMVC 的内部工作流程可以分为以下几个步骤:
- 用户请求:用户通过浏览器发送一个 HTTP 请求到服务器。
- DispatcherServlet:请求首先到达 DispatcherServlet,这是 SpringMVC 的核心组件。它负责将请求分发到相应的处理器。
- HandlerMapping:DispatcherServlet 调用 HandlerMapping 来确定哪个 Controller 处理这个请求。HandlerMapping 根据请求的 URL 找到合适的 Controller。
- Controller:找到合适的 Controller 后,DispatcherServlet 将请求转发给这个 Controller。Controller 处理请求,调用业务逻辑(Model),并返回视图名和模型数据。
- Model:Controller 调用 Model 来处理数据,并将结果返回给视图。Model 包含应用程序的数据和业务逻辑。
- ViewResolver:DispatcherServlet 调用 ViewResolver 将视图名解析为实际的视图对象。ViewResolver 根据视图名找到相应的视图模板,并将模型数据传递给视图。
- View:视图对象生成最终的 HTML 页面,并将其返回给用户。视图负责将模型数据展示给用户,通常是 JSP、Thymeleaf 等模板引擎生成的 HTML 页面。
- 响应用户:最终生成的 HTML 页面通过 HTTP 响应返回给用户的浏览器,用户可以看到处理后的结果。
下面是一个 springmvc 的例子
作为父工程,我们先删除 src,再编辑它的依赖
导入springmvc需要的依赖
web servlet
ioc spring-context
mvc spring-webmvc
<!--
导入springmvc需要的依赖
web servlet
ioc spring-context
mvc spring-webmvc
-->
<properties>
<spring.version>6.0.6</spring.version>
<servlet.api>9.1.0</servlet.api>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- springioc相关依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- web相关依赖 -->
<!-- 在 pom.xml 中引入 Jakarta EE Web API 的依赖 -->
<!--
在 Spring Web MVC 6 中,Servlet API 迁移到了 Jakarta EE API,因此在配置 DispatcherServlet 时需要使用
Jakarta EE 提供的相应类库和命名空间。错误信息 “‘org.springframework.web.servlet.DispatcherServlet’
is not assignable to ‘javax.servlet.Servlet,jakarta.servlet.Servlet’” 表明你使用了旧版本的
Servlet API,没有更新到 Jakarta EE 规范。
-->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId>
<version>${servlet.api}</version>
<scope>provided</scope>
</dependency>
<!-- springwebmvc相关依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
(完整的配置文件)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.eu.adouzi</groupId>
<artifactId>ssm-springmvc-part</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<!--
导入springmvc需要的依赖
web servlet
ioc spring-context
mvc spring-webmvc
-->
<properties>
<spring.version>6.0.6</spring.version>
<servlet.api>9.1.0</servlet.api>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- springioc相关依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- web相关依赖 -->
<!-- 在 pom.xml 中引入 Jakarta EE Web API 的依赖 -->
<!--
在 Spring Web MVC 6 中,Servlet API 迁移到了 Jakarta EE API,因此在配置 DispatcherServlet 时需要使用
Jakarta EE 提供的相应类库和命名空间。错误信息 “‘org.springframework.web.servlet.DispatcherServlet’
is not assignable to ‘javax.servlet.Servlet,jakarta.servlet.Servlet’” 表明你使用了旧版本的
Servlet API,没有更新到 Jakarta EE 规范。
-->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId>
<version>${servlet.api}</version>
<scope>provided</scope>
</dependency>
<!-- springwebmvc相关依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</project>
新建一个模块,使用插件将它转化成 web 工程
新建类HelloControll
package org.eu.adouzi.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* Hello 控制器
*
* @author shiraayano
* @date 2025/01/10 21:01
*/
@Controller
public class HelloController {
/**
* 你好
*
* @return {@link String}
*/
//定义handler
//handler -> spring/hello return "hello"
@RequestMapping("springmvc/hello")//对外访问的地址 也是到handler注册的注解
@ResponseBody//直接然会字符串给前端,不找字符解析器
public String hello() {
System.out.println("hello handler method is running...");
return "hello";
//hello会返回给前端
}
}
创建 config 包,在包下创建配置类 MvcConfig
package org.eu.adouzi.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
/**
* MVC 配置
*
* @author shiraayano
* @date 2025/01/10 21:15
*
* 将controller扫描到spring容器中
* 将handlerMapping handlerAdapter 扫描到spring容器中
*/
@Configuration
@ComponentScan("org.eu.adouzi.controller")
public class MvcConfig {
@Bean
public RequestMappingHandlerMapping handlerMapping(){
return new RequestMappingHandlerMapping();
}
@Bean
public RequestMappingHandlerAdapter handlerAdapter(){
return new RequestMappingHandlerAdapter();
}
}
SpringMVC 对外提供有接口是替代 web.xml
创建SpringMvcInit 类
生成实现方法
package org.eu.adouzi.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
* Spring MVC 初始化
*
* @author shiraayano
* @date 2025/01/10 21:27
*/
public class SpringMvcInit extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* 获取根配置类
*
* @return {@link Class<?>[]}
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
/**
* 获取 Servlet 配置类
*
* @return {@link Class<?>[]}
*/
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[0];
}
/**
* 获取 Servlet 映射
*
* @return {@link String[]}
*/
@Override
protected String[] getServletMappings() {
return new String[0];
}
}
package org.eu.adouzi.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
* Spring MVC 初始化
*
* @author shiraayano
* @date 2025/01/10 21:27
*/
public class SpringMvcInit extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* 获取根配置类
*
* @return {@link Class<?>[]}
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
/**
* 获取 Servlet 配置类
*
* @return {@link Class<?>[]}
*/
//设置我们项目对应的配置类
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {MvcConfig.class};
}
/**
* 获取 Servlet 映射
*
* @return {@link String[]}
*/
//配置springmvc内部自带的servlet的访问地址
@Override
protected String[] getServletMappings() {
return new String[]{"/"};//允许全部
}
}
编辑运行调试配置,添加 tomcat
部署项目
运行...报错
看起来像是 jdk 版本高了
总结
1.正常申明 Controller 方法
package org.eu.adouzi.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* Hello 控制器
*
* @author shiraayano
* @date 2025/01/10 21:01
*/
@Controller
public class HelloController {
/**
* 你好
*
* @return {@link String}
*/
//定义handler
//handler -> spring/hello return "hello"
@RequestMapping("springmvc/hello")//对外访问的地址 也是到handler注册的注解
@ResponseBody//直接然会字符串给前端,不找字符解析器
public String HelloController() {
System.out.println("hello handler method is running...");
return "hello";
//hello会返回给前端
}
}
2.写一个配置类,指定 HandlerMapping 和 HandlerAdapter,以及将 Handler 对应的 Controller 放入 ioc 容器
package org.eu.adouzi.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
/**
* MVC 配置
*
* @author shiraayano
* @date 2025/01/10 21:15
*
* 将controller扫描到spring容器中
* 将handlerMapping handlerAdapter 扫描到spring容器中
*/
@Configuration
@ComponentScan("org.eu.adouzi.controller")
public class MvcConfig {
@Bean
public RequestMappingHandlerMapping handlerMapping(){
return new RequestMappingHandlerMapping();
}
@Bean
public RequestMappingHandlerAdapter handlerAdapter(){
return new RequestMappingHandlerAdapter();
}
}
3.按照 springmvc 的约定固定写一个类去继承 AbstractAnnotationConfigDispatcherServletInitializer
(只要继承这个类,项目启动的时候就会被加载)
package org.eu.adouzi.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
* Spring MVC 初始化
*
* @author shiraayano
* @date 2025/01/10 21:27
*/
public class SpringMvcInit extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* 获取根配置类
*
* @return {@link Class<?>[]}
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
/**
* 获取 Servlet 配置类
*
* @return {@link Class<?>[]}
*/
//设置我们项目对应的配置类
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {MvcConfig.class};
}
/**
* 获取 Servlet 映射
*
* @return {@link String[]}
*/
//配置springmvc内部自带的servlet的访问地址 (设置拦截路径)
@Override
protected String[] getServletMappings() {
return new String[]{"/"};//拦截全部
}
}