SpringMVC 核心组件与工作流程全解析

Pybullet及仿真环境测试 pybullet仿真 阅读详情

1. SpringMVC:为什么它是Java Web开发的“交通枢纽”?

如果你刚开始接触Java Web开发,可能会被各种框架搞得眼花缭乱。我刚开始学的时候,也觉得SpringMVC这个名字听起来很“高大上”,好像是什么深奥的架构。但后来用多了才发现,它其实就像一个城市里的“交通指挥中心”。想象一下,一个城市每天有成千上万的车辆(HTTP请求)从四面八方涌来,如果没有一个高效的交通指挥系统(SpringMVC),整个城市就会陷入瘫痪和混乱。SpringMVC就是这个指挥中心,它负责接收所有进城的车辆(请求),然后根据车辆的目的地(URL),快速、准确地把它们引导到对应的处理站(Controller方法),处理完后再把结果(响应)送回去。

那么,SpringMVC到底是什么呢?简单说,它是Spring家族中专门用来构建Web应用程序的模块。在经典的SSM(SpringMVC + Spring + MyBatis)组合里,它就扮演着“表现层”的角色,负责和用户的浏览器打交道。你可能会问,Servlet也能干这个活,为什么还要用框架?我刚开始也有这个疑问。后来一个项目里,我用纯Servlet写了个小功能,光是解析请求参数、处理响应、跳转页面就写了一堆重复代码,维护起来特别头疼。而SpringMVC把这些繁琐的“脏活累活”都封装好了,提供了清晰的分工和流程,让我们开发者只需要关注最核心的业务逻辑:收到什么数据,要做什么处理,最后返回什么结果。

它的核心设计思想源于经典的MVC模式,但做了更精细的组件化拆分。MVC大家应该不陌生,就是把一个应用分成三块:Model(模型,装数据)、View(视图,展示界面)、Controller(控制器,处理逻辑)。SpringMVC在这个基础上,把“控制器”这个角色又拆成了好几个专业组件,比如专门找路的HandlerMapping、专门干活的HandlerAdapter、专门解析视图的ViewResolver。这种“专业的人干专业的事”的设计,让整个请求处理流程像一条高效的流水线,每个环节职责单一,不仅性能好,而且特别容易扩展和维护。接下来,我们就钻进这个“指挥中心”内部,看看它的核心部件到底是怎么运转的。

2. 深入核心组件:拆解SpringMVC的“五脏六腑”

要理解SpringMVC怎么工作,光知道它是个“指挥中心”还不够,你得认识里面的关键“官员”和“部门”。这些组件各司其职,协同合作,构成了框架的骨架。我刚开始看源码的时候也是一头雾水,后来我把它们想象成一个公司里的不同岗位,一下子就清晰了。

2.1 总指挥:DispatcherServlet

