본문 바로가기
개발입문/SPRING 게시판 만들기

[SPRING] 프레젠테이션계층의 CRUD 구현

by 양히◡̈ 2022. 10. 12.

프레젠테이션 계층의 CRUD 구현하기

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

따라서 Controller 클래스를 만들고, 필요한 만큼 메소드의 분기를 이용하는 구조로 작성할 것이다.

작성하기 전에, 원하는 기능을 호출하는 방식을 미리 정리해두면 좋다.

Task
URL
Method
Parameter
From
URL이동
전체목록
/board/list
GET
등록
/board/register
POST
모든항목
입력화면 필요
이동
조회
/board/get
GET
bno=123
삭제
/board/remove
POST
bno
입력화면 필요
이동
수정
board/modify
POST
모든항목
입력화면 필요
이동
 
 

 

전체목록 조회

src/main/java > kr.icia.controller > new Class 생성 > name: BoardController

package kr.icia.controller;

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 kr.icia.service.BoardService;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;

@Log4j
@Controller
@RequestMapping("/board/*")
@AllArgsConstructor
public class BoardController {
	private BoardService service;
	
	@GetMapping("/list")
	public void list(Model model) {
		log.info("list");
		model.addAttribute("list", service.getList());
		//java 코드에서 생성된 결과를 jsp 페이지로 전달한다
		
		//컨트롤러 >> 서비스 >> 매퍼 >> mybatis
	}
}

@Controller //스프링의 빈으로 인식

@RequestMapping // "/board/"로 시작하는 모든 처리를 BoardController가 하겠다는 의미

먼저, 전체 목록을 보여주는 기능을 구현해 보았다.

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

 

이제 테스트를 해볼 것이다.

src/test/java > kr.icia.controller > new Class 생성 > name: BoardControllerTests

package kr.icia.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;

@WebAppConfiguration // Servlet 설정을 하겠다고 서버에 알림
@RunWith(SpringJUnit4ClassRunner.class)
@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 BoardControllerTests {
	@Setter(onMethod_ = @Autowired)
	private WebApplicationContext ctx;
	// 웹으로 프로그램을 테스트하기 위한 객체
	private MockMvc mockMvc;
	// mvc 모델 모형 객체

	@Before // 테스트 실행 전에 먼저 실행하라고 알린다
	public void setup() {
		this.mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build();
	}

	@Test
	public void testList() throws Exception {
		log.info(
				mockMvc.perform(MockMvcRequestBuilders.get("/board/list")).andReturn().getModelAndView().getModelMap());
		// /borad/list 요청에 대한 처리를 get 방식으로 하고 그 결과를 andReturn()으로 받아서
		// getModelAndView()를 통해 model로 전환 후, 결과를 getModelMap()으로 jsp페이지로 출력한다
	}
}

@WebAppConfiguration 어노테이션은 Servlet의 ServletContext를 이용하기 위해서이다.

@Before 어노테이션이 적용된 setup() 는 모든 테스트 전에 매번 실행되는 메소드이다.

mockMvc 말 그대로 가짜 mvc. 가짜 URL과 파라미터 등을 브라우저에서 사용하는 것처럼 만들어서 Controller를 실행해볼 수 있다.

Reference ▶ [부스트코스 웹 프로그래밍] 스프링 MVC (tistory.com)

기존 Tests 클래스에서는 root-context.xml 만 필요로 했지만, Controller는 servlet-context.xml도 필요로하므로 둘 다 명시해주어야 한다.

더보기

*JUnit Test 오류 : javax.servlet.SessionCookieConfig

JUnit으로 테스트 해보면 오류가 나는데, 이는 Servlet 버전이 낮아 클래스를 찾지 못하는 상황이다.

따라서 Servlet 버전을 바꾸어야 한다.

Maven 에서 Servlet-api 의 최신 버전으로 pom.xml 을 변경해준다.

버전을 바꾸고 다시 JUnit 테스트를 하면 결과가 잘 출력된다.

 

 

게시글 등록

이번에는 글쓰기 부분을 구현하기 위해 PostMapping으로 추가할 것이다.

