spring MVC执行流程

详细的项目结构

src
├── main
│   ├── java
│   │   ├── com.example
│   │   │   ├── config
│   │   │   │   └── SpringMvcInitializer.java      // 配置 DispatcherServlet
│   │   │   │   └── SpringConfig.java             // Spring MVC 配置
│   │   │   ├── controller
│   │   │   │   └── UserController.java           // 控制器,返回 JSON
│   │   │   ├── service
│   │   │   │   └── UserService.java              // 服务层,处理业务逻辑
│   │   │   └── model
│   │   │   │   └── User.java                     // 数据模型
│   └── webapp
│       └── WEB-INF
│           └── web.xml(可选,可省略)
  • 注意:我们不再需要 views 文件夹和 userInfo.jsp,因为不再渲染 HTML 页面。

详细代码实现(每个步骤对应之前的流程)

1. HTTP 请求(1. http请求)
  • 描述:用户通过浏览器、Postman 或其他客户端发送 GET /user/info?id=1 到服务器,请求用户信息。
  • 细节:请求可以是 HTTP GET 方法,URL 包含查询参数 id,期望返回 JSON 格式的数据。
  • 测试方式
    • 使用 Postman:设置请求方法为 GET,URL 为 http://localhost:8080/user/info?id=1,Headers 中可添加 Accept: application/json
    • 浏览器直接访问(需要确保服务器支持 JSON 响应)。
  • 通俗解释:就像你在餐厅点了一份外卖,期望收到菜的配方(JSON 数据)而不是直接上菜(HTML 页面)。

2. DispatcherServlet 接收请求(2. 寻找控制器)
  • 描述DispatcherServlet 作为 Spring MVC 的核心控制器,接收 HTTP 请求,并分发到合适的处理器。
  • 配置细节:我们使用 AbstractAnnotationConfigDispatcherServletInitializer 替代传统 web.xml,确保 DispatcherServlet 加载 SpringConfig 配置。
  • 代码SpringMvcInitializer.java):
    package com.example.config;
    
    import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
    
    public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
        @Override
        protected Class<?>[] getRootConfigClasses() {
            // 根应用上下文配置(这里可以用于其他非 MVC 的配置,如数据源)
            return null;
        }
    
        @Override
        protected Class<?>[] getServletConfigClasses() {
            // 指定 Spring MVC 配置类
            return new Class<?>[] { SpringConfig.class };
        }
    
        @Override
        protected String[] getServletMappings() {
            // 所有请求(/)都由 DispatcherServlet 处理
            return new String[] { "/" };
        }
    }
    
  • 注意事项
    • getServletMappings 中的 "/" 表示拦截所有请求(包括静态资源),如果需要处理静态资源(如 CSS、JS),需要额外配置(见后文)。
    • 确保项目部署到支持 Servlet 3.0+ 的容器(如 Tomcat 8+)。
  • 通俗解释:服务员(DispatcherServlet)在餐厅入口接单,准备分发到后厨(Controller)。

3. HandlerMapping 匹配处理器(3. 调用控制器)
  • 描述DispatcherServlet 调用 HandlerMapping(通常是 RequestMappingHandlerMapping),根据 URL /user/info 找到 UserControllergetUserInfo 方法。
  • 配置细节@EnableWebMvc 自动启用 RequestMappingHandlerMapping,无需额外配置。
  • 代码UserController.java):
    package com.example.controller;
    
    import com.example.model.User;
    import com.example.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController // 标记为 REST 控制器,自动返回 JSON,无需视图
    public class UserController {
        @Autowired
        private UserService userService;
    
        @GetMapping("/user/info") // 处理 GET 请求,路径为 /user/info
        public User getUserInfo(@RequestParam("id") int id) {
            // 调用服务层查询用户信息
            User user = userService.getUserById(id);
            return user; // 直接返回 User 对象,Spring 自动转换为 JSON
        }
    }
    
  • 注意事项
    • @RestController 结合 @GetMapping 简洁地定义了 REST API,@RequestParam 绑定 URL 参数 id
    • Spring 依赖 Jackson 库将 User 对象序列化为 JSON,确保项目有 jackson-databind 依赖。
  • 通俗解释:服务员(DispatcherServlet)问前台(HandlerMapping):“这单谁做?”前台说:“交给这个厨师(UserController)处理,返回菜的配方(JSON)。”

