|
|
| 이름 | 설명 |
|---|---|
| @Controller | 해당 클래스가 Controller임을 나타내기 위한 어노테이션 |
| @RequestMapping | 요청에 대해 어떤 Controller, 어떤 메소드가 처리할지를 맵핑하기 위한 어노테이션 |
| @RequestParam | Controller 메소드의 파라미터와 웹요청 파라미터와 맵핑하기 위한 어노테이션 |
| @ModelAttribute | Controller 메소드의 파라미터나 리턴값을 Model 객체와 바인딩하기 위한 어노테이션 |
| @SessionAttributes | Model 객체를 세션에 저장하고 사용하기 위한 어노테이션 |
@MVC에서 Controller를 만들기 위해서는 작성한 클래스에 @Controller를 붙여주면 된다. 특정 클래스를 구현하거나 상속할 필요가 없다.
package com.easycompany.controller.annotation; @Controller public class LoginController { ... }
앞서 DefaultAnnotationHandlerMapping에서 언급한 대로 <context:component-scan> 태그를 이용해 @Controller들이 있는 패키지를 선언해 주면 된다.
@Controller만 스캔 한다면 include, exclude 등의 필터를 사용하라.
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:component-scan base-package="com.easycompany.controller.annotation" /> </beans>
@RequestMapping은 요청에 대해 어떤 Controller, 어떤 메소드가 처리할지를 맵핑하기 위한 어노테이션이다. @RequestMapping이 사용하는 속성은 아래와 같다.
| 이름 | 타입 | 설명 |
|---|---|---|
| value | String[] | URL 값으로 맵핑 조건을 부여한다. @RequestMapping(value=”/hello.do”) 또는 @RequestMapping(value={”/hello.do”, ”/world.do” })와 같이 표기하며, 기본값이기 때문에 @RequestMapping(”/hello.do”)으로 표기할 수도 있다. ”/myPath/*.do”와 같이 Ant-Style의 패턴매칭을 이용할 수도 있다. |
| method | RequestMethod[] | HTTP Request 메소드값을 맵핑 조건으로 부여한다. HTTP 요청 메소드값이 일치해야 맵핑이 이루어 지게 한다. @RequestMapping(method = RequestMethod.POST)같은 형식으로 표기한다. 사용 가능한 메소드는 GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE이다 |
| params | String[] | HTTP Request 파라미터를 맵핑 조건으로 부여한다. params=“myParam=myValue”이면 HTTP Request URL중에 myParam이라는 파라미터가 있어야 하고 값은 myValue이어야 맵핑한다. params=“myParam”와 같이 파라미터 이름만으로 조건을 부여할 수도 있고, ”!myParam”하면 myParam이라는 파라미터가 없는 요청 만을 맵핑한다. @RequestMapping(params={“myParam1=myValue”, “myParam2”, ”!myParam3”})와 같이 조건을 주었다면, HTTP Request에는 파라미터 myParam1이 myValue값을 가지고 있고, myParam2 파라미터가 있어야 하고, myParam3라는 파라미터는 없어야 한다. |
@RequestMapping은 클래스 단위(type level)나 메소드 단위(method level)로 설정할 수 있다.
(1) type level
/hello.do 요청이 오면 HelloController의 hello 메소드가 수행된다.
@Controller @RequestMapping("/hello.do") public class HelloController { @RequestMapping //type level에서 URL을 정의하고 Controller에 메소드가 하나만 있어도 요청 처리를 담당할 메소드 위에 @RequestMapping 표기를 해야 제대로 맵핑이 된다. public String hello(){ ... } }
(2) method level
/hello.do 요청이 오면 hello 메소드,
/helloForm.do 요청은 GET 방식이면 helloGet 메소드, POST 방식이면 helloPost 메소드가 수행된다.
@Controller public class HelloController { @RequestMapping(value="/hello.do") public String hello(){ ... } @RequestMapping(value="/helloForm.do", method = RequestMethod.GET) public String helloGet(){ ... } @RequestMapping(value="/helloForm.do", method = RequestMethod.POST) public String helloPost(){ ... } }
(3) type + method level
둘 다 설정할 수도 있는데, 이 경우엔 type level에 설정한 @RequestMapping의 value(URL)를 method level에서 재정의 할수 없다.
/hello.do 요청시에 GET 방식이면 helloGet 메소드, POST 방식이면 helloPost 메소드가 수행된다.
@Controller @RequestMapping("/hello.do") public class HelloController { @RequestMapping(method = RequestMethod.GET) public String helloGet(){ ... } @RequestMapping(method = RequestMethod.POST) public String helloPost(){ ... } }
AbstractController 상속받아 구현한 예제 코드 LoginController를 어노테이션 기반의 Controller로 구현해 보겠다.
기존의 LoginController는 URL /loginProcess.do로 오는 요청의 HTTP 메소드가 POST일때 handleRequestInternal 메소드가 실행되는 Controller였는데, 다음과 같이 구현할 수 있겠다.
package com.easycompany.controller.annotation; ... @Controller public class LoginController { @Autowired private LoginService loginService; @RequestMapping(value = "/loginProcess.do", method = RequestMethod.POST) public String login(HttpServletRequest request) { String id = request.getParameter("id"); String password = request.getParameter("password"); Account account = (Account) loginService.authenticate(id,password); if (account != null) { request.getSession().setAttribute("UserAccount", account); return "redirect:/employeeList.do"; } else { return "login"; } } }
위 예제 코드에서 서비스 클래스를 호출하기 위해서 @Autowired가 사용.
@RequestParam은 Controller 메소드의 파라미터와 웹요청 파라미터와 맵핑하기 위한 어노테이션이다.
관련 속성은 아래와 같다.
| 이름 | 타입 | 설명 |
|---|---|---|
| value | String | 파라미터 이름 |
| required | boolean | 해당 파라미터가 반드시 필수 인지 여부. 기본값은 true이다. |
아래 코드와 같은 방법으로 사용되는데, 해당 파라미터가 Request 객체 안에 없을때 그냥 null값을 바인드 하고 싶다면, pageNo 파라미터 처럼 required=false로 명시해야 한다. name 파라미터는 required가 true이므로, 만일 name 파라미터가 null이면 org.springframework.web.bind.MissingServletRequestParameterException이 발생한다.
@Controller public class HelloController { @RequestMapping("/hello.do") public String hello(@RequestParam("name") String name, //required 조건이 없으면 기본값은 true, 즉 필수 파라미터 이다. 파라미터 pageNo가 존재하지 않으면 Exception 발생. @RequestParam(value="pageNo", required=false) String pageNo){ //파라미터 pageNo가 존재하지 않으면 String pageNo는 null. ... } }
위에서 작성한 LoginController의 login 메소드를 보면 파라미터 아이디와 패스워드를 Http Request 객체에서 getParameter 메소드를 이용해 구하는데, @RequestParam을 사용하면 아래와 같이 변경할수 있다.
package com.easycompany.controller.annotation; ... @Controller public class LoginController { @Autowired private LoginService loginService; @RequestMapping(value = "/loginProcess.do", method = RequestMethod.POST) public String login( HttpServletRequest request, @RequestParam("id") String id, @RequestParam("password") String password) { Account account = (Account) loginService.authenticate(id,password); if (account != null) { request.getSession().setAttribute("UserAccount", account); return "redirect:/employeeList.do"; } else { return "login"; } } }
@ModelAttribute의 속성은 아래와 같다.
| 이름 | 타입 | 설명 |
|---|---|---|
| value | String | 바인드하려는 Model 속성 이름. |
@ModelAttribute는 실제적으로 ModelMap.addAttribute와 같은 기능을 발휘하는데, Controller에서 2가지 방법으로 사용된다.
(1) 메소드 리턴 데이터와 Model 속성(attribute)의 바인딩.
메소드에서 비지니스 로직(DB 처리같은)을 처리한 후 결과 데이터를 ModelMap 객체에 저장하는 로직은 일반적으로 자주 발생한다.
... @RequestMapping(value = "/updateDepartment.do", method = RequestMethod.GET) public String formBackingObject(@RequestParam("deptid") String deptid, ModelMap model) { Department department = departmentService.getDepartmentInfoById(deptid); //DB에서 부서정보 데이터를 가져온다. model.addAttribute("department", department); //데이터를 모델 객체에 저장한다. return "modifydepartment"; } ...
@ModelAttribute를 메소드에 선언하면 해당 메소드의 리턴 데이터가 ModelMap 객체에 저장된다.
위 코드를 아래와 같이 변경할수 있는데, 사용자로 부터 GET방식의 /updateDepartment.do 호출이 들어오면,
formBackingObject 메소드가 실행 되기 전에 DefaultAnnotationHandlerMapping이 org.springframework.web.bind.annotation.support.HandlerMethodInvoker을 이용해서
(@ModelAttribute가 선언된)getEmployeeInfo를 실행하고, 결과를 ModelMap객체에 저장한다.
결과적으로 getEmployeeInfo 메소드는 ModelMap.addAttribute(“department”, departmentService.getDepartmentInfoById(…)) 작업을 하게 되는것이다.
... @RequestMapping(value = "/updateDepartment.do", method = RequestMethod.GET) public String formBackingObject() { return "modifydepartment"; } @ModelAttribute("department") public Department getEmployeeInfo(@RequestParam("deptid") String deptid){ return departmentService.getDepartmentInfoById(deptid); //DB에서 부서정보 데이터를 가져온다. } 또는 public @ModelAttribute("department") Department getDepartmentInfoById(@RequestParam("deptid") String deptid){ return departmentService.getDepartmentInfoById(deptid); } ...
(2) 메소드 파라미터와 Model 속성(attribute)의 바인딩.
@ModelAttribute는 ModelMap 객체의 특정 속성(attribute) 메소드의 파라미터와 바인딩 할때도 사용될수 있다.
아래와 같이 메소드의 파라미터에 ”@ModelAttribute(“department”) Department department” 선언하면 department에는 (Department)ModelMap.get(“department”) 값이 바인딩된다.
따라서, 아래와 같은 코드라면 formBackingObject 메소드 파라미터 department에는 getDepartmentInfo 메소드가 ModelMap 객체에 저장한 Department 데이터가 들어 있다.
... @RequestMapping(value = "/updateDepartment.do", method = RequestMethod.GET) public String formBackingObject(@ModelAttribute("department") Department department) { //department에는 getDepartmentInfo에서 구해온 데이터들이 들어가 있다. System.out.println(employee.getEmployeeid()); System.out.println(employee.getName()); return "modifydepartment"; } @ModelAttribute("department") public Department getDepartmentInfo(@RequestParam("deptid") String deptid){ return departmentService.getDepartmentInfoById(deptid); //DB에서 부서정보 데이터를 가져온다. } ...
@SessionAttributes는 model attribute를 session에 저장, 유지할 때 사용하는 어노테이션이다. @SessionAttributes는 클래스 레벨(type level)에서 선언할 수 있다. 관련 속성은 아래와 같다.
| 이름 | 타입 | 설명 |
|---|---|---|
| types | Class[] | session에 저장하려는 model attribute의 타입 |
| value | String[] | session에 저장하려는 model attribute의 이름 |
사용가능한 메소드 파라미터는 아래와 같다.
메소드는 임의의 순서대로 파라미터를 사용할수 있다. 단, BindingResult가 메소드의 argument로 사용될 때는 바인딩 할 커맨드 객체가 바로 앞에 와야 한다.
public String updateEmployee(...,@ModelAttribute("employee") Employee employee, BindingResult bindingResult,...) <!-- (O) --> public String updateEmployee(...,BindingResult bindingResult, @ModelAttribute("employee") Employee employee,...) <!-- (X) -->
사용가능한 메소드 리턴 타입은 아래와 같다.
(1) ModelAndView - 커맨드 객체와 @ModelAttribute이 적용된 메소드의 리턴 데이터가 담긴 Model 객체와 View 정보가 담겨 있다.
@RequestMapping(value = "/updateDepartment.do", method = RequestMethod.GET) public ModelAndView formBackingObject(@RequestParam("deptid") String deptid) { Department department = departmentService.getDepartmentInfoById(deptid); ModelAndView mav = new ModelAndView("modifydepartment"); mav.addObject("department", department); return mav; } 또는 public ModelAndView formBackingObject(@RequestParam("deptid") String deptid, ModelMap model) { Department department = departmentService.getDepartmentInfoById(deptid); model.addAttribute("department", department); ModelAndView mav = new ModelAndView("modifydepartment"); mav.addAllObjects(model); return mav; }
http://localhost:8080/gamecast/display.html -> display
http://localhost:8080/gamecast/displayShoppingCart.html -> displayShoppingCart
http://localhost:8080/gamecast/admin/index.html -> admin/index@RequestMapping(value = "/updateDepartment.do", method = RequestMethod.GET) public Model formBackingObject(@RequestParam("deptid") String deptid, Model model) { Department department = departmentService.getDepartmentInfoById(deptid); model.addAttribute("department", department); return model; } 또는 @RequestMapping(value = "/updateDepartment.do", method = RequestMethod.GET) public Model formBackingObject(@RequestParam("deptid") String deptid) { Department department = departmentService.getDepartmentInfoById(deptid); Model model = new ExtendedModelMap(); model.addAttribute("department", department); return model; }
@RequestMapping(value = "/updateDepartment.do", method = RequestMethod.GET) public Map formBackingObject(@RequestParam("deptid") String deptid) { Department department = departmentService.getDepartmentInfoById(deptid); Map model = new HashMap(); model.put("department", department); return model; } 또는 @RequestMapping(value = "/updateDepartment.do", method = RequestMethod.GET) public Map formBackingObject(@RequestParam("deptid") String deptid, Map model) { Department department = departmentService.getDepartmentInfoById(deptid); model.put("department", department); return model; }
<!--(O)--> @RequestMapping(value = "/updateDepartment.do", method = RequestMethod.GET) public String formBackingObject(@RequestParam("deptid") String deptid, ModelMap model) { Department department = departmentService.getDepartmentInfoById(deptid); model.addAttribute("department", department); return "modifydepartment"; } <!--(X)--> @RequestMapping(value = "/updateDepartment.do", method = RequestMethod.GET) public String formBackingObject(@RequestParam("deptid") String deptid) { Department department = departmentService.getDepartmentInfoById(deptid); ModelMap model = new ModelMap(); model.addAttribute("department", department); return "modifydepartment"; }
|
|