본문 바로가기
JAVA/Spring

Spring MVC - 파라미터저장법①(Controller 메서드의 매개변수 - DTO)

by 설총이 2018. 9. 11.
[web.xml]


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
<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
 
<!-- ' /* ' ==> 어떤 경로에오는 파일이건 전부 체크 -->
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
 
<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 첫번째 요청엔 똑같은 이름의 servlet-name을 찾아 xml파일을 읽어들인다. -->
</servlet>
 
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>
cs



1. 서버가 시작되면서 web.xml을 읽으면서 시작한다.

맨 처음에 filter를 먼저 읽게되고 들어오는 모든 파일을 UTF-8처리 해주는 작업을 먼저해주고



2. .do로 실행되는 dispatcher를 읽는다.

dispatcher가 실행되면서 같은 서블릿네임을 가진 xml파일을 찾아간다.



[distpacher-servlet.xml]



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<bean id="helloController"
    class="spring.controller.HelloController" />
        
    <bean id="newArticleController" class="spring.controller.NewArticleController"
    p:articleService-ref="articleService" />
 
<bean id="articleService" class="spring.service.ArticleService" />
 
<!-- hello라는 setName을 리졸버가 받는다 그것을, /WEB-INF/views/hello.jsp 로 만들어주고 이 완성값을 
    디스페쳐에게 돌려준다. -->
<bean id="viewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/" />
    <property name="suffix" value=".jsp" />
</bean>
<!-- property들을 앞에 붙히고 뒤에붙혀서 뷰 경로를 만들어준다 -->
 
cs



3.

spring.controller.HelloController, 

spring.controller.NewArticleController, 

spring.service.ArticleService 세개의 java 클래스 파일을 bean객체화 함과 동시에 밑에 viewResolver의 정보를 로딩해놓는다.


동시에 어노테이션 @Controller를 올린 클래스들은, 컨트롤러 객체로도 생성된다.




또는, 


1
2
3
4
5
@Autowired
private ArticleService articleService;
 
<context:annotation-config/>
<context:component-scan base-package="spring.controller"/>
cs


빈객체를 일일이 생성할 필요없이, 모든 패키지를 스캔하겠다는 의미의 태그를 사용할 수 있다.

그리고 articleService부분을 @Autowired속성을 걸어서 사용 가능하다.





-------- 페이지 시작 ---------



[index.jsp]


1
2
3
4
<body>
<h2>Hello World!</h2>
<a href="article/newArticle.do">파라미터 저장하기</a><br>
</body>
cs




4. 처음 앵커태그로 article/newArticle.do로 요청이 들어가게되면, 앵커태그는 'GET' 방식으로 요청이 들어가게 된다.



[NewArticleController.java]



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
@Controller
@RequestMapping("/article/newArticle.do")
public class NewArticleController {
 
    private ArticleService articleService;
 
    // 컨트롤러 메서드 리턴타입이 String인 경우
    // 리턴값을 view name으로 사용한다.
    @RequestMapping(method = RequestMethod.GET)
    public String form() {
        return "article/newArticleForm";
    }
 
    @RequestMapping(method = RequestMethod.POST)
    public String submit(@ModelAttribute("command") NewArticleCommand command) {
        // 모델 데이터는 dispatcher를 통해 뷰로 다 알아서 전달이 된다.
        // 1. 객체 생성해서 저장하고
        // 2. 같은이름으로 전달된 파라미터의 값을 setter로 저장함
        // 3. model 데이터에 추가한다 ==> 뷰로 넘어가며 데이터도 같이 넘어간다.
        // 명시하지않으면 첫글자가 소문자인 newArticleCommand로 getter를 통해 꺼낼 수
        // 있다.(${newArticleCommand.xxxx})
        // 그 이름이 지정해주고 싶다면, @ModelAttribute("command") 를 사용해
key로 쓸 이름을 지정할 수 있다.
        articleService.writeArticle(command);
        return "article/newArticleSubmit";
    }
 
    public void setArticleService(ArticleService articleService) {
        this.articleService = articleService;
    }
}
cs





5. @Controller의 @RequestMapping에있는 /article/newArticle.do로 요청이 들어왔으나,

앵커태그로 들어오는 GET방식으로 요청이 들어왔기때문에,

method방식을 get으로 넣어논 public String form(){...} 이 실행 된다.


또한, @Controller에 해당하는 클래스의 메서드는 return 타입이 String으로 돌아가는경우 그 String값을 viewName으로 사용한다.

리턴값을 ModelAndView.setViewName("") 으로 사용하는것과 같다.






6. viewName값을 리턴하면서 dispatcher가 리턴값을 받고, dispatcher가 그 네임을 viewResolver로 바로 요청(Request)한다.


return값이 "article/newArticleForm" 이고, Resolver의 prefix와 suffix에 맞추어서 뷰경로가 결정된다.


1
2
3
4
5
<bean id="viewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/" />
    <property name="suffix" value=".jsp" />
</bean>
cs



article/newArticleForm 라는 스트링 값에

앞에 prefix가 붙고,

뒤에 suffix가 붙는다.


즉 view경로는 '/WEB-INF/views/' + 'article/newArticleForm' + '.jsp' 가 된다.

-prefix-                    -viewName-                         -suffix-


경로에 맞춰서 /WEB-INF/views/article/newArticleForm.jsp 에있는 jsp페이지를(뷰::view) Open한다.

물론, 웹페이지에있는 url경로는 처음 요청한 /article/newArticle.do에서 변하지않는다.




[/WEB-INF/views/article/newArticleForm.jsp]


