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

이언덕·2026년 5월 17일

아이티센 부트캠프

목록 보기
68/115
post-thumbnail

문제

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

로또 선택 화면에서 숫자 이미지를 클릭하면 서버로 선택한 숫자가 전달된다.

선택한 숫자와 서버에서 만든 랜덤 숫자를 비교한 뒤, 결과 화면에서 성공 또는 실패 결과를 출력한다.


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

  • 이전에 Servlet&JSP로 구현했던 로또 프로그램을 Spring MVC 방식으로 다시 구현한다.
  • 사용자는 lottoForm.html에서 숫자 이미지 6개 중 하나를 클릭한다.
  • 숫자 이미지를 클릭하면 선택한 숫자가 GET 방식으로 /lotto 요청에 전달된다.
  • 서버에서는 LottoController가 /lotto 요청을 처리한다.
  • 컨트롤러는 사용자가 누른 숫자와 서버에서 만든 랜덤 숫자를 비교한다.
  • 비교 결과에 따라 성공 메시지와 실패 메시지를 다르게 만든다.
  • 결과 메시지와 이미지 경로는 기존에 만들어둔 LottoVO 객체에 담는다.
  • Model에 LottoVO 객체를 저장해서 lottoView.html로 전달한다.
  • 결과 화면에서는 Thymeleaf를 사용해 메시지와 이미지를 출력한다.
  • 번호를 틀렸을 때만 재시도 링크가 출력되도록 처리한다.




문제 해석

이 문제는 단순히 숫자 이미지를 화면에 보여주는 문제가 아니다.
사용자가 숫자 이미지를 클릭했을 때 그 숫자가 서버로 전달되고, 서버에서 랜덤 숫자와 비교한 뒤, 결과 화면까지 출력되어야 하는 흐름을 구현하는 문제다.


먼저 lottoForm.html에서는 사용자가 클릭할 수 있는 숫자 이미지 버튼을 만들어야 한다.
각 이미지는 화면에 보이는 이미지 역할만 하는 것이 아니라, 클릭했을 때 서버로 특정 숫자 값을 전달하는 버튼 역할도 해야 한다.


그래서 숫자 이미지를 button 태그 안에 넣고, 각 버튼에 name="num"과 value를 지정했다.
이렇게 하면 사용자가 3번 이미지를 클릭했을 때 /lotto?num=3처럼 선택한 숫자가 요청 파라미터로 전달된다.


그 다음 서버에서는 LottoController가 num 값을 받는다.
컨트롤러는 서버에서 1부터 6까지의 랜덤 숫자를 하나 만들고, 사용자가 선택한 숫자와 비교한다.


두 숫자가 같으면 성공 메시지와 해 이미지를 준비한다.
두 숫자가 다르면 실패 메시지와 비 이미지를 준비한다.


이 결과는 문자열 두 개를 따로 화면으로 보내는 것이 아니라, 기존에 있던 LottoVO 객체에 담아서 전달한다.
마지막으로 lottoView.html에서는 Model에 담긴 LottoVO를 꺼내 결과 메시지와 이미지를 출력한다.


즉 이 실습의 핵심 흐름은 아래와 같다.


숫자 이미지 클릭 → GET 요청 전달 → Controller에서 num 받기 → 랜덤 숫자 생성 → 숫자 비교 → LottoVO 생성 → Model에 저장 → lottoView.html 출력




풀이 순서

이번 실습은 화면에서 값을 보내는 흐름, 컨트롤러에서 값을 처리하는 흐름, 결과 화면에서 값을 꺼내 출력하는 흐름으로 나누어 구현했다.
각 단계는 아래 순서대로 진행했다.
1. 기존 LottoVO 구조 확인
2. DTO처럼 사용하는 LottoVO에서 getter만 있어도 되는 이유 정리
3. lottoForm.html에서 숫자 이미지 버튼 만들기
4. button의 name과 value로 선택 숫자 전달하기
5. LottoController에서 /lotto 요청 처리하기
6. @RequestParam으로 사용자가 누른 숫자 받기
7. 서버에서 1부터 6까지의 랜덤 숫자 만들기
8. 사용자가 누른 숫자와 랜덤 숫자 비교하기
9. 성공/실패 결과에 따라 메시지와 이미지 경로 만들기
10. 결과 데이터를 LottoVO 객체에 담기
11. Model에 LottoVO와 이전 페이지 정보를 저장하기
12. lottoView.html에서 결과 메시지와 이미지 출력하기
13. 재시도 링크가 실패했을 때만 출력되도록 수정하기




