ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [SpringBoot] 1주차 JAVA 이해 및 ping API 구현
    Study/SpringBoot 2026. 3. 10. 17:48

     앞으로 10주간 스터디를 통해 배운 내용을 현재 카테고리에 기록하겠다.

    이번 주차 공부 내용

    • JAVA 문법 정리
    • 스터디 진행 위한 기반 설정(깃허브 레포, 브랜치 설정)
    • IntelliJ를 이용한 Spring Boot 프로젝트 생성
    • 표준 패키지 구조(controller, service, repository, domain, common) 이해
    • 공통 응답 객체(ApiResponse) 적용 및 /api/ping API 구현

     


     Java 기본 핵심 문법 정리 📖

    1. 변수와 데이터 타입 (Variables & Data Types)

     자바는 강한 타입 언어(Strongly Typed)이므로 모든 변수는 선언할 때 그 안에 담길 데이터의 종류를 명시해야 한다.

     

    • 기본 타입 (Primitive Types): 실제 값을 변수에 저장합니다.
      • 정수: int (가장 많이 씀), long (큰 숫자)
      • 실수: double
      • 논리: boolean (true / false)
    • 참조 타입 (Reference Types): 실제 객체가 있는 메모리 주소를 저장한다.
      • String, ApiResponse, 직접 만드는 모든 Class가 여기에 해당
      • 값이 없으면 null을 가질 수 있다는 것이 특징

    2. 제어문 (Control Flow)

     프로그램의 흐름을 결정하는 문법이다.

    • 조건문 (if-else, switch): 상황에 따라 다른 코드를 실행
    • 반복문 (for, while): 같은 작업을 여러 번 반복
      • 향상된 for문: for (String s : list) 처럼 배열이나 리스트의 요소를 하나씩 꺼낼 때 매우 편리하다.

    3. ⭐️ 객체지향 프로그래밍 (OOP) ⭐️

     가장 중요한 부분, 스프링 부트는 이 객체지향의 원리를 극대화해서 사용


          < 클래스와 객체 (Class & Object) >

    • 클래스: 붕어빵 틀 (설계도)
    • 객체(인스턴스): 붕어빵 (설계도로 만든 실제 결과물)

         < OOP의 4대 특징 >

    1. 캡슐화 (Encapsulation): 데이터를 외부로부터 숨기고(private), 메서드를 통해서만 접근하게 한다. (예: Getter/Setter)
    2. 상속 (Inheritance): 부모 클래스의 기능을 자식이 물려받아 재사용한다. (extends)
    3. ⭐️다형성 (Polymorphism)⭐️: 가장 중요. 하나의 타입(부모)이 여러 가지 형태(자식)로 동작할 수 있는 능력이다.
    4. 추상화 (Abstraction): 공통적인 특징만 뽑아내어 틀을 만든다. (interface, abstract class)

     


    4. 예외 처리 (Exception Handling)

    프로그램 실행 중 발생할 수 있는 에러에 대비하는 방법이다.

    • try-catch-finally: 에러가 날 것 같은 코드를 try 안에 넣고, 에러가 나면 catch에서 처리한다.
    • throws: 해당 메서드에서 에러가 나면 처리하지 않고 호출한 상대에게 넘긴다.

    5. 컬렉션 프레임워크 (Collections Framework)

     여러 개의 데이터를 효율적으로 관리하기 위한 표준 도구이다.

    인터페이스 특징 대표 클래스
    List 순서가 있고 중복을 허용함 ArrayList
    Set 순서가 없고 중복을 허용하지 않음 HashSet
    Map Key-Value 쌍으로 데이터를 저장함 HashMap

     


    6. 인터페이스와 제어 (Interface & Implements)

     스프링 부트에서 Service와 Repository를 만들 때 많이 쓰게 될 구조.

    • 인터페이스: 기능을 만들기 위한 약속(규격)을 정해두는 것.
    • 구현체: 인터페이스의 약속을 실제로 코드로 구현한 클래스.
    • 이유: 나중에 구현 내용이 바뀌더라도(예: MySQL 쓰다가 MongoDB로 바꿈), 인터페이스를 쓰는 쪽의 코드는 고칠 필요가 없게 하기 위해서이다.

     


    스터디를 위한 패키지 구조 설정 🧬

     스프링 부트의 정석적인 계층형 구조를 따라 패키지를 구성했다. 처음에는 com.study.springbootstudy 아래에 폴더가 한 줄로 보였으나 중간 패키지 접기(Compact Middle Packages) 설정을 해제하여 구조를 익혔다.

    패키지명 역할 및 학습 포인트
    common 공통 응답(ApiResponse), 에러 코드 등 프로젝트 전역에서 쓰이는 규격 정의
    controller 클라이언트의 요청을 받는 접점. @RestController의 역할을 학습
    service 비즈니스 로직의 핵심. 향후 인터페이스를 활용한 다형성 실습의 장
    domain 데이터의 모델링. DB 테이블과 매핑되는 Entity 개념의 기초
    repository 데이터 저장소 접근. 인터페이스를 통한 추상화 학습 예정

     

     


    주요 구현 코드 💻

     공통 응답 객체 (ApiResponse.java)

     성공 시 일관된 JSON 형식을 반환하기 위해 제네릭을 활용한 공통 객체를 만들었다.

    package com.study.springbootstudy.common; // 패키지 경로 추가
    
    import lombok.AllArgsConstructor; // 임포트 추가
    import lombok.Getter;
    
    @Getter // 이 어노테이션이 있어야 아래 필드들을 '사용'하는 것으로 인식함
    @AllArgsConstructor // 이 어노테이션이 있어야 '4개의 인수'를 받는 생성자가 만들어짐
    public class ApiResponse<T> {
        private boolean isSuccess;
        private String code;
        private String message;
        private T result;
    
        public static <T> ApiResponse<T> onSuccess(T result) {
            return new ApiResponse<>(true, "COMMON200", "요청에 성공하였습니다.", result);
        }
    }

     

     

    💻 코드 설명 및 쓰인 문법 정리 💻

    package com.study.springbootstudy.common;

     이 클래스가 위치한 컴퓨터상의 주소이다. 자바는 폴더 구조를 통해 클래스를 관리하며, 나중에 다른 곳에서 이 클래스를 쓰려면 이 주소를 찾는다.

     

    import lombok.AllArgsConstructor;

     외부 라이브러리인 Lombok의 기능을 빌려 쓰겠다는 선언이다. 자바 기본 문법에는 없는 기능을 추가할 때 사용한다.

     

    코드 자동화 Lombok 어노테이션

    • @Getter: 자바 클래스의 필드값을 가져오는 getIsSuccess(), getResult() 같은 메서드를 코드로 일일이 짜지 않아도 자동으로 생성해 준다.
    • @AllArgsConstructor: 모든 필드를 매개변수로 받는 생성자를 자동으로 만들어준다. new ApiResponse(true, "200", ...) 처럼 객체를 만들 수 있게 해준다.

     

    public class ApiResponse<T>

    유연한 설계, 제네릭 (Generics,  <T>)

    • ApiResponse<T>에서 T는 Type의 약자이다. 응답 데이터(result)가 문자열일 수도, 숫자일 수도, 혹은 리스트일 수도 있기 때문에 어떤 타입이든 유연하게 담을 수 있도록 '타입 파라미터'를 사용한 것이다.

    객체의 데이터 구성 (Fields)

    • private boolean isSuccess; (기본 타입): 성공/실패 여부를 담는 스위치이다.
    • private String code; (참조 타입): "COMMON200" 같은 내부 관리용 에러/성공 코드이다.
    • private String message; (참조 타입): 사용자에게 보여줄 메시지이다.
    • private T result; (제네릭 타입): 위에서 선언한 T 타입의 실제 데이터가 담기는 공간이다.

     

    정적 팩토리 메서드 (Static Factory Method)

    • public static <T> ApiResponse<T> onSuccess(T result)
      • static: 이 메서드는 new로 객체를 만들지 않아도 ApiResponse.onSuccess()처럼 클래스 이름으로 바로 호출할 수 있다.
      • <T> (메서드 앞): 이 메서드 안에서 제네릭 타입 T를 자유롭게 쓰겠다는 선언이다.
      • onSuccess (이름): 생성자보다 이름을 가지는 메서드가 훨씬 직관적이다. 성공했을 때 응답을 바로 만든다.
    • return new ApiResponse<>(true, "COMMON200", "요청에 성공하였습니다.", result);
      • 실제로 메모리에 ApiResponse 객체를 생성해서 돌려주는 부분이다.
      • <> (다이아몬드 연산자) 안은 앞에서 T라고 했으므로 생략해도 자바가 알아서 추론한다.

    ⭐️ Public과 Private의 차이 ⭐️
    구분 public (공개) private (비밀)
    접근 가능 범위 프로젝트 내 어디서든 접근 가능 해당 클래스 내부에서만 접근 가능
    비유 스마트폰의 액정 화면과 버튼 스마트폰 내부의 회로와 칩셋
    목적 외부와 소통하는 '창구' 역할 데이터 보호 및 내부 로직 숨기기

     


     컨트롤러 (PingController.java)

     간단한 연결 테스트를 위한 /api/ping 엔드포인트를 설계했다.

    package com.study.springbootstudy.controller;
    
    import com.study.springbootstudy.common.ApiResponse;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class PingController {
        @GetMapping("/api/ping")
        public ApiResponse<String> ping() {
            return ApiResponse.onSuccess("pong");
        }
    }

     

     

    💻 코드 설명 및 쓰인 문법 정리 💻

    @RestController

     가장 중요한 어노테이션으로, 자바의 일반 클래스를 웹 서버의 부품(컨트롤러)으로 바꾼다.

    • 원리: 이 어노테이션 안에는 @Controller와 @ResponseBody라는 두 가지 기능이 합쳐져 있다.
    • 핵심 기능: 보통의 자바 메서드는 값을 반환하면 그게 끝이지만, @RestController가 붙은 클래스의 메서드는 반환하는 객체(여기서는 ApiResponse)를 자동으로 JSON 형식({ "isSuccess": true, ... })으로 변환해서 브라우저나 앱에 보내준다.
    • 학습 포인트: 개발자가 직접 JSON 문자열을 만들 필요 없이, 자바 객체만 던져주면 스프링이 알아서 처리한다는 점이 핵심이다.
    @GetMapping("/api/ping")

     웹 브라우저의 주소창과 자바의 메서드를 연결해주는 우체국 역할이다.

    • HTTP Method (GET): 데이터를 조회하거나 단순히 연결을 확인할 때 사용하는 방식이다. 브라우저 주소창에 주소를 치고 들어가는 행위가 바로 GET 방식이다.
    • Path (/api/ping): 서버의 도메인(localhost:8080) 뒤에 붙는 세부 주소이다.
    • 학습 포인트: 주소와 메서드를 1:1로 매핑한다고 해서 핸들러 매핑(Handler Mapping)이라고 부른다. 

    메서드 호출과 리턴의 흐름

    • public ApiResponse<String> ping()
      • 누군가 localhost:8080/api/ping에 접속하면 스프링 부트가 이 ping() 메서드를 직접 호출한다.
      • new PingController()라고 객체를 만들지 않아도 되는 이유는, 스프링이 시작될 때 이 클래스를 빈(Bean)이라는 부품으로 미리 등록해서 관리하기 때문이다.
    • return ApiResponse.onSuccess("pong");
      • ApiResponse 클래스의 정적 메서드를 호출해 성공 응답 객체를 만든다.
      • 여기서 넘겨준 문자열 "pong"은 ApiResponse<T>의 T 자리에 들어가게 된다. (제네릭의 실전 활용)


    코드가 실행될 때 논리적 순서 요약

    1. 클라이언트: 서버에게 /api/ping 주소로 GET 요청 보냄
    2. 스프링 부트: 컨트롤러를 보고 주소 파악 및 PingController에 @GetMapping("/api/ping")를 찾음
    3. 메서드 실행: ping() 메서드를 실행해서 ApiResponse 객체를 결과로 받음
    4. 응답 변환: 결과가 객체인 걸 보고 클라이언트가 읽을 수 있게 JSON으로 변환함
    5. 결과: 클라이언트 화면에 {"isSuccess":true, "code":"COMMON200", "message":"요청에 성공하였습니다.", "result":"pong"} 출력함

    메인 애플리케이션 (SpringbootStudyApplication.java)

    스프링 부트의 시작점, 현재 DB 설정이 없어 발생하는 에러를 방지하는 코드가 포함되어 있다.

    package com.study.springbootstudy;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    // import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 
    // DB를 불러올 때 에러가 생겨서 주석처리함
    
    @SpringBootApplication
    public class SpringbootStudyApplication {
        public static void main(String[] args) {
            SpringApplication.run(SpringbootStudyApplication.class, args);
        }
    }

     

     

    💻 코드 설명 및 쓰인 문법 정리 💻

    @SpringBootApplication

     클래스 위에 붙은 이 어노테이션은 이 프로젝트를 단순한 자바 프로그램에서 강력한 웹 서버로 바꿀 세 가지 핵심 기능이 숨어 있다.

    • @SpringBootConfiguration: 이 클래스는 설정을 담당하는 클래스라고 알려준다.
    • @EnableAutoConfiguration: 스프링 부트의 가장 큰 특징인 자동 설정을 킨다. 즉, 라이브러리를 추가하면 스프링이 알아서 세팅해주는 것이다.
    • @ComponentScan: 패키지 스캔의 핵심이다. 메인 클래스 위치를 기준으로 하위 패키지에 있는 @RestController, @Service 등을 찾아내서 스프링의 관리 대상으로 등록한다.
    public static void main(String[] args)

     순수 자바 문법이다.

    • main 메서드: 자바 프로그램이 실행될 때 컴퓨터가 가장 먼저 찾는다. 모든 자바 앱은 여기서 시작된다.
    • static인 이유: 프로그램이 시작될 때 객체를 생성하지 않고도 바로 실행할 수 있어야 하기 때문에 '정적(static)' 메서드로 선언한다.
    • String[] args: 프로그램 실행 시 외부에서 던져주는 옵션(파라미터)들을 받는 바구니다. 보통은 비어 있지만, 서버 실행 시 특정 포트를 지정하거나 모드를 바꿀 때 사용한다.
    SpringApplication.run(...)

     main 메서드 안에서 호출되는 이 코드로 프로젝트를 구동시킨다.

    • SpringbootStudyApplication.class: 이 클래스에 붙은 설정을 보고 시동의 주체를 알려준다.
    • 하는 일:
      1. 스프링 컨테이너(부품 보관소)를 만든니다.
      2. 패키지를 스캔해서 부품(Bean)들을 조립한다.
      3. 내장된 웹 서버(Tomcat)를 실행해서 우리가 localhost:8080으로 접속할 수 있게 만든다.

    실행 흐름 요약

    1. @SpringBootApplication이 프로젝트의 모든 설정을 자동으로 읽어오고,
    2. main 메서드가 프로그램의 시작을 알리면,
    3. SpringApplication.run이 실제로 서버를 띄우고 부품들을 연결한다.
    4. 만약 준비 안 된 기능(DB 등) 때문에 시동이 안 걸린다면, exclude 옵션으로 그 부분만 잠시 빼고 할 수 있다.

     

    서버가 정상적으로 열린 모습


    트러블슈팅 🛠️

    [Issue1] Java 버전 호환성 문제 (25 → 21)
    • 현상: Java 25 환경에서 프로젝트 빌드 시 Lombok 및 Spring Boot 내부 라이브러리 인식 오류 발생.
    • 원인: Java 25는 최신 버전으로, 아직 주요 라이브러리(Lombok, ByteBuddy 등)의 바이트코드 지원이 완벽하지 않음.
    • 해결: 안정성이 검증된 Java 21 LTS(Long Term Support) 버전으로 변경.
    • 배운 점: 개발 환경을 구축할 때는 무조건 최신 버전보다는 생태계의 지원 여부와 안정성(LTS)을 우선 고려해야 함을 깨달음.
    [Issue2] DataSource 자동 설정 충돌

     

    • 현상: 서버 구동 시 Failed to configure a DataSource 에러 발생하며 실행 중단.
    • 원인: build.gradle에 DB 관련 의존성은 포함되었으나, 실제 DB 연결 정보(URL 등)가 설정되지 않아 스프링 부트의 자동 설정(Auto-configuration)이 실패함.
    • 해결: 메인 클래스의 @SpringBootApplication 어노테이션에 exclude = {DataSourceAutoConfiguration.class} 옵션을 추가하여 명시적으로 자동 설정을 제외함.

     


    1주차를 마치며

     아무래도 자바 자체를 처음 접하다보니 생각보다 처음 세팅에 어려움을 느꼈고, 인텔리제이를 열자마자 수많은 에러 메시지(특히 주황색 폴더와 빨간 글씨들)는 당황스러웠었다. 하지만 하나씩 논리적으로 원인을 파악하며 정리하고 해결하는 과정에서 자바 문법과 전체적인 스프링 부트에 더 흥미가 생겼다. 앞으로 10주간 파이팅~~

제목 없는 코딩 블로그