본문 바로가기
Dev/Spring

스프링 5 @Controller 구현과 테스트

by vellahw 2022. 11. 1.

 

 

스프링 MVC의 Controller는 하나의 클래스 내에서 여러 메소드를 작성하고 @RequestMapping 등을 이용해서 URL을 분기하는 구조로 작성할 수 있기 때문에 하나의 클래스에서 필요한 만큼 메소드의 분기를 이용하는 구조로 작성한다.

 

<테이블 설계>

업무 URL 메소드 파라미터 URL 이동
전체 목록 /board/list GET      
등록 처리 /board/register POST 모든 항목 입력화면 필요 이동
조회 /board/get GET bno = ?    
삭제 처리 /board/remove POST bno 입력화면 필요 이동
수정 처리 /board/modify POST 모든 항목 입력화면 필요 이동
  • 폼: 해당 URL을 호출하기 위해 별도의 입력화면이 필요하다는 뜻

 

 

🎇. 서비스 클래스

https://tavi.tistory.com/80

 

스프링 @Service 서비스 구현과 테스트

0. BoardMapper.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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLI..

tavi.tistory.com

 

 

🎇 BoardContoller 작성

  • 컨트롤러 클래스에 URL 분석된 내용들을 반영하는 메소드를 설계한다.

 

 

1. 전체 목록을 가져오기 위한 처리와 테스트

  • BoardContoller는 BoardService 타입의 객체와 연동해야 하므로 의존성에 대한 처리도 같이 진행함.

 

▼ BoardContoller 

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
package org.hw.controller;
 
import org.hw.service.BoardService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
 
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;
 
@Controller
@Log4j
@RequestMapping("/board/*"//'/board'로 시작하는 모든 처리를 함
@AllArgsConstructor
public class BoardContoller {
    
    private BoardService service;
    
    @GetMapping("/list")
    public void list(Model model) {
        
        log.info("list");
        
        model.addAttribute("list", service.getList());
    }
}
cs

BoardContoller는 BoardService에 대해서 의존적이므로 @@AllArgsConstructor를 이용해서 생성자를 만들고 자동으로 주입하도록 한다.

list()는 나중에 게시물의 목록을 전달해야 하므로 Modle을 파라미터로 지정하고 이를 BoardServiceImpl 객체의 getList()에 결과를 담아 전달한다.

 

▼ 테스트 클래스 (BoardContollerTest)

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
package org.hw.controller;
 
import org.hw.service.BoardServiceTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
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.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
 
import lombok.Setter;
import lombok.extern.log4j.Log4j;
 
@RunWith(SpringJUnit4ClassRunner.class)
 
//Servlet의 ServletContext를 사용하기 위함
// = WebApplicationContext를 사용하기 위함
@WebAppConfiguration
 
@ContextConfiguration({
"file:src/main/webapp/WEB-INF/spring/root-context.xml",
"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"})
@Log4j
public class BoardContollerTest {
    
    @Setter(onMethod_ = { @Autowired })
    private WebApplicationContext ctx;
    
    //'가짜 mvc'- 가짜로 파라미터와 URL 등을 만들어 컨트롤러 실행 가능
    private MockMvc mockMvc; 
 
    @Before //모든 테스트 전에 매번 실행되는 메소드임을 표시
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build();
    }
    
    //DB에 저장된 게시물 보기
    @Test
    public void testList() throws Exception {
        log.info(mockMvc.perform(MockMvcRequestBuilders.get("/board/list")) //get방식 호출
                .andReturn().getModelAndView().getModelMap());
        
    }
}
cs
  • perform : 요청 설정 메서드를 통해 요청에 대한 설정을 할 수 있다.
  • andReturn() : 요청을 실행한 결과를 MvcReesult 타입으로 리턴

 

테스트 실행

테스트 실행 결과 로그

 

 

 

2. 등록 처리와 테스트

▼ BoardContoller에 추가

 

▼ 테스트 클래스 코드 추가 (BoardContollerTest)

  • MockMvcRequestBuilder의 post()를 이용하면 POST 방식으로 데이터를 전달 가능
  • param( ): 전달해야 하는 파라미터들 지정 가능 (<input> 태그와 유사한 역할을 함)

 

 

 테스트 실행

로그 확인

 

DB 전송 확인

 

 

 

3. 조회 처리와 테스트

  • 특별한 경우가 아니라면 조회는 GET 방식으로 처리함

 

▼ BoardContoller에 추가

bno 값을 좀 더 명시적으로 처리하기 위해 @RequestParam 이용

화면 쪽으로 해당 번호의 게시물을 전달해야 하기 때문에 Model을 파라미터로 지정함

 

▼ 테스트 클래스 코드 추가 (BoardContollerTest)

특정 게시물을 조회할 때는 반드시 bno(글번호)가 필요하므로 param()을 통해 추가하고 실행한다.

 

 테스트 실행

16번 게시글 조회 가능

 

Model에 담겨있는 BoardVO의 인스턴스의 내용 확인 가능

 

 

 

4. 수정 처리와 테스트

수정 작업은 등록과 유사한데, 변경된 내용을 수집해서 BoardVO 파라미터로 처리하고 BoardService를 호출한다.

수정 작업을 시작하는 화면의 경우에는 GET 방식으로 접근하지만 실제 작업은 POST 방식으로 동작하므로 @PostMapping을 이용해서 처리함

 