1
2
3
4
5
6
7
게시글 쓰기 입력 폼:
<form method="post">
    <input type="hidden" name="parentid" value="10" /
    제목: <input type="text" name="title" /><br/>
    내용: <textarea name="content"></textarea><br /
    <input type="submit" />
</form>
cs



또한, 반드시 폼에서 보내지는 name값과

같은 DTO가 존재해야하며, DTO가 가지는 변수명의 이름이 같아야한다


[NewArticleCommand.java]


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
public class NewArticleCommand {
 
    private String title;
    private String content;
    private int parentid;
    
    
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public int getParentid() {
        return parentid;
    }
    public void setParentid(int parentid) {
        this.parentid = parentid;
    }
    @Override
    public String toString() {
        return "NewArticleCommand [title=" + title + ", content=" 
+ content + ", parentid=" + parentid + "]";
    }
}
cs



이번엔 Form형태의 전송이다. parentid, title, content 세가지의 name과 value값 세가지로 전송되는데,

이번 Form은 POST방식으로 보내지게된다. POST방식임을 기억하자





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Controller
@RequestMapping("/article/newArticle.do")
public class NewArticleController {
 
    @Autowired
    private ArticleService articleService;
 
    @RequestMapping(method = RequestMethod.POST)
    public String submit(@ModelAttribute("command") NewArticleCommand command) {
        // 모델 데이터는 dispatcher를 통해 뷰로 다 알아서 전달이 된다.
        // 1. 객체 생성해서 저장하고
        // 2. 같은이름으로 전달된 파라미터의 값을 setter로 저장함
        // 3. model 데이터에 추가한다 ==> 뷰로 넘어가며 데이터도 같이 넘어간다.
        // 명시하지않으면 첫글자가 소문자인 newArticleCommand로 getter를 통해 꺼낼 수
        // 있다.(${newArticleCommand.xxxx})
        // 그 이름이 지정해주고 싶다면, @ModelAttribute("command") 를 사용해 
key로 쓸 이름을 지정할 수 있다.
        articleService.writeArticle(command);
        return "article/newArticleSubmit";
    }
cs



POST방식으로 요청들어왔기때문에 이번엔 public String submit(){} 메서드를 실행하게되는데,

이번에는 매개변수가 NewArticleCommand command가 있다.

Controller의 RequestMapping으로 이루어진 메서드가 실행이 될때, 

모델 데이터는 dispatcher를 통해 저장이된다. 그 순서와 방법은 다음과 같다.


----------------------------------------------------------------------------------------------------------------------------------


 모델 데이터는 dispatcher를 통해 뷰로 다 알아서 전달이 된다.

 1. 매개변수로 들어온 객체를 생성해서 저장하고

 2. 같은이름으로 전달된 파라미터의 값을 setter로 저장

 3. model 데이터에 추가한다 ==> 뷰로 넘어갈때 데이터도 자동으로 같이 넘어간다.

 명시하지않으면 첫글자가 소문자인 newArticleCommand로 ★★getter를 통해★★ 꺼낼 수 있다.

ex)${newArticleCommand.xxxx})


key값을 따로 지정해주고 싶다면, @ModelAttribute("command") 를 사용해 key로 쓸 이름을 지정할 수 있다.

==>${command.xxx}로 사용할 수 있게 된다.




다시한번더 강조하지만, 이부분에서 가능한 이유는

반드시 폼에서 보내지는 name값과 같은 DTO(getter/setter)가 존재해야하며, 

DTO(getter/setter)가 가지는 변수명과 이름이 같아야한다




return '뷰'로 넘어가기전에 articleService.writeArticle(command); 메서드를 요청했기때문에,



1
2
3
4
public class ArticleService {
    public void writeArticle(NewArticleCommand command) {
    System.out.println("신규 게시글 등록 : " + command);
}
cs



Console창에 이러한 시스템 메시지를 뿌려준 후,

return 한다.......... 


물론 여기서도 return값이 String이기때문에 이것은


@Controller에 해당하는 클래스의 메서드는 return 타입이 String으로 돌아가는경우

 String값을 viewName으로 사용한다. 

를 다시 한번더 기억하자


즉 view경로는 '/WEB-INF/views/' + 'article/newArticleSubmit' + '.jsp' 가 된다.

-prefix-                        -viewName-                         -suffix-


경로에 맞춰서 /WEB-INF/views/article/newArticleSubmit.jsp 에있는 jsp페이지를(뷰::view) Open한다.

물론, 웹페이지에있는 url경로는 처음 요청한 /article/newArticle.do에서 변하지않는다.


마지막 jsp페이지에서는 model 데이터를 저장한 상태로 뿌려지기때문에 EL로 꺼낼 수 있다.

여기서 처음 Form메서드를 요청할때와 다르게 데이터를 저장까지 한 이유는,

매개변수에 DTO(setter/getter)가 있었기 때문이다.


[/WEB-INF/views/article/newArticleSubmit.jsp]


1
2
3
4
5
<body>
    게시글 등록됨:<br>
    제목: ${command.title}<br>
    내용: ${command.content }
</body>
cs



아까 newArticleForm의 input태그창에 적어놓은 값들이 결과값으로 나오게 된다.



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

Spring MVC - 예제(List로 출력)  (2) 2018.09.12
@Autowired, @Resource, @Inject의 차이  (0) 2018.09.11
Spring - Maven웹프로젝트 web.xml설정  (0) 2018.09.11
Spring MVC 설정  (0) 2018.09.11
Spring - mybatis 연결  (0) 2018.09.10