首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

SpringMVC 核心註解深度解析:@ModelAttribute 與 @SessionAttribute

     編輯:Java 綜合教學

前言

在 SpringMVC 開發中,@ModelAttribute 和 @SessionAttribute 是兩個極具實用價值卻常被誤解的註解。前者負責在控制器方法執行前預先綁定模型數據,後者則實現了跨請求的會話級數據共享。本文將從原理、用法、源碼分析三個維度,為你徹底講透這兩個註解的核心機制。

一、@ModelAttribute 註解詳解

1.1 核心作用

@ModelAttribute 標註的方法會在每個目標處理方法(@RequestMapping)執行之前被調用。其本質是允許開發者在進入業務邏輯前,預先操縱模型數據,實現「預處理」邏輯的復用。

1.2 兩種數據存入 Model 的方式

方式一:通過 Map/Model 參數存入(不推薦)

@ModelAttribute
public void populateStudent(@RequestParam(value = "id", required = false) String idStr, Map<String, Object> map) {
    try {
        Integer id = Integer.parseInt(idStr);
        System.out.println("student id: " + id);
        map.put("student", new Student(1, "李四", 23));
    } catch (NumberFormatException ignored) { }
}

缺點:Spring 會額外向 Model 中放入一個鍵為 void、值為 null 的條目,污染模型數據。

方式二:利用 value 屬性 + 返回值(推薦)

@ModelAttribute("student")
public Student getStudent(@RequestParam(value = "id", required = false) String idStr) {
    Student student = null;
    try {
        Integer id = Integer.parseInt(idStr);
        System.out.println("student id: " + id);
        student = new Student(1, "李四", 23);
    } catch (NumberFormatException ignored) { }
    return student;
}

優點:Model 中僅包含指定鍵值對("student" -> Student對象),代碼更優雅、語義更清晰。

總結:SpringMVC 在調用目標方法前,將 @ModelAttribute 的 value 作為 key,方法返回值作為 value 存入 Model。

1.3 源碼級流程分析

核心邏輯位於 HandlerMethodInvoker.invokeHandlerMethod(Spring 3.x/4.x)或 RequestMappingHandlerAdapter(Spring 5+)。關鍵步驟如下:

  1. 第 14 行循環:遍歷所有標註 @ModelAttribute 的方法。
  2. 第 16 行:解析方法參數(支持與目標方法相同的參數類型,如 @RequestParam)。
  3. 第 20-31 行:獲取 value 屬性,若 Model 中已存在同名屬性則跳過(不覆蓋),否則調用方法並將返回值存入 Model。
  4. 第 40 行:最後才調用真正的目標處理方法。

1.4 目標方法中讀取模型數據

假設有兩個 @ModelAttribute 方法分別返回 student 和 student2:

情況一:目標方法參數未加 @ModelAttribute

@RequestMapping("/updateStudent")
public String update(Student student2) { ... }

控制台輸出:student: Student{id=23, studentName='李四', age=23}
規則:Spring 會根據參數類型(Student)在 Model 中尋找匹配的屬性,若有多個同類型屬性,使用默認命名約定(類名首字母小寫)匹配。

情況二:目標方法參數顯式加 @ModelAttribute("student2")

@RequestMapping("/updateStudent")
public String update(@ModelAttribute("student2") Student student2) { ... }

控制台輸出:student: Student{id=23, studentName='王五', age=33}
規則:強制指定從 Model 中獲取 key 為 "student2" 的屬性。

1.5 參數綁定源碼追蹤

在 HandlerMethodInvoker.resolveHandlerArguments 中:

  • 若參數有 @ModelAttribute,取其 value 作為 attrName。
  • 最終進入 resolveModelAttribute:優先從 implicitModel 獲取;若無且為 Session 屬性則從 Session 獲取;否則實例化新對象。
  • 關鍵邏輯:if ("".equals(name)) name = Conventions.getVariableNameForParameter(methodParam); —— 未指定時自動推導默認名。

1.6 核心總結

  1. 目標方法參數名與 @ModelAttribute 方法的 value 無直接關係,只與類型相關。
  2. 不加註解時:多同類型屬性用默認名匹配。
  3. 加註解時:多同類型、不同 value 時,必須顯式指定使用哪個 value。

二、@SessionAttribute 註解

2.1 官方定義

@SessionAttributes(類級註解)聲明需存入 Spring MVC 會話模型的屬性名稱。標註的屬性會自動同步至 HTTP Session。

2.2 核心機制(實戰理解)

@SessionAttribute 指的是 SpringMVC 管理的會話模型。向其中添加值時,同時會寫入 HTTP Session。調用 SessionStatus.setComplete() 時,會清空 SpringMVC 會話模型,並移除對應鍵的 HTTP Session 數據;但通過 request.getSession().setAttribute() 手動存入的數據不會被清除。其他情況下兩者行為一致。

2.3 典型應用場景

  • 向導式表單提交(Wizard Form):跨步驟保持表單對象。
  • 購物車、用戶偏好設置等跨請求共享數據。
  • 配合 SessionStatus 實現精確的會話清理。

三、最佳實踐建議

場景推薦做法
預處理通用模型數據使用 @ModelAttribute("key") + 返回值方式
目標方法需區分多個同類型模型參數加 @ModelAttribute("specificKey")
跨請求保持對象狀態類上加 @SessionAttributes("key"),結束時 sessionStatus.setComplete()
僅需臨時存放、不需跨請求直接用 Model/Map,勿用 SessionAttribute

四、總結

@ModelAttribute 是「請求級預處理器」,解決模型數據準備的重複代碼問題;@SessionAttributes 是「會話級模型容器」,解決跨請求狀態保持問題。理解其執行順序、數據存取優先級、清理機制,是掌握 SpringMVC 數據流轉的關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved