🌐 Spring Boot에서 로그 출력하는 방법

Spring Boot에서는 로그 출력을 쉽게 설정하고 사용할 수 있습니다. 로그는 애플리케이션의 상태를 파악하고 문제를 디버깅하는 데 매우 중요한 역할을 합니다. 이번 글에서는 Spring Boot에서 로그를 출력하는 방법과 설정 방법에 대해 알아보겠습니다.

📝 Spring Boot 로깅 설정

Spring Boot는 기본적으로 Logback을 로깅 구현체로 사용합니다. Spring Boot에서는 `application.properties` 또는 `application.yml` 파일을 통해 로깅 설정을 할 수 있습니다. 기본적으로 로그 레벨은 INFO로 설정되어 있습니다. 로그 레벨을 변경하거나 로그 파일을 설정할 수 있습니다.

👉 예시: `application.properties`

logging.level.root=INFO  # 기본 로그 레벨 설정
logging.level.org.springframework.web=DEBUG  # 특정 패키지에 대해 로그 레벨 설정
logging.level.org.apache.coyote.http11=TRACE  # org.apache.coyote.http11 패키지의 로그 레벨을 TRACE로 설정

logging.file.name=app.log  # 로그 파일 이름
logging.file.path=/var/logs  # 로그 파일 경로

👉 예시: `application.yml`

logging:
  level:
    root: INFO
    org.springframework.web: DEBUG
    org.apache.coyote.http11: TRACE  # TRACE 로그 레벨 설정
  file:
    name: app.log
    path: /var/logs

위 설정에서는 `org.apache.coyote.http11` 패키지의 로그 레벨을 `TRACE`로 설정했습니다. `TRACE`는 가장 세부적인 레벨로, 로그를 통해 매우 상세한 정보를 출력할 수 있습니다. 이를 통해 HTTP 요청과 관련된 세부적인 정보를 추적할 수 있습니다.

📝 SLF4J 로그 사용하기

Spring Boot에서 로그를 출력하려면 SLF4J API를 사용합니다. SLF4J는 다양한 로깅 구현체와 통합할 수 있는 API입니다. `LoggerFactory`를 통해 로거를 생성하고, `Logger` 객체를 이용하여 로그를 출력할 수 있습니다.

👉 로그 출력 코드

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {
    
    // SLF4J Logger 선언
    private static final Logger logger = LoggerFactory.getLogger(MyController.class);
    
    @GetMapping("/hello")
    public String hello() {
        logger.debug("디버그 레벨 로그");
        logger.info("정보 레벨 로그");
        logger.warn("경고 레벨 로그");
        logger.error("에러 레벨 로그");
        
        return "Hello, Spring Boot!";
    }
}

📝 로그 레벨

SLF4J를 통해 출력할 수 있는 로그 레벨에는 4가지가 있습니다. 각 로그 레벨은 로그의 중요도를 나타냅니다.

  • DEBUG: 개발 중에 유용한 정보를 출력하는 레벨입니다. 디버깅을 할 때 주로 사용됩니다.
  • INFO: 애플리케이션의 주요 흐름을 나타내는 로그입니다.
  • WARN: 경고 메시지로, 큰 문제는 아니지만 주의해야 할 상황을 알립니다.
  • ERROR: 오류가 발생했을 때 출력되는 로그입니다.
  • TRACE: 가장 상세한 로그 레벨로, 매우 세부적인 정보 출력에 사용됩니다. 주로 개발 중에 트러블슈팅을 위해 사용됩니다.

📝 Logback 설정 파일 커스터마이징

Spring Boot에서 로그 출력을 더 세밀하게 제어하려면 Logback 설정 파일을 사용하여 로그 출력을 커스터마이징할 수 있습니다. `logback-spring.xml` 파일을 생성하여 콘솔 출력 형식, 로그 파일 경로, 로그 레벨 등을 설정할 수 있습니다.

예시: `logback-spring.xml`

<configuration>
    <!-- 콘솔 로그 출력 설정 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <!-- 파일 로그 출력 설정 -->
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>/var/logs/app.log</file>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <!-- 로그 레벨 설정 -->
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="FILE"/>
    </root>
</configuration>

📝 외부 로깅 라이브러리 사용

Spring Boot에서는 기본적으로 Logback을 사용하지만, 다른 로깅 라이브러리인 Log4j2를 사용할 수도 있습니다. 이를 위해서는 `spring-boot-starter-log4j2` 의존성을 추가하고, `log4j2-spring.xml` 파일을 통해 설정을 커스터마이징할 수 있습니다.

👉 Log4j2 의존성 추가

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

이 의존성을 추가한 후, `log4j2-spring.xml` 파일을 생성하여 로그 출력을 설정할 수 있습니다.

📝 logging.level.org.apache.coyote.http11=trace

Apache Tomcat의 HTTP/1.1 커넥터를 다루는 내부 클래스입니다.
이 설정을 사용하면 다음과 같은 Tomcat 내부 동작을 로그로 확인할 수 있습니다:

  • 클라이언트 요청 파싱 과정
  • 커넥션 생성 및 종료
  • Keep-Alive 연결 처리
  • 헤더 처리 및 파이프라인 관련 정보

🎯결론

Spring Boot에서 로그를 출력하는 방법은 매우 간단하며, SLF4J와 Logback을 사용하면 다양한 로그 레벨과 설정을 통해 애플리케이션의 상태를 쉽게 모니터링하고 문제를 디버깅할 수 있습니다. 로그 출력 형식을 커스터마이징하여 더 세밀하게 로깅을 제어할 수도 있습니다. 올바른 로그 설정은 애플리케이션의 품질을 향상시키고 유지보수성을 높이는 데 중요한 역할을 합니다.

서블릿 컨테이너란? 자바 웹 애플리케이션의 보이지 않는 조력자

웹 개발을 하다 보면 "서블릿(Servlet)"뿐만 아니라 "서블릿 컨테이너(Servlet Container)"라는 단어도 자주 접하게 됩니다.
그렇다면 서블릿 컨테이너는 무엇일까요? 이 글에서는 서블릿 컨테이너의 정의, 역할, 동작 방식, 그리고 대표적인 구현체에 대해 쉽게 설명해드립니다.

📌 서블릿 컨테이너란?

서블릿 컨테이너는 서블릿(Servlet) 객체를 관리하고 실행하는 환경을 제공하는 소프트웨어입니다. 웹 서버와 서블릿 사이에서 중간 역할을 하며, 다음과 같은 기능을 제공합니다.

  • 클라이언트의 HTTP 요청을 서블릿에 전달
  • 서블릿의 실행 결과를 HTTP 응답으로 변환
  • 서블릿 객체의 생성, 초기화(init), 서비스(doGet/doPost), 소멸(destroy) 주기 관리
  • 보안, 로깅, 세션 관리 등의 부가 기능 제공

🔁 서블릿 컨테이너의 동작 흐름

서블릿 컨테이너는 다음과 같은 순서로 동작합니다.

  1. 사용자가 웹 브라우저에서 http://localhost:8080/hello 같은 URL로 요청
  2. 웹 서버가 요청을 받아 서블릿 컨테이너에 전달
  3. 서블릿 컨테이너는 해당 URL에 매핑된 서블릿을 찾아 실행 (doGet() 또는 doPost())
  4. 서블릿이 요청을 처리하고 응답을 생성
  5. 서블릿 컨테이너가 응답을 HTTP 형태로 브라우저에 전달

🧰 서블릿 컨테이너가 제공하는 기능

서블릿 컨테이너는 단순히 서블릿을 실행하는 것 외에도 다양한 기능을 제공합니다.

  • 라이프사이클 관리 - 서블릿 객체 생성부터 소멸까지 전 과정 관리
  • 요청 매핑 - URL과 서블릿 클래스를 연결
  • 멀티 스레딩 - 여러 사용자의 요청을 동시에 처리
  • 보안 처리 - 인증, 권한 부여 처리 가능
  • 세션 관리 - 사용자의 로그인 상태 유지

🚀 대표적인 서블릿 컨테이너

컨테이너 특징
Apache Tomcat 가장 널리 사용되는 서블릿 컨테이너. Spring, JSP와도 잘 통합됨
Jetty 가볍고 빠른 성능. 내장형 웹 서버로도 자주 사용
Undertow 비동기/논블로킹 처리에 강함. WildFly 애플리케이션 서버에서 사용

🎯 마무리

서블릿 컨테이너는 자바 웹 애플리케이션의 핵심 기반 기술입니다.
눈에 띄지 않지만 HTTP 요청과 응답을 매끄럽게 처리하고, 서블릿의 생명주기를 관리하는 보이지 않는 조력자라고 할 수 있죠.

Spring Boot를 사용하더라도 내부적으로는 Tomcat 같은 서블릿 컨테이너를 사용하는 구조이므로, 개념을 잘 이해해두면 다양한 웹 프레임워크를 다루는 데 큰 도움이 됩니다 😊

'Java > Java' 카테고리의 다른 글

[Java] 서블릿(Servlet)이란?  (1) 2025.04.09
[Java(자바)] 현재 날짜, 현재 시간 구하기  (1) 2025.03.04

✅ 사용 중인 포트 다시 사용할 때의 에러 메시지, 확인 방법, 종료 방법 완벽 정리

웹 서버를 개발하거나 테스트하다 보면 아래와 같은 메시지를 한 번쯤은 마주치게 됩니다.

Web server failed to start. Port 8080 was already in use.

이 글에서는
- 포트 충돌 시 발생하는 메시지
- 사용 중인 포트 확인 방법
- 포트를 종료하고 다시 사용하는 방법
을 정리해 드릴게요. 개발 중 겪는 잦은 문제를 쉽게 해결해보세요!

🛑 사용 중인 포트로 서버 실행 시 나타나는 에러 메시지

Spring Boot나 Node.js, Python Flask 등에서 서버를 실행하다가 이미 해당 포트가 사용 중일 경우, 다음과 같은 오류가 발생합니다.

Web server failed to start. Port 8080 was already in use.

이 메시지는 8080 포트가 이미 다른 프로세스에 의해 사용 중이라는 의미입니다. 해결하려면 먼저 어떤 프로세스가 포트를 점유하고 있는지 확인해야 해요.

🔍 사용 중인 포트 확인하는 방법 (Windows 기준)

CMD 또는 PowerShell에서 아래 명령어를 입력하세요:

netstat -ano | findstr :8080
컬럼 설명
TCP/UDP 사용 중인 프로토콜
Local Address 사용 중인 IP 및 포트 번호
PID 해당 포트를 사용하는 프로세스 ID

예시 출력:

TCP    0.0.0.0:8080     0.0.0.0:0       LISTENING       10256

여기서 마지막 숫자 10256은 이 포트를 사용 중인 프로세스 ID(PID)입니다.

🧨 해당 포트를 종료(Kill)하는 방법

Taskkill 명령어 사용

taskkill /PID 10256 /F
  • /PID: 종료할 프로세스 ID
  • /F: 강제로 종료

성공적으로 종료되면 해당 포트가 해제되고, 다시 사용할 수 있게 됩니다.

🧪 포트를 자주 사용할 경우 팁

  • 서버 종료를 잊지 마세요
    IDE에서 서버를 실행 후 수동으로 종료하지 않으면 포트가 계속 점유될 수 있어요.
  • 자동 종료 스크립트 작성
    start.sh 또는 stop.sh 같은 스크립트를 만들어 자동화하면 실수를 줄일 수 있어요.
  • IDE 설정 확인
    IntelliJ, VSCode 등에서는 백그라운드에서 자동 실행된 서버가 포트를 점유하는 경우도 있습니다.

💬 마무리

개발 도중 “포트 충돌”은 정말 자주 마주치는 문제예요.
하지만 위의 방법대로 차근차근 확인하고 종료하면 금방 해결할 수 있어요.
포트 관련 문제로 시간을 낭비하지 마시고, 빠르게 체크하고 개발에 집중하세요! 💪

 

'프로그래밍 > 일반' 카테고리의 다른 글

와이어프레임(Wireframe)이란?  (0) 2025.02.25
RabbitMQ란?  (0) 2025.02.05


🌐 서블릿(Servlet)이란? 

자바로 웹 애플리케이션을 개발하다 보면 Servlet(서블릿) 이라는 개념을 반드시 만나게 됩니다.
서블릿은 웹 요청을 처리하고 응답을 만들어주는 서버 측 프로그램이에요.
이번 글에서는 서블릿의 개념부터 동작 원리, 기본 코드 예제까지 쉽게 정리해드립니다! 🚀

📝 서블릿(Servlet)이란?

Servlet(서블릿)은 Java 언어로 작성된 서버 사이드 웹 컴포넌트로, 클라이언트의 요청(Request)을 받아 응답(Response)을 반환하는 역할을 합니다.

  • HTTP 요청을 처리하고 HTML, JSON 등의 결과를 돌려줌
  • Java 기반이기 때문에 이식성이 뛰어나고 안정성도 우수
  • Jakarta EE (기존 Java EE)의 표준 기술

📝 서블릿의 동작 흐름

  1. 사용자가 웹 브라우저에서 요청을 보냄 (http://example.com/hello)
  2. 웹 서버(예: Tomcat)가 이 요청을 받고 서블릿에게 전달
  3. 서블릿이 doGet() 또는 doPost() 메서드로 요청을 처리
  4. 처리 결과를 HTML 형식으로 응답 생성
  5. 브라우저는 그 응답을 사용자에게 표시

📝 서블릿의 주요 메서드

메서드 설명
init() 서블릿 초기화 시 1번 실행 (서버 시작 시)
doGet() GET 방식 요청 처리
doPost() POST 방식 요청 처리
destroy() 서블릿 종료 시 1번 실행 (서버 종료 시)

📝 서블릿 코드 예제


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException {

        res.setContentType("text/html;charset=UTF-8");
        PrintWriter out = res.getWriter();
        out.println("<h1>Hello, Servlet!</h1>");
    }
}


📝 서블릿의 특징 요약

  • Java 기반의 웹 기술
  • HTTP 요청을 받아 처리
  • 웹 서버(Tomcat 등)에서 실행됨
  • JSP, Spring 등 웹 프레임워크의 기반 기술


📝 서블릿 vs JSP vs Spring MVC

기술 설명
Servlet Java 코드로 모든 웹 요청을 직접 처리
JSP HTML에 Java 코드를 섞어 동적 페이지 생성
Spring MVC 서블릿 기반의 고급 프레임워크. 구조화된 웹 개발 지원

📌 JSP와 Spring도 결국 서블릿 위에서 동작합니다!

📝 서블릿을 실행하려면?

  1. Java 프로젝트 생성
  2. HttpServlet 클래스를 상속한 서블릿 작성
  3. URL 매핑: @WebServlet 또는 web.xml 사용
  4. Tomcat 같은 서블릿 컨테이너에 배포

🎯 마무리

서블릿은 Java 웹 개발의 가장 기초이자 중심이 되는 기술입니다.
비록 직접 서블릿만으로 개발하는 경우는 적지만, JSP, Spring 같은 고급 웹 기술의 기반이 되기 때문에 잘 이해해 두면 웹 개발에 큰 도움이 됩니다!

궁금한 점이 있다면 댓글로 남겨주세요 😊
다음 글에서는 JSP와 서블릿의 차이점 또는 실습 예제를 더 소개해볼게요!

📢 UI 개발, XML vs Jetpack Compose 무엇을 선택할까?

안녕하세요. 오늘은 안드로이드 UI 개발을 할 때 선택할 수 있는 두 가지 방식, 전통적인 XML 기반 레이아웃Jetpack Compose에 대해 비교 분석하고, 어떤 방식을 선택하는 것이 더 좋을지 개인적인 의견을 나눠보려 합니다.


📝 전통적인 XML 기반 UI 개발

안드로이드 개발을 해보신 분이라면 가장 익숙한 방식이 XML 레이아웃 파일을 사용한 UI 정의일 겁니다.

✅ 장점

  • 오랜 시간 검증된 방식으로 대부분의 레거시 프로젝트가 사용
  • 디자이너와 개발자의 역할 구분이 명확
  • Layout Editor를 통한 시각적 편집 가능

❌ 단점

  • UI와 로직이 분리되어 동적 UI 구성 시 복잡
  • findViewById나 View Binding 필요
  • 보일러플레이트 코드가 많아짐

📝 Jetpack Compose 기반 UI 개발

Jetpack Compose는 Kotlin 코드로 UI를 직접 선언하는 최신 방식입니다. 선언형 UI 패러다임을 도입했죠.

✅ 장점

  • UI와 로직을 한 곳에서 관리 가능
  • 상태 기반의 선언형 UI로 데이터 변경 시 UI 자동 갱신
  • 코드 간결, 재사용성 높음
  • Google이 적극 지원

❌ 단점

  • 처음엔 학습 곡선 존재
  • 기존 XML 코드와 완전한 호환은 아님
  • 일부 라이브러리 미지원 가능성 (점점 개선 중)

📝 XML과 Compose 비교 요약표

항목 XML 기반 UI Jetpack Compose
선언 방식 XML + Kotlin 분리 Kotlin 코드로 UI 선언
상태 관리 복잡, 코드 분산 간결, 상태 기반
생산성 중간 높음
러닝 커브 낮음 약간 높음
유지보수 복잡해지기 쉬움 모듈화 용이
Google 지원 유지 수준 주력 방향


📝 어떤 방식을 권장할까?

개인적으로는 Jetpack Compose를 권장합니다.

  • Google의 공식적인 미래 방향은 Compose 중심
  • MVVM과의 조합 시 매우 강력한 개발 경험
  • 초기 학습은 필요하지만 익숙해지면 XML보다 효율적

단, 기존 프로젝트 유지보수나 팀 내 역량에 따라 XML도 유효한 선택입니다.


📝 마무리

안드로이드 UI 개발은 빠르게 진화하고 있습니다. 이제는 XML보다 Jetpack Compose 같은 선언형 프로그래밍 방식이 대세가 되고 있습니다.

지금부터라도 Compose를 실습해보며, 새로운 UI 개발 방식을 익혀보세요!

👉 여러분은 어떤 방식을 사용하고 계신가요? 댓글로 의견을 나눠 주세요 😊

 

💻 관련 링크

 

Spring Boot를 이용해 애플리케이션을 개발할 때 가장 중요한 부분 중 하나는 빌드 도구의 선택입니다. Maven과 Gradle은 Spring Boot에서 주로 사용되는 두 가지 빌드 도구로, 각각의 특성과 장단점이 있습니다. 이번 글에서는 두 도구의 특징과 차이점을 자세히 살펴보고, 최근 트렌드에 따른 사용 현황도 분석해 보겠습니다.


1. Maven의 특징

📝 구성 방식

👉 XML 기반 설정:
Maven은 pom.xml 파일을 사용하여 프로젝트 설정, 의존성 관리, 플러그인 설정 등을 선언적으로 구성합니다.

👉 Convention over Configuration:
정해진 기본 구조와 설정 덕분에 초보자도 쉽게 접근할 수 있습니다.

📝 의존성 관리

👉 체계적인 관리:
중앙 저장소를 통해 의존성을 관리하며, 의존성 트리 관리 기능으로 버전 충돌 문제를 최소화합니다.

📝 플러그인 생태계

👉 풍부한 플러그인:
다양한 빌드, 테스트, 배포 작업을 수행할 수 있는 플러그인이 잘 갖춰져 있어 안정적인 빌드 환경을 제공합니다.

📝 학습 곡선

👉 명시적 설정:
XML 기반의 명시적인 설정 방식은 이해하기 쉽지만, 복잡한 구성이 필요할 때는 설정 파일이 길어지고 관리가 어려워질 수 있습니다.


2. Gradle의 특징

📝 구성 방식

👉 DSL 스크립트 방식:
Gradle은 Groovy 또는 Kotlin DSL을 사용해 build.gradle 또는 build.gradle.kts 파일로 빌드 설정을 작성합니다. 코드처럼 작성할 수 있어 매우 유연합니다.

📝 빌드 속도

👉 빠른 빌드:
인크리멘털 빌드, 캐시, 병렬 빌드를 지원하여 대규모 프로젝트에서도 빠른 빌드 시간을 제공합니다.

📝 유연성

👉 커스텀 로직 추가 용이:
스크립트 방식 덕분에 필요에 따라 커스텀 빌드 로직을 쉽게 추가할 수 있으며, 복잡한 빌드 과정도 효율적으로 처리할 수 있습니다.

📝 의존성 관리 및 플러그인

👉 유연한 설정:
Maven과 유사한 의존성 관리 기능을 제공하면서도, 스크립트 기반 설정으로 복잡한 요구사항에 맞게 조정하기가 용이합니다.


3. Maven과 Gradle의 비교


항목 Maven Gradle
구성 방식 XML 기반의 선언적 구성 Groovy/Kotlin DSL을 활용한 스크립트 방식
학습 곡선 표준화된 구조로 상대적으로 단순 유연하지만 자유도가 높아 초기 학습이 다소 복잡할 수 있음
빌드 속도 전체 빌드 방식으로 비교적 느릴 수 있음 인크리멘털 빌드 및 병렬 빌드 지원으로 빠른 빌드 시간 제공
유연성 정형화된 구조로 제한적 커스텀 빌드 로직 추가 등 매우 유연함
생태계 및 안정성 오랜 기간 사용되어 안정적이며, 플러그인 생태계가 풍부함 최신 기술에 적합, Android 등 다양한 분야에서 인기가 높음

👉 초기 설정 및 유지 관리:
Maven은 표준화된 구조 덕분에 설정과 유지 관리가 용이하지만, Gradle은 복잡한 빌드 로직 구현에 유리한 반면 초기 설정이 다소 복잡할 수 있습니다.

👉 확장성과 성능:
대규모 프로젝트나 빌드 속도가 중요한 상황에서는 Gradle의 인크리멘털 빌드와 캐시 기능이 큰 장점으로 작용합니다.


4. 최근 트렌드와 사용 현황

최근에는 Gradle의 사용이 점점 증가하고 있습니다. 그 이유는 다음과 같습니다.

👉 빠른 빌드 시간:
인크리멘털 빌드와 병렬 빌드 기능 덕분에 대규모 프로젝트에서도 빌드 시간이 크게 단축됩니다.

👉 유연한 스크립팅:
Groovy 또는 Kotlin DSL을 통한 스크립트 방식은 복잡한 빌드 로직을 손쉽게 구현할 수 있어 최신 개발 환경에 적합합니다.