4. Controller 处理请求并返回数据(4. 调用业务逻辑进行处理)
  • 描述UserController 调用 UserService 执行业务逻辑,模拟查询用户信息,返回 User 对象。
  • 代码UserService.javaUser.java):
    // User.java(模型类,优化为支持 JSON 序列化)
    package com.example.model;
    
    import com.fasterxml.jackson.annotation.JsonProperty; // 可选,用于自定义 JSON 字段名
    
    public class User {
        private String name;
        private int age;
    
        // 无参构造(Jackson 要求,用于反序列化)
        public User() {}
    
        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        @JsonProperty("name") // 可选,指定 JSON 字段名
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
    
        @JsonProperty("age")
        public int getAge() { return age; }
        public void setAge(int age) { this.age = age; }
    
        @Override
        public String toString() {
            return "User{name='" + name + "', age=" + age + "}";
        }
    }
    
    // UserService.java(服务层,模拟业务逻辑)
    package com.example.service;
    
    import com.example.model.User;
    import org.springframework.stereotype.Service;
    
    @Service
    public class UserService {
        public User getUserById(int id) {
            // 模拟从数据库查询,实际项目中可能用 JPA、MyBatis 或 JDBC
            return new User("User" + id, 20 + id);
        }
    }
    
  • 注意事项
    • User 类添加了无参构造和 getter/setter 方法,以支持 Jackson 的 JSON 序列化/反序列化。
    • @JsonProperty 是可选的,用于自定义 JSON 字段名(如将 name 映射为 userName)。
    • @Service 注解使 UserService 成为 Spring Bean,可通过 @Autowired 自动注入。
  • 通俗解释:厨师(Controller)叫助手(UserService)查菜谱(数据库),炒好一道菜(User 数据),打包成 JSON 配方返回。

5. DispatcherServlet 接收数据(5. 视图处理结果)
  • 描述DispatcherServlet 接收 User 对象,并通过 Spring 的 HttpMessageConverter(默认使用 MappingJackson2HttpMessageConverter)将其转换为 JSON 格式。
  • 细节:Spring 自动检测返回的 User 对象类型,使用 Jackson 库序列化为 JSON,并设置 HTTP 响应头 Content-Type: application/json
  • 代码:无额外代码,DispatcherServlet 内部处理。
  • 注意事项
    • 确保 pom.xml 中有 jackson-databind 依赖,否则 Spring 无法序列化 JSON。
    • 如果 JSON 格式需要自定义(如日期格式、忽略某些字段),可配置 ObjectMapper
  • 通俗解释:服务员(DispatcherServlet)拿到菜的配方(User 对象),用打印机(HttpMessageConverter)打印成 JSON 格式。

