1. web 모듈 설정
build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.6'
id 'io.spring.dependency-management' version '1.1.5'
}
group = 'me.progfrog.idol'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}
application.properties
- 포트 설정 9000
server.port=9000
WebApplication
package me.progfrog.idol.web;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
2. 타겟 페이지
설명 | HTTP 메서드와 URL |
타겟 페이지 | GET /home |
AllowedUserResponse
package me.progfrog.idol.web.dto;
public record AllowedUserResponse(
Boolean isAllowed
) {
}
HomeController
- 타겟 페이지로 접근을 시도했을 때, 입장 가능 상태의 사용자라면 접근을 허용하고 만약 허용되지 않은 사용자라면 대기용 웹 페이지로 리다이렉트 하는 흐름을 가지고 있다.
- 앞서, 토큰을 사용하여 입장 가능 여부를 판단하도록 코드를 변경하였는데 같은 도메인이면 이와 같이 port가 달라도 쿠키를 활용할 수 있다.
package me.progfrog.idol.web.controller;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import me.progfrog.idol.web.dto.AllowedUserResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.util.Arrays;
@Controller
public class HomeController {
RestTemplate restTemplate = new RestTemplate();
@GetMapping("/home")
public String getHome(@RequestParam(name = "queue", defaultValue = "default") String queue,
@RequestParam(name = "user-id") Long userId,
HttpServletRequest request) {
var cookies = request.getCookies();
var cookieName = "user-queue-%s-token".formatted(queue);
var token = "";
if (cookies != null) {
var cookie = Arrays.stream(cookies).filter(i -> i.getName().equalsIgnoreCase(cookieName)).findFirst();
token = cookie.orElse(new Cookie(cookieName, "")).getValue();
}
var uri = UriComponentsBuilder
.fromUriString("http://127.0.0.1:9010")
.path("/api/v1/queue/allowed")
.queryParam("queue", queue)
.queryParam("user-id", userId)
.queryParam("token", token)
.encode()
.build()
.toUri();
ResponseEntity<AllowedUserResponse> response = restTemplate.getForEntity(uri, AllowedUserResponse.class);
if (response.getBody() == null || !response.getBody().isAllowed()) {
// 입장 가능 상태가 아니라면, 대기용 웹 페이지로 리다이렉트
return "redirect:http://127.0.0.1:9010/waiting-room?user-id=%d&redirect-url=%s".formatted(
userId, "http://127.0.0.1:9000/home?user-id=%d".formatted(userId));
}
// 입장 가능 상태라면 해당 페이지를 진입
return "home";
}
}
home.index
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IDOL</title>
<style>
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
background: #000;
}
.container {
position: relative;
width: 100%;
height: 100%;
}
.container img {
width: 100%;
height: 100%;
object-fit: cover;
position: absolute;
z-index: 1;
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 2;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #fff;
font-family: 'Arial', sans-serif;
text-align: center;
}
.overlay h1 {
font-size: 3em;
margin: 0;
animation: fadeIn 2s forwards;
}
.overlay p {
font-size: 1.5em;
animation: fadeIn 4s forwards;
opacity: 0;
}
.video-container {
margin-top: 20px;
width: 80%;
max-width: 800px;
position: relative;
z-index: 2;
}
iframe {
width: 100%;
height: 450px;
border: none;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
</style>
</head>
<body>
<div class="container">
<img th:src="@{/images/idol.webp}" alt="Idol Image">
<div class="overlay">
<h1>★IDOL★</h1>
<p>거짓말은 최고의 사랑인걸?</p>
<div class="video-container">
<iframe width="560" height="315" src="https://www.youtube.com/embed/GqP628id5Kg?si=FROm2245LYq6ULDH" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div>
</div>
</div>
</body>
</html>
3. 동작 확인
타겟 페이지 접근 시, 대기용 웹 페이지로 넘어갔다가 대기 후 타겟 페이지로 접근하는 흐름을 확인할 수 있다.
반응형