자세한 풀이

이제 풀이 순서에 맞춰 실제 코드를 작성한 흐름을 정리한다.
이번 실습의 핵심은 HTML에서 서버로 값을 보내고, 컨트롤러가 그 값을 처리한 뒤, 다시 결과 화면으로 데이터를 전달하는 것이다.

1. 기존 LottoVO 구조 확인

이번 실습에서는 결과 화면에 출력할 데이터를 객체에 담아서 전달한다.
결과 화면에 필요한 값은 두 가지다.

  • 결과 메시지
  • 출력할 이미지 경로

이 두 값을 컨트롤러에서 각각 따로 넘길 수도 있지만, 이미 만들어져 있던 LottoVO를 사용하면 하나의 객체로 묶어서 전달할 수 있다.
LottoVO는 이번 실습에서 결과 데이터를 화면으로 넘겨주는 전달 객체 역할을 한다.


코드는 아래와 같다.

package com.example.springlab.domain;
import lombok.Getter;
import lombok.AllArgsConstructor;
@Getter
@AllArgsConstructor
public class LottoVO {
    private String result;
    private String imgName;
}

result에는 성공 또는 실패 메시지가 들어간다.
imgName에는 결과 화면에서 보여줄 이미지 경로가 들어간다.


예를 들어 사용자가 누른 숫자와 랜덤 숫자가 같으면 result에는 추카추카가 들어가고, imgName에는 /images/sun.png가 들어간다.
반대로 숫자가 다르면 result에는 아쉽네요.. 다음 기회를 !!가 들어가고, imgName에는 /images/rain.png가 들어간다.


데이터 흐름 예상

컨트롤러에서 결과를 판단한 뒤 new LottoVO(result, imgName)을 실행한다.
그러면 결과 메시지와 이미지 경로가 LottoVO 객체 안에 저장된다.


그 다음 model.addAttribute("lotto", vo)를 실행하면 화면에서는 lotto라는 이름으로 이 객체를 사용할 수 있다.
그래서 lottoView.html에서는 ${lotto.result}로 결과 메시지를 출력하고, ${lotto.imgName}으로 이미지 경로를 꺼내 사용할 수 있다.


2. 궁금했던 점: getter만 있는데 값이 어떻게 저장되는가

LottoVO를 보면서 처음 헷갈렸던 부분은 getter만 있고 setter가 없다는 점이었다.
처음에는 값을 사용하려면 먼저 setter로 값을 저장한 다음, getter로 다시 꺼내야 한다고 생각했다.


예상했던 흐름은 아래와 같았다.

LottoVO vo = new LottoVO();
vo.setResult(result);
vo.setImgName(imgName);
vo.getResult();
vo.getImgName();

이렇게 보면 setter가 값을 저장하고, getter가 저장된 값을 반환하는 구조처럼 느껴진다.
하지만 이번 코드에서는 setter를 사용하지 않았다.


이번 실습에서는 아래 코드로 객체를 생성한다.

LottoVO vo = new LottoVO(result, imgName);

처음에는 여기서 result와 imgName이 어떻게 LottoVO 안에 저장되는지 헷갈릴 수 있다.


핵심은 @AllArgsConstructor다.
@AllArgsConstructor는 모든 멤버변수를 매개변수로 받는 생성자를 자동으로 만들어준다.


즉, 실제로는 아래와 같은 생성자가 만들어진 것과 같다.

public LottoVO(String result, String imgName) {
    this.result = result;
    this.imgName = imgName;
}

그래서 new LottoVO(result, imgName)을 실행하는 순간, result 값은 LottoVO의 result 변수에 저장되고, imgName 값은 LottoVO의 imgName 변수에 저장된다.
즉, 이번 실습에서는 setter가 값을 저장하는 것이 아니라, 생성자가 값을 저장하는 역할을 한다.


getter는 언제 사용되는가

getter는 이미 저장된 값을 꺼낼 때 사용된다.
컨트롤러에서는 LottoVO 객체를 만든 뒤 Model에 담는다.

LottoVO vo = new LottoVO(result, imgName);
model.addAttribute("lotto", vo);

이렇게 하면 lottoView.html에서는 lotto라는 이름으로 LottoVO 객체를 사용할 수 있다.
그리고 화면에서 아래처럼 작성하면 Thymeleaf가 내부적으로 getResult()와 getImgName()을 호출해서 값을 꺼낸다.

