아래와 같은 컨트롤러 클래스가 있을 경우 return "getBoardList.do" 혹은 
return "getBoardList.jsp"가 갖는 의미가 무엇인가?

@Controller
public class InsertBoardController {

	@RequestMapping(value="/insertBoard.do")
	public String insertBoard(BoardVO vo, BoardDAO bdDao) {
		System.out.println("InsertBoardController 글 등록 처리~");
		
		bdDao.insertBoard(vo);
		
		return "getBoardList.do";  ① 
//		return "getBoardList.jsp"; ②
	}
}

MVC에서 Controller는 기본적으로 Model에 대한 처리(DB로 부터 적정 정보 획득)와 이후 이동할 페이지 정보(View 정보)를
return 하는 역할이 Controller가 하는 역할이다.

따라서 return "getBoardList.do"가 갖는 의미도 Model에 대한 처리(bdDao.insertBoard(vo);)와 이후 이동할 페이지 정보 
즉 View 정보를 반환하는 역할의 의미가 return "getBoardList.do";인 것이다. 

따라서 Context Path가 member라고 한다면 return "getBoardList.do";의 실행은 http://localhost/member/getBoardList.do와 같은 url 형태의 request 요청이 발생하게 하는 역할이 return "getBoardList.do";의 의미이다.

return "getBoardList.jsp";의 경우는 /member/getBoardList.jsp를 막바로 호출하는 형태라고 한다면 return "getBoardList.do";의 경우는 getBoardList.do에 해당하는 특정 컨트롤러의 특정 메소드 실행후 그 특정 메소드가 지정하는 .jsp 페이지로의 이동을 의미하게 된다.

참고적으로 Controller 메소드가 return 하는 View 정보는 기본적으로 포워딩 방식으로 동작한다. 
따라서 사용자의 브라우저 주소줄에 
http://xxx.xxx.xx/member/insertBoard.do로 요청에 대해서 
return "getBoardList.do"; 해도 
사용자의 브라우저 주소줄은 http://xxx.xxx.xx/member/insertBoard.do로 변함이 없다. 
만일 포워딩이 아니라 리다이렉트 방식으로 동작하게 할려면 
return "redirect:getBoardList.do";와 같이 해야 한다.  
그러면 사용자의 브라우저 주소줄은 http://xxx.xxx.xx/member/getBoardList.do와 같이 변경되어 나타날 것이다.

※ 본 내용은 구멍가게 코딩단의 "코드로 배우는 스프링 웹 프로젝트"라는 책의 내용을 공부하다가 정리하게 된 내용이다.


Spring MVC의 동작 구조, 동작 흐름을 파악하는 것이 그렇게 간단하지가 않다.

게시판 관련 작업을 한다고 할때 다음과 같은 클래스들이 있다고 가정해 보자.


BoardDAO : interface로 MyBatis XML Mapper를 활용하여 DB 연동 작업

BoardDAOImpl : BoardDAO interface를 구현한 클래스

BoardController : @RequestMapping 어노테이션을 활용하여 HTTP URL과 jsp 뷰단을 mapping(연결)하는 역할


이상과 같을 때 게시물에 대한 페이징 처리를 위해 Criteria라는 클래스가 있다고 하자.


public class Criteria 

{

private int myPage;          //MySQL limit 구문에서 시작 페이지로 지정할 변수

private int perPageNum;   //한 페이지당 보여질 게시물 갯수


public int getMyPage() {  //myPage에 대한 getter

... 생 략 ...

}

public void setMyPage(int myPage) {  //myPage에 대한 setter

... 생 략 ...

}


... 이하 생략 ...

}


이 클래스는 전체 게시물을 하나의 페이지당 몇 개씩 보여줄 것인지의 정보와 전체 페이지들 중에서 몇 번째 페이지의 게시물을 가져올 것인지에 대한 정보를 관리하는 역할하는 클래스이다.

이를 때에 BoardController에 아래와 같은 페이징 처리하는 메소드가 있다고 가정하자.


@Controller

@RequestMapping("/board/*")

public class BoardController 

{

private static final Logger logger = LoggerFactory.getLogger(BoardController.class);


... 중략 ...


@RequestMapping(value = "/listCri", method=RequestMethod.GET)

public void listAll(Criteria cri, Model model) throws Exception

{

model.addAttribute("list", service.listCriteria(cri));

}


... 이하 생략 ...

}


이상의 상황에서 다음과 같은 url 접속이 있을 때 위의 각각의 클래스들이 어떻게 연결지어가면서 동작하는가 하는 것이다.

(아래에서 myPage와 perPageNum은 Criteria의 멤버 변수명과 일치해야 한다)


http://localhost:8080/board/listCri?myPage=3&perPageNum=15


와 같이 접속해 오면 @RequestMapping 어노테이션에 의해 BoardController의 다음 메소드가 실행이 될 것이다.