▼ BoardContoller에 추가

service.modify()는 수정 여부를 boolean 타입으로 지정했기 때문에 true일 경우에만 RedirectAttributes에 추가한다.

 

▼ 테스트 클래스 코드 추가 (BoardContollerTest)

 

 테스트 실행

 

수정된 DB 확인

 

 

 

5. 삭제 처리와 테스트

  • 삭제는 반드시 POST 방식으로만 처리

 

▼ BoardContoller에 추가

 

▼ 테스트 클래스 코드 추가 (BoardContollerTest)

 

 테스트 실행

로그 확인
DB단 삭제 확인

 

 

🎈 완성된 컨트롤러 클래스

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
package org.hw.controller;
 
import org.hw.domain.BoardVO;
import org.hw.service.BoardService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
 
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;
 
@Controller
@Log4j
@RequestMapping("/board/*"//'/board'로 시작하는 모든 처리를 함
@AllArgsConstructor
public class BoardContoller {
    
    private BoardService service;
    
    //전체 게시글 보기
    @GetMapping("/list")
    public void list(Model model) {
        
        log.info("list");
        
        model.addAttribute("list", service.getList());
    }
    
    //게시글 등록
    @PostMapping("/register")
    public String register(BoardVO board, RedirectAttributes rttr) {
    //RedirectAttributes: 등록 작업이 끝난 후 다시 목록으로 이동하기 위함
        
        log.info("register: " + board);
        
        service.register(board); //입력처리
        
        rttr.addFlashAttribute("result",  board.getBno()); //새롭게 등록된 번호를 가짐
        
        return "redirect:/board/list"//입력 성공시 글목록 페이지로 리다이렉트
    }
    
    //게시글 조회
    @GetMapping("/get")
    public void get(@RequestParam("bno") Long bno, Model model) {
        
        log.info("/get");
        model.addAttribute("board", service.get(bno));
    }
    
    //게시글 수정
    @PostMapping("/modify")
    public String modify(BoardVO board, RedirectAttributes rttr) {
        
        log.info("modify: " + board);
        
        if(service.modify(board)) { //true라면
            rttr.addAttribute("result""success");
        }
        
        return "redirect:/board/list";
    }
    
    //게시글 삭제
    @PostMapping("/remove")
    public String remove(@RequestParam("bno") Long bno, RedirectAttributes rttr) {
            
        log.info("remove!!!! " + bno);
        
        if(service.remove(bno)) { //true라면
            rttr.addAttribute("result""success");
        }
            
        return "redirect:/board/list"//삭제 성공시 글목록 페이지로 리다이렉트
    }
}
cs

 

🎈 완성된 테스트 클래스

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
package org.hw.controller;
 
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
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.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
 
import lombok.Setter;
import lombok.extern.log4j.Log4j;
 
@RunWith(SpringJUnit4ClassRunner.class)
 
//Servlet의 ServletContext를 사용하기 위함
// = WebApplicationContext를 사용하기 위함
@WebAppConfiguration
 
@ContextConfiguration({
"file:src/main/webapp/WEB-INF/spring/root-context.xml",
"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"})
@Log4j
public class BoardContollerTest {
    
    @Setter(onMethod_ = { @Autowired })
    private WebApplicationContext ctx;
    
    //'가짜 mvc'- 가짜로 파라미터와 URL 등을 만들어 컨트롤러 실행 가능
    private MockMvc mockMvc; 
 
    @Before //모든 테스트 전에 매번 실행되는 메소드임을 표시
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build();
    }
    
    //DB에 저장된 게시물 보기
    @Test
    public void testList() throws Exception {
        log.info(mockMvc.perform(MockMvcRequestBuilders.get("/board/list")) //get방식 호출
                .andReturn().getModelAndView().getModelMap());
    }
    
    //게시글 등록
    @Test
    public void testRegister() throws Exception {
    
        String resultPage = mockMvc.perform(MockMvcRequestBuilders.post("/board/register")
                .param("title""테스트 새글 제목")
                .param("content""테스트 새글 내용")
                .param("writer""테스트 새글 작성자")) //param 쿼리 스트링 설정
                .andReturn().getModelAndView().getViewName();
        
        log.info(resultPage);
    }
    
    //게시글 조회
    @Test
    public void testGet() throws Exception {
        log.info(mockMvc.perform(MockMvcRequestBuilders
                .get("/board/get")
                .param("bno""16"))
                .andReturn()
                .getModelAndView().getModelMap());
    }
 
    //게시글 수정
    @Test
    public void testModify() throws Exception {
    
        String resultPage = mockMvc.perform(MockMvcRequestBuilders.post("/board/modify")
                .param("bno""16")
                .param("title""수정된 테스트 새글 제목")
                .param("content""수정된 테스트 새글 내용")
                .param("writer""수정된 테스트 새글 작성자"))
                .andReturn().getModelAndView().getViewName();
        
        log.info(resultPage);
    }
 
    //게시글 삭제
    @Test
    public void testRemove() throws Exception {
    
        String resultPage = mockMvc.perform(MockMvcRequestBuilders
                .post("/board/remove")
                .param("bno""16"))
                .andReturn().getModelAndView().getViewName();
        
        log.info(resultPage);
    }
}
cs

댓글