6. 移除 ViewResolver(6. 视图模板解析)
  • 描述:因为我们不再返回 HTML 页面,移除 ViewResolver 和 JSP 相关配置。
  • 代码SpringConfig.java):
    package com.example.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.EnableWebMvc;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration
    @EnableWebMvc
    @ComponentScan(basePackages = "com.example")
    public class SpringConfig implements WebMvcConfigurer {
        // 移除 ViewResolver Bean,因为我们直接返回 JSON
        // 如果需要处理静态资源,可以在这里添加配置
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/resources/**")
                    .addResourceLocations("classpath:/static/");
        }
    }
    
  • 注意事项
    • @EnableWebMvc 启用了 Spring MVC 的所有功能,但默认禁用了 Spring Boot 的自动静态资源处理。如果需要静态资源(如 CSS、JS),需手动配置 addResourceHandlers
    • 移除 ViewResolver 后,Spring 专注于 REST API,不再处理视图模板。
  • 通俗解释:服务员发现不需要盘子(JSP),直接把菜的配方(JSON)打包送出。

7. 返回 JSON 数据(7. 数据直接返回)
  • 描述User 对象被序列化为 JSON,返回给客户端。最终响应为:
    {
        "name": "User1",
        "age": 21
    }
    
  • 细节
    • Spring 使用 MappingJackson2HttpMessageConverter 进行序列化。
    • 返回的 HTTP 状态码默认是 200 OK。
    • 如果需要自定义 JSON 格式(如日期、字段过滤),可以配置 ObjectMapper
      @Bean
      public ObjectMapper objectMapper() {
          ObjectMapper mapper = new ObjectMapper();
          mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
          return mapper;
      }
      
  • 代码:已在 UserController.java 中实现。
  • 通俗解释:服务员把菜的配方(JSON)直接交给送餐员(客户端),不需要装盘(HTML)。

8. 返回 HTTP 响应(8. http响应)
  • 描述:客户端(浏览器、Postman)收到 JSON 数据,可以解析或显示。
  • 细节
    • 响应头包括 Content-Type: application/json; charset=UTF-8
    • 如果客户端是 Postman,JSON 数据直接显示;如果是浏览器,可能需要插件(如 JSONView)格式化显示。
  • 测试验证
    1. 打开 Postman,设置请求方法为 GET,URL 为 http://localhost:8080/user/info?id=1
    2. 点击发送,查看响应:
      {
          "name": "User1",
          "age": 21
      }
      
    3. 确保服务正常运行,依赖配置正确。
  • 通俗解释:送餐员(客户端)收到菜的配方(JSON),可以直接查看或用在其他地方。

完整依赖配置(Maven 示例)

确保 pom.xml 包含以下依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.14.0</version>
    </dependency>
    <dependency>
        <groupId>jakarta.servlet</groupId>
        <artifactId>jakarta.servlet-api</artifactId>
        <version>6.0.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>
  • 说明jackson-databind 是 JSON 序列化/反序列化的核心库,确保版本兼容 Spring。

可能扩展和注意事项

  1. 参数验证

    • 可以使用 @Valid@NotNull 验证 id 参数:
      @GetMapping("/user/info")
      public User getUserInfo(@RequestParam @NotNull int id) {
          return userService.getUserById(id);
      }
      
      需要添加 hibernate-validator 依赖:
      <dependency>
          <groupId>org.hibernate.validator</groupId>
          <artifactId>hibernate-validator</artifactId>
          <version>6.2.5.Final</version>
      </dependency>
      
  2. 异常处理

    • 可以使用 @ExceptionHandler@ControllerAdvice 处理异常:
      @ControllerAdvice
      public class GlobalExceptionHandler {
          @ExceptionHandler(Exception.class)
          @ResponseBody
          public Map<String, Object> handleException(Exception e) {
              Map<String, Object> result = new HashMap<>();
              result.put("error", "Internal Server Error");
              result.put("message", e.getMessage());
              return result;
          }
      }
      
  3. 跨域支持(CORS)

    • 如果前端在不同域名,需配置 CORS:
      @Configuration
      public class SpringConfig implements WebMvcConfigurer {
          @Override
          public void addCorsMappings(CorsRegistry registry) {
              registry.addMapping("/**")
                      .allowedOrigins("http://localhost:3000") // 允许的源
                      .allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的方法
                      .allowedHeaders("*"); // 允许的头
          }
      }
      
  4. 性能优化

    • 可以使用 @Cacheable 缓存查询结果:
      @Service
      public class UserService {
          @Cacheable("users")
          public User getUserById(int id) {
              return new User("User" + id, 20 + id);
          }
      }
      
      需要添加 spring-boot-starter-cachespring-context-support 依赖。
  5. 静态资源处理

    • 如果需要静态资源(如 CSS、JS),在 SpringConfig 中配置:
      @Override
      public void addResourceHandlers(ResourceHandlerRegistry registry) {
          registry.addResourceHandler("/resources/**")
                  .addResourceLocations("classpath:/static/")
                  .setCachePeriod(3600); // 缓存 1 小时
      }
      

对应图中的流程变化(更详细)

  • 原图中的 ViewResolverView(HTML/FTL) 被移除,因为我们直接返回 JSON。
  • 新流程简化为:
    1. HTTP 请求 → DispatcherServlet
    2. DispatcherServletHandlerMappingUserController
    3. UserController 调用 UserService → 返回 User 对象
    4. DispatcherServlet 转换 User 为 JSON → 返回 HTTP 响应

运行和测试

  1. 运行环境

    • 使用 JDK 11 或更高版本。
    • 部署到 Tomcat 8+ 或运行 Spring Boot 项目。
    • 确保 Maven 依赖下载完整。
  2. 测试

    • 使用 Postman 测试 GET http://localhost:8080/user/info?id=1
    • 预期响应:
      {
          "name": "User1",
          "age": 21
      }
      
  3. 调试

    • 检查日志,确保 DispatcherServletHandlerMappingHttpMessageConverter 正常工作。
    • 如果 JSON 格式错误,检查 User 类是否有无参构造、getter/setter。

总结

通过上述详细修改,我们将 Spring MVC 从返回 JSP 页面改为返回 JSON 数据,适合 RESTful API 开发。我补充了技术细节(如 Jackson 配置、参数验证、异常处理等)和代码注释,确保每个步骤清晰易懂。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/977512.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux中的cgdb的基本使用

1.cgdb的简介 Linux中的cgdb是一个基于GDB&#xff08;GNU Debugger&#xff09;的图形化调试前端&#xff0c;它结合了GDB的命令行界面功能和代码查看窗口&#xff0c;为开发者提供了一个更为直观的调试体验。 cgdb的作用和功能&#xff1a; 直观调试体验&#xff1a;cgdb提供…

欧拉回路与哈密尔顿回路: Fleury算法与Hierholzer 算法(C++)

图论中的回路是指一个路径, 它从某个顶点开始, 经过所有边恰好一次, 并回到起始顶点. 定义 欧拉回路: 从一个顶点出发, 经过每条边恰好一次, 并且最终回到起始顶点. 哈密尔顿回路: 从一个顶点出发, 经过每个顶点恰好一次, 并且最终回到起始顶点. 欧拉路径: 从一个顶点出发, …

数据结构 之 【无头单向非循环链表】(C语言实现)

下面将 无头单向非循环链表 简称为 单链表 头指针&#xff1a;指向链表第一个节点的指针 链表为空时&#xff0c;头指针也为空 要实现单链表&#xff0c;就是要实现单链表的 增删查改 一、无头单向非循环链表的c语言实现 1.准备工作 #include <stdio.h> #include <s…

傅里叶变换+注意力机制!CCF-A离你并不遥远!

今天给大家推荐一个&#xff0c;创新Top且热度持续攀升的方向&#xff1a;傅里叶变换注意力机制&#xff01; 傅里叶变换能够捕捉到频域的特征&#xff0c;而注意力机制则能使模型专注任务相关信息。两者结合&#xff0c;不仅能提升模型的性能和效率&#xff0c;还能增强模型的…

【学习笔记】计算机网络(四)

第4章 网络层 文章目录 第4章 网络层4.1 网络层的几个重要概念4.1.1 网络层提供的两种服务虚电路服务&#xff08;Virtual Circuit Service&#xff09;数据报服务&#xff08;Datagram Service&#xff09; 4.1.2 网络层的两个层面 4.2 网际协议 IP - IPv44.2.1 虚拟互连网络4…

Ollama部署本地大模型DeepSeek-R1-Distill-Llama-70B

文章目录 一、下模二、转模1. 下载转换工具2. 安装环境依赖3. llama.cpp1. 转换脚本依赖2. llama.cpp安装依赖包3. llama.cpp编译安装4. 格式转换 三、Ollama部署1. 安装启动Ollama2. 添加模型3. 测试运行 一、下模 #模型下载 from modelscope import snapshot_download model…

【GPT】从GPT1到GPT3

every blog every motto: Although the world is full of suffering&#xff0c; it is full also of the overcoming of it 0. 前言 从GPT1 到GPT3 1. GPT1 论文&#xff1a; https://s3-us-west-2.amazonaws.com/openai-assets/research-covers/language-unsupervised/lan…

stm32使用(无线串口)实现收发、判断数据+DMA(HAL库)

目录 前言&#xff1a; 1. 用CubeMX配置串口DMA所需要的环境 &#xff08;1&#xff09;打开CubeMAX&#xff0c;点击红框 &#xff08;2&#xff09;查找stm32F103C8T6的芯片 &#xff08;3&#xff09;配置SYS &#xff08;4&#xff09;配置RCC时钟 &#xff08;5&am…

QT入门--QMainWindow

从上向下依次是菜单栏&#xff0c;工具栏&#xff0c;铆接部件&#xff08;浮动窗口&#xff09;&#xff0c;状态栏&#xff0c;中心部件 菜单栏 创建菜单栏 QMenuBar* mybar1 menuBar(); 将菜单栏放到窗口中 setMenuBar(mybar1); 创建菜单 QMenu *myfilemenu mybar1-…

重构清洁想象,石头科技首创五轴仿生机械手打破传统清洁边界

2月25日&#xff0c;主题为“重构清洁想象”的石头科技2025发布会在上海天文馆正式召开。石头科技清洁产品BU总裁钱启杰在会上宣布&#xff0c;石头科技正式成为上海天文馆授权合作伙伴&#xff0c;希望借助航天科技到家庭科技的跨越&#xff0c;进一步简化家庭清洁工作&#x…

Amazon Outposts:构建混合云的安全堡垒,让数据安全“零距离”

在数字化转型的浪潮中&#xff0c;企业纷纷拥抱混合云架构以兼顾敏捷性与本地化需求。然而&#xff0c;如何确保数据在本地与云端的无缝流转中始终安全可控&#xff0c;成为企业面临的核心挑战。Amazon Outposts 作为AWS推出的混合云解决方案&#xff0c;不仅将原生AWS服务延伸…

详解Redis如何持久化

引言 本文介绍了 Redis 的两种持久化方式&#xff1a;RDB 和 AOF。RDB 按时间间隔快照存储&#xff0c;AOF 记录写操作。阐述了它们的配置、工作原理、恢复数据的方法、性能与实践建议&#xff0c;如降低 fork 频率、控制内存等&#xff0c;还提到二者可配合使用&#xff0c;最…

【Ambari】Ranger KMS

目录 一、Ranger KMS介绍 二、KMS基于Ranger插件安装 一、Ranger KMS介绍 Ranger KMS是把数据存储入后台数据库中。通过Ranger Admin可以集中化管理KMS服务。 Ranger KMS有三个优点 l Key management Ranger admin 提供了创建&#xff0c;更新&#xff0c;删除密钥的Web UI…

vscode设置终端复制快捷键(有坑!!!)

vscode的编辑页面和终端的复制粘贴快捷键是不一样的。 vscode的终端复制快捷键为ctrlshiftC&#xff0c;当然&#xff0c;自己可以自定义设置 vscode设置终端复制快捷键&#xff08;有坑&#xff01;&#xff01;&#xff01;&#xff09;_vs code 不能复制-CSDN博客文章浏览…

angular舒尔特方格

说明&#xff1a;我计划用angular实现舒尔特方格的功能&#xff0c;必须是动态的&#xff0c;比如33&#xff0c;55&#xff0c;9*9&#xff0c;而且无论是什么样式的&#xff0c;都必须保持正方形&#xff0c;然后还有时间监听&#xff0c;计算用户完成方格的时间&#xff0c;…

提升数据洞察力:五款报表软件助力企业智能决策

概述 随着数据量的激增和企业对决策支持需求的提升&#xff0c;报表软件已经成为现代企业管理中不可或缺的工具。这些软件能够帮助企业高效处理数据、生成报告&#xff0c;并将数据可视化&#xff0c;从而推动更智能的决策过程。 1. 山海鲸报表 概述&#xff1a; 山海鲸报表…

DistilQwen2.5发布:通义千问蒸馏小模型再升级

01 引言 因高计算成本和复杂性&#xff0c;在例如移动设备和边缘计算场景等资源有限的环境中&#xff0c;限制了大语言模型的普及。如何在保留模型性能的同时提高计算效率并降低部署成本&#xff0c;已成为研究和工业界必须面对的关键挑战。 在此背景下&#xff0c;我们正式…

VS2022配置FFMPEG库基础教程

1 简介 1.1 起源与发展历程 FFmpeg诞生于2000年&#xff0c;由法国工程师Fabrice Bellard主导开发&#xff0c;其名称源自"Fast Forward MPEG"&#xff0c;初期定位为多媒体编解码工具。2004年后由Michael Niedermayer接任维护&#xff0c;逐步发展成为包含音视频采…

【前端基础】Day 1 HTML

总结&#xff1a; 1. Web标准的构成 2. 基本标签 目录 1. Web标准的构成 2. 基本标签 2.1快捷键 2.2.1标题标签 2.2.2段落和换行标签 2.2.3文本格式化标签 2.2.4div和span标签 2.3.1 图像标签和路径 2.3.2路径 2.3.3超链接标签 2.4注释标签 2.5特殊字符 1. Web标准…

Android Realm数据库使用与集成指南

本地存储storage集成创建Realm数据模型插入和更新数据模型数据查询统计数据分页查询处理表数据删除操作总结Realm 是一款专为移动端和嵌入式场景设计的高性能、跨平台的 对象数据库(NoSQL),由 MongoDB 团队维护。它的核心思想是将数据模型直接映射到对象(如 Java/Kotlin、S…