BoardController.java파일을 열어 @GetMapping("/list") 코드 아래에 내용을 추가한다.

	@PostMapping("/register")
	public String register(BoardVO board, RedirectAttributes rttr) {
		//@Controller 어노테이션이 붙고, component scan에 package가 지정되어 있다면
		//매개변수 인자들은 스프링이 자동으로 생성 할당한다
		log.info("register : " + board);
		service.register(board);
		rttr.addFlashAttribute("result", board.getBno());
		//redirect시키면서 1회용 값을 전달한다
		return "redirect:/board/list";
	}

redirect Attributes를 이용해서 등록 작업이 끝난 후 다시 목록으로 이동하게 만들었다.

 

테스트해보기 위해 BoardControllerTests 의 @Test 아래 내용을 추가한다. (이전 Test는 주석처리한 후 구동한다)

 

	@Test
	public void testRegister() throws Exception {
		String result = mockMvc
				.perform(MockMvcRequestBuilders.post("/board/register").param("title", "테스트 새글 제목")
						.param("content", "테스트 새글 내용").param("writer", "user"))
				.andReturn().getModelAndView().getViewName();
		//post요청으로 /board/register가 발생되면 파라미터로 제목,내용,작성자를 전달하고,
		//그 결과를 받아서 전달할 수 있는 mav형태로 바꾸고 객체의 이름을 표시
		log.info(result);
	}

실행하면 새로운 데이터가 추가된다.

 

 

 

게시글 상세보기(글읽기)

이번에는 글 상세보기(조회) 메소드를 구현해볼 것이다.

BoardController 에 코드를 추가한다.

	//제목 링크를 클릭하여 글 상세보기 - get 방식
	@GetMapping("/get")
	public void get(@RequestParam("bno") Long bno, Model model) {
		//@RequestParam: 요청 전달값으로 글번호 이용
		log.info("/get");
		model.addAttribute("board", service.get(bno));
		//전달값으로 명시만 하면 스프링이 자동처리
		//사용하는 부분만 추가 구현
	}

 

그리고 BoardControllerTests에도 내용을 추가한다.

	@Test
	public void testGet() throws Exception {
		log.info(mockMvc.perform(MockMvcRequestBuilders.get("/board/get").param("bno", "2")).andReturn()
				.getModelAndView().getModelMap());
	}	//2번게시물 내용 읽기
 
 
 
 
 
 
 

게시글 수정

이번에는 수정처리를 해볼 것이다. BoardController에 코드를 입력한다.

	//post요청으로 /modify가 온다면 아래 메소드를 수행
	@PostMapping("/modify")
	public String modify(BoardVO board, RedirectAttributes rttr) {
		log.info("modify:" + board);
		if (service.modify(board)) {
			rttr.addFlashAttribute("result", "success");
		}
		//수정이 성공하면 success 메세지가 포함되어 이동하고, 실패해도 메세지 빼고 이동함
		return "redirect:/board/list";
	}

 

BoardControllerTests에 코드를 입력한다.

	@Test
	public void testModify() throws Exception {
		String result = mockMvc.perform(MockMvcRequestBuilders.post("/board/modify").param("bno", "1")
				.param("title", "수정된 테스트 새글 제목0928").param("content", "수정된 테스트 새글 내용0928").param("writer", "user0928"))
				.andReturn().getModelAndView().getViewName();
		
		log.info(result);
	}

 

 

 

 

게시글 삭제

이번에는 삭제 부분을 구현할 것이다.

BoardController 에 코드를 입력한다.

	@PostMapping("/remove")
	public String remove(@RequestParam("bno") Long bno, RedirectAttributes rttr) {
		log.info("remove..." + bno);
		if (service.remove(bno)) {
			rttr.addFlashAttribute("result", "success");
		}
		return "redirect:/board/list";
	}

 

BoardControllerTests에 코드를 입력한다.

	@Test
	public void testRemove() throws Exception {
		String result = mockMvc.perform(MockMvcRequestBuilders.post("/board/remove").param("bno", "21")).andReturn()
				.getModelAndView().getViewName();
		log.info(result);
	}

완료메세지와 함께 sql에서도 잘 삭제된 것을 확인할 수 있다.

 

 

댓글