2025.8.28: Hello, Spring!

jiyongg·2025년 8월 28일

TIL: Today I Learned

목록 보기
29/30

오랜만에 TIL을 쓴다.

이번 주 화요일에 드디어 해커톤이 끝났다. 결과부터 말하자면 광탈했다. 😂

뭐 여기에 대해서는 예견된 결과였다고 말할 수밖에 없겠다.. 서비스가 불안정하기도 했고 우리가 경험이 부족하기도 했다. 해커톤 과정에 대해서는 나중에 회고록으로 따로 써 보도록 하겠다.

이제 2학기부터는 스프링을 공부해 보고자 한다. 아직 확정은 아니지만 이번 학기에는 동아리에서 스프링을 사용하는 프로젝트를 반 년 간 진행하게 될 것 같다. 사실 회장님이 장고와 스프링 둘 중 하나를 선택하게 해 주었다. 나는 하면서 배운다는 생각, 그리고 어차피 취업하려면 스프링을 공부해야 한다는 생각으로 스프링을 선택했다.

다음 주면 개강이긴 하지만, 조금이라도 공부해 두고 가는 편이 낫지 않을까라고 생각해서 2학기 첫 세션까지 남아있는 시간동안 최대한 스프링을 속성으로 공부해 볼 생각이다.

오늘은, IntelliJ IDEA를 이용해 Hello, World! 를 출력하는 스프링 부트 앱을 만들어 보고, 코드의 의미에 대해 간단하게 파헤쳐 보았다.

1. 🗂️ IntelliJ IDEA 프로젝트 생성

일일이 IntelliJ IDEA라고 부르긴 귀찮으므로, 여기서부턴 인텔리제이라고 부르겠다.

먼저 인텔리제이를 켜준다.

TIL을 쓰기 전에 앞서 미리 테스트해 본 프로젝트가 보인다.

새 프로젝트를 클릭한다.

제너레이터에 있는 Spring Boot를 클릭하고, 이름과 그룹을 적당히 지정해준다. 물음표 위에 커서를 올리면 해당 항목에 대한 설명을 띄워준다. JDK는 내 컴퓨터에 깔려 있는 것으로 선택했다. 그 밑의 Java는 JDK가 21이니 이를 따라 21로 선택했다. 그런데, 솔직히 잘 알고서 선택한 것은 아니라서, 각 자바 버전의 차이점은 찾아봐야 할 것 같다. 일단 앞서 만들었던 프로젝트는 이 세팅으로 진행했고, 잘 동작하는 것을 확인했다.

2. 💻 코드 작성

스프링 공식 홈페이지의 Quickstart에 있는 튜토리얼을 따라 코드를 그대로 작성해 볼 것이다.

프로젝트 생성 후 src/main/java/패키지이름/프로젝트명.java를 연다.

그러면 아래와 같은 코드가 나타날 것이다.

package 패키지이름;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class 프로젝트명Application {

    public static void main(String[] args) {
        SpringApplication.run(프로젝트명Application.class, args);
    }

}

아래와 같이 바꾼다.

package 패키지이름;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class 프로젝트명Application {

    public static void main(String[] args) {
        SpringApplication.run(프로젝트명Application.class, args);
    }

    @GetMapping("/hello")
    public String sayHello(@RequestParam(value = "myName", defaultValue = "World") String name) {
        return String.format("Hello, %s!", name);
    }
}

인텔리제이에서는 자동으로 import문을 추가해준다. 편리하다. @SpringBootApplication 부분부터 입력하다 보면 알아서 위의 import 부분이 완성되어 있을 것이다.

이제 우측 위의 ▷ 버튼을 클릭하거나 Ctrl + F5를 눌러서 실행해본다.

Started 프로젝트명Application ~가 뜨면 http://localhost:8080으로 접속해본다.

???: 안 되잖아? 사기 치냐?

진정하라. 위의 @GetMapping에서 알 수 있듯, Hello World를 보기 위해서는 /hello 경로로 가야 한다. http://localhost:8080/hello로 접속해 보자.

Hello, World! 가 반겨준다!

여기엔 재미있는 사실이 하나 더 숨어 있는데, 경로 뒤에 myName이라는 Query Parameter를 붙여보자. http://localhost:8080/hello?myName=John 식으로..

