Spring ํ”„๋กœ์ ํŠธ ์„ค์ • ๋ฐ ๊ธฐ์ดˆ
Spring ๐ŸŒฑ

Spring ํ”„๋กœ์ ํŠธ ์„ค์ • ๋ฐ ๊ธฐ์ดˆ

๊น€์˜ํ•œ๋‹˜์˜ Spring ์ˆ˜์—…์„ ๋“ฃ๊ณ  ์ •๋ฆฌํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

๊ณต์‹ ์‚ฌ์ดํŠธ

https://spring.io

๊ณต์‹๋ฌธ์„œ์— Document, Getting Started ๋“ฑ์„ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

https://start.spring.io

Dependency - SpringWeb, ThymeLeaf

Gradle์€ ๋ฒ„์ „์„ค์ •, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ฐ€์ ธ์˜ค๊ณ , ๋ผ์ดํ”„ ์‚ฌ์ดํด ๊ด€๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

build.gradle

repository - mavenCentral ์ด๋ผ๋Š” ์‚ฌ์ดํŠธ์—์„œ dependency๋ฅผ ๋‹ค์šด๋กœ๋“œํ•œ๋‹ค.

dependencies - ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค ๊ฐ€์ ธ์˜จ๋‹ค.

ํ”„๋กœ์ ํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด log: Tomcat Started on port(s) 8080 ๋ผ๋Š” ๋กœ๊ทธ๊ฐ€ ๋‚จ๋Š”๋ฐ, ์Šคํ”„๋ง์ด ๋‚ด์žฅํ•˜๋Š” ์›น ์„œ๋ฒ„๊ฐ€ TomCat์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

์Šคํ”„๋ง์—์„œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ดํŽด๋ณด๊ธฐ

External Libraries ๋ฅผ ๋ณด๋ฉด ์—„์ฒญ๋‚˜๊ฒŒ ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์˜จ ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

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'
}

์—์„œ, starter-web์€ ๊ทธ ์•ˆ์— ํ†ฐ์บฃ, ์›น ๋“ฑ ๋˜ ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์˜์กด์„ ํ•˜๊ณ  ์žˆ๊ณ  Gradle์€ ์˜์กดํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋‹ค ๊ฐ€์ ธ์˜ค๋Š” ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

์—ฌ๊ธฐ์„œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ฐ„์˜ ์˜์กด๊ด€๊ณ„๋ฅผ ์‚ดํŽด๋ณผ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์Šคํ”„๋ง๋ถ€ํŠธ ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์“ฐ๋ฉด, ์Šคํ”„๋ง ์ฝ”์–ด๋„ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์„œ๋ฒ„์—์„œ ๋กœ๊น… ์—ญ์‹œ ์ค‘์š”ํ•œ๋ฐ, ์Šคํ”„๋ง ๊ฐ™์€ ๊ฒฝ์šฐ Gradle Dependencies๋ฅผ ๋ณด๋ฉด spring-boot-starter-loggin ์•ˆ์— slf4j, logback ๋“ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. (์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์Šคํ”„๋ง ์ง„์˜์—์„œ ์ถ”๊ฐ€ํ•œ ๊ฒƒ)

ํ…Œ์ŠคํŠธ ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ junit(ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ)๋“ฑ์ด ์ถ”๊ฐ€๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. (๊ทธ ์™ธ mockito(๋ชฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ), assertj(ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ), spring-test ๋“ฑ์ด ์žˆ๋‹ค.)

View ํ™˜๊ฒฝ ์„ค์ •

  • Welcome Page ๋งŒ๋“ค๊ธฐ
    • ์Šคํ”„๋ง์€ src > resources > static์— index.html ํŒŒ์ผ์„ ๋งŒ๋“ค๋ฉด, ํ•ด๋‹น ํŽ˜์ด์ง€๊ฐ€ ๋ณด์—ฌ์ง„๋‹ค. (์ •์  ํŽ˜์ด์ง€)
  • thymeleaf ํ…œํ”Œ๋ฆฟ ์—”์ง„ ์ ์šฉํ•˜๊ธฐ (๊ทธ ์™ธ FreeMarker, Groovy, Mustache ๋“ฑ์ด ์žˆ๋‹ค)
  • Web Application์—์„œ ์ฒซ ๋ฒˆ์งธ ์ง„์ž…์ ์„ Controller๋ผ ํ•œ๋‹ค.
package com.kakaopay.springstudy.hellospring.controller;

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

@Controller
public class HelloController {

    @GetMapping("hello")
    public String hello(Model model) {
        model.addAttribute("data", "hello");
        return "hello";
    }

}
  • hello.html
    • ๊ฒฐ๊ณผ
        <!DOCTYPE html> 
        <html xmlns:th="http://www.thymeleaf.org"> 
            <head> 
              <meta charset="UTF-8"> 
              <title>Hello</title> 
            </head> 
            <body> 
              <p th:text="'์•ˆ๋…•ํ•˜์„ธ์š”.' + ${data}"> ??? </p> 
            </body> 
        </html>