👉 다양한 플랫폼 지원:
Android 개발에서 Gradle이 표준 빌드 도구로 자리 잡으면서, 서버 사이드(Spring Boot)뿐만 아니라 여러 분야에서 Gradle의 인기가 상승하고 있습니다.

반면, Maven은 여전히 많은 기업과 프로젝트에서 사용되며, 안정성과 단순함을 선호하는 팀에서 선택되고 있습니다. 최신 트렌드와 빌드 성능 최적화 요구에 따라 새로운 프로젝트나 대규모 시스템에서는 Gradle의 채택이 늘어나는 추세입니다.


 

🎯 결론

Spring Boot 프로젝트에서의 빌드 도구 선택은 프로젝트의 규모와 팀의 기술 역량에 따라 달라질 수 있습니다.

👉 Maven
    • 장점: 안정적이고 표준화된 설정, 관리가 쉬움
    • 적합한 경우: 소규모 프로젝트나 초보자, 정해진 규칙을 따르는 환경

👉 Gradle
    • 장점: 빠른 빌드 속도, 유연한 커스텀 빌드 로직 지원
    • 적합한 경우: 대규모 프로젝트, 최신 기술 스택 적용, 복잡한 빌드 로직 필요 시

최근 트렌드를 보면 Gradle의 인기가 상승하고 있으므로, 성능과 유연성이 중요한 프로젝트라면 Gradle을 고려해 보시는 것이 좋습니다. 물론 팀 내 경험이나 프로젝트 특성에 따라 Maven 역시 훌륭한 선택이 될 수 있습니다.


여러분의 프로젝트 환경과 요구사항에 맞는 최적의 빌드 도구를 선택하여 효율적인 개발 환경을 구축해 보시길 바랍니다.

📢 display 속성 정리 


🙌 CSS의 display 속성은 HTML 요소가 화면에 어떻게 렌더링될지를 결정하는 중요한 속성입니다. 이 속성을 이해하면 웹 페이지의 레이아웃을 효과적으로 설계할 수 있습니다.

📝 display: block 

  block에 해당하는 태그 

  <div>, <p>, <h1>~<h6>, <ul>, <ol>,  <li>, <table>, <blockquote>, <form>, <hr>, <figure>

block 의 특징

✔ 기본 width값 : 100%, 지정하지 않으면 부모 요소의 너비를 전부 차지한다. 한 줄에 여러 태그를 표시할 수 없다.
✔ width, height 값을 가질 수 있다 
✔ 상하좌우 모든 margin 값을 가질 수 있다



📝 display: inline

  inline 에 해당하는 태그 

<img>, <br>, <span>, <sub> <input>, <label>, <a>, <button>, <b>, <s>, <i>

inline 의 특징

✔ 기본 width값 : 컨텐츠 너비값, 한 줄에 여러 태그를 표시할 수 있다.
✔ width, height 값을 가질 수 없음, 같은 지정해도 무시됨
✔ 상하 margin값을 가질 수 없음

 

📝 display: inline-block 

 inline-block 의 특징

✔ 기본 width값 : 컨텐츠 너비값, 한 줄에 여러 태그를 표시할 수 있다.
✔ width, height 값을 가질 수 있음
✔ 상하 margin값을 가질 수 없음

 

 

📢 [Java Spring Boot] 스프링 부트에서 Swagger 사용하기

🙌 Swagger는 API 문서를 자동으로 생성해주는 도구로, Spring Boot에서는 Springdoc OpenAPI 라이브러리를 사용하여 쉽게 설정할 수 있습니다.

📝 Swagger(OpenAPI)란?

🙌 Swagger는 REST API를 시각화하여 쉽게 테스트하고 문서를 자동으로 생성해주는 도구입니다.
Spring Boot에서는 주로 springdoc-openapi 라이브러리를 사용하여 Swagger UI를 제공하며, 이를 통해 API를 웹 브라우저에서 손쉽게 확인할 수 있습니다.

📝 Spring Boot에서 Swagger 적용하기

    ✅ springdoc-openapi 의존성 추가

    ✔ Spring Boot 2.x 이상에서는 springdoc-openapi 라이브러리를 사용합니다.
    ✔ Spring Boot 프로젝트에서 다음과 같은 의존성을 추가합니다.

// Gradle - build.gradle
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.5'

// Maven - pom.xml
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
    <version>2.8.5</version> 
</dependency>


    ✅
Swagger UI 확인하기

      🙌 의존성을 추가한 후 프로젝트를 실행하면, Swagger UI를 확인할 수 있습니다.

      기본적으로 http://localhost:8080/swagger-ui.html 주소에서 Swagger UI가 제공됩니다.
      OpenAPI JSON 문서는 http://localhost:8080/v3/api-docs에서 확인할 수 있습니다.


