개발/[Spring] 블로그 만들기

[코드로 배우는 스프링 웹 프로젝트] 10강. 프레젠테이션(웹) 계층의 CRUD 구현

ee2ee2 2021. 12. 30. 23:27
728x90
반응형

해당 프로젝트는 코드로 배우는 스프링 웹 프로젝트(개정판)을 기반으로 진행됩니다.


1. Controller의 작성

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


2. BoardController의 작성

: org.zerock.controller 패키지 생성후, BoardController.java를 작성한다.

 

BoardController.java

앞서 작성한 글에 작성항 등록, 조회, 수정, 삭제에 대한 모든 메소드를 작성하였다.

package org.zerock.controller;

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 org.zerock.domain.BoardVO;
import org.zerock.service.BoardService;

import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;

@Controller
@Log4j
@RequestMapping("/board/*")
@AllArgsConstructor //생성자를 만들고 자동으로 주입하도록 함
public class BoardController {

	//@AllArgsConstructor를 안쓰려면, 아래와 같이 작성하여 처리
	//@Setter(onMethod_ = {@Autowired}) 
	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) {
		log.info("register : " + board);
		
		service.register(board);
		
		rttr.addFlashAttribute("result", board.getBno());
		
		return "redirect:/board/list"; //'redirect:' : 스프링 MVC가 내부적으로 response.serdRedirect()를 처리함
	}
	
	//글 조회 메소드
	@GetMapping("/get")
	public void get(@RequestParam("bno") Long bno, Model model) {
		log.info("/get..");
		model.addAttribute("get", service.get(bno));
	}
	
	//글 수정 메소드
	@PostMapping("/modify")
	public String modify(BoardVO board, RedirectAttributes rttr) {
		log.info("modify.." + board);
		
		if(service.modify(board)) {
			rttr.addFlashAttribute("result", "success");
		}
		
		return "redirect:/board/list";
	}
	
	//글 삭제 메소드
	@GetMapping("/remove")
	public String remove(@RequestParam("bno") Long bno, Model model, RedirectAttributes rttr) {
		log.info("/remove..");
		
		if( service.remove(bno)) {
			rttr.addFlashAttribute("result", "success");
		}

		return "redirect:/board/list";	
	}
}


/*
- @Controller 어노테이션을 추가하여, 스프링의 Bean으로 인식할 수 있도록 함.
- @RequestMapping : /board로 시작하는 모든 처리를 BoardController가 하도록 지정
*/

 

3. BoardControllerTests.java

: 위 작성된 함수에 대해 테스트 하는 코드로, 한 메소드에 각각 테스트 하는 것이 좋지만 해당 글에서는 전체 소스를 업로드 하겠다.

 

'/src/test/java' 폴더에 org.zero.controller 패키지 생성 후, BoardControllerTests 클래스를 생성한다.

BoardControllerTests.java

package org.zerock.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)
//Test for Controller
@WebAppConfiguration
@ContextConfiguration({"file:src/main/webapp/WEB-INF/spring/root-context.xml","file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"})

//Java 설정일 때,
// @ContextConfiguration(classes= {org.zerock.config.RootConfig.class, org.zerock.config.ServletConfig.class})
@Log4j
public class BoardControllerTests {
	
	@Setter(onMethod_= {@Autowired})
	private WebApplicationContext ctx;
	
    	//가짜 MVC라고 생각하면 됨. 가짜로 URL과 파라미터 등을 브라우저에서 사용하는 것 처럼 만들어서 Contoroller를 실행해 볼 수 있음.
	private MockMvc mockMvc;
	
	@Before
	public void setup() {
		this.mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build();
	}
	
	@Test
	public void testsList() throws Exception{
		log.info(
				mockMvc.perform(MockMvcRequestBuilders.get("/board/list")).
				andReturn().
				getModelAndView().
				getModelMap());
	}
	
	@Test
	public void testRegister() throws Exception {
		String resultPage = mockMvc.perform(MockMvcRequestBuilders.post("/board/register")
				.param("title", "테스트 새 글 제목")
				.param("content", "테스트 새 글 내용")
				.param("writer", "user01"))
				.andReturn()
				.getModelAndView()
				.getViewName();
		
		log.info(resultPage);
	}
	
	@Test
	public void testsGet() throws Exception{
		log.info(
				mockMvc.perform(MockMvcRequestBuilders.get("/board/get").param("bno", "1")).
				andReturn().
				getModelAndView().
				getModelMap());
	}
	
	@Test
	public void testModify() throws Exception {
		String resultPage 
				= mockMvc.perform(MockMvcRequestBuilders.post("/board/modify")
				.param("bno", "3")
				.param("title", "테스트 수정 글 제목")
				.param("content", "테스트 수정 글 내용")
				.param("writer", "user02"))
				.andReturn()
				.getModelAndView()
				.getViewName();
		
		log.info(resultPage);
	}
	
	@Test
	public void testRemove() throws Exception{
		String resultPage = 
				mockMvc.perform(MockMvcRequestBuilders.get("/board/remove").param("bno", "25")).
				andReturn().
				getModelAndView().
				getViewName();
		
		log.info(resultPage);
	}
}

/*
 * @WebAppConfiguration : 스프링의 WebApplicationContext를 이용하기 위함.
 * @Before : 모든 테스트 전 매번 실행되는 메소드임을 명시
 * 
 */

기존 테스트 코드와 좀 다르게 진행되는데, 이유는 웹을 개발할 때 매번 URL을 테스트하기 위해서 Tomcat과 같은 WAS를 기동하는 불편한 단계를 생략하기 위함이다. 스프링의 테스트 기능을 활용하면 개발 당시, Tomcat(WAS)을 실행하지 않고도 스프링과 웹 URL을 테스트할 수 있다.