Home > Spring > πŸƒ[Spring] Spring Bootλ₯Ό μ‚¬μš©ν•˜μ—¬ HTML, CSS, JS둜 λ§Œλ“  Frontend νŽ˜μ΄μ§€λ₯Ό 둜컬 μ„œλ²„μ™€ μ—°κ²°ν•˜λŠ” 방법은 λ¬΄μ—‡μΌκΉŒμš”?

πŸƒ[Spring] Spring Bootλ₯Ό μ‚¬μš©ν•˜μ—¬ HTML, CSS, JS둜 λ§Œλ“  Frontend νŽ˜μ΄μ§€λ₯Ό 둜컬 μ„œλ²„μ™€ μ—°κ²°ν•˜λŠ” 방법은 λ¬΄μ—‡μΌκΉŒμš”?
Spring Framework

πŸƒ[Spring] Spring Bootλ₯Ό μ‚¬μš©ν•˜μ—¬ HTML, CSS, JS둜 λ§Œλ“  Frontend νŽ˜μ΄μ§€λ₯Ό 둜컬 μ„œλ²„μ™€ μ—°κ²°ν•˜λŠ” 방법은 λ¬΄μ—‡μΌκΉŒμš”?

  • Spring Bootλ₯Ό μ‚¬μš©ν•˜μ—¬ HTML, CSS, JavaScript둜 λ§Œλ“  ν”„λŸ°νŠΈμ—”λ“œ νŽ˜μ΄μ§€λ₯Ό 둜컬 μ„œλ²„μ™€ μ—°κ²°ν•˜λ €λ©΄ λ‹€μŒκ³Ό 같은 단계가 ν•„μš”ν•©λ‹ˆλ‹€.
    • 이 κ³Όμ •μ—μ„œλŠ” 정적 λ¦¬μ†ŒμŠ€λ₯Ό Spring Boot ν”„λ‘œμ νŠΈμ— ν¬ν•¨ν•˜κ³ , 컨트둀러λ₯Ό 톡해 μš”μ²­μ„ μ²˜λ¦¬ν•˜μ—¬ μ •μ νŽ˜μ΄μ§€λ₯Ό μ œκ³΅ν•˜λŠ” 방법을 μ„€λͺ…ν•©λ‹ˆλ‹€.

1️⃣ Spring Boot ν”„λ‘œμ νŠΈμ— 정적 파일 μΆ”κ°€.

  • HTML, CSS, JavaScript νŒŒμΌμ€ Spring Boot ν”„λ‘œμ νŠΈμ˜ 정적 λ¦¬μ†ŒμŠ€ 디렉토리에 λ°°μΉ˜ν•©λ‹ˆλ‹€.

πŸ‘‰ ν”„λ‘œμ νŠΈ 디렉토리 ꡬ쑰.

src
 └── main
     β”œβ”€β”€ java
     β”‚    └── com.example.demo (νŒ¨ν‚€μ§€ ꡬ쑰)
     β”‚         └── DemoApplication.java
     β”œβ”€β”€ resources
     β”‚    β”œβ”€β”€ static
     β”‚    β”‚    β”œβ”€β”€ css
     β”‚    β”‚    β”‚    └── styles.css
     β”‚    β”‚    β”œβ”€β”€ js
     β”‚    β”‚    β”‚    β”œβ”€β”€ scripts.js
     β”‚    β”‚    β”‚    └── login-scripts.js
     β”‚    β”‚    β”œβ”€β”€ signup.html
     β”‚    β”‚    └── login.html
     β”‚    └── templates (ν•„μš”ν•œ 경우 Thymeleaf ν…œν”Œλ¦Ώ 파일)
     └── application.properties
  • static λ””λ ‰ν† λ¦¬λŠ” 기본적으둜 정적 λ¦¬μ†ŒμŠ€λ₯Ό μ œκ³΅ν•˜λŠ” 역할을 ν•˜λ©°, μ—¬κΈ°μ„œ CSS, JavaScript, 이미지 및 HTML νŒŒμΌμ„ λ‘œλ“œν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • HTML 파일(signup.html, login.html)은 직접 static 디렉토리에 λ°°μΉ˜ν•˜μ—¬ μ„œλ²„κ°€ μš”μ²­μ„ λ°›μœΌλ©΄ 직접 λ‘œλ“œλ˜λ„λ‘ ν•©λ‹ˆλ‹€.

2️⃣ Spring Boot 컨트둀러 μ„€μ •.

  • Spring Boot μ—μ„œ /loginκ³Ό /signup μš”μ²­μ„ μ²˜λ¦¬ν•˜λ„λ‘ κ°„λ‹¨ν•œ 컨트둀러λ₯Ό λ§Œλ“­λ‹ˆλ‹€.
package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class AuthController {
    
    @GetMapping("/login")
    public String loginPage() {
        return "login.html"; // static/login.html νŒŒμΌμ„ λ°˜ν™˜
    }
    
    @GetMapping("/signup")
    public String signupPage() {
        return "signup.html"; // static/signup.html νŒŒμΌμ„ λ°˜ν™˜
    }
}

3️⃣ 정적 파일 및 μžμ› μ ‘κ·Ό

  • HTML νŒŒμΌμ—μ„œ CSS 및 JavaScript νŒŒμΌμ— λŒ€ν•œ 경둜λ₯Ό μˆ˜μ •ν•˜μ—¬ Spring Bootμ—μ„œ μ œκ³΅ν•˜λŠ” 정적 λ¦¬μ†ŒμŠ€λ₯Ό μ œλŒ€λ‘œ 뢈러올 수 μžˆκ²Œν•©λ‹ˆλ‹€.

πŸ‘‰ login.html(μ˜ˆμ‹œ)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login Page</title>
    <link rel="stylesheet" href="/css/styles.css"> <!-- μ ˆλŒ€ 경둜둜 μˆ˜μ • -->
</head>
<body>
    <div class="login-container">
        <form id="loginForm" class="login-form">
            <h2>Login</h2>
            <div class="input-group">
                <label for="login-email">Email</label>
                <input type="email" id="login-email" name="login-email" required>
            </div>
            <div class="input-group">
                <label for="login-password">Password</label>
                <input type="password" id="login-password" name="login-password" required>
            </div>
            <button type="submit">Login</button>
            <p class="signup-link">Don't have an account? <a href="/signup">Sign up here</a></p> <!-- Spring Boot 경둜 μ‚¬μš© -->
        </form>
    </div>
    <script src="/js/login-scripts.js"></script> <!-- μ ˆλŒ€ 경둜둜 μˆ˜μ • -->
</body>
</html>

4️⃣ Spring Boot μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ‹€ν–‰

  • 이제 Spring Boot μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μ‹€ν–‰ν•˜λ©΄ 둜컬 μ„œλ²„μ—μ„œ /login 및 /signup 경둜둜 μ ‘κ·Όν•˜μ—¬ ν”„λŸ°νŠΈμ—”λ“œ νŽ˜μ΄μ§€λ₯Ό λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

πŸ‘‰ μ• ν”Œλ¦¬κ²Œμ΄μ…˜ μ‹€ν–‰ λͺ…λ Ήμ–΄

./gradlwe bootRun #Gradle μ‚¬μš©μ‹œ
mvn spring-boot:run # Maven μ‚¬μš©μ‹œ

5️⃣ μΆ”κ°€ μ„€μ •(ν•„μš”ν•œ 경우)

1️⃣ CORS μ„€μ •

  • ν”„λŸ°νŠΈμ—”λ“œ νŽ˜μ΄μ§€μ—μ„œ λ‹€λ₯Έ μ„œλ²„μ˜ API에 μ ‘κ·Όν•˜λ €λ©΄ CORS 섀정이 ν•„μš”ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    • WebMvcConfigurerλ₯Ό μ‚¬μš©ν•˜μ—¬ λ‹€μŒκ³Ό 같이 μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins("http://localhost:8080")
                        .allowedMethods("GET", "POST", "PUT", "DELETE");
            }
        };
    }
}

