
먼저 문제 원본은 아래와 같다.
로또 선택 화면에서 숫자 이미지를 클릭하면 서버로 선택한 숫자가 전달된다.
선택한 숫자와 서버에서 만든 랜덤 숫자를 비교한 뒤, 결과 화면에서 성공 또는 실패 결과를 출력한다.
문제에서 실제로 구현해야 하는 조건만 다시 정리하면 이렇다.
- 이전에
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는 넘겨받은 객체의 값을 꺼내 출력한다.