<h2 th:text="${lotto.result}">결과화면</h2>
<img th:src="${lotto.imgName}">

즉, 화면에서 ${lotto.result}라고 쓰면 실제 흐름은 lotto.getResult()를 호출하는 것처럼 이해하면 된다.
화면에서 ${lotto.imgName}이라고 쓰면 실제 흐름은 lotto.getImgName()을 호출하는 것처럼 이해하면 된다.


정리하면 이번 코드에서 값의 흐름은 아래와 같다.


Controller에서 result, imgName 생성 → new LottoVO(result, imgName)으로 값 저장 → Model에 lotto 이름으로 저장 → Thymeleaf에서 getter로 값 꺼내 출력


3. lottoForm.html에서 숫자 이미지 버튼 만들기

사용자가 로또 숫자를 선택할 수 있도록 lottoForm.html에 숫자 이미지 6개를 배치했다.
처음에는 이미지만 보여주면 되는 것처럼 보이지만, 실제로는 이미지를 클릭했을 때 서버로 숫자 값이 전달되어야 한다.


그래서 각 이미지를 button 태그 안에 넣었다.
각 버튼에는 같은 이름인 num을 사용했다.
대신 value는 각각 1, 2, 3, 4, 5, 6으로 다르게 설정했다.


이렇게 하면 사용자가 어떤 이미지를 클릭했는지 서버가 num 값으로 구분할 수 있다.

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Document</title>
</head>
<body>
<h1>Lotto Game</h1>
<hr/>
<form method="get" action="/lotto">
    <button type="submit" name="num" value="1">
        <img src="../images/1.png" alt="로또 추첨" style="width: 70px; height: 70px"/>
    </button>
    <button type="submit" name="num" value="2">
        <img src="../images/2.png" alt="로또 추첨" style="width: 70px; height: 70px"/>
    </button>
    <button type="submit" name="num" value="3">
        <img src="../images/3.png" alt="로또 추첨" style="width: 70px; height: 70px"/>
    </button>
    <button type="submit" name="num" value="4">
        <img src="../images/4.png" alt="로또 추첨" style="width: 70px; height: 70px"/>
    </button>
    <button type="submit" name="num" value="5">
        <img src="../images/5.png" alt="로또 추첨" style="width: 70px; height: 70px"/>
    </button>
    <button type="submit" name="num" value="6">
        <img src="../images/6.png" alt="로또 추첨" style="width: 70px; height: 70px"/>
    </button>
</form>
</body>
</html>

여기서 중요한 부분은 button 태그의 name과 value다.
사용자가 3번 이미지를 클릭하면 name="num"과 value="3"이 합쳐져 num=3이라는 요청 파라미터가 만들어진다.


데이터 흐름

사용자가 3번 이미지를 클릭했다고 하면, 3번 버튼의 name="num"과 value="3"이 함께 사용된다.
form의 전송 방식은 GET이고 요청 주소는 /lotto다.
그래서 최종 요청은 /lotto?num=3 형태가 된다.


컨트롤러에서는 이 num 값을 @RequestParam("num")으로 받을 수 있다.
즉 흐름은 아래와 같다.


3번 이미지 클릭 → num=3 생성 → /lotto?num=3 요청 → @RequestParam("num") int num으로 값 받기


4. LottoController에서 요청 처리하기

이제 /lotto 요청을 처리할 컨트롤러를 작성한다.
lottoForm.html에서 숫자 이미지를 클릭하면 /lotto?num=선택숫자 형태로 요청이 들어온다.
컨트롤러에서는 @RequestParam("num")을 사용해 이 값을 받는다.


그리고 서버에서는 Random을 사용해 1부터 6까지의 숫자 중 하나를 랜덤으로 만든다.
이 랜덤 숫자와 사용자가 누른 숫자를 비교해서 성공인지 실패인지 판단한다.


성공이면 result에는 추카추카를 넣고, imgName에는 /images/sun.png를 넣는다.
실패이면 result에는 아쉽네요.. 다음 기회를 !!를 넣고, imgName에는 /images/rain.png를 넣는다.


실패했을 때는 다시 이전 로또 선택 화면으로 돌아갈 수 있어야 하므로, request.getHeader("referer")로 이전 페이지 주소를 가져와 previousPage라는 이름으로 Model에 저장했다.

