Spring 2.5 為 Spring MVC 引入註解驅動模型,Controller 無需實作介面、無需 XML 定義 URL 映射,純 POJO + 註解即可完整表達 Web 層邏輯。核心註解 @Controller、@RequestMapping、@RequestParam、@ModelAttribute、@SessionAttributes、@InitBinder 涵蓋請求映射、參數綁定、模型管理、視圖解析全流程。
@Controller
@RequestMapping("/forum.do")
public class BbtForumController {
@Autowired
private BbtForumService bbtForumService;
@RequestMapping // 處理 /forum.do
public String listAllBoard() {
bbtForumService.getAllBoard();
return "listBoard"; // 邏輯視圖名
}
}
<beans ... xmlns:context="..." xmlns:p="...">
<!-- 1. 掃描 Controller,隱式註冊 AutowiredAnnotationBeanPostProcessor 等 -->
<context:component-scan base-package="com.baobaotao.web"/>
<!-- 2. 關鍵:註解處理器適配器,解析 @RequestMapping 等 -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<!-- 3. 視圖解析器:邏輯視圖名 → 物理 JSP 路徑 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp"/>
</beans>
@Controller
public class BbtForumController {
@RequestMapping("/listAllBoard.do")
public String listAllBoard() { return "listBoard"; }
@RequestMapping("/listBoardTopic.do")
public String listBoardTopic(int topicId) { return "listTopic"; }
}
@Controller
@RequestMapping("/bbtForum.do")
public class BbtForumController {
@RequestMapping(params = "method=listAllBoard")
public String listAllBoard() { return "listBoard"; }
@RequestMapping(params = "method=listBoardTopic")
public String listBoardTopic(int topicId) { return "listTopic"; }
}
@RequestMapping(params = "method=createTopic", method = RequestMethod.POST)
public String createTopic() { return "createTopic"; } // 僅 POST 生效
| 參數類型 | 綁定規則 | 備註 |
|---|---|---|
| 基本類型 / String | 按參數名匹配 URL 參數,自動類型轉換 | 基本類型缺參數拋 TypeMismatchException |
| JavaBean (Command/Form Object) | 屬性名匹配 URL 參數,支援巢狀屬性 dept.deptId | 缺參數基本類型屬性預設值 (0/false) |
@RequestParam("xxx") | 強制指定 URL 參數名,可設 required=false | 改變預設匹配行為 |
| Servlet API 對象 | HttpServletRequest, HttpServletResponse, HttpSession | 自動注入當前請求/響應/會話 |
ModelMap / Map | 綁定隱含模型對象,向視圖傳遞數據 | model.addAttribute("key", val) |
@ModelAttribute("xxx") | 從模型/Session 獲取屬性綁定參數 | 配合 @SessionAttributes 跨請求共享 |
Errors / BindingResult | 驗證結果對象,必須緊跟 Command Object 後 | 表單驗證必備 |
SessionStatus | 控制 Session 屬性清理,status.setComplete() | 表單完成清理 @SessionAttributes |
// URL: /bbtForum.do?method=listBoardTopic&id=1&userId=10&userName=tom&dept.deptId=12
@RequestMapping(params = "method=listBoardTopic")
public String listBoardTopic(
@RequestParam("id") int topicId, // 綁定 id 參數
User user, // 綁定 userId、userName、dept.deptId
ModelMap model) { // 注入模型對象
model.addAttribute("currUser", user);
return "listTopic";
}
進階用法:@SessionAttributes(types=User.class)、@SessionAttributes(value={"a","b"}, types={User.class, Dept.class})
| 返回類型 | 視圖解析規則 | 模型處理 |
|---|---|---|
| void | 邏輯視圖名 = 請求 URL 路徑 (去除副檔名) | 無 |
| String | 返回值即邏輯視圖名 | 透過 ModelMap 參數控制 |
| ModelMap | 邏輯視圖名 = 請求 URL 路徑 | 返回的 ModelMap 為模型 |
| ModelAndView | 完全控制視圖與模型 | 傳統方式,兼容性最好 |
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="com.baobaotao.web.MyBindingInitializer"/>
</property>
</bean>
public class MyBindingInitializer implements WebBindingInitializer {
public void initBinder(WebDataBinder binder, WebRequest request) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
df.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(df, false));
binder.registerCustomEditor(String.class, new StringTrimmerEditor(false));
}
}
@Controller
public class MyFormController {
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
df.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(df, false));
}
}
@Controller
@RequestMapping("/bbtForum.do")
public class BbtForumController {
@ModelAttribute("items") // 每次請求前執行,返回值放入模型 key="items"
public List<String> populateItems() {
List<String> list = new ArrayList<String>();
list.add("item1"); list.add("item2");
return list;
}
@RequestMapping(params = "method=listAllBoard")
public String listAllBoard(ModelMap model) {
// 直接訪問 model.get("items") → size=2
return "listBoard";
}
}
@RequestMapping(params="method=xxx"),XML 僅需一個 ParameterMethodNameResolver@RequestMapping(value="/users/{id}", method=RequestMethod.GET) + @PathVariable (Spring 3.0+)@ExceptionHandler (Spring 3.0+) 或 XML HandlerExceptionResolver@InitBinder 設定 setAllowedFields 防止大量賦值攻擊Spring MVC 註解驅動模型是 Web 框架設計的里程碑,將「配置」內化為「代碼意圖」,讓開發者專注於業務邏輯而非 XML 角力。配合 Spring 3.0+ 的 @PathVariable、@ExceptionHandler、@CookieValue、@RequestHeader 等增強,構建現代化 Web 應用更加得心應手。