[아이티센 부트캠프] Spring boot 실습

이언덕·2026년 5월 25일

아이티센 부트캠프

목록 보기
72/115
post-thumbnail

문제

먼저 문제 원본은 아래와 같다.

문제에서 실제로 구현해야 하는 조건만 다시 정리하면 이렇다.

  • 요청 주소는 /study/{id}/thymeleaf 형식이다.
  • {id} 위치에 들어오는 숫자에 따라 서로 다른 외부 사이트로 이동해야 한다.
  • 컨트롤러 메서드는 한 개만 만들어서 해결해야 한다.
  • 요청 주소 안의 {id} 값은 @PathVariable로 받는다.
  • /study/1/thymeleaf 요청은 https://abbo.tistory.com/56으로 이동한다.
  • /study/2/thymeleaf 요청은 https://abbo.tistory.com/57으로 이동한다.
  • /study/3/thymeleaf 요청은 https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html로 이동한다.
  • /study/4/thymeleaf 요청은 https://www.baeldung.com/dates-in-thymeleaf로 이동한다.

이 문제의 핵심은 화면에 값을 출력하는 것이 아니라, 요청 주소에 포함된 숫자를 읽고 그 숫자에 맞는 외부 사이트로 바로 이동시키는 것이다.




문제 해석

이 문제는 Thymeleaf 화면을 만들어서 링크를 보여주는 문제가 아니다.
요청 경로에 들어온 숫자를 읽고, 그 숫자에 따라 컨트롤러에서 바로 다른 사이트로 이동시키는 문제다.


처음에는 Model에 studyUrl 값을 담아서 처리하려고 했다.
하지만 Model은 값을 화면으로 넘겨줄 때 사용하는 객체다.
즉, model.addAttribute("studyUrl", "...")로 값을 담으면 그 값을 보여줄 Thymeleaf 파일이 필요하다.


이번 문제는 별도의 화면 구현 없이 바로 이동해야 하므로 Model을 사용할 필요가 없다.
대신 컨트롤러 메서드에서 문자열을 반환할 때 앞에 redirect:를 붙이면 된다.


이 흐름을 정리하면 아래와 같다.
요청 주소 입력 → @PathVariable로 id 추출 → id 값에 따라 redirect 주소 선택 → 브라우저가 외부 사이트로 이동




풀이 순서

  1. 요청 주소 /study/{id}/thymeleaf 구조 확인
  2. {id} 값을 받기 위해 @PathVariable 사용
  3. 처음 작성한 Model 방식의 문제점 확인
  4. redirect: 방식으로 외부 사이트 이동 처리
  5. id 값에 따라 다른 주소를 반환하도록 if문 작성
  6. 잘못된 번호가 들어왔을 때 기본 이동 경로 처리
  7. 최종 코드 작성
  8. 요청 주소별 이동 결과 확인




자세한 풀이

이번 실습은 컨트롤러 메서드 하나로 여러 요청을 처리해야 한다.
따라서 요청 주소의 일부를 변수처럼 받아오는 @PathVariable이 핵심이다.


여기서 중요한 점은 Model에 값을 담는 방식과 redirect:로 이동시키는 방식이 완전히 다르다는 것이다.
Model은 화면에 데이터를 넘길 때 쓰고, redirect:는 브라우저를 다른 주소로 이동시킬 때 쓴다.



1. 요청 주소 구조 확인

문제에서 요구한 요청 주소는 아래처럼 생겼다.

/study/1/thymeleaf
/study/2/thymeleaf
/study/3/thymeleaf
/study/4/thymeleaf

여기서 바뀌는 부분은 가운데 숫자다.
즉, /study/와 /thymeleaf는 고정이고, 가운데 숫자만 요청마다 달라진다.


이럴 때는 요청 매핑 주소를 아래처럼 작성할 수 있다.

@RequestMapping("/study/{id}/thymeleaf")

{id}는 실제 요청 주소에 들어오는 값을 변수처럼 받겠다는 의미다.
예를 들어 /study/3/thymeleaf로 요청하면 {id} 자리에는 3이 들어온다.


데이터 흐름

// 사용자가 입력한 요청 주소
/study/3/thymeleaf

// 컨트롤러 매핑 주소
/study/{id}/thymeleaf

// 실제로 추출되는 값
id = 3

→ 사용자가 /study/3/thymeleaf로 요청한다.
→ Spring MVC는 /study/{id}/thymeleaf 패턴과 요청 주소를 비교한다.
→ 가운데 숫자 3을 {id} 값으로 인식한다.
→ 그 값이 컨트롤러 메서드의 id 매개변수로 들어간다.


즉, 이 문제에서는 요청 주소에 들어온 숫자를 먼저 꺼내야 하고, 그 숫자에 따라 이동할 주소를 정해야 한다.



