[Spring] Todo 추가 기능 만들기 (1) - 컨트롤러 코드에서 뷰 이름 리턴 VS redirect:URL을 리턴

민지·2024년 1월 24일
0

Todo 추가 기능 만들기 - 컨트롤러 코드에서 뷰 이름 리턴 VS redirect:URL 리턴


현재까지 만든 이 /list-todos 페이지에 버튼을 추가로 넣어서, 해당 버튼을 누르면 새로운 Todo 페이지("/add-todo")로 리다이렉션하게끔 만들 것이다.

결론부터 말하자면, /add-todo URL에서 description 작성 후 submit을 눌렀더니, /add-todo URL이 아닌 /list-todos 페이지로 리다이렉션된 것을 볼 수 있다. 하지만 여전히 추가된 todo는 적용되지 않았다.

1. listTodos.jsp코드에 button을 누르면 /add-todo 링크로 바꿔주는 코드 추가

Bootstrap에서 버튼을 만들 때는 btn 클래스를 사용하며, 버튼을 클릭 가능하게 하려면 btn-success 클래스도 함께 추가한다.

<a href = "add-todo" class = "btn btn-success">Add Todo</a>

해당 코드를 listTodos.jsp에 추가한 실행결과는 다음과 같다.

이제, /add-todo에 대응되는 컨트롤러 코드를 TodoController클래스에 추가하고, addTodo.jsp 파일을 만들겠다.

2. TodoController에 ShowNewTodo메서드 추가 & addTodo.jsp 추가

// add-todo -> showNewTodoPage메서드만 가져왔다.
	@RequestMapping("/add-todo")
	public String ShowNewTodoPage() {

		return "addTodo";
	}

// addTodo.jsp
<html>
	<head>
		<link href = "webjars/bootstrap/5.1.3/css/bootstrap.min.css" rel = "stylesheet">
		<title>Add Todo Page</title>
	</head>
	<body>
		<div class = "container">
			<h1>Enter Todo Details</h1>
			<script src="webjars/bootstrap/5.1.3/js/bootstrap.min.js"></script>
			<script src="webjars/jquery/3.6.0/jquery.min.js"></script>
		</div>
	</body>
</html>

3. addTodo.jsp에 Todo 입력받을 form 만들기

<html>
	<head>
		<link href = "webjars/bootstrap/5.1.3/css/bootstrap.min.css" rel = "stylesheet">
		<title>Add Todo Page</title>
	</head>
	<body>
		<div class = "container">
			<h1>Enter Todo Details</h1>
            <form method = "post">
            	Description : <input type = "text" name = "description"> <br>
                <input type = "submit" class = "btn btn-success" />
            </form>
			<script src="webjars/bootstrap/5.1.3/js/bootstrap.min.js"></script>
			<script src="webjars/jquery/3.6.0/jquery.min.js"></script>
		</div>
	</body>
</html>

실행결과

하지만 해당 Description에 텍스트를 입력하고 제출을 눌러도, 다시 똑같은 페이지인 /add-todo로 돌아온다. 하지만 내가 원했던 건, /add-todo에서 Description에 텍스트를 입력하고 제출을 누른 후 -> /list-todos 페이지로 가서 추가된 todo를 볼 수 있게 되는 것이었다.

왜 /list-todos가 아닌 /add-todo로 돌아올까?

왜냐하면, ShowNewTodoPage()에서 GET, POST 등 모든 종류의 request를 하나의 메서드에서 처리하고 있기 때문이었다.

// add-todo -> Get, POST
	@RequestMapping("/add-todo")
	public String ShowNewTodoPage() {
		return "addTodo";
	}

LoginController에서의 작업과 마찬가지로 submit 버튼 누르기 전후로 GET 메서드 -> POST 메서드로 바뀐다는 사실을 이용하면 된다. 다시 말해, LoginController에서와 똑같이, TodoController에서도 GET메서드와 POST메서드에 따라 다른 메서드를 만들어 별도의 처리를 해주어, 페이지 리다이렉션을 할 수 있게 해야 한다.

// TodoController의 Get, POST 메서드에 따른 다른 처리를 해주는 메서드들

// add-todo - GET
	@RequestMapping(value = "/add-todo", method = RequestMethod.GET)
	public String showNewTodoPage() {

		return "addTodo";
	}

	// add-todo - POST
	@RequestMapping(value = "/add-todo", method = RequestMethod.POST)
	public String addNewTodoPage() {

		return "listTodos";
	}

위 코드처럼, submit 버튼을 누르기 전에는 addTodo.jsp화면을 보여주고, submit 버튼을 누르면 POST 메서드로 바뀌어서 listTodos.jsp 화면을 보여준다.

다음의 실행결과는, /add-todo에서 description을 적고 submit 버튼을 누른 뒤, listTodos.jsp 화면으로 리다이렉션이 될 것을 기대한 화면이다. 헷갈리지 말아야 할 점은 해당 웹사이트의 URL은 localhost:8080/add-todo인 것이다. (listTodos.jsp는 보여지는 뷰 화면이고 URL과 다른 개념)

그런데 왜, listTodos.jsp에서는 빈 리스트를 보여주었을까?

아래의 코드를 보며 원인을 생각해보자.

