# 웹 개발/프레임워크

spring @ModelAttribute

dev-jjong 2013. 6. 8. 20:32

@ModelAttribute 를 이용하면 2가지 작업이 가능


1. @RequestMapping 어노테이션이 적용되지 않은 별도 메소드로 모델에 추가될 객체를 생성가능

2. 커맨드 객체의 초기화 작업을 수행


두개의 RequestMapping 된 메소드가 같은 내용의 모델을 필요로 한다고 할때,

보통 그냥 별도의 메소드로 빼서 그것을 참조하게 한다. 

단 이렇게 하면 공통 메소드에 추가 조건절이 들어갈 수 도 있고 리턴에 대해서도 사용하는 측에서 맞춰야한다.


이때 @ModelAttribute를 사용할 수 있다.

@ModelAttribute 를 메소드에 적용하면 해당 메소드가 생성한 객체가 뷰에 전달된다!!!!

아하.. 그래서 return 에 없는 객체들을 jsp 에서 참조가능했구나!!!!!!

즉, 이 어노테이션은 ModelAttribute , 모델속성!! 이라는 의미의 단어를 그대로 뜻하는 것이다!!! 



@Controller

public class GameSearchController {

@Autowired

private SearchService searchService;


@ModelAttribute("searchTypeList")

public List<SearchType> referenceSearchTypeList() {

List<SearchType> options = new ArrayList<SearchType>();

options.add(new SearchType(1, "전체"));

options.add(new SearchType(2, "아이템"));

options.add(new SearchType(3, "캐릭터"));

return options;

}



@ModelAttribute("popularQueryList")

public String[] getPopularQueryList() {

return new String[] { "게임", "창천2", "위메이드" };

}


@RequestMapping("/search/main.do")

public String main() {

return "search/main";

}


@RequestMapping("/search/game.do")

public ModelAndView search(@ModelAttribute("command") SearchCommand command) {

ModelAndView mav = new ModelAndView("search/game");

System.out.println("검색어 = " + command.getQuery().toUpperCase());

SearchResult result = searchService.search(command);

mav.addObject("searchResult", result);

return mav;

}

}



해서 위의 콘트롤러를 보면 리턴해줄 모델의 값은 단지 mav일뿐이다. 허나 @ModelAttribute 어노테이션을 다른 메소드에 붙이므로써

모델에 속성을 추가하게 되는것이다!



다른 용도는 커맨드 객체 초기화 부분이다.

@ModelAttribute 어노테이션을 사용하면, 커맨드 객체의 초기화 작업을 수행할 수도 있다.

그럴수 밖에... 

@Controller

@RequestMapping("/account/create.do")

public class CreateAccountController {


@ModelAttribute("command")

public MemberInfo formBacking(HttpServletRequest request) {

if (request.getMethod().equalsIgnoreCase("GET")) {

MemberInfo mi = new MemberInfo();

Address address = new Address();

address.setZipcode(autoDetectZipcode(request.getRemoteAddr()));

mi.setAddress(address);

return mi;

} else {

return new MemberInfo();

}

}


private String autoDetectZipcode(String remoteAddr) {

return "000000";

}


@RequestMapping(method = RequestMethod.GET)

public String form() {

return "account/creationForm";

}


@RequestMapping(method = RequestMethod.POST)

public String submit(@ModelAttribute("command") MemberInfo memberInfo,

BindingResult result) {

new MemberInfoValidator().validate(memberInfo, result);

if (result.hasErrors()) {

return "account/creationForm";

}

return "account/created";

}

}


GET/POST 각각의 요청에 따라 객체 초기화가 가능하다.

위에서보면 submit 시의 command 가 바로 @ModelAttribute("command") 의 객체를 가르키게 된다.

왜냐면 @ModelAttribute 어노테이션이 적용된 메소드가 @RequestMapping 어노테이션이 적용된 메소드보다 먼저 호출되므로,

초기화 작업처럼 되는것이다.


그리고 ModelAttribute 어노테이션이 적용된 메소드는 RequestMapping 어노테이션이 적용된 메소드와 동일한 타입의 파라미터를 가질 수 있다.

 @ModelAttribute("command")

public MemberInfo formBacking(HttpServletRequest request) {


HttpServletRequest 말고도 Locale, @RequestParam 어노테이션 적용, @PathVariable 어노테이션등을 적용가능하다.