그러면 Hello, World! 대신 Hello, John! 이 나온다!

3. 🔎 분석

어떻게 이것이 동작하는 것인지 살펴보고자 한다. 일단 내가 이해한 만큼 적었는데, 나도 스프링 뉴비이기 때문에 틀릴 수도 있다..

먼저, 모든 코드 중에 가장 내 눈길을 끌었던 것은 @SpringBootApplication, @RestController와 같이 @로 시작하는 친구들이었다.

파이썬에는 @으로 시작하는 데코레이터가 존재하는데, 자바에도 데코레이터가 있는 것일까? 결론부터 말하자면 이 친구들은 데코레이터는 아니고 annotation이라는 것이다.

annotation?

그런데 내가 파이썬을 공부할 때에도 annotation이라는 말을 본 적이 있었다.

예를 들어, 파이썬에서는 type annotation이라는 개념이 있다. 이 개념은 함수나 메소드의 매개변수, 반환값을 알려주거나, 어떤 변수의 값을 알려주는 개념이다.

def my_func(str_arg: str, int_arg: int) -> str:
    return f"Hello {str_arg} from {int_arg} players!"

my_var: str = "Hello World!"

뭐 이런 식으로 말이다..

자바에서는 @가 annotation을 나타낸다고 한다. 메소드나 클래스의 역할이나 메타 정보를 제공하고, 컴파일러가 이 annotation을 가지고 추가적인 작업을 한다고 한다. 또한 표준과 메타로 나뉜다고 하는데.. 일단 어노테이션에 대해서는 나중에 자세히 알아봐야겠다.

1) annotation

  • @SpringBootApplication: @SpringBootConfiguration, @EnableAutoConfiguration, @ComponentScan을 모두 합친 convenience annotation이다.
    • @SpringBootConfiguration: 이 클래스에 스프링 부트 앱의 @Configuration이 있다는 것을 의미한다.
    • @EnableAutoConfiguration: 프레임워크가 알아서 필요한 Configuration을 추측해서 설정해준다.
    • @ComponentScan: @Component들을 스캔한다.
      • 자바에는 Bean이라는 개념이 있으며, Bean은 재사용 가능한 자바 객체 (컴포넌트)를 의미한다고 한다.
      • 스프링 역시 Bean이라는 개념을 사용하는데, 이에 대한 annotation이 두 개가 있다고 한다. 개발자가 직접 등록해야 하는 @Bean@ComponentScan에 의해 자동으로 등록되는 @Component이다.
      • 여담으로 @ComponentScan이 오늘 공부 중에 제일 이해하기 어려웠던 annotation이었다. 최대한 이것저것 찾아봤는데, 정확하진 않을 수도 있다.
  • @RestController: @Controller@ResponseBody를 합친 convenience annotation이다.
    • @ResponseBody: 메소드의 반환값이 웹의 응답 본문으로 bound된다.
      • 위의 sayHello 메소드는 문자열을 반환해서 그대로 raw text가 반환되지만, 메소드가 객체나 배열 등을 반환하면 Jackson2를 사용해 직렬화된 JSON 텍스트로 반환된다.
  • @RequestMapping: 이 annotation의 인자 경로로 들어오는 HTTP 요청을 이 annotation이 붙어 있는 메소드로 매핑시킨다 (routing).
    • @GetMapping은 이름에서 알 수 있듯, HTTP 요청 중에 GET 요청만을 받는다.
  • @RequestParam: Query Parameter를 정의한다.
    • 위의 코드에서는 myName이라는 Query Parameter를 정의하고, 이 Query Parameter의 값을 메소드에서 name이라는 문자열 변수로 사용한다. 기본값은 World이다.
      • 위에서 /hello로 접속했을 때 Hello, World!가 출력된 이유는 기본값이 World였기 때문이고, /hello?myName=John으로 접속했을 때 Hello, John!이 출력된 이유는 myName이라는 Query Parameter의 값이 John이 되었기 때문이다.

2) 메소드

  • SpringApplication.run: SpringApplication 클래스에 실행 책임을 위임하는 메소드이다. 프로젝트명Application.class를 인자로 전달해서 기본 스프링 컴포넌트를 알려준다.

참고) @ResponseBody 실험

