Controller와 View의 연결 방법
Controller와 view의 연결 실습
기본적인 코드는 spring01 -> src/main/java -> com.example.spring01 패키지 안에다가 파일 생성
-연결의 흐름- 컨트롤러에 갔다가 모델에 값을 저장하고 페이지로 넘겨서 출력을 시킨다. |
-ajax란??-
Asynchronous JavaScript and XML의 약자 입니다.
javascript와 xml을 이용하여 비동기 통신을 하는 기능입니다.
쉽게 말해서 새로고침 없이 새로 고침 효과를 볼 수 있는 기능 (실시간으로 변화하는 페이지..)
ajax는 데이터를 갱신하는 곳에서 사용한다면 페이지 전환 없이 동적으로 변화하는 모습을 자연스럽게 구현할 수 있습니다.
-동기식과 비동기식-
동기식 방식 : 클라이언트가 서버에게 요청하고 응답이 올 때까지 기다리는 것.
비동기식 방식 : 클라이언트가 서버에게 요청을 하고 응답이 오기 전까지 다른일을 할 수 있다.
- JSON (JavaScript Object Notation) 이란? -
* JSON은 경량(Lightweight) 의 DATA-교환 형식
* Javascript에서 객체를 만들 때 사용하는 표현식을 의미한다.
* JSON 표현식은 사람과 기계 모두 이해하기 쉬우며 용량이 작아서, 최근에는 JSON이 XML을 대체해서 데이터 전송 등에 많이 사용한다.
* 특정 언어에 종속되지 않으며, 대부분의 프로그래밍 언어에서 JSON 포맷의 데이터를 핸들링 할 수 있는 라이브러리를 제공한다.
-예제-
main.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"%>
<!-- 설정상 jsp파일을 직접 실행할 수 없다. WEB-INF안에 있기 때문에 직접실행 불가 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<%@include file = "Include/header.jsp" %>
</head>
<body>
<%@include file = "Include/menu.jsp" %>
<h2>${message }</h2>
</body>
</html>
|
cs |
header.jsp (상단)
1
2
3
4
5
6
7
8
9
10
|
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<!-- 태그 라이브러리에서 c, fmt(숫자 지원) 태그를 작성 -->
<!-- pom.xml에 jstl이 라이브러리에 들어있기 때문에 바로 사용할 수 있다. -->
<c:set var = "path" value = "${pageContext.request.contextPath }"/>
<!-- contextpath가 사이트의 식별자(한서버에 여러가지 사이트가 돌아갈 경우에) -->
<script src="http://code.jquery.com/jquery-3.3.1.min.js"></script>
|
cs |
menu.jsp (메뉴)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- views/include/menu.jsp -->
<!-- taglib랑 c:set는 header.jsp 에 있지만 만약 작성하지 않을시에 에러가 발생할 수 있으므로 작성한다. -->
<%@ taglib prefix = "c"
uri = "http://java.sun.com/jsp/jstl/core"%>
<c:set var = "path" value = "${pageContext.request.contextPath }"/>
<!-- 자바 코드에서 String path =request.getContextPath()와 같은뜻이다 -->
<div style = "text-align: center;">
<a href = "${path }/">main</a>
<a href = "${path }/gugu.do?dan=7">구구단</a>
<!-- do를 jsp로 바꾸어도 WEB-INF폴더 안에 파일이 있으면 컨트롤러를 거치지 않으면 바로 이동할 수 없다. (보안 때문에) -->
<!-- 컨트롤러 파일로 이동한다 -->
<a href = "${path }/test.do">테스트</a>
<a href = "${path }/member/list.do">회원관리</a>
</div>
<hr>
|
cs |
MainController.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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
package com.example.spring01.controller;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
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 model.dto.ProductDTO;
@Controller //@컨트롤러 어노테이션을 사용해야 서버가 구동될때 자동적으로 올라간다.
//@Controller 어노테이션을 붙이면 해당 클래스가 컨트롤러 역할을 한다.
public class MainController {
//로그 객체 생성 , maincontroller.class에서 로그를 가져온다.
private static final Logger logger =
LoggerFactory.getLogger(MainController.class);
//시작페이지로 이동
@RequestMapping("/") //url pattern mapping
public String main(Model model)
{
//Model : 데이터를 담는 그릇 역할, map 구조로 저장됨
// model.addattribute("변수명", 값)
model.addAttribute("message","홈페이지 방문을 환영합니다.");
// <beans:property name = "prefix" value="WEB-INF/views" />
// <beans:property name = "suffix" value = ".jsp" />
// /WEB-INF/ views/main.jsp
return "main"; //원래 코드는 "/WEB-INF/views/main.jsp"이지만 servlet-context에
//main을 제외한 나머지 코드가 정의되어 있기 때문에 따로 작성하지 않아도 된다.
}
@RequestMapping(value="gugu.do",method=RequestMethod.GET) //구구단 관련 메소드
public String gugu(@RequestParam int dan, Model model) {
//int dan = 7;
String result = "";
for(int i =1; i<=9; i++) {
result += dan+"x"+i+"="+dan*i+"<br>";
}
model.addAttribute("result", result);
// gugu.jsp 로 포워딩
// <beans:property name = "prefix" value = "/WEB-INF/views/" />
// <beans:property name = "suffix" value =".jsp" />
return "test/gugu";
//return "/WEB-INF/views/gugu.jsp";
}
//리턴 타입이 void 인 경우 RequestMapping와 동일한 페이지로 넘어감
@RequestMapping("test")
public void test() {
}
@RequestMapping("test/doA") //url pattern
public String doA(Model model) {
logger.info("doA called..."); //로그 출력
//model.addAttribute(key,value)
model.addAttribute("message", "홈페이지 방문을 환영합니다.");
// 리턴타입이 void 이면 method가 종료된 후 doA.jsp로 포워드 됨
return "test/doB"; //doB.jsp로 포워딩됨
}
//void인 경우 url name과 같은 페이지로 포워딩 (method name과)
@RequestMapping("test/doB")
public void doB() {
logger.info("doB called...");
//method가 종료된 후 doB.jsp로 포워드 된다.
}
//ModelAndView : Model - 데이터 저장소, View 화면
// 데이터와 포워드할 페이지의 정보
// forward : 주소 그대로, 화면 전환, 대량의 데이터 전달
// redirect : 주소 바뀜, 화면 전환, 소량의 get 방식 데이터 전달
@RequestMapping("test/doC")
//HasgMap에 값을 담아 전달하는 메소드
public ModelAndView doC() {
Map<String, Object> map = new HashMap<>();
//맴에 객체 저장
map.put("product", new ProductDTO("샤프", 1000));
//new ModelAndView("view의 이름", "맵변수명", 맵);
//하지만 ModelAndView는 값을 하나밖에 못 받는다.
return new ModelAndView("test/doC","map",map);
}
@RequestMapping("test/doD")
public String doD() {
//redirect의 경우 return type을 String으로 설정
//doE.jsp로 리다이렉트 됨
return "redirect:/test/doE"; //포워드 //리다이렉트는 완전히 페이지가 변경되고, 다른 표현들은 값만 보내는것
// return "redirect:/hello.jsp";
}
@RequestMapping("test/doE")
public void doE() {
//doE.jsp로 포워드
}
}
|
cs |
test.jsp (테스트 파일, doF()메소드 포함)
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
|
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<%@ include file = "Include/header.jsp" %>
<script>
function doF(){
$.ajax({ //비동기 방식 (페이지가 넘어가지 않고 그 페이지에서 바로 자료가 변경됨)
type : "post",
url : "${path}/test/doF",
success : function(result){
$("#result").html(
"상품명:"+result.name+",가격:"+result.price);
}
});
}
</script>
</head>
<body>
<%@ include file = "Include/menu.jsp" %>
<h2>링크 테스트</h2>
<a href = "${path }/test/doA">doA</a><br>
<a href = "${path }/test/doB">doB</a><br>
<a href = "${path }/test/doC">doC</a><br>
<a href = "${path }/test/doD">doD</a><br>
<a href = "javascript:doF()">doF</a><br>
<div id = "result"></div>
</body>
</html>
|
cs |
gugu.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>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<%@ include file = "../Include/header.jsp"%>
</head>
<body>
<%@ include file = "../Include/menu.jsp"%>
<h2>구구단 계산 결과</h2>
${result }
</body>
</html>
|
cs |
doB.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>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<%@ include file = "../Include/header.jsp" %> <!-- header.jsp 를 포함 -->
</head>
<body>
<%@ include file = "../Include/menu.jsp" %> <!-- menu.jsp 를 포함 -->
doB 페이지
<h2>${message }</h2>
</body>
</html>
|
cs |
doC.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>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<%@ include file="../Include/header.jsp"%>
</head>
<body>
<%@ include file = "../Include/menu.jsp" %>
상품명 : ${map.product.name }<br>
가격 : ${map.product.price }
</body>
</html>
|
cs |
페이지별 View와 Controller 연결 방법
메인에서 구구단 클릭 : 구구단 버튼을 클릭하면 dan="7" 값을 넘겨주고, 컨트롤러 파일로 이동해서 gugu()메소드를 사용해 구구단 출력값을 gugu.jsp 파일로 넘겨서 gugu.jsp파일에서 출력됨. (http://localhost:8080/spring01/gugu.do?dan=7) 테스트 클릭 : http://localhost:8080/spring01/test.do 링크테스트 doA 클릭 : 메인 컨트롤러 파일로 이동해서 model을 매개변수로 받은 doA메소드에 있는 값들을 출력함 (http://localhost:8080/spring01/test/doA) 링크테스트 doB 클릭 : 메인 컨트롤러파일로 이동해서 doB()메소드를 실행하지만 리턴타입이 void라 method 종료된 후 doB.jsp로 포워딩 (실행 된다) (http://localhost:8080/spring01/test/doB) 링크테스트 doC 클릭 : 메인 컨트롤러 파일로 이동해서 doC() 메소드를 실행하고, HaspMap에 출력할 값을 담아 doC.jsp 파일로 리턴시켜서 doC.jsp 파일에서 출력이 된다. (http://localhost:8080/spring01/test/doC) 링크테스트 doD 클릭 : 미구현 (doE 파일을 아직 안만들었음) 링크테스트 doF 클릭 : 링크테스트 화면에서 바로 출력됨 페이지 변경 X (비동기 방식이기 때문) (http://localhost:8080/spring01/test.do) |
메인 컨트롤러 파일의 테스트 클래스 생성
MainController.java 우클릭 -> new -> other -> JUnit Test Case -> 이름 입력후 finish
MainControllerTest.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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
package com.example.spring01.controller;
import static org.junit.Assert.*;
import javax.inject.Inject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MockMvcBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
//JUnit4로 테스트
//스프링에서 작동되는 junit4runner을 이용해서 테스트를 한다.
@RunWith(SpringJUnit4ClassRunner.class)
//웹 설정 파일의 경로 지정
@WebAppConfiguration
@ContextConfiguration(// src/main/webapp/WEB-INF/spring 디렉터리 내부에 있는 하위 모든 xml을 참조한다는 뜻
locations = {"file:src/main/webapp/WEB-INF/spring/**/*.xml"})
public class MainControllerTest {
//로깅 처리를 위한 객체 선언
private static final Logger logger = LoggerFactory.getLogger(MainControllerTest.class);
@Inject //의존관계 주입
WebApplicationContext wac;
MockMvc mockMvc; //가상으로 컨트롤러를 테스트하기 위한 객체
@Before //테스트 전에 호출되는 코드
public void setup() throws Exception{
//컨트롤러를 셋업
mockMvc=MockMvcBuilders.webAppContextSetup(this.wac).build();
//셋업이 되었다고 출력
System.out.println("setup...");
}
@Test //JUnit가 테스트 하는 코드
public void testDoA() throws Exception {
//뷰가 완성되지 않은 상태에서도 테스트가 가능하다.
mockMvc.perform(MockMvcRequestBuilders.get("/doA"));
//현재 doA는 get방식이 아니기 때문에 찾을수 없다고 에러를 발생시킨다.
//하지만 /doA 앞에 /test를 붙이면 컨트롤러 클래스에서 맵핑이 되기때문에 실행이 된다.
logger.info("doA...");
}
}
|
cs |
mockMvc.perform(MockMvcRequestBuilders.get("/tast/doA")); 로 코드를 변경시 컨트롤러 클래스에서 맵핑이 되기때문에 "doA called..."출력
mockMvc.perform(MockMvcRequestBuilders.get("/doA")); 로 실행할 시에는 get방식이 아니기 때문에 "No mapping for GET /doA" 문구가 출력된다.
아래 책은 제가 공부할때 활용했던 책으로 추천드리는 책이니 한번씩 읽어보시는것을 추천드립니다!! ㅎㅎ
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.