๋™์ž‘ํ™˜๊ฒฝ

  • ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋ฆฌํ„ดํ•œ String์„ ViewResolver๊ฐ€ ํ™”๋ฉด์„ ์ฐพ์•„ ์ฒ˜๋ฆฌํ•œ๋‹ค.
    • ์Šคํ”„๋ง ๋ถ€ํŠธ ํ…œํ”Œ๋ฆฟ์—”์ง„ ๊ธฐ๋ณธ viewName ๋งคํ•‘
    • resources: templates/{viewName}.html
  • ์ฐธ๊ณ 
    • spring-boot-dedvtools ๋ผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด html ํŒŒ์ผ์„ ์ปดํŒŒ์ผ๋งŒ ํ•ด์ฃผ๋ฉด ์„œ๋ฒ„ ์žฌ์‹œ์ž‘ ์—†์ด View ํŒŒ์ผ ๋ณ€๊ฒฝ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

๋นŒ๋“œ์™€ ์‹คํ–‰

$ ./gradlew build

$ cd build

$ java -jar hello-spring-0.0.1-SNAPSHOT.jar

๋นŒ๋“œ ์ง€์šฐ๊ธฐ

$ ./gradlew clean

์Šคํ”„๋ง ์›น ๊ฐœ๋ฐœ ๊ธฐ์ดˆ

  • ์ •์  ์ปจํ…์ธ 
    • Spring์€ Controller์— ๋งตํ•‘๋œ ๊ฒŒ ์—†๋‹ค๋ฉด static ํด๋”์—์„œ ์ •์  ํŒŒ์ผ์„ ์ฐพ๋Š”๋‹ค.
  • MVC์™€ ํ…œํ”Œ๋ฆฟ ์—”์ง„
    • MVC๋Š” Model, View, Controller์˜ ์ค€๋ง, ๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ๋ฅผ ์œ„ํ•จ (View๋Š” ํ™”๋ฉด์„ ๊ทธ๋ฆฌ๋Š” ๊ฒƒ์—๋งŒ, Model์€ ๋ฐ์ดํ„ฐ์˜ ํ˜•์‹๋งŒ, Controller๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๋งŒ ๊ด€๋ฆฌ)
    • Parameter ๋ฐ›๊ธฐ
    @GetMapping("hello-mvc")
    public String helloMVC(@RequestParam(value = "name", required = false) String name, Model model) {
        model.addAttribute("name", name);
        return "hello-template";
    }
  • API (๋ณดํ†ต HTML์ด ์•„๋‹Œ JSON ํฌ๋ฉง์œผ๋กœ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ „๋‹ฌ, React, Android, Vue ํ˜น์€ ์„œ๋ฒ„์™€ ํ†ต์‹ )
    • @ResponseBody๋Š” Body์— ์ด ๋ฌธ์ž์—ด์„ ๋„ฃ์„ ๊ฒƒ์„ ์˜๋ฏธํ•จ (๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ณด๋‚ผ ๊ฒƒ์ด๋ผ๋Š” ๊ฑธ ์˜๋ฏธํ•จ, default๊ฐ€ true์ด๊ธฐ ๋•Œ๋ฌธ์— default=false๊ฐ€ ์—†๋‹ค๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ)
    @GetMapping("hello-string")
    @ResponseBody
    public String helloString(@RequestParam("name") String name) {
        return "hello " + name;
    }
  • JSON ํฌ๋ฉง์œผ๋กœ ๋ฆฌํ„ดํ•˜๊ธฐ (default๊ฐ€ JSON ๋ฆฌํ„ด)
    • ResponseBody ์–ด๋…ธํ…Œ์ด์…˜์ด ์žˆ๋‹ค๋ฉด ViewResolver๊ฐ€ ์•„๋‹Œ, HttpMessageConverter๊ฐ€ ์ž‘๋™ํ•œ๋‹ค.
      • ๋‹จ์ˆœ ๋ฌธ์ž์—ด์ด๋ฉด StringHttpMessageConverter ์•„๋‹ˆ๋ผ๋ฉด MappingJackson2HttpMessageConverter๊ฐ€ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค. (๋”ฐ๋ผ์„œ ๊ฐ์ฒด๊ฐ€ JSON ํ˜•์‹์œผ๋กœ ๋ฐ”๋€Œ์–ด ๋ฆฌํ„ด๋˜๋Š” ๊ฒƒ)
    static class Hello {
        private String name;
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
    }

    @GetMapping("hello-api")
    @ResponseBody
    public Hello helloJSON(@RequestParam("name") String name) {
        Hello hello = new Hello();
        hello.setName(name);
        return hello;
    }
  • ๊ฒฐ๊ณผ