실제로 한 번 실험을 해 보았다.

package com.example.helloworld;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class HelloworldApplication {

    public static void main(String[] args) {
        SpringApplication.run(HelloworldApplication.class, args);
    }

    @GetMapping("/hello")
    public String sayHello(@RequestParam(value = "myName", defaultValue = "World") String name) {
        return String.format("Hello, %s!", name);
    }

    @GetMapping("/array")
    public int[] printArray() {
        return new int[] {1, 2, 3};
    }

}
  • /hello로의 요청은 sayHello 메소드에서 처리하는데, 이 메소드는 문자열을 반환한다.
  • 반면, /array로의 요청은 printArray 메소드에서 처리하며, 이 메소드는 int의 배열을 반환한다.

포스트맨을 켜고, 두 경로에 각각 요청을 보내보자.

두 요청 모두 위와 같은 헤더로 진행한다.

먼저, /hello 경로로 요청을 보냈을 때의 모습이다. Content-Typetext/plain인 것을 볼 수 있다.

이번엔 /array 경로로 요청을 보내 보았다. 아까와 다르게 JSON 문자열이 반환되었고, Content-Typeapplication/json이라고 되어 있는 것을 볼 수 있다!

4. 🖼️ 배너 바꾸기

스프링 부트 앱을 실행했을 때의 콘솔 창이다.

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.5.5)

뭔가 이걸 바꿔서 원하는 아스키 아트를 넣을 수 있지 않을까? 라고 생각했는데, 사람 생각은 다 똑같은 것 같다. 이것은 배너라고 하는 것으로, src/main/resources 경로에 banner.txt를 생성해서 그 내용을 바꿀 수 있다고 한다.

나는 https://emojicombos.com/hatsune-miku-ascii-art 이곳에서 적당한 하츠네 미쿠 아스키 아트를 하나 복사해서 넣어 보았다. ㄴㄷㅆ

뭔가 아까보단 덜 심심하다. 그런데 아직 좀 심심하다. 미쿠에게 색을 입혀보고 싶은데.. 가능할까? 가능하다! banner.txt를 열고 색을 적용하고 싶은 부분 앞에 ${AnsiColor.색상명}을 입력하면 된다.

그리고 다시 돌려보면..

짜잔!

배너로 사용할 아스키 아트는 ASCII Art Archive 등에서 마음에 드는 것을 구하거나, Image to Braille 등의 사이트에서 가지고 있는 이미지를 아스키 아트로 변환해서 구할 수도 있다. 아니면, 텍스트를 가지고 스프링 배너를 만들어 주는 사이트 Spring Boot banner.txt generator와 같은 것들도 있다.

5. 🔚 결론

오늘은 스프링 부트로 헬로 월드를 만들어 스프링 부트의 첫걸음을 떼어 보았다. 뭔가 장고와 비슷하면서도 다른 부분들이 있는 것 같다.

스프링을 공부할 때에는 김영한이라는 분의 강의가 국룰처럼 여겨지고 있는 것 같다. 내 주변에서도 김영한님 이야기를 하고, 커뮤니티 등에서도 김영한님 이야기를 하고 있더라.. 나도 그래서 김영한님 강의를 들어 볼 생각이다. 다만, 전부 다 들으려면 비용이 어마무시하더라. 그래서 무료로 공개되어 있는 강의로 스프링을 간단히 파악하고, 심화 개념은 오라일리와 유데미, 코세라 등을 이용해서 공부해 볼 계획이다.

그리고 자바 개발에 있어서는 VS Code보단 인텔리제이가 더 좋다고 하여, 학생 혜택으로 인텔리제이의 얼티밋 버전을 무료로 받아서 써 보고 있다. 처음에 세팅할 때에는 머리가 좀 아팠는데, 그래도 써보니깐 꽤 괜찮은 IDE인 것 같다.

아직 VS Code에서 완전히 갈아탈 수준인 것 같다는 생각은 안 들어서, 당분간은 스프링 프로젝트와 같은 자바 프로젝트에서 인텔리제이를 이용하고 다른 프로젝트에서는 VS Code를 쓸 생각이다.

6. 📚 참고 자료

profile
그냥 쓰고 싶은 것 쓰는 개발(?) 블로그

0개의 댓글