@RequestMapping(value = "/listCri", method=RequestMethod.GET)

public void listAll(Criteria cri, Model model) throws Exception

{

model.addAttribute("list", service.listCriteria(cri));

}


그리고 여기서 개발자의 손을 떠난 보이지 않는 영역가운데서 Spring에 의해서 모종의 동작들이 내부적으로 진행이 되는 것이다. 위의 listAll() 메소드에 개발자가 작성한 코드는 딸랑 한 줄 뿐이다. 이런 면이 편리하기도 하지만 내막을 모르면 개발자는 눈감고 더듬는 더듬이가 되는 것이다. 

위의 메소드에서 내부적으로 Spring 프레임웤이 자동으로 Criteria 클래스의 객체를 생성하면서 http url에 있는 myPage, perPageNum의 값을 각각 Criteria의 두 멤버 변수의 getter, setter를 이용해서 값을 할당하게 된다.

그런 후에 model을 이용해서 jsp 단에 해당 값을 넘기고 @RequestMapping의 value에 지정한 값인 listCri라는 이름의 jsp인 listCri.jsp를 실행한다(이것 또한 명시적으로 return "listCri"라고 하지 않았지만 또 역시 내부적으로 Spring에 의해처 처리가 되는 영역이다).


그런데 여기서 Criteria의 멤버 변수 perPageNum을 pgNum으로 변경할 경우 다음과 같이 접속을 하면 어떻게 될까?


http://localhost:8080/board/listCri?myPage=3&pgNum=15


만일 멤버 변수만 perPageNum을 pgNum으로 변경했다면 위의 접속은 15페이지 값이 적용되지 않는다.

원리상 되야 될것 같은데 정상동작하지 않는다.

해법은 perPageNum에 맞게 명명된 getter와 setter를 pgNum에 맞게 변경해 주어야 한다. 이것까지 변경해 주어야 위의 url은 비로소 정상 동작을 하는 것이다.

pgNum에 대한 getter, setter 명명 규칙대로 변경하면 getter는 getPgNum()이 될 것이고 setter는 setPgNum()이 될 것이다.

이렇게 getter, setter 명명 규칙에 맞게 메소드 명을 변경하지 않으면(대소문자도 정확히) 아래 URL은 정상 동작을 기대하지 말아야 한다.


http://localhost:8080/board/listCri?myPage=3&pgNum=15


순수 Java/JSP로 개발할 때는 개발자가 직접 코딩해야 하던 것들이 Spring을 이용하면 개발자의 손 가락을 쉬게해 주는 여러 편리한 면도 있지만 이 편리함이라는 게 개발자의 손을 떠난 영역에서 동작하는 것들이 점점 많아 지게 된다는 이야기가 되고 개발자는 더듬이가 되어가야 한다는 이야기로 귀결하는 것 같다.

그래도 아무튼 뭐 어쩌겠는가?




Spring에서의 @RequestMapping 어노테이션에 대한 간단 정리


-. @RequestMapping 어노테이션은 Spring 웹 애플리케이션에서 가장 자주 사용되는 annotation이다.

-. @RequestMapping은 http request로 들어오는 url을 특정 controller 클래스나 메소드로 연결시키는 역할을 한다.

-. @RequestMapping은 controller에 있어서 class에 적용할수도 있고 특정 method에 적용할수도 있다.


아래의 예를 통해서 확인해 보자.


@Controller

@RequestMapping("/home")

public class TestController 

{

     //아래 @RequestMapping은 

     //hostname:port/home/에 대한 http request url에 대응하는 역할

    @RequestMapping("/")

    String getName(){

        return "Hello from getName() method";

    }

 

     //아래 @RequestMapping은 

     //hostname:port/home/info/에 대한 http request url에 대응하는 역할

    @RequestMapping("/info")

    String showInfo(){

        return "Hello from showInfo() method";

    }

}


-. http://localhost:8080/home/은 getName()을 호출하게 된다.

-. http://localhost:8080/home/info은 showInfo()을 호출하게 된다.


아래와 같이 @RequestMapping을 이용해서 특정한 method에 Multiple URI를 적용할수도 있다. 


@Controller

@RequestMapping("/home")

public class TestController 

{

    @RequestMapping(value={"", "/info", "info*","view/*,**/msg"})

    String myMultiMapping(){

        return "Hello from myMultiMapping()";

    }

}


위와 같이 @RequestMapping은 와일드 카드(wildcards)도 사용할수 있다. 

위의 코드에서 아래의 모든 URL들은 myMultiMapping() 메소드로 연결될 것이다.


localhost:8080/home

localhost:8080/home/

localhost:8080/home/info

localhost:8080/home/infosub

localhost:8080/home/view/

localhost:8080/home/view/view



+ Recent posts