package com.example.springlab.controller;
import com.example.springlab.domain.LottoVO;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Random;
@Controller
public class LottoController {
    @RequestMapping("/lotto")
    public String lotto(@RequestParam("num") int num, HttpServletRequest request, Model model) {
        int randomNum = new Random().nextInt(6) + 1;
        String result = "";
        String imgName = "";
        String referer = "";
        System.out.println("내가 누른 번호: " + num);
        System.out.println("랜덤 번호: " + randomNum);
        if (num == randomNum) {
            result = "추카추카";
            imgName = "/images/sun.png";
        } else {
            result = "아쉽네요.. 다음 기회를 !!";
            imgName = "/images/rain.png";
            referer = request.getHeader("referer");
        }
        LottoVO vo = new LottoVO(result, imgName);
        model.addAttribute("lotto", vo);
        model.addAttribute("previousPage", referer);
        return "lottoView";
    }
}

이 컨트롤러에서 num은 사용자가 선택한 숫자다.
randomNum은 서버가 만든 랜덤 숫자다.


num == randomNum이 참이면 성공 결과가 만들어진다.
거짓이면 실패 결과가 만들어진다.


데이터 흐름

사용자가 4번 이미지를 클릭하면 /lotto?num=4 요청이 들어온다.
@RequestParam("num") int num에는 4가 저장된다.


그 다음 new Random().nextInt(6) + 1이 실행되면서 서버에서 1부터 6까지의 랜덤 숫자가 만들어진다.
만약 랜덤 숫자도 4라면 if (num == randomNum) 조건이 참이 된다.
그러면 성공 메시지와 해 이미지 경로가 저장된다.


반대로 랜덤 숫자가 4가 아니라면 조건이 거짓이 된다.
그러면 실패 메시지와 비 이미지 경로가 저장되고, 이전 페이지 주소도 함께 가져온다.


마지막으로 new LottoVO(result, imgName)을 통해 결과 객체를 만들고, model.addAttribute("lotto", vo)로 화면에 전달한다.


5. lottoView.html에서 결과 화면 출력하기

컨트롤러에서 return "lottoView"를 실행하면 lottoView.html이 응답 화면으로 사용된다.
이 화면에서는 Model에 저장된 lotto 객체를 꺼내 결과 메시지와 이미지를 출력한다.


lotto.result는 결과 메시지이고, lotto.imgName은 이미지 경로다.
이미지를 가운데 정렬하기 위해 img 태그에 display: block; margin: 0 auto;를 지정했다.


img 태그는 기본적으로 inline 성격이 있기 때문에 margin: 0 auto만으로는 가운데 정렬이 제대로 되지 않을 수 있다.
그래서 display: block을 같이 사용했다.

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1 style="text-align: center">로또 결과</h1>
<hr/>
<h2 th:text="${lotto.result}" style="color:red; text-align: center">결과화면</h2>
<img th:src="${lotto.imgName}" style="display: block; margin: 0 auto;">
<hr/>
<h2 th:if="${previousPage != null and previousPage != ''}" style="text-align: center">
    <a th:href="${previousPage}">재시도</a>
</h2>
</body>
</html>

th:text="${lotto.result}"는 LottoVO에 저장된 결과 메시지를 화면에 출력한다.
th:src="${lotto.imgName}"는 LottoVO에 저장된 이미지 경로를 src 값으로 사용한다.


th:if="${previousPage != null and previousPage != ''}"는 previousPage 값이 있을 때만 해당 태그를 출력한다.
그래서 번호를 틀렸을 때만 재시도 링크가 화면에 나타난다.


데이터 흐름

컨트롤러에서 model.addAttribute("lotto", vo)를 실행했기 때문에, 화면에서는 ${lotto.result}와 ${lotto.imgName}을 사용할 수 있다.


성공했을 때는 lotto.result에 추카추카가 들어 있고, lotto.imgName에는 /images/sun.png가 들어 있다.
그래서 화면에는 성공 메시지와 해 이미지가 출력된다.


실패했을 때는 lotto.result에 아쉽네요.. 다음 기회를 !!가 들어 있고, lotto.imgName에는 /images/rain.png가 들어 있다.
그래서 화면에는 실패 메시지와 비 이미지가 출력된다.


추가로 실패했을 때만 previousPage에 이전 페이지 주소가 들어간다.
그래서 th:if="${previousPage != null and previousPage != ''}" 조건이 참이 되고, 재시도 링크가 출력된다.


6. 트러블 슈팅: 재시도 링크가 성공했을 때도 출력되는 문제