πŸ“ CORS(Cross-Origin Resource Sharing)

μ›Ή λΈŒλΌμš°μ €μ—μ„œ μ‹€ν–‰λ˜λŠ” μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ λ‹€λ₯Έ λ„λ©”μΈμ—μ„œ ν˜ΈμŠ€νŒ… λ˜λŠ” λ¦¬μ†ŒμŠ€μ— μ ‘κ·Όν•  수 μžˆλ„λ‘ ν•˜λŠ” λ³΄μ•ˆ λ©”μ»€λ‹ˆμ¦˜μž…λ‹ˆλ‹€.
기본적으둜 μ›Ή λΈŒλΌμš°μ €λŠ” λ³΄μ•ˆμƒμ˜ 이유둜, ν•œ λ„λ©”μΈμ—μ„œ λ‘œλ“œλœ μ›Ή νŽ˜μ΄μ§€κ°€ λ‹€λ₯Έ 도메인에 μš”μ²­μ„ λ³΄λ‚΄λŠ” 것을 μ œν•œν•©λ‹ˆλ‹€.
이λ₯Ό β€œλ™μΌ 좜처 μ •μ±…(Same-Origin-Policy)”라고 ν•©λ‹ˆλ‹€.

2️⃣ API와 μ—°κ²°.

  • 둜그인, νšŒμ›κ°€μž… λ“±μ˜ κΈ°λŠ₯을 κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄ λ°±μ—”λ“œ APIλ₯Ό μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    • 예λ₯Ό λ“€μ–΄, /login APIλ₯Ό λ§Œλ“€μ–΄ JavaScriptμ—μ„œ ν•΄λ‹Ή API둜 AJAX μš”μ²­μ„ 보낼 수 μžˆμŠ΅λ‹ˆλ‹€.

πŸ“ AJAX(Asynchronous JavaScript and XML)

μ›Ή νŽ˜μ΄μ§€λ₯Ό μƒˆλ‘œκ³ μΉ¨ν•˜μ§€ μ•Šκ³  비동기 λ°©μ‹μœΌλ‘œ μ„œλ²„μ™€ 데이터λ₯Ό 주고받을 수 있게 ν•΄μ£ΌλŠ” κΈ°μˆ μ„ λ§ν•©λ‹ˆλ‹€.
μ›Ή νŽ˜μ΄μ§€λ₯Ό λ™μ μœΌλ‘œ μ—…λ°μ΄νŠΈ ν•  수 있기 λ•Œλ¬Έμ— μ‚¬μš©μžκ°€ 더 λΉ λ₯΄κ³  직관적인 κ²½ν—˜μ„ ν•  수 μžˆλ„λ‘ λ„μ™€μ€λ‹ˆλ‹€.

6️⃣ μš”μ•½.

  • Spring Boot ν”„λ‘œμ νŠΈμ˜ static 디렉토리에 HTML, CSS, JavaScript νŒŒμΌμ„ λ„£μ–΄ 정적 λ¦¬μ†ŒμŠ€λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€.
  • 컨트둀러λ₯Ό 톡해 /login 및 /signup 경둜λ₯Ό μ„€μ •ν•˜κ³  HTML νŒŒμΌμ„ λ‘œλ“œν•©λ‹ˆλ‹€.
  • JavaScript μ½”λ“œλŠ” ν”„λŸ°νŠΈμ—”λ“œμ—μ„œ ν•„μš”ν•œ λ™μž‘μ„ μ²˜λ¦¬ν•˜λ©°, μΆ”κ°€λ‘œ APIλ₯Ό ν˜ΈμΆœν•  수 μžˆμŠ΅λ‹ˆλ‹€.