👉 실행 결과 



📝
Swagger 문서화 추가하기

🙌 Swagger에서 API를 보기 좋게 표시하려면, @Operation 및 @Parameter 등의 어노테이션을 활용합니다.

    ✅ Controller에서 API 문서 작성하기

        @Tag(name, description): API 그룹을 지정합니다.
        @Operation(summary, description): API의 제목과 설명을 추가합니다.
        @Parameter(description): 요청 파라미터에 대한 설명을 추가합니다.

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.ArrayList;

@RestController
@RequestMapping("/users")
@Tag(name = "User API", description = "사용자 관리 API")  // API 그룹 태그
public class UserController {

    private final List<String> users = new ArrayList<>();

    @GetMapping
    @Operation(summary = "모든 사용자 조회", description = "저장된 모든 사용자 목록을 조회합니다.")
    public List<String> getUsers() {
        return users;
    }

    @PostMapping
    @Operation(summary = "사용자 추가", description = "새로운 사용자를 추가합니다.")
    public String addUser(@RequestParam @Parameter(description = "추가할 사용자 이름") String name) {
        users.add(name);
        return "User added: " + name;
    }
}


    ✅
DTO(데이터 전송 객체) 문서화

       Swagger에서 DTO를 자동으로 문서화하려면, @Schema 어노테이션을 사용합니다.

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Schema(description = "사용자 정보 DTO")
public class UserDto {

    @Schema(description = "사용자 ID", example = "1")
    private Long id;

    @Schema(description = "사용자 이름", example = "홍길동")
    private String name;
}


👉 실행 결과 

 

📝 Swagger 설정 변경하기

🙌 Swagger의 기본 설정을 변경하려면 application.yml 또는 application.properties에서 설정을 추가합니다.

    ✅ API 기본 정보 설정

// application.yml
springdoc:
  api-docs:
    path: /api-docs  # API 문서 경로 변경
  swagger-ui:
    path: /swagger-ui  # Swagger UI 경로 변경
    operationsSorter: method  # API 정렬 방식 (method 기준)
    disable-swagger-default-url: true  # 기본 Swagger URL 비활성화


// application.properties
springdoc.api-docs.path=/api-docs
springdoc.swagger-ui.path=/swagger-ui
springdoc.swagger-ui.operationsSorter=method
springdoc.swagger-ui.disable-swagger-default-url=true

 

📝 보안 설정 (Swagger UI 접근 제한)

🙌  Swagger는 개발 및 테스트 환경에서 유용하지만, 운영 환경에서는 보안이 필요합니다.
🙌  Spring Security를 사용하는 경우 Swagger에 대한 접근을 제한할 수 있습니다.

     Spring Security 설정 추가

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
                .anyRequest().authenticated()
            )
            .csrf(csrf -> csrf.disable());  // CSRF 비활성화 (개발 환경)

        return http.build();
    }
}

 

📝 Swagger UI에서 API 테스트하기

🙌 이제 Swagger UI에서 API를 테스트할 수 있습니다.

     Swagger UI 접속

      ✔ 브라우저에서 http://localhost:8080/swagger-ui.html 열기

    API 테스트

      ✔  GET /users 실행 → 모든 사용자 목록 확인
      ✔  POST /users?name=홍길동 실행 → 사용자 추가
      ✔  다시 GET /users 실행 → 추가된 사용자 확인


📚  Swagger 적용 과정 요약

springdoc-openapi  의존성 추가
@Operation, @Parameter 등을 활용하여 API 문서화
Swagger UI에서 API 테스트 (/swagger-ui)
application.yml에서 Swagger 설정 변경 가능
Spring Security 설정을 추가하여 접근 제한 가능

🚀 Swagger를 활용하면 API를 보다 체계적으로 관리할 수 있으며, 개발자 간의 협업도 용이해집니다. 

📢 [mybatis] sql 문의 부등호 사용시 오류 해결 방법 


🙌 mybatis내의 sql 문 사용예제입니다. (ms-sql server sql 문을 이용한 예제입니다.)

    <select id="verifySms" parameterType="String" resultType="String">
        select 'Y'
        from verifyTelephone
        where authCode = #{authCode}
        and datediff(hour, createDate, GETDATE()) = 1
    </select>

 

🙌  하지만, 부등호가 사용되면 오류가 발생합니다. 

    <select id="verifySms" parameterType="String" resultType="String">
        select 'Y'
        from verifyTelephone
        where authCode = #{authCode}
        and datediff(hour, createDate, GETDATE()) <= 1
    </select>

 