처음에는 결과 화면 아래에 재시도 링크를 그냥 작성했다.
재시도 링크 자체를 항상 화면에 두고, href 값만 previousPage로 연결한 상태였다.


처음 작성한 코드는 아래와 같았다.

<h2>
    <a th:href="${previousPage}">재시도</a>
</h2>

하지만 이렇게 작성하면 로또 번호를 맞춘 경우에도 재시도 링크가 화면에 출력된다.
성공했을 때는 이전 페이지 주소가 필요 없는데도 링크 태그 자체는 남아 있기 때문이다.


문제는 href 값이 비어 있는 것과 링크 태그가 출력되지 않는 것은 다르다는 점이다.
previousPage 값이 빈 문자열이어도 a 태그를 화면에 작성해두면 사용자는 재시도 글자를 보게 된다.


그래서 재시도 링크 전체에 th:if를 추가했다.
조건은 previousPage가 null이 아니고, 빈 문자열도 아닐 때만 참이 되도록 작성했다.

<h2 th:if="${previousPage != null and previousPage != ''}" style="text-align: center">
    <a th:href="${previousPage}">재시도</a>
</h2>

이렇게 수정하면 실패했을 때만 previousPage에 이전 페이지 주소가 들어간다.
성공했을 때는 previousPage가 빈 문자열이므로 조건이 거짓이 되어 재시도 링크가 출력되지 않는다.


즉, 수정 흐름은 아래와 같다.

  • 실패한 경우에는 referer에 이전 페이지 주소를 저장한다.
  • Model에 previousPage 이름으로 이전 페이지 주소를 저장한다.
  • lottoView.html에서 previousPage 값이 있을 때만 재시도 링크를 출력한다.
  • 성공한 경우에는 previousPage가 빈 문자열이므로 재시도 링크가 출력되지 않는다.




최종 코드

최종적으로 필요한 파일은 LottoVO.java, lottoForm.html, LottoController.java, lottoView.html이다.
앞에서 단계별로 나누어 확인한 코드를 실제 실행 가능한 흐름으로 다시 정리하면 아래와 같다.

LottoVO.java

package com.example.springlab.domain;
import lombok.Getter;
import lombok.AllArgsConstructor;
@Getter
@AllArgsConstructor
public class LottoVO {
    private String result;
    private String imgName;
}

LottoVO는 결과 메시지와 이미지 경로를 담는 객체다.
@AllArgsConstructor가 생성자를 만들어주기 때문에 new LottoVO(result, imgName)으로 값을 저장할 수 있다.
@Getter가 getter를 만들어주기 때문에 Thymeleaf 화면에서 저장된 값을 꺼낼 수 있다.


lottoForm.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Document</title>
</head>
<body>
<h1>Lotto Game</h1>
<hr/>
<form method="get" action="/lotto">
    <button type="submit" name="num" value="1">
        <img src="../images/1.png" alt="로또 추첨" style="width: 70px; height: 70px"/>
    </button>
    <button type="submit" name="num" value="2">
        <img src="../images/2.png" alt="로또 추첨" style="width: 70px; height: 70px"/>
    </button>
    <button type="submit" name="num" value="3">
        <img src="../images/3.png" alt="로또 추첨" style="width: 70px; height: 70px"/>
    </button>
    <button type="submit" name="num" value="4">
        <img src="../images/4.png" alt="로또 추첨" style="width: 70px; height: 70px"/>
    </button>
    <button type="submit" name="num" value="5">
        <img src="../images/5.png" alt="로또 추첨" style="width: 70px; height: 70px"/>
    </button>
    <button type="submit" name="num" value="6">
        <img src="../images/6.png" alt="로또 추첨" style="width: 70px; height: 70px"/>
    </button>
</form>
</body>
</html>

button의 name은 모두 num으로 같게 두고, value만 숫자별로 다르게 설정했다.
그래서 사용자가 클릭한 버튼의 값이 /lotto?num=숫자 형태로 전달된다.


LottoController.java

package com.example.springlab.controller;
import com.example.springlab.domain.LottoVO;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Random;
@Controller
public class LottoController {
    @RequestMapping("/lotto")
    public String lotto(@RequestParam("num") int num, HttpServletRequest request, Model model) {
        int randomNum = new Random().nextInt(6) + 1;
        String result = "";
        String imgName = "";
        String referer = "";
        System.out.println("내가 누른 번호: " + num);
        System.out.println("랜덤 번호: " + randomNum);
        if (num == randomNum) {
            result = "추카추카";
            imgName = "/images/sun.png";
        } else {
            result = "아쉽네요.. 다음 기회를 !!";
            imgName = "/images/rain.png";
            referer = request.getHeader("referer");
        }
        LottoVO vo = new LottoVO(result, imgName);
        model.addAttribute("lotto", vo);
        model.addAttribute("previousPage", referer);
        return "lottoView";
    }
}