// TodoController의 list-todos URL 메서드 부분
// list-todos
	@RequestMapping("/list-todos")
	public String listAllTodos(ModelMap model) {

		List<Todo> todos = todoService.findByUsername("minjiki2");

		model.addAttribute("todos", todos);

		return "listTodos";
	}

// listTodos.jsp의 body 부분
<body>
		<div class = "container">
			<h1>Your Todos</h1>
	 		<table class = "table">
				<thead>
					<tr>
						<th>id</th>
						<th>Description</th>
						<th>Deadline</th>
						<th>is Done?</th>
					</tr>
				</thead>
				<tbody>
					<c:forEach items = "${todos}" var = "todo">
						<tr>
							<td>${todo.id}</td>
							<td>${todo.description}</td>
							<td>${todo.deadline}</td>
							<td>${todo.done}</td>
						</tr>
					</c:forEach>
				</tbody>
			</table>
			<a href = "add-todo" class = "btn btn-success">Add Todo</a>
			<script src="webjars/bootstrap/5.1.3/js/bootstrap.min.js"></script>
			<script src="webjars/jquery/3.6.0/jquery.min.js"></script>
		</div>
	</body>

왜 빈 리스트를 보여주였냐면, 결론부터 말하자면 model scope와 URL이 무엇인지 파악하는 것이 핵심이었다.

list-todos request URL을 처리해주는 컨트롤러코드는, TodoService에 하드코딩으로 넣은 리스트값을 model에 추가해, 리턴하는 뷰 이름인 "listTodos.jsp"를 화면에 보여줌으로써, 빈 리스트가 아닌 3개의 값들을 보여줄 수 있었다.

하지만!

addNewTodoPage()메서드의 URL은 /add-todo URL이다!! /list-todos request URL이 아니라는 거다. 즉, 해당 컨트롤러 코드에는 listTodos.jsp로 보내는 그 어떠한 모델값도 없다. model scope는 by default로, request scope와 동일하기에 /list-todos에서 추가했던 todos 모델은 /add-todos에서는 해당 모델값을 적용할 수 없기에, "listTodos.jsp"에서 ${todos}를 불러올 수 없었던 것이다!!

그럼 이제 showNewTodoPage()가 리턴하는 addTodo.jsp에서 description을 submit해, /add-todo request URL을 받는 addNewTodoPage()에서 listTodos.jsp 뷰를 보여주되, 빈 리스트를 보여주지 않게 만들어줘야 한다.

4. addNewTodoPage()에서 "뷰 이름이 아닌, URL을 리턴해" /list-todos URL로 리다이렉션하기

만일 해결책으로 빈 리스트를 model로 보내주는 코드를 또 쓴다면, 코드가 중복되어서 보기에 좋지 않다.

그보다는, addNewTodoPage()메서드에서 리턴하는 값을 model을 추가하지 않은 addNewTodoPage()의 listTodos.jsp가 아니라, model을 추가한 listAllTodos()의 listTodos.jsp 페이지로 리다이렉션할 것이다.

수정한 코드 부분만 따오면 다음과 같다.

// list-todos
	@RequestMapping("/list-todos")
	public String listAllTodos(ModelMap model) {

		List<Todo> todos = todoService.findByUsername("minjiki2");
		model.addAttribute("todos", todos);

		return "listTodos";
	}

@RequestMapping(value = "/add-todo", method = RequestMethod.POST)
	public String addNewTodoPage() {

		// return "listTodos";
		return "redirect:list-todos";
	}

다시 말해, addNewTodoPage()메서드에서 listTodos 뷰 이름을 리턴하는 것이 아니라!
redirect:list-todos 를 통해서 /list-todos URL로 페이지 리다이렉션을 하는 것이다!! 그럼 /list-todos URL과 mapping되어 있는 listAllTodos메서드를 다시 실행하게 된다.

즉, /add-todo에서 description 작성 후 submit을 눌러 POST method가 되면, 다시 /list-todos URL로 가는 것이다.


실행결과, /add-todo URL에서 description 작성 후, submit을 눌렀더니, URL이 /list-todos로 페이지 리다이렉션이 된 것을 확인할 수 있었다. /list-todos URL과 mapping된 listAllTodos메서드를 실행해, 기존의 3개의 정적 데이터값만 화면에 보이게 된 것이다.

그렇지만 여전히, /add-todo URL에서 추가한 description이 Todo.java 객체에 들어가지 않아, 실행결과 여전히 초기값인 3개의 정적 리스트만 출력하고 있다. 다음 포스팅에서 해당 내용을 다뤄보자.

마치며..

  • /add-todo URL에서 description을 추가하고 submit 버튼을 눌렀더니, return "redirect:list-todos;"를 통해, /list-todos URL로 페이지 리다이렉션이 된 것을 확인할 수 있었다.

    @RequestMapping(value = "/add-todo", method = RequestMethod.POST)
        public String addNewTodoPage() {
    
            // return "listTodos";
            return "redirect:list-todos";
        }
  • 하지만 아직 Todo 내부 list 에, add-todo에서 작성한 description이 추가되지 않은 사실을 확인할 수 있었다.




이 시리즈는 Udemy 강의의 내용을 정리한 것입니다.
https://www.udemy.com/course/spring-boot-and-spring-framework-korean/

profile
배운 내용을 바로바로 기록하자!

0개의 댓글