본문 바로가기
Web/Spring

Spring MVC(2)

by 미티치 2016. 5. 16.

- Spring MVC 기초 사용법




 

 

Spring MVC 프로젝트는 개발자의 수고를 덜어줄 수 있게 미리 MVC2패턴으로 스프링 컨테이너가 다 만들어 놓은 프로젝트라고 이전에 언급했었다.

 

 

 

■ Spring MVC Project 기초 사용법

 

먼저 home.jsp가 아닌 게시판의 view.jsp를 HomeController에서 불러보자.

home.jsp가 있던 WEB-INF/views/에 board폴더를 하나 생성해서 그 안에 view.jsp를 생성한다. 이 view파일을 보여주려면 HomeController에서 RequestMapping을 해주어야 한다. ( 41번째 줄~)

 

[ HomeController ]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.javalec.mvctest;
 
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
 
import com.javalec.mvctest.member.Member;
 
@Controller
public class HomeController {
    private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
    
    /**
     * Simply selects the home view to render by returning its name.
     */
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Locale locale, Model model) {
        logger.info("Welcome home! The client locale is {}.", locale);
        
        Date date = new Date();
        DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
        
        String formattedDate = dateFormat.format(date);
        
        model.addAttribute("serverTime", formattedDate );
        
        return "home";
    }
    
    //요부분!!
    @RequestMapping("/board/view")
    public String view(){
        return "board/view";
    }
cs

 

 

정말 간단하지 않은가?? 어노테이션을 사용해서 클라이언트가 호출할 값을 @RequestMapping( ) 여기에 지정해주고, 이 호출한 값에 지정할 jsp 파일을 메소드 안에 지정하면 된다. views 폴더까지의 경로는 ViewResolver로 지정되어 있기 때문에 views 이하의 경로+파일명만 리턴해주면 알아서 /WEB-INF/views/board/view.jsp를 웹에서 보여준다.

 

 




 

그럼 이제부터 설명할 기초 문법들은 HomeController에 추가되는 작업들이다.




 

Model 객체와 ModelAndView 객체 사용



( views/board/ 위치에 reply.jsp와 content.jsp를 생성하세용 )

 

- Model 객체와 ModelAndView 객체의 차이점 ?

: Model 객체는 데이터를 관리하는 객체이고, ModelAndView는 데이터와 경로를 관리하는 객체

 -> 그렇다면 Model 객체의 Scope(범위)는 어디까지인가? Controller안에서 사용

 

[ HomeController ]

- Model 객체는 매개변수로 받을 때 생성해서 아래와 같이 사용하기만 하면 된다. Model은 데이터를 넘기기 위해 사용하기 때문에 return값은 view파일 이름이다. 

- 하지만 ModelAndView 객체는 메소드 안에서 객체를 직접 생성해서 사용한다. ModelAndView 객체는 데이터와 경로를 같이 관리하기 때문에 ModelAndView에 데이터를 set하고 setViewName으로 view파일 경로까지 지정하여 이 ModelAndView 객체를 리턴한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    //1. model사용 -> model은 파라메터로 그냥 이렇게 쓰기만하면됨 (객체 생성하는거 아님)
    @RequestMapping("/board/reply")
    public String reply(Model model){
        //데이터를 웹에서 받아서 넘길수있는 객체 ->생성하지 않고 이렇게 그냥 쓰기만하면된다. 
        //mvc의 model과 다르다. 이전에 boardDAO에서 bean을 받아서 넘기는거랑 비슷
        model.addAttribute("id",30);
        return "board/reply";
    }
    //2. modelAndView (데이터와 경로를 관리하는 객체)
    @RequestMapping("/board/content")
    public ModelAndView content(){
        ModelAndView mav = new ModelAndView();
        mav.addObject("id",30);
        mav.setViewName("board/content");    
        return mav;
    }
cs

 

 [ reply.jsp ] = [ content.jsp ]

1
2
3
4
5
6
7
8
9
10
11
12
<%@ 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>Insert title here</title>
</head>
<body>
    ID : ${id}
</body>
</html>
cs

 


출력결과 및 분석

 

 

 










Model과 Request를 같이 사용하는 방법


( views/board/ 위치에 confirmId.jsp와 checkId.jsp를 생성하세용 )

( 두가지 방법의 차이를 보이기 위해서 confirmId, checkId를 따로 생성한것일 뿐! )




[ HomeController ]

- Request객체를 쓸 때는 Model처럼 메소드의 매개변수로 HttpServletRequest를 받아서 쓰면 된다. 가장 일반적인 방법.

- 메소드 checkId는 confirmId와 같은 방식이지만 어노테이션을 사용한 방법이다. HttpServletRequest 객체 대신에 @RequestParam으로 매개변수에서 지정하여 전달한다.


