Spring MVC 的參數綁定機制負責將 HTTP 請求參數自動映射到 Controller 方法的形參上。早期版本使用 PropertyEditor(屬性編輯器),自 3.x 版起改用 Converter(轉換器) 體系,提供更強大、線程安全的類型轉換能力。註解適配器(RequestMappingHandlerAdapter)會對標註 @RequestMapping 的方法進行適配,自動完成參數綁定。
無需額外註解,適配器即可識別並注入以下類型:
HttpServletRequest / HttpServletResponse / HttpSession:原生 Servlet API 物件。Model / ModelMap / Map:向視圖傳遞資料,如 model.addAttribute("item", item),頁面以 ${item.xxx} 取值。用於綁定單一請求參數,屬性如下:
value:請求參數名,若與形參名不一致時必須指定。required(預設 true):true 表示必須存在,否則拋 400/500 錯誤;false 允許缺失。defaultValue:預設值,若請求無此參數則使用,甚至可覆蓋 required=true。public String editItem(@RequestParam(value="item_id", required=true) String id) { ... }
最佳實踐: 若請求參數名與形參名一致,可省略 @RequestParam,適配器自動綁定。
當請求參數名與形參名一致時,自動綁定基本類型(int, double, boolean 等)及其包裝類、String。注意: 基本類型無法接收 null 或空字串,否則拋出轉換異常;開發中建議對可能為空的參數使用包裝類型(Integer, Boolean 等)。
僅包含簡單類型屬性的 POJO。請求參數名與 POJO 屬性名一致時自動賦值:
// 請求: ?name=foo&price=100
public String editItemSubmit(Items items) { ... } // Items 有 name、price 屬性
若多個 POJO 含有相同屬性名(如 Items 和 User 都有 name),需建立包裝類別,頁面參數加前綴:
public class QueryVo { private Items items; }
// 頁面: items.name, items.price
public String submit(QueryVo queryVo) { ... }
關鍵規則: 集合(List、Set、Map)不能直接寫在 Controller 方法參數,必須包裝在物件中。
多個同名參數(如 Checkbox)以逗號分隔傳遞,Controller 用 String[] 接收。
// 表單命名: users[0].firstName, users[0].lastName, users[1].firstName...
public class UserListForm { private List<User> users; }
public void test(UserListForm form) { ... }
陷阱: Spring 會依最大索引建立 List,若索引不連續(如 0, 1, 20),中間元素會是非 null 但屬性為 null 的物件。
語法同 List,但 必須在 Set 中預先 add 相應數量的模型物件,且最大索引不可超過 Set 大小,否則拋 InvalidPropertyException。
最靈活,鍵值由字串指定:
// 表單: users['x'].firstName, users['x'].lastName...
public class UserMapForm { private Map<String, User> users; }
Spring MVC 無預設日期綁定,需自行實作。兩種主流方案:
@InitBinder,註冊 CustomDateEditor。PropertyEditorRegistrar,配合 ConfigurableWebBindingInitializer 注入 RequestMappingHandlerAdapter。Converter<String, Date>,在 convert() 中解析日期字串。FormattingConversionServiceFactoryBean,註冊自定義 Converter。<mvc:annotation-driven conversion-service="conversionService">。public class CustomDateConverter implements Converter<String, Date> {
public Date convert(String source) {
try { return new SimpleDateFormat("yyyy-MM-dd HH-mm-ss").parse(source); }
catch (Exception e) { return null; }
}
}
@RequestParam、簡單類型、POJO、包裝 POJO、集合(陣列/List/Set/Map)的綁定規則與命名慣例。PropertyEditor。