这是整个框架的绝对核心,所有请求的入口和出口。它本质上就是一个Servlet,配置在web.xml里,会拦截你指定的所有请求(通常是/)。你可以把它理解为公司的“前台总机”或者“调度中心”。它自己不处理具体业务,但所有事情都得经过它。它的主要工作就三件:接收请求、协调调度、返回响应。当一个HTTP请求到达Tomcat服务器后,Tomcat会根据web.xml的配置,把匹配的请求统统交给DispatcherServlet来处理。我踩过的一个坑是,在web.xml里配置它的<url-pattern>时,新手容易写成/*.do,但实际上更常见的做法是配置成/,表示拦截所有请求(静态资源除外,这个后面会说),这样才能支持更灵活的URL风格,特别是RESTful API。

2.2 导航员:HandlerMapping

请求来了,DispatcherServlet第一个问题就是:“这个活该找谁干?” 这时候就需要HandlerMapping(处理器映射器)出场了。它的职责就是根据当前请求的URL,找到对应的处理器(Handler)。这个过程就像你用地图APP导航:输入目的地(URL),APP(HandlerMapping)帮你找到最佳的路线和终点(具体的Controller和方法)。SpringMVC提供了多种映射策略,比如基于注解的RequestMappingHandlerMapping(现在最常用),基于Bean名称的BeanNameUrlHandlerMapping,还有以前基于XML配置的SimpleUrlHandlerMapping。当你在一个Controller类的方法上写@RequestMapping("/user/login")时,RequestMappingHandlerMapping就会把这个注解信息注册到自己的“地图”里,建立URL和方法的对应关系。

2.3 执行者与适配器:Handler与HandlerAdapter

找到该谁干活(Handler)之后,下一个问题是怎么让他干。这里的Handler通常就是我们写的Controller中的某个方法。但是,Controller的方法千变万化,参数类型、返回值类型都可能不同。DispatcherServlet需要一个统一的方式来调用这些各异的方法。这就是HandlerAdapter(处理器适配器)存在的意义。适配器模式在这里得到了完美体现。HandlerAdapter就像一个“万能接口转换器”,它知道如何与特定类型的Handler打交道。比如,最常用的RequestMappingHandlerAdapter就知道如何去执行那些带有@RequestMapping注解的方法,它会负责解析方法参数(把HTTP请求里的参数自动绑定到方法的String、int、甚至自定义对象参数上),调用方法,再把方法的返回值(可能是个字符串"success",也可能是个ModelAndView对象)封装成一个统一的ModelAndView结构,交给后面的流程。

我遇到过一个问题,自定义了一个处理器,实现了Controller接口,但请求总是报404。排查了半天才发现,光有Handler还不行,还必须有一个能适配它的HandlerAdapter。默认情况下,开启注解驱动(<mvc:annotation-driven/>)会注册多个适配器,其中就包括能处理Controller接口的SimpleControllerHandlerAdapter。如果你用了很冷门的处理器类型,可能就需要自己配置对应的适配器了。

2.4 视图渲染师:ViewResolver与View

业务逻辑处理完了,生成了数据和视图名,接下来就要把结果展示给用户看了。ViewResolver(视图解析器)的任务是把控制器返回的逻辑视图名(比如"userInfo")解析成具体的视图对象(View)。这个过程可以理解为,经理说“把那份报告给我”,秘书(ViewResolver)需要知道报告是放在哪个文件夹、是什么格式的(是PDF还是Word),然后找到它。通常我们会配置一个InternalResourceViewResolver,并设置前缀(prefix)和后缀(suffix),例如前缀是/WEB-INF/views/,后缀是.jsp。那么当控制器返回"userInfo"时,ViewResolver就会把它解析成/WEB-INF/views/userInfo.jsp这个具体的JSP文件路径,并封装成一个JstlView对象。

最后,View接口负责真正的渲染工作。它拿到Model(其实就是一堆存在request域里的数据)和解析好的物理视图,进行合成。对于JSP视图,就是执行JSP页面,把Model中的数据用EL表达式${}展示出来;对于JSON视图,则是把数据序列化成JSON字符串写入响应体。SpringMVC支持多种视图技术,除了JSP,还有Thymeleaf、FreeMarker、PDF、Excel等,非常灵活。

3. 一次请求的完整旅程:图解SpringMVC工作流程

知道了每个部件是干嘛的,现在我们把他们串起来,看看一个HTTP请求从浏览器发出,到收到响应,在SpringMVC内部到底经历了怎样的“奇幻漂流”。这个过程是面试中的常客,也是理解框架精髓的关键。我画过无数遍这个流程图,每次都有新体会。

第一步:用户发起请求。 用户在浏览器输入http://yourdomain.com/app/user/login,点击提交。这个请求经过网络,到达我们的Web服务器(如Tomcat)。

第二步:DispatcherServlet拦截请求。 Tomcat根据web.xml的配置,发现所有以/app/开头的请求都应该由名为dispatcher的Servlet处理。于是,请求被转交给了DispatcherServlet的service()方法,最终会调用到doDispatch()这个核心调度方法。

第三步:寻找合适的处理器(Handler)。 DispatcherServlet拿着请求的URL(这里是/user/login),去问所有注册的HandlerMapping:“嘿,这个地址你们谁负责?” 通常,RequestMappingHandlerMapping会翻看自己维护的注解映射表,发现@RequestMapping("/user/login")对应的是UserController类的login方法。于是它返回一个HandlerExecutionChain对象,这个对象里不仅包含了找到的Handler(即login方法对应的可执行对象),还可能包含一系列配置好的Interceptor(拦截器)。

第四步:获取对应的处理器适配器(HandlerAdapter)。 DispatcherServlet拿到Handler后,它自己还是不知道该怎么调用这个方法。于是它又去问所有注册的HandlerAdapter:“你们谁擅长跟这种类型的Handler打交道?” RequestMappingHandlerAdapter举手说:“我擅长,这种带@RequestMapping注解的方法归我管。” 于是DispatcherServlet就拿到了合适的适配器。

第五步:执行处理器,处理业务逻辑。 这是最核心的一步。RequestMappingHandlerAdapter开始工作:

  1. 它会解析login方法的签名,发现方法需要两个参数:一个String username,一个String password。
  2. 它从HTTP请求中(可能是URL参数,也可能是表单POST体)提取出username和password的值。
  3. 它可能会进行类型转换(比如把字符串"123"转成int类型),数据校验(如果参数有@Valid注解)。
  4. 然后,它调用UserController的实例,执行login(username, password)这个方法。
  5. 方法内部可能会调用Service层、访问数据库,最后返回一个结果。假设我们返回一个字符串"success"。

第六步:处理返回结果,封装ModelAndView。 HandlerAdapter把方法返回的"success"字符串,以及方法执行过程中可能放入Model的数据(比如model.addAttribute("user", userObj)),一起封装成一个ModelAndView对象。这个对象包含了模型数据和逻辑视图名。

第七步:解析视图。 DispatcherServlet拿着ModelAndView中的逻辑视图名"success",去找ViewResolver。InternalResourceViewResolver根据配置(前缀/WEB-INF/views/,后缀.jsp),把"success"解析成具体的视图对象:/WEB-INF/views/success.jsp对应的JstlView。

第八步:渲染视图。 DispatcherServlet把上一步得到的View对象,以及ModelAndView中的模型数据,交给View去渲染。JstlView会将模型数据(那个user对象)设置到HttpServletRequest的属性中,然后请求转发(RequestDispatcher.forward)到/WEB-INF/views/success.jsp页面。

第九步:生成响应。 JSP页面被执行,生成HTML。HTML内容作为响应体,通过一系列的过滤器、Servlet,最终由Tomcat发送回用户的浏览器。用户就看到登录成功的页面了。

整个流程中,DispatcherServlet就像一个经验丰富的项目经理,它自己不写代码,但知道每个环节该找谁,确保流程顺畅。而HandlerMapping、HandlerAdapter、ViewResolver就是它手下的几个得力干将。理解了这个流程,你再去看SpringMVC的源码,或者配置一些高级功能,就会觉得有章可循,不再是黑盒了。

4. 从零搭建:手把手实现一个SpringMVC入门案例

理论讲得再多,不如亲手搭一个。下面我就带你从零开始,创建一个最简单的SpringMVC项目。我会把每一步的细节和可能遇到的坑都讲清楚,你可以跟着一起操作。

4.1 环境准备与项目创建

首先,你需要一个Java开发环境(JDK 8或以上)和一个IDE,比如IntelliJ IDEA。我们创建一个Maven Web项目。

  1. 新建项目:在IDEA里选择New Project -> Maven,勾选Create from archetype,然后选择maven-archetype-webapp。这个骨架会帮我们生成一个标准的Web目录结构。
  2. 配置pom.xml:项目创建好后,打开pom.xml,添加SpringMVC的依赖。核心就三个:spring-webmvc(它本身会依赖spring-context和spring-web),以及Servlet API。注意Servlet API的scope要设为provided,因为Tomcat服务器本身会提供这个库。
<properties>
    <spring.version>5.3.23</spring.version> <!-- 使用一个稳定的版本 -->
</properties>

<dependencies>
    <!-- Spring MVC 核心 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- Servlet API -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
    <!-- JSP API (如果用JSP做视图) -->
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>javax.servlet.jsp-api</artifactId>
        <version>2.3.3</version>
        <scope>provided</scope>
    </dependency>
</dependencies>
  1. 补全目录结构:Maven骨架生成的webapp目录下可能缺少WEB-INF和web.xml。你需要手动创建src/main/webapp/WEB-INF目录,并在其下创建web.xml文件。同时,建议在src/main下创建java和resources目录,分别存放Java源代码和配置文件。

4.2 配置核心控制器与Spring容器

这是让SpringMVC跑起来最关键的两步配置。

  1. 配置DispatcherServlet (web.xml):在web.xml中,我们需要声明并配置DispatcherServlet。同时,告诉它Spring配置文件的位置,这样它启动时就会去加载这个配置,初始化Spring的ApplicationContext(IoC容器)。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
          http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- 1. 配置SpringMVC的前端控制器:DispatcherServlet -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 指定SpringMVC配置文件的位置和名称 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <!-- 设置容器在启动时就加载这个Servlet,而不是第一次请求时才加载 -->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- 2. 配置DispatcherServlet的映射,拦截所有请求 -->
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- 3. 配置字符编码过滤器,解决POST请求中文乱码 -->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

这里有个细节:<url-pattern>/</url-pattern>表示拦截所有请求,但不会拦截像.jsp这样的请求。对于静态资源(.js, .css, .jpg),需要额外配置,否则也会被DispatcherServlet拦截导致404。我们稍后在Spring配置里解决。

  1. 编写SpringMVC核心配置文件 (spring-mvc.xml):这个文件放在src/main/resources下。它的作用是开启注解驱动、自动扫描组件、配置视图解析器等。
<?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/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 1. 开启注解扫描,让Spring管理Controller等组件 -->
    <context:component-scan base-package="com.yourpackage.controller"/>

    <!-- 2. 开启MVC注解驱动。
         这一行配置至关重要!它相当于一次性注册了:
         - RequestMappingHandlerMapping (处理器映射器)
         - RequestMappingHandlerAdapter (处理器适配器,支持@RequestBody, @ResponseBody等)
         - ExceptionHandlerExceptionResolver (异常处理器)
         等一系列默认组件。 -->
    <mvc:annotation-driven/>

    <!-- 3. 配置视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/> <!-- 视图文件的前缀 -->
        <property name="suffix" value=".jsp"/> <!-- 视图文件的后缀 -->
    </bean>

    <!-- 4. 处理静态资源:告诉DispatcherServlet,对于`/resources/**`这样的路径,直接去`/resources/`目录下找,别走MVC流程 -->
    <mvc:resources mapping="/resources/**" location="/resources/"/>
    <!-- 或者使用更简单的方式:将静态资源请求交由默认的Servlet处理 -->
    <mvc:default-servlet-handler/>
</beans>

4.3 编写第一个Controller与视图

环境配好了,我们来写点真正的代码。

  1. 创建Controller:在com.yourpackage.controller包下创建HelloController。
package com.yourpackage.controller;

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

@Controller // 这个注解标记该类是一个SpringMVC的控制器,会被组件扫描到
public class HelloController {

    @RequestMapping("/hello") // 建立URL `/hello` 与下面方法的映射关系
    public String sayHello() {
        System.out.println("HelloController的sayHello方法被调用了!");
        // 返回一个逻辑视图名,视图解析器会将其解析为 `/WEB-INF/views/welcome.jsp`
        return "welcome";
    }
}
  1. 创建JSP视图:在webapp/WEB-INF/views/目录下(如果没有就创建),新建一个welcome.jsp文件。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Welcome</title>
</head>
<body>
    <h1>恭喜你!第一个SpringMVC程序运行成功!</h1>
    <p>当前时间:<%= new java.util.Date() %></p>
</body>
</html>
  1. 配置与运行:将项目部署到Tomcat(IDEA里配置Tomcat运行环境,选择war exploded部署方式)。启动Tomcat,在浏览器访问 http://localhost:8080/你的项目名/hello。如果一切顺利,你应该能看到“恭喜你!”的页面,并且控制台打印了那句输出。

这个简单的案例虽然只涉及一个URL映射,但它已经完整地走通了SpringMVC的核心流程:请求被DispatcherServlet拦截,HandlerMapping根据/hello找到sayHello方法,HandlerAdapter执行该方法,返回视图名"welcome",ViewResolver将其解析为/WEB-INF/views/welcome.jsp,最终渲染JSP页面返回给浏览器。通过这个动手过程,前面讲的那些抽象组件是不是变得具体多了?

5. 核心注解实战:让你的Controller更强大

会用@RequestMapping写个Hello World只是开始。SpringMVC提供了一整套强大的注解,能让你优雅地处理各种复杂的Web场景。这些注解就像是给你的Controller方法配备的“瑞士军刀”,用好了能极大提升开发效率和代码可读性。下面我挑几个最常用、也最容易出错的详细讲讲。

5.1 @RequestMapping:路由映射的基石

这是你最早接触也是使用最频繁的注解。它的作用就是建立请求URL与处理方法的映射关系。除了最基本的value(或path)指定URL,它还有几个非常实用的属性。

  • method:指定请求的HTTP方法。这是实现RESTful风格API的基础。例如:

    @RequestMapping(value = "/users", method = RequestMethod.GET)
    public List<User> getUsers() { ... } // 获取用户列表
    
    @RequestMapping(value = "/users", method = RequestMethod.POST)
    public User createUser(@RequestBody User user) { ... } // 创建新用户
    

    为了更简洁,Spring还提供了衍生注解:@GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping。上面两个例子可以写成:

    @GetMapping("/users")
    @PostMapping("/users")
    
  • params:要求请求必须包含某些特定参数。可以用来做简单的请求过滤。比如:

    @RequestMapping(value = "/user", params = "type=admin")
    public String getAdminUser() { ... }
    

    只有像/user?type=admin这样的请求才会匹配到这个方法。

  • headers:要求请求必须包含某些特定的HTTP头。常用于区分客户端类型或版本。例如:

    @RequestMapping(value = "/api/data", headers = "X-API-Version=1")
    public String getDataV1() { ... }
    

一个常见的坑:@RequestMapping可以放在类级别和方法级别。类级别的注解定义了一个通用的路径前缀。这在进行模块化开发时非常有用。但要注意,路径拼接时不要重复/。例如:

@Controller
@RequestMapping("/order") // 类级别
public class OrderController {
    @GetMapping("/list") // 方法级别,最终路径是 /order/list
    public String list() { ... }
}

如果类级别是/order/,方法级别是/list,最终路径会是/order//list,虽然大多数容器能处理,但最好保持风格一致,避免多余的斜杠。

5.2 请求参数绑定:@RequestParam, @PathVariable, @RequestBody

如何方便地获取请求中的参数,是Web开发的基础。SpringMVC提供了多种方式。

  • @RequestParam:用于获取查询参数或表单数据。它最常用的场景是处理key=value这种简单参数。

    @GetMapping("/user")
    public String getUser(@RequestParam("id") Long userId,
                          @RequestParam(value = "name", required = false, defaultValue = "Guest") String userName) {
        // 访问 /user?id=123&name=张三
        // userId = 123, userName = "张三"
        // 如果请求中没有name参数,则userName使用默认值"Guest"
    }
    

    required默认为true,如果请求中没有这个参数会抛出异常。defaultValue提供了默认值,设置它时required会自动变为false。

  • @PathVariable:用于获取URL路径模板中的变量。这是RESTful风格URL的标配。

    @GetMapping("/users/{userId}/orders/{orderId}")
    public String getOrder(@PathVariable Long userId, @PathVariable("orderId") Long orderNo) {
        // 访问 /users/100/orders/2001
        // userId = 100, orderNo = 2001
    }
    

    注意URL模板中的变量名{userId}需要与方法参数名userId一致,如果不一致,需要在@PathVariable注解中指定,如@PathVariable("orderId")。

  • @RequestBody:用于获取请求体(Request Body)的内容,通常用于接收JSON或XML格式的复杂数据。这是开发前后端分离的API时必用的注解。

    @PostMapping("/users")
    public ResponseEntity<User> createUser(@RequestBody User user) {
        // 前端发送一个JSON对象:{"username":"john", "email":"john@example.com"}
        // SpringMVC会使用HttpMessageConverter(如Jackson)自动将JSON反序列化为User对象
        User savedUser = userService.save(user);
        return ResponseEntity.ok(savedUser);
    }
    

    这里有个关键点:要使用@RequestBody,必须在配置中开启<mvc:annotation-driven/>或者使用@EnableWebMvc,这样才会注册能够处理JSON的HttpMessageConverter(比如MappingJackson2HttpMessageConverter)。

参数绑定的本质:SpringMVC的参数绑定是通过一系列HandlerMethodArgumentResolver(处理器方法参数解析器)来完成的。@RequestParam有对应的解析器,@PathVariable也有,@RequestBody也有。当HandlerAdapter执行方法前,会遍历这些解析器,看哪个能处理当前参数,然后由它负责从请求中提取数据并转换成方法所需的类型。理解这一点,对于后面处理复杂参数或自定义参数解析非常有帮助。

5.3 模型与视图:@ModelAttribute 与 @SessionAttribute

这两个注解用于在请求之间共享数据,它们操作的是不同的作用域。

  • @ModelAttribute:这个注解功能比较灵活,有两种主要用法。

    1. 用在方法上:标注的方法会在本控制器每个处理方法执行前被调用。通常用于准备一些公用的模型数据。例如,一个编辑用户信息的页面,需要先加载用户数据。
      @ModelAttribute
      public void populateModel(@RequestParam("id") Long id, Model model) {
          User user = userService.findById(id);
          model.addAttribute("user", user); // 将user对象放入模型
      }
      
      @GetMapping("/edit")
      public String editForm() {
          // 进入这个方法时,model里已经有一个名为"user"的属性了
          return "user/editForm";
      }
      
    2. 用在方法参数上:将模型中的属性绑定到方法参数上,或者将请求参数绑定到命令对象上并同时放入模型。
      @PostMapping("/update")
      public String updateUser(@ModelAttribute("user") User user) {
          // 这里的user对象,会从模型属性中获取(如果已有),
          // 同时也会用请求参数来更新这个对象的字段。
          userService.update(user);
          return "redirect:/user/list";
      }
      
      这种用法在表单回显和更新时非常方便。
  • @SessionAttribute:用于在多个请求之间共享数据,数据存储在HttpSession中。这个注解是声明在类级别的,用来指定哪些模型属性需要存入Session。

    @Controller
    @SessionAttributes("shoppingCart") // 声明名为"shoppingCart"的模型属性要存入session
    public class OrderController {
    
        @GetMapping("/cart/add")
        public String addToCart(@RequestParam Long productId, Model model) {
            ShoppingCart cart = ... // 获取或创建购物车
            cart.addItem(productId);
            model.addAttribute("shoppingCart", cart); // 放入model,同时会自动存入session
            return "cart/view";
        }
    
        // 在后续的请求中,可以直接从session中获取
        @GetMapping("/cart/checkout")
        public String checkout(SessionStatus status, @SessionAttribute("shoppingCart") ShoppingCart cart) {
            // 处理结账逻辑...
            status.setComplete(); // 清除通过@SessionAttributes存入session的数据
            return "order/confirm";
        }
    }
    

    需要注意的是,@SessionAttributes声明的属性只在当前控制器的处理流程中有效,并且需要通过SessionStatus.setComplete()来清理,或者等待Session过期。它和直接使用HttpSession的setAttribute方法有所不同,后者作用域更广,生命周期更长。

掌握这些注解,你的Controller就能游刃有余地处理各种输入输出、数据共享和视图跳转的需求了。在实际项目中,灵活组合使用它们,是写出清晰、健壮Web层代码的关键。

【springMVC】SpringMVC的工作流程解析 ​ SpringMVC是一个基于Spring开发的MVC轻量级框架,是Spring3.0后发布的组件,SpringMVC和Spring可以无缝整合,使用DispatcherServlet作为前端控制器,且内部提供了处理器映射器、处理器适配器、视图解析器等组件,可以简化JavaBean封装,Json转化、文件上传等操作,其将web层进行解耦,并管理应用所需对象的生命周期,大大地简化了日常的开发。 阅读详情

相关推荐

保姆级教程:用PyBullet仿真多指灵巧手抓取鸡蛋(含ROS2配置全流程)

本文提供了一份详细的PyBullet仿真教程,指导如何实现多指灵巧手对鸡蛋等易碎物体的安全抓取。内容涵盖从环境搭建、URDF模型导入、力/位混合控制策略到完整的ROS2集成与配置全流程,旨在帮助机器人研究者构建高保真仿真环境,并弥合仿真到现实的差距。

w1x2y3的博客 436

pybullet学习(一)——安装与入门pybullet

pybullet学习(一)——安装与入门pybullet

bulletstart的博客 3万+

keil软件调试(Debug)仿真教程(软件调试和硬件调试的区别)及常用调试按键详解

单片机的调试分为两种,一种是使用软件模拟调试,第二种是硬件调试,两种调试方式各有不同,软件模拟调试有误差,而硬件调试,借用仿真器调试是嵌入式开发中常用方法。

weixin_51624736的博客 3万+

RL仿真库pybullet

PyBullet是一个基于引擎的物理仿真Python接口,主要用于机器人仿真模拟。

m0_51866860的博客 1091

OpenDRIVE车道计算避坑指南:为什么你的poly3曲线总对不齐?

本文深入解析OpenDRIVE标准中车道几何计算的三大核心难题:参数化三次多项式(ParamPoly3)的坐标系转换与参数映射、车道偏移与宽度的优先级判定,以及螺旋线(Spiral)接续的平滑性保障。通过实战案例与代码示例,提供了一套避免车道线错位与曲率不连续的精确计算与验证方法,是高精地图开发与仿真场景构建的实用避坑指南。

q9w8e7r6t5的博客 425

cMake编译 VS2026+opencv4.12.0+opencv_contrib-4.12.0

本文提供了OpenCV 4.12.0集成CUDA、cuDNN和ONNX Runtime的详细编译指南。主要步骤包括:准备Visual Studio 2026、CMake 4.2.0、CUDA 12.6和cuDNN 9.16.0;设置无空格和中文的路径结构;配置关键CMake变量(如开启CUDA支持、指定路径等);以及最终的编译安装过程。注意事项包括:版本一致性检查、cuDNN文件复制、国内用户需手动获取.cache文件等。文章还提供了常见问题解决方案,如通过设置CUDA_NVCC_FLAGS参数解决VS版本

weixin_46624734的博客 1386

利用pybullet 实现ur5 仿真

想做一个机械臂仿真软件,以前利用C++ 结合FCL和OSG实现了一个半成品,但是这种方案需要根据机械臂DH参数,解析出机械臂各关节位姿然后利用OSG渲染,并且需要自己实现逆解算法,过于麻烦了。pybullet 具备了上述所有的要素,动力学引擎使用bullet,渲染使用OpenGL,并可以直接加载URDF文件,而且提供了 正逆算法。,负责机器人模型的建模,描述各机器人的连杆和关节,还有质量属性,颜色等。4,设置各关节角度,并判单是否碰撞。3,利用逆解算法,求出各关节角度。1,利用URDF文件,加载模型。

qthello 3650

ICC 实战解析——CTS 时钟树综合中的关键设置与优化策略

本文深入解析ICC工具中CTS时钟树综合的关键设置与优化策略,涵盖时钟树异常引脚设置、目标参数配置、非默认布线规则(NDR)等核心技术。通过实战案例展示如何有效控制时钟偏差、优化信号完整性,并平衡功耗与面积,为芯片物理设计提供专业指导。

weixin_30872577的博客 328

SpringMVC工作流程 -- 详解

SpringMVC一,SpringMVC简介二,SpringMVC的工作原理图执行流程三,SpringMVC核心组件前端控制器DispatcherServlet处理器映射器HandlerMapping处理器适配器HandlerAdapter处理器Handler视图解析器ViewResolver 一,SpringMVC简介 MVC:是一种架构模式,将业务逻辑和页面展示分离,使程序分层、分工合作,既相互独立,又协同合作。 MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种

布诺的博客 3万+

DFRobot MGC3130电容式手势传感器库深度解析

电容式近场感应(Electric Near Field Sensing)是一种非接触、抗干扰的三维空间感知技术,其原理基于人体介电特性对高频电场的扰动响应,具备低功耗、高鲁棒性与零物理接触等核心优势。该技术广泛应用于医疗人机交互、工业HMI、智能家电等对可靠性与环境适应性要求严苛的嵌入式场景。DFRobot_MGC3130库正是面向Microchip MGC3130芯片的工程化实现,封装了I²C驱动、ASU硬件加速调度及多层抽象API,支持手势识别、触控检测与接近唤醒等功能动态切换。结合电容式近场感应与嵌入

weixin_34620658的博客 552

512分辨率万能遮罩模型实战指南:从下载到高精度应用

本文提供了512分辨率万能遮罩模型的完整实战指南。该模型经过超过540万次迭代,专门优化了对头发、手、眼睛等复杂区域的识别。文章详细介绍了从可靠渠道下载、环境部署、使用DF_ICE工具批量应用遮罩,到利用XSeg Editor进行高精度精修的全流程,旨在帮助用户显著提升AI换脸合成视频的质量与效率。

y2z3a4b5c的博客 1167

springMVC工作流程

SpringMVC的工作原理图: SpringMVC流程 1、 用户发送请求至前端控制器DispatcherServlet。 2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。 3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。 4、 DispatcherServlet调用HandlerAdapter处理器适配器。 5、 HandlerAda

mmxgl的博客 6416

海康DS-7604N-K1/RTB固件包

【摘要】海康DS-7604N-K1/RTB萤石云设备发布V4.30.091版本升级程序(2022.09.19),仅适用于指定型号。升级前需先升级至V3.4.106基础版本,刷机会重置设备为未激活状态,需重新设置admin密码。该机型支持密码/手势登录,无密码时可通过U盘升级。注意事项:升级存在风险,需确认程序适用性;升级过程严禁断电;必须阅读压缩包内的刷机说明。此为定制机型,非必要不建议升级。(150字)

海康威视技术支持 1580

【SpringMVC】工作流程及入门案例

Spring MVC(Model-View-Controller)是一个基于Java的Web应用程序框架,它是Spring框架的一部分。Spring MVC提供了一个简单、灵活且强大的模型,用于构建Web应用程序,它遵循MVC设计模式。这个模式有助于将应用程序的表示层、业务逻辑层和数据访问层分离,使得开发更加模块化和易于维护。

让优秀成为一种习惯! 2600

5G射频到底是啥?方案怎么搭?工作流程、SAW选型、PA选型一口气讲透(工程师秒懂版)

很多人一提 5G 射频,脑子里先冒出来的是几个零件名:👉 PA👉 LNA👉 SAW👉 天线👉 开关但真正做方案时,这些东西不是一堆分立器件,而是一条完整的“信号流水线”。更准确地说,。Qualcomm 对 RFFE 的定义就是“把信息转换成可发送的射频信号,并把接收到的信号转换回有用信息”的那一整套组件。

weixin_43199439的博客 538

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

【Spring】一文了解SpringMVC的核心功能及工作流程,以及核心组件及注解

Spring MVC框架采用MVC模式构建Web应用,核心思想是将请求处理、视图渲染和数据模型分离。其核心组件包括DispatcherServlet(中央处理器)、Handler(控制器)、HandlerMapping(请求映射)和ViewResolver(视图解析)。工作流程为:请求先被DispatcherServlet拦截,通过HandlerMapping找到对应Controller处理业务逻辑,返回ModelAndView后由ViewResolver解析视图,最终渲染返回响应。 前后端分离模式下,后端

Shad0wLEO的博客 845

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

SpringMVC工作流程与核心组件

SpringMVC 的详细工作流程和其中的核心组件介绍。

weixin_43954951的博客 646

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

SpringMVC 的核心组件有哪些?

1. 前端控制器 DispatcherServlet 作用:Spring MVC 的入口函数.接收请求,响应结果,相当于转发器,中央处理器.有了 DispatcherServlet 减少了其它组件之间的耦合度.用户请求到达前端控制器,它就相当于 MVC 模式中的 C,DispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性. “耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量.耦合的强弱取.

徐明晓的博客 7515

SpringMVC框架:从原理到实战全解析

本文阐述了SpringMVC作为企业级Web开发首选框架的优势,包括无缝集成Spring生态、强大的请求处理能力和灵活的视图机制。核心部分详细解析了DispatcherServlet等关键组件及其协作流程,并通过10个步骤完整呈现请求处理链路。实战章节基于SpringBoot演示了环境搭建、请求映射、参数绑定、视图渲染(Thymeleaf)、拦截器和全局异常处理等核心功能实现。进阶技巧部分涵盖类型转换器、静态资源配置和跨

2401_83675559的博客 1561

SpringMVC的工作流程

在上述过程中,DispatcherServlet、HandlerMapping、HandlerAdapter和ViewResolver对象的工作是在框架内部执行的,开发人员只需要配置DispatcherServlet,完成Controller中的业务处理并在View中展示相应信息。DispatcherServlet是前端控制器,是整个流程控制的中心。(5) HandlerAdapter会调用并执行Handler(处理器),这里的处理器指的就是程序中编写的Controller类,也被称之为后端控制器。

2509_94198371的博客 734

SpringMVC工作流程

一:SpringMVC的工作原理图  二:SpringMVC流程 用户发送请求至前端控制器DispatcherServlet。 DispatcherServlet收到请求调用HandlerMapping处理器映射器。 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。 D...

huofuman960209的博客 2448

【Spring MVC 核心机制】核心组件和工作流程解析

理解这些组件的工作机制,不仅能帮助你更好地使用 Spring MVC,也能让你在遇到问题时快速定位到具体的环节。Spring MVC 作为一款强大的 Web 框架,将这些复杂的操作高度抽象化,通过组件协作简化了开发者的工作。由于不同的处理器(如基于注解的 Controller 或简单的接口实现)有不同的调用方式,Spring MVC 提供了。HandlerMapping 就像电话客服系统,当你拨打不同的分机号,系统会将你的请求转接给不同的部门。是整个工作流程的核心,贯穿了请求的每一步。

Yan.love的博客 1205

SpringMVC核心组件与处理流程全解析

Spring MVC通过DispatcherServlet作为中央调度器,利用HandlerMapping定位处理器,HandlerAdapter执行Controller方法,处理模型数据后通过ViewResolver和View进行视图渲染(或直接输出数据)。配合强大的注解体系,实现了清晰的MVC分层和高效的Web请求处理。理解这些核心组件及其交互流程是掌握Spring MVC的基础。

m0_75107803的博客 580

SpringMVC基础入门及工作流程---全方面详细介绍

SpringMVC基础入门及工作流程和静态资源的处理

m0_73192864的博客 2157
上一篇: 从原理到脚本:用Python3实现sqli-labs布尔盲注自动化攻击(附完整代码)
下一篇: 生物信息学新手必看:5分钟搞定mfuzz时间序列基因表达聚类分析
github5actions
博客等级 码龄1天 0粉丝 1824原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值