Spring MVC 中 Controller 負責接收請求、協調業務邏輯、封裝模型資料並指向視圖。本文系統整理 @Controller 定義、@RequestMapping 多維映射、方法參數/返回值支援、@ModelAttribute/@SessionAttributes 資料共享、以及自訂類型轉換器。
@Controller
public class MyController {
@RequestMapping("/showView")
public ModelAndView showView() {
ModelAndView mav = new ModelAndView();
mav.setViewName("viewName");
mav.addObject("attrName", "attrValue");
return mav;
}
}
兩種註冊方式:
<bean class="com.xxx.MyController"/><context:component-scan base-package="com.xxx.web.controller"> 可排除 @Service 等。@RequestMapping → 方法路徑為絕對路徑(相對 context root)。@RequestMapping("/test") → 方法路徑相對於類別路徑(/test/showView)。@Controller
@RequestMapping("/test/{category}")
public class MyController {
@RequestMapping("/detail/{id}")
public ModelAndView detail(@PathVariable String category, @PathVariable int id) { ... }
}
/test/books/detail/101 → category="books", id=101。@PathVariable("id") 可指定模板變數名,避免非 debug 編譯失效。*:@RequestMapping("*/wildcard")。| 註解 | 來源 | 屬性 | 必要性 |
|---|---|---|---|
@RequestParam | 請求參數 | value/name, required(default true), defaultValue | required=false 可選 |
@CookieValue | Cookie | value, required, defaultValue | 同 @RequestParam |
@RequestHeader | 請求頭 | value, required, defaultValue | 大小寫不敏感 |
@RequestMapping("/param")
public String param(@RequestParam(required=false) String name, @RequestParam("age") int age) { ... }
@RequestMapping(value="/test", params={"p1=v1", "p2", "!p3"}) → p1 必等於 v1、p2 必存在、p3 必不存在。method={RequestMethod.GET, RequestMethod.POST} 限制 HTTP 方法。headers={"Host=localhost", "Accept"} 限制請求頭。HttpServletRequest, HttpServletResponse, HttpSession(注意 Session 可能為 null)。WebRequest、NativeWebRequest。InputStream/Reader(請求體)、OutputStream/Writer(回應體)。@PathVariable, @RequestParam, @CookieValue, @RequestHeader。@ModelAttribute 標記的命令物件/表單物件。MultipartFile:檔案上傳。Errors/BindingResult:緊接在驗證物件之後,保存驗證結果。ModelAndView:模型+視圖名稱。Model/ModelMap/Map:僅模型,視圖名由 RequestToViewNameTranslator 推斷。View 物件:直接渲染,可配合模型參數。String:視圖名稱,可配合模型參數。void:自寫回應或由 RequestToViewNameTranslator 推斷視圖。@ResponseBody:透過 HttpMessageConverter 直接寫入回應體(REST API 常用)。@ModelAttribute("name") 指定。@ModelAttribute("hello")
public String putHello() { return "world"; }
@RequestMapping("/say")
public void say(@ModelAttribute("hello") String hello, Writer w) throws IOException {
w.write("Hello " + hello); // 輸出 Hello world
}
@SessionAttributes)。@ModelAttribute("name") 指定,否則用返回類型類名首字母小寫。@Controller
@RequestMapping("/myTest")
@SessionAttributes(value={"intValue","strValue"}, types={User.class})
public class MyController { ... }
value:屬性名列表;types:類型列表(屬性名為類名首字母小寫)。@RequestMapping("/use")
public void use(@ModelAttribute("user1") User u1, @ModelAttribute User user, HttpSession session) { ... }
@ModelAttribute 未指定 name 且類型不匹配)。@Controller
public class MyController {
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyyMMdd"), true));
// 自訂 PropertyEditor
binder.registerCustomEditor(User.class, new PropertyEditorSupport() {
@Override public void setAsText(String text) { setValue(new User(1, text)); }
@Override public String getAsText() { return ((User)getValue()).getUsername(); }
});
}
@RequestMapping("/date/{d}")
public void handle(@PathVariable Date d, Writer w) throws IOException { w.write(d.toString()); }
}
initBinder。public class MyWebBindingInitializer implements WebBindingInitializer {
@Override public void initBinder(WebDataBinder binder, WebRequest request) {
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyyMMdd"), true));
}
}
XML 註冊:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="com.xxx.MyWebBindingInitializer"/>
</property>
</bean>
@RestController(@Controller + @ResponseBody)開發 REST API。@ModelAttribute 命令物件 + BindingResult 驗證,配合 JSR-303 註解(@Valid)。@SessionAttributes,避免過大物件佔用記憶體;考慮 Redis 分散式 Session。Formatter/ConversionService 替代 PropertyEditor,支援線程安全與泛型。BindException,可用 @ControllerAdvice + @ExceptionHandler 統一處理。