[Spring] @ModelAttribute 및 중첩 커맨드 객체, Model & ModelAndView

| @ModelAttribute


@ModelAttribute는 스프링에서 JSP파일에 반환되는 Model 객체에 속성값을 주입하거나 바인딩할 때 사용되는 어노테이션이다. 컨트롤러(Controller) 객체에서 2가지 방법으로 사용된다.


@ModelAttribute("serverTime")
public String getServerTime(Locale locale) {
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
return dateFormat.format(date);
}

먼저 메서드에 @ModelAttribute를 붙이는 경우다. 이 때 serverTime 속성을 Model 객체에 아래와 같은 코드를 실행함으로서 반환되는 dateFormat.format(date) 값을 바인딩한다. 이 값은 JSP 파일에서 사용할 수 있다.


@RequestMapping(value="/memJoin", method=RequestMethod.POST)
public String memJoin(@ModelAttribute("mem") Member member) {
service.memberRegister(member);
return "memJoinOk";
}

다음은 컨트롤러 메서드의 인수에 어노테이션을 부착하는 경우다. @ModelAttribute을 써서 HTTP 요청에 들어있는 속성값들을 Member 커맨드 객체에 자동적으로 바인딩 하게 된다. 만일 @ModelAttribute([NAME]) 형태로 붙일경우 JSP파일에서 ${[NAME].property} 형태로 Model 객체의 값을 사용할 수 있게 된다.


@Controller
@RequestMapping("/member")
public class MemberController {

@Resource(name="memService")
MemberService service;

@ModelAttribute("serverTime")
public String getServerTime(Locale locale) {
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
return dateFormat.format(date);
}

@RequestMapping(value="/memJoin", method=RequestMethod.POST)
public String memJoin(@ModelAttribute("mem") Member member) {
service.memberRegister(member);
return "memJoinOk";
}
}

위 두 가지 방식을 동시에 써서 @ModelAttribute를 써서 JSP파일에 전달하는 Model 객체에 serverTime 속성과 mem으로 표현되는 Member 객체의 데이터를 넘겨줄 수 있다. 


<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>memJoinOk</title>
</head>
<body>
<h1> memJoinOk</h1>

ID : ${mem.memId} <br/>
PW : ${mem.memPw} <br/>
Mail : ${mem.memMail} <br/>
Phone : ${mem.memPhone.memPhone1} - ${mem.memPhone.memPhone2} - ${mem.memPhone.memPhone3} <br/>
<P> The time on the server is ${serverTime}. </P>
<a href="/mvc/resources/html/memJoin.html"> Go MemberJoin</a>
</body>
</html>


| 중첩 커맨드 객체


사용자가 HTTP로 사용자 데이터를 보내올 때 커맨드 객체를 여러 번 중첩시켜서 보낼 수 있다. 이 중첩 커맨드 객체는 VOList 형태로 데이터를 받을 수 있다. HTML 파일에서 데이터를 전송할 때 데이터의 name 속성은 아래처럼 커맨드 객체의 속성명과 인덱스 그리고 속성을 명시해야한다.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Member Join</h1>
<form action="/lec19/member/memJoin" method="post">
...

PHONE1 : <input type="text" name="memPhones[0].memPhone1" size="5"> -
<input type="text" name="memPhones[0].memPhone2" size="5"> -
<input type="text" name="memPhones[0].memPhone3" size="5"><br />
PHONE2 : <input type="text" name="memPhones[1].memPhone1" size="5"> -
<input type="text" name="memPhones[1].memPhone2" size="5"> -
<input type="text" name="memPhones[1].memPhone3" size="5"><br />

...
</form>
<a href="/lec19/resources/html/login.html">LOGIN</a> &nbsp;&nbsp; <a href="/lec19/resources/html/index.html">MAIN</a>
</body>
</html>

PHONE1, PHONE2의 중첩 커맨드 객체는 아래의 List형태의 MemPhone 객체 리스트로 받을 수 있다.


public class Member {

private String memId;
private String memPw;
private String memMail;
private List<MemPhone> memPhones;

...
}
public class MemPhone {

private String memPhone1;
private String memPhone2;
private String memPhone3;

public String getMemPhone1() {
return memPhone1;
}
public void setMemPhone1(String memPhone1) {
this.memPhone1 = memPhone1;
}
public String getMemPhone2() {
return memPhone2;
}
public void setMemPhone2(String memPhone2) {
this.memPhone2 = memPhone2;
}
public String getMemPhone3() {
return memPhone3;
}
public void setMemPhone3(String memPhone3) {
this.memPhone3 = memPhone3;
}

}


| Model & ModelAndView 


컨트롤러에서 뷰에 데이터를 전달하기 위해 사용되는 객체로 ModelModelAndView가 있다. ModelModelAndView의 차이는 Model은 데이터만을 전달하기 위한 객체이고 ModelAndView는 데이터와 뷰의 이름을 함께 전달하는 객체다.


아래 코드를 보면 Model은 객체에 속성값을 넣어 JSP에 해당 속성값을 제공하는 역할을 한다. ModelAndViewModel이 하는 역할 뿐만 아니라 해당 뷰의 이름을 추가하여 전달할 수 있다. 또한 메서드의 리턴값에도 차이가 있다.

@RequestMapping(value = "/memModify", method = RequestMethod.POST)
public String memModify(Model model, Member member) {

Member[] members = service.memberModify(member);

model.addAttribute("memBef", members[0]);
model.addAttribute("memAft", members[1]);

return "memModifyOk";
}


@RequestMapping(value = "/memModify", method = RequestMethod.POST)
public ModelAndView memModify(Member member) {

Member[] members = service.memberModify(member);

ModelAndView mav = new ModelAndView();
mav.addObject("memBef", members[0]);
mav.addObject("memAft", members[1]);

mav.setViewName("memModifyOk");

return mav;
}


이 글을 공유하기

댓글(2)

  • 2019.08.22 13:18 신고

    안녕하세요 자세한 강좌를 올려 주셔서 잘 보고 있습니다.
    궁금한 부분이 있는데요
    @ModelAttirbue 가 메소드에 붙으면 해당 컨트롤러(클래스) 안에 있는 모든 서버스에
    같이 넘어 가게 되는 건가요?
    예제를 보면 memJoin 서비스를 호출할때 같이 serverTime 가 view에 넘어가자나요?
    만약에 memModify나 memDelete 서버스가 더 있다고 할때
    이 서비스를 호출 할때도 같이 serverTime가 넘어 가는 것인지
    어떤 조건이 있어서 특별한 조건이 만족할 때만 serverTime가 넘어 가는 것인지 궁금합니다.

    • 2019.08.23 17:34 신고

      댓글 감사합니다! Model 객체에 serverTime이 추가되어 넘어갑니다. 따라서 memModify, memDelete 서비스를 추가해도 같이 model에 추가되어 view 단으로 넘어갑니다!

Designed by JB FACTORY