컨트롤러는 사용자가 누른 숫자와 랜덤 숫자를 비교한다.
그 결과를 LottoVO에 담고, Model에 저장해서 결과 화면으로 전달한다.


lottoView.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1 style="text-align: center">로또 결과</h1>
<hr/>
<h2 th:text="${lotto.result}" style="color:red; text-align: center">결과화면</h2>
<img th:src="${lotto.imgName}" style="display: block; margin: 0 auto;">
<hr/>
<h2 th:if="${previousPage != null and previousPage != ''}" style="text-align: center">
    <a th:href="${previousPage}">재시도</a>
</h2>
</body>
</html>

결과 화면에서는 lotto.result로 결과 메시지를 출력하고, lotto.imgName으로 결과 이미지를 출력한다.
previousPage 값이 있을 때만 재시도 링크가 출력되도록 th:if를 사용했다.




실행 결과 확인

로또 숫자 이미지를 클릭하면 /lotto?num=선택숫자 형태로 요청이 전달된다.
서버 콘솔에서는 사용자가 누른 번호와 랜덤 번호가 출력된다.


두 숫자가 같으면 성공 메시지와 해 이미지가 출력된다.
이때는 previousPage가 빈 문자열이므로 재시도 링크가 보이지 않는다.


두 숫자가 다르면 실패 메시지와 비 이미지가 출력된다.
이때는 previousPage에 이전 페이지 주소가 들어가기 때문에 재시도 링크가 함께 출력된다.


즉 실행 결과는 아래처럼 나뉜다.

  • 성공한 경우: 추카추카 메시지와 해 이미지 출력
  • 실패한 경우: 아쉽네요.. 다음 기회를 !! 메시지와 비 이미지 출력, 재시도 링크 출력

이번 실행 결과를 통해 성공 화면과 실패 화면이 조건에 따라 다르게 출력되는 것을 확인할 수 있다.




실습하면서 확인한 점

이번 실습에서는 Spring MVC에서 요청 파라미터를 받고, 처리 결과를 객체에 담아 화면으로 전달하는 흐름을 확인했다.
특히 DTO처럼 사용하는 객체에 setter가 없어도 생성자로 값을 저장할 수 있다는 점을 확실히 정리할 수 있었다.

  • button 태그에 name과 value를 주면 클릭한 버튼의 값을 요청 파라미터로 전달할 수 있다.
  • GET 방식에서는 요청 파라미터가 주소 뒤에 ?num=3 형태로 붙는다.
  • @RequestParam은 요청 파라미터 값을 컨트롤러 메서드의 매개변수로 받아올 때 사용한다.
  • Random().nextInt(6) + 1을 사용하면 1부터 6까지의 랜덤 숫자를 만들 수 있다.
  • 컨트롤러에서 만든 값은 그냥 지역변수로 두면 화면에서 사용할 수 없다.
  • 화면에서 사용하려면 Model에 저장해야 한다.
  • 여러 값을 묶어서 화면으로 전달할 때는 LottoVO 같은 전달 객체를 사용할 수 있다.
  • setter가 없어도 생성자를 통해 객체 안에 값을 저장할 수 있다.
  • @AllArgsConstructor는 모든 멤버변수를 받는 생성자를 자동으로 만들어준다.
  • @Getter는 저장된 값을 화면에서 꺼낼 수 있게 해준다.
  • Thymeleaf의 ${lotto.result}는 내부적으로 getResult()를 호출하는 흐름으로 이해하면 된다.
  • 이미지를 가운데 정렬할 때는 display: block과 margin: 0 auto를 함께 사용할 수 있다.
  • 특정 조건에서만 화면 요소를 출력하려면 th:if를 사용할 수 있다.

이번 실습의 핵심은 화면에서 값을 보내는 것보다, 컨트롤러에서 만든 결과 데이터를 어떻게 화면까지 전달하는지 이해하는 것이다.
LottoVO는 결과를 담고, Model은 그 객체를 화면에 넘겨주며, Thymeleaf는 넘겨받은 객체의 값을 꺼내 출력한다.

0개의 댓글