🙌  MyBatis에서 <(작다), >(크다) 같은 부등호를 사용할 때는 XML의 특성상 엔티티 코드로 변환해야 합니다.   

🚨 오류 원인

XML에서는 <와 >를 태그로 인식하기 때문에, 직접 사용하면 파싱 오류가 발생합니다.

✅ 해결 방법: &lt;, &gt; 사용

< → &lt;
> → &gt;

🙌 아래와 같이 사용하면 오류가 발생하지 않습니다.

    <select id="verifySms" parameterType="String" resultType="String">
        select 'Y'
        from verifyTelephone
        where authCode = #{authCode}
        and datediff(hour, createDate, GETDATE()) &lt;= 1
    </select>

 

 

 

 

 

 

📢 [java spring boot] cors 허용하는 방법

📌 REST API를 통해 다른 서버의 데이터에 접근하는 경우 CORS(Cross-Origin Resource Sharing) 정책 위반 문제로 오류가 발생할 수 있습니다. 

📌 크롬의 개발자 도구에서 확인하면 아래와 같은 오류를 확인할 수 있습니다.
Access to XMLHttpRequest at '데이터 제공 도메인' from origin '데이터 요청 도메인' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

📌 데이터 제공 서버에 설정을 통해 문제를 해결할 수 있습니다.


📝 Controller에서 개별적으로 CORS 설정하기

🙌 특정 컨트롤러 또는 메서드에만 CORS를 허용하고 싶다면, @CrossOrigin 애너테이션을 사용하면 됩니다.

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://example.com", allowedHeaders = "*") // 특정 도메인 허용
public class SampleController {

    @GetMapping("/data")
    public String getData() {
        return "Hello, CORS!";
    }

    @PostMapping("/submit")
    @CrossOrigin(origins = "http://anotherdomain.com") // 특정 메서드에만 허용
    public String submitData(@RequestBody String data) {
        return "Received: " + data;
    }
}

 

📝 전역 CORS 설정

🙌 Spring Security를 사용하지 않거나, 단순한 CORS 설정이 필요한 경우 WebMvcConfigurer를 이용할 수 있습니다.

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**") // 모든 엔드포인트에 대해 CORS 적용
                .allowedOrigins("http://example.com") // 허용할 도메인
                // 여러 Origin을 허용하려면 ,로 구분
                // allowedOrigins("*") → 모든 도메인 허용 (보안상 위험할 수 있음)
                // allowCredentials(true) 사용 시, allowedOrigins("*")를 사용할 수 없음
                .allowedMethods("GET", "POST", "PUT", "DELETE") // 허용할 HTTP 메서드
                .allowedHeaders("*") // 모든 헤더 허용
                .allowCredentials(true); // 쿠키 인증 허용
    }
}

또는, 

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {

            @Override
            public void addCorsMappings(org.springframework.web.servlet.config.annotation.CorsRegistry registry) {
                registry.addMapping("/**")
                    .allowedOrigins("http://example.com")
                    .allowedMethods("GET", "POST", "PUT", "DELETE")
                    .allowedHeaders("*");
            }
        };
    }
}

이런 식으로도 가능합니다.

 

📝 Spring Boot 설정 파일 (application.yml)로 CORS 설정

🙌 Spring Boot 2.4 이상에서는 application.yml에서도 CORS 설정을 할 수 있지만, WebMvcConfigurer나 SecurityConfig보다 세부적인 설정이 어렵습니다.

spring:
  web:
    cors:
      allowed-origins: "http://example.com"
      allowed-methods: "GET,POST,PUT,DELETE"
      allowed-headers: "*"
      allow-credentials: true



📝 Spring Security와 함께 글로벌 CORS 설정하기

🙌 Spring Security를 사용할 경우 WebMvcConfigurer만 설정해도 CORS 문제가 해결되지 않을 수 있습니다. 이럴 때는 SecurityFilterChain에서 CORS 설정을 적용해야 합니다.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.config.annotation.web.configurers.CorsConfigurer;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .cors(cors -> cors.configurationSource(request -> {
                var config = new org.springframework.web.cors.CorsConfiguration();
                config.addAllowedOrigin("http://example.com"); // 허용할 도메인
                config.addAllowedMethod("*"); // 모든 HTTP 메서드 허용
                config.addAllowedHeader("*"); // 모든 헤더 허용
                return config;
            }))
            .csrf(csrf -> csrf.disable()) // 필요시 CSRF 비활성화
            .authorizeHttpRequests(auth -> auth.anyRequest().permitAll()) // 모든 요청 허용 (설정에 맞게 수정)
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));

        return http.build();
    }
}

 

 

 

+ Recent posts