RequestParam : HTTP 요청 파라미터를 메소드 파라미터에 넣어주는 어노테이션이다. 가져올 요청 파라미터의 이름을 @RequestParam 어노테이션의 기본 값으로 지정해주면 된다. 요청 파라미터의 값은 메소드 파라미터의 타입에 따라 적절하게 변환된다. @RequestParam을 사용했다면 해당 파라미터가 반드시 있어야한다. 값이 없거나 순서가 다르면 400에러를 발생시킨다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    //Model과 Request를 다 쓰는 방법
    @RequestMapping("/board/confirmId")
    public String confirmId(HttpServletRequest httpServletRequest, Model model){
        String id = httpServletRequest.getParameter("id");
        String pw = httpServletRequest.getParameter("pw");
        model.addAttribute("id",id);
        model.addAttribute("pw",pw);
        
        return "board/confirmId";
    }
    //위의 방법은 값을 안넘기면 값이 출력이 안넘어오지만 , annotation방식은 값을 안넘기면 400에러를 발생시킨다 -> 더 명확하다
    // + 그리고 파라미터 순서를 어기면 안된다.
    //위와 같은 방법과 같은 방식! 어노테이션
    @RequestMapping("/board/checkId")
    public String checkId(@RequestParam("id"String id, @RequestParam("pw"String pw, Model model){
        model.addAttribute("id",id);
        model.addAttribute("pw",pw);        
        
        return "board/checkId";
    }
cs



[ confirmId.jsp ] = [ checkId.jsp ]

1
2
3
4
5
6
7
8
9
10
11
12
13
<%@ 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>Insert title here</title>
</head>
<body>
    ID : ${id}<br>
    PW : ${pw}
</body>
</html>
cs





출력결과 및 분석

 



 

- 실습은 이전 페이지에서 값을 넘겨준 것이 아니라 주소창에서 값을 지정해서 넘겨준 것이다.

- 넘겨진 값이 제대로 넘어온 것을 확인할 수 있다.

 









넘길 데이터가 많아져서 request객체가 많아질땐 어떻게 해야하나?


( views/member/ 위치에 join.jsp 생성하세용 )



[ HomeController ]

: 아래 코드처럼 넘겨야할 값이 많아질 땐 넘길 데이터를 한번에 받아줄 Member 객체(Bean)를 사용한다. 데이터가 저장된 member는 model 객체에 attribute로 지정되어 데이터를 전달한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
    @RequestMapping("/member/join")
    public String joinData(@RequestParam("name"String name,@RequestParam("id"String id, 
            @RequestParam("pw"String pw, @RequestParam("email"String email, Model model){
        Member member = new Member();
        member.setName(name);
        member.setId(id);
        member.setPw(pw);
        member.setEmail(email);
        
        model.addAttribute("memberInfo",member);
        return "member/join";
    }
 
cs


[ join.jsp ]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!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=utf-8">
<title>Insert title here</title>
</head>
<body>
    NAME : ${memberInfo.name}<br>
    ID : ${memberInfo.id}<br>
    PW : ${memberInfo.pw}<br>
    EMAIL : ${memberInfo.email}
</body>
</html>
cs




출력결과 및 분석




- 주소창에서 get방식으로 넘긴 값들을 제대로 전달 받은 것을 확인할 수 있다.






하지만 위에 코드처럼 넘기는 값이 많아지면, 매개변수로 받아야하는 값이 많아져 코드가 가독성이 떨어지게 된다. 위와 똑같은 출력 결과를 갖지만 좀 더 간결하게 작성하려면 아래와 같은 방식이 있다.




[ HomeController ]

: 이 방식은 간편하지만 오히려 명확하지 않아 자칫 헷갈릴 수 있는 코드이다. 위의 코드를 알고있어야 이부분도 알 수있다. 매개변수로 받은 Member 객체에 컨테이너가 알아서 전달받은 데이터값을 저장하고 지정된 url로 보내주는 기능까지 하고있다. 

1
2
3
4
5
6
    //위에처럼 쓰면 코드가 길고 불편하기 때문에 이와같은 방식을 사용한다. 
    @RequestMapping("/member/join")
    public String joinData2(Member member){
        //get방식으로 넘긴 값을 매개변수로 넘어온 member 객체에 '컨테이너'가 알아서 set해준다. 
        return "member/join";
    }
cs


[ join.jsp ]  소스코드 수정했음!

: 컨테이너가 내부에서 전달하는 Member객체(Bean)는 "member"에 지정되어서 넘어오는 것 같다. ${member.name}에서 member를 다른 이름으로 바꾸면 값이 넘어오지 않는다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!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=utf-8">
<title>Insert title here</title>
</head>
<body>
    NAME : ${member.name}<br>
    ID : ${member.id}<br>
    PW : ${member.pw}<br>
    EMAIL : ${member.email}
</body>
</html>
cs








값을 넘기는 또 하나의 방법


( views/student/ 위치에 studentView.jsp 파일 생성하세용 )


[ HomeController ]

: @RequestMapping에서 { } 안에 전달할 파라미터를 지정하고 매개변수로 @PathVariable로 이 파라미터를 넘긴다. ( @RequestParam처럼) 그리고 넘길 데이터를 model에 setAttribute하여 넘기기만하면 된다.


PathVariable : @RequestMapping의 URL 정의 부호의 중괄호{} 에 명시된 패스 변수를 받는다. @Controller는 URL에서 파라미터에 해당하는 부분에 {}을 넣는 URI 템플릿을 사용할 수 있다. 컨트롤러 메소드 파라미터에는 @PathVariable  어노테이션을 이용해 URI 템플릿 중에서 어떤 파라미터를 가져올지 결정할 수 있다. @RequestMapping( ) 에 들어가는 URI의 중괄호에 패스변수를 넣는다. 이 변수이름을 @PathVariable 어노테이션 값으로 넣어서 메소드 파라미터에 부여해주면 된다. 파라미터의 타입은 URL의 내용이 적절히 변환될 수 있는 것을 사용해야하며, 만약  int타입을 썼을 경우 반드시 해당 패스변수자리에 int형 값이 들어있어야한다. 타입이 일치하지 않는 값이 들어왔을때 별다른 예외처리가 없다면 HTTP 400 에러가 날 것이다.


이전에는 URL에서 값을 넘기는 방식으로 URL?name=minsu 이렇게 넘겼는데 PathVariable을 사용하면 URL/minsu 이렇게 값을 넘길 수 있다.

1
2
3
4
5
6
    //주소창에 mvctest/student/10 이렇게 검색하면 값이 넘어감
    @RequestMapping("/student/{studentId}")
    public String getStudent(@PathVariable String studentId, Model model){
        model.addAttribute("studentId",studentId);
        return "student/studentView";
    }
cs



[ studentView ] 

1
2
3
4
5
6
7
8
9
10
11
12
<%@ 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>Insert title here</title>
</head>
<body>
    ID : ${studentId}<br>
</body>
</html>
cs



출력결과 및 분석





- 주소창에서 값을 넘기는 방식이 이전의 방식들과는 다른 점에 유의해야한다.










resource 사용



한가지 더 정리하자면, 우리가 servlet-context.xml에 보면 아래와 같은 코드가 있다. MVC(1)에서도 설명했지만, 이부분은 개발자가 사용할 자원을 저장해놓는 resource 위치를 매핑해놓은 부분이다. 다음 예제를 보자

1
2
    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
    <resources mapping="/resources/**" location="/resources/" />
cs



기본적으로 가지고 있던 resources 위치에 img 폴더를 생성하고 그 안에 png파일을 넣어보자.



이 이미지를 출력하기 위해서 home.jsp에 다음과 같은 한 줄을 추가!해보자

[ home.jsp ]

1
<p> <img src="resources/img/stitch_fromJ.png"></p>
cs



출력 결과 



- 정상적으로 이미지 파일이 출력되었음을 확인할 수 있다.





그렇다면 모든 자원을 resource 파일에 넣지 않고 폴더를 하나 더 생성하려면 어떻게 해야할까? 다음과 같이 resources01/img 폴더를 생성해서 png파일을 넣어보자.



이번에 추가한 이미지도 출력하기 위해 home.jsp에 2번 줄 코드를 추가한다.

[ home.jsp ]

1
2
<p> <img src="resources/img/stitch_fromJ.png"></p>
<p> <img src="resources01/img/stitch_fromJ.png"></p>
cs




출력 결과 



- 1번째 줄 코드의 이미지태그는 출력되었지만 resources01/img/ 에 위치한 파일은 출력되지않았다.






왜 이런 결과가 나올까? 정답은 servlet-context.xml에 resource 폴더가 매핑되어 있지 않기 때문이다. 그렇다면 우리가 의도한대로 실행하기 위해선는 servlet-context.xml에 다음 2번줄 코드와 같이 resources01폴더도 매핑시켜 주어야 한다.


1
2
    <resources mapping="/resources/**" location="/resources/" />
    <resources mapping="/resources01/**" location="/resources01/" />
cs





출력 결과 




resources01 폴더 안에 있는 경로들도 읽을 수 있게 되어 의도한대로 두 이미지파일이 출력되었다.







Form에서 값 넘기기































'Web > Spring' 카테고리의 다른 글

Spring MVC Board (1)_Spring Board  (0) 2016.05.19
Spring MVC(3)_Annotation & @RequestMapping  (0) 2016.05.17
Spring MVC(1)  (0) 2016.05.16
Spring 한글처리  (0) 2016.05.16
Spring(4)_Environment,Properties  (0) 2016.05.13