2. 처음 작성한 Model 방식의 문제점

처음에는 아래처럼 Model에 이동할 주소를 담았다.

package com.example.springlab.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class StudyPathController {
    @RequestMapping("/study/{id}/thymeleaf")
    public String study(@PathVariable int id, Model model) {
        if (id == 1) {
            model.addAttribute("studyUrl", "https://abbo.tistory.com/56");
        } else if (id == 2) {
            model.addAttribute("studyUrl", "https://abbo.tistory.com/57");
        } else if (id == 3) {
            model.addAttribute("studyUrl", "https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html");
        } else if (id == 4) {
            model.addAttribute("studyUrl", "https://www.baeldung.com/dates-in-thymeleaf");
        }

        return " ";
    }
}

이 방식의 문제는 Model에 값을 담았다고 해서 브라우저가 자동으로 이동하지 않는다는 점이다.
Model은 컨트롤러에서 만든 데이터를 화면 파일로 전달할 때 사용하는 객체다.


즉, 위 코드에서 studyUrl에 주소를 담으면 그 주소를 사용할 Thymeleaf 파일이 필요하다.
예를 들어 화면에서 아래처럼 값을 꺼내서 링크로 보여주거나 이동 처리를 해야 한다.

<a th:href="${studyUrl}">이동하기</a>

하지만 문제에서는 Thymeleaf 화면을 구현하라고 하지 않았다.
요청 패스에 따라 바로 다른 사이트로 이동하라고 했다.


그래서 이 문제는 Model에 주소를 담는 방식보다 컨트롤러에서 바로 redirect:를 반환하는 방식이 맞다.


데이터 흐름

// 컨트롤러에서 Model에 값 저장
model.addAttribute("studyUrl", "https://abbo.tistory.com/56");

// 이 값은 화면 파일에서 꺼내 써야 한다.
studyUrl = "https://abbo.tistory.com/56"

// 하지만 브라우저가 자동으로 이동하는 것은 아니다.

→ model.addAttribute()는 데이터를 저장하는 코드다.
→ 저장한 데이터는 Thymeleaf 같은 화면 파일에서 꺼내 써야 한다.
→ 컨트롤러가 주소를 Model에 담았다고 해서 브라우저가 자동으로 외부 사이트로 이동하지 않는다.
→ 따라서 화면 파일 없이 바로 이동하려면 redirect:를 사용해야 한다.


정리하면 Model은 값을 화면에 전달하는 용도이고, redirect:는 브라우저를 다른 주소로 이동시키는 용도다.



3. redirect 방식으로 외부 사이트 이동 처리

화면 파일 없이 바로 이동하려면 반환 문자열 앞에 redirect:를 붙이면 된다.

return "redirect:https://abbo.tistory.com/56";

이 코드는 abbo.tistory.com/56이라는 문자열을 화면 이름으로 찾는 것이 아니다.
Spring MVC에게 이 주소로 다시 이동하라는 응답을 만들라고 알려주는 코드다.


컨트롤러에서 redirect:를 반환하면 서버는 브라우저에게 이동할 주소를 알려준다.
그 다음 실제 이동은 브라우저가 다시 요청하면서 이루어진다.


데이터 흐름

// 1. 사용자가 요청
/study/1/thymeleaf

// 2. 컨트롤러에서 반환
return "redirect:https://abbo.tistory.com/56";

// 3. 브라우저가 최종 이동
https://abbo.tistory.com/56

→ 사용자가 /study/1/thymeleaf로 요청한다.
→ 컨트롤러는 id 값이 1인지 확인한다.
→ id가 1이면 "redirect:https://abbo.tistory.com/56"을 반환한다.
→ Spring MVC는 브라우저에게 해당 주소로 이동하라는 응답을 보낸다.
→ 브라우저는 외부 사이트로 다시 요청을 보내고 화면이 이동된다.


이 흐름을 알면 return "thymeleaf"와 return "redirect:..."의 차이도 이해하기 쉽다.
return "thymeleaf"는 화면 파일 이름을 찾는 것이고, return "redirect:..."는 브라우저를 다른 주소로 이동시키는 것이다.



4. id 값에 따라 이동 주소 나누기

이제 @PathVariable로 받은 id 값에 따라 이동할 주소를 나누면 된다.

if (id == 1) {
    return "redirect:https://abbo.tistory.com/56";
} else if (id == 2) {
    return "redirect:https://abbo.tistory.com/57";
} else if (id == 3) {
    return "redirect:https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html";
} else if (id == 4) {
    return "redirect:https://www.baeldung.com/dates-in-thymeleaf";
}

여기서는 문자열 비교가 아니라 숫자 비교다.
그래서 equals()가 아니라 ==를 사용해도 된다.


id는 int 타입이다.
int는 객체가 아니라 기본 자료형이기 때문에 값 자체를 비교할 때 ==를 사용한다.


데이터 흐름

// 요청 주소
/study/2/thymeleaf

// @PathVariable 결과
id = 2

// 조건문 흐름
if (id == 1) {
    // 실행 안 됨
} else if (id == 2) {
    return "redirect:https://abbo.tistory.com/57";
}

// 최종 이동
https://abbo.tistory.com/57

→ 사용자가 /study/2/thymeleaf로 요청한다.
→ {id} 자리에 있는 2가 int id로 들어온다.
→ 첫 번째 조건 id == 1은 false다.
→ 두 번째 조건 id == 2가 true다.
→ 컨트롤러는 "redirect:https://abbo.tistory.com/57"을 반환한다.
→ 브라우저는 해당 주소로 이동한다.


즉, if문은 요청 주소에서 꺼낸 숫자를 보고 어떤 사이트로 보낼지 선택하는 역할을 한다.



5. 잘못된 번호가 들어온 경우 처리

문제에는 1부터 4까지의 요청만 제시되어 있다.
하지만 사용자가 /study/10/thymeleaf처럼 없는 번호로 요청할 수도 있다.


이런 경우 아무 값도 반환하지 않으면 문제가 생긴다.
그래서 마지막에는 기본 이동 경로를 하나 작성해두는 것이 안전하다.

return "redirect:/";

이 코드는 조건에 맞는 번호가 없으면 프로젝트의 기본 경로 /로 이동시키겠다는 의미다.


데이터 흐름

// 요청 주소
/study/10/thymeleaf

// @PathVariable 결과
id = 10

// 조건문 확인
id == 1  // false
id == 2  // false
id == 3  // false
id == 4  // false

// 기본 이동
return "redirect:/";

→ 사용자가 문제에서 정한 범위 밖의 숫자를 요청한다.
→ 모든 if, else if 조건이 false가 된다.
→ 마지막 return "redirect:/";가 실행된다.
→ 브라우저는 기본 경로 /로 이동한다.


이렇게 마지막 반환값을 작성하면 예상하지 못한 요청이 들어와도 컨트롤러 메서드가 정상적으로 끝난다.



6. 최종 동작 흐름

전체 흐름은 아래처럼 정리할 수 있다.

/study/1/thymeleaf
→ id = 1
→ redirect:https://abbo.tistory.com/56

/study/2/thymeleaf
→ id = 2
→ redirect:https://abbo.tistory.com/57

/study/3/thymeleaf
→ id = 3
→ redirect:https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html

/study/4/thymeleaf
→ id = 4
→ redirect:https://www.baeldung.com/dates-in-thymeleaf

요청 주소는 하나의 패턴으로 받지만, 실제 이동 주소는 id 값에 따라 달라진다.


이 문제의 핵심은 컨트롤러 메서드를 여러 개 만드는 것이 아니라, 하나의 메서드에서 @PathVariable 값을 기준으로 분기 처리하는 것이다.




최종 코드

실제로 제출할 수 있는 최종 코드는 아래와 같다.
Model은 사용하지 않고, redirect: 반환값만 사용한다.

package com.example.springlab.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class StudyPathController {

    @RequestMapping("/study/{id}/thymeleaf")
    public String study(@PathVariable int id) {

        if (id == 1) {
            return "redirect:https://abbo.tistory.com/56";
        } else if (id == 2) {
            return "redirect:https://abbo.tistory.com/57";
        } else if (id == 3) {
            return "redirect:https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html";
        } else if (id == 4) {
            return "redirect:https://www.baeldung.com/dates-in-thymeleaf";
        }

        return "redirect:/";
    }
}




실습하면서 확인한 점

  • @PathVariable은 요청 주소 안에 들어온 값을 매개변수로 받을 때 사용한다.
  • /study/{id}/thymeleaf에서 {id}는 실제 요청 주소의 숫자 부분을 받는 자리다.
  • Model은 컨트롤러 데이터를 화면 파일로 넘길 때 사용한다.
  • Model에 주소를 담는다고 해서 브라우저가 자동으로 이동하지 않는다.
  • 화면 파일 없이 바로 이동하려면 return "redirect:주소" 형식으로 작성한다.
  • return "redirect:https://..."는 외부 사이트로 이동시킬 때 사용할 수 있다.
  • int 타입 값 비교는 equals()가 아니라 ==로 처리한다.
  • 컨트롤러 메서드를 하나만 만들어도 @PathVariable과 조건문을 사용하면 여러 요청을 처리할 수 있다.
  • 문제에서 요구한 주소를 그대로 확인해야 한다. 특히 /study/2/thymeleaf는 56이 아니라 57로 이동해야 한다.

0개의 댓글