Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
| 29 | 30 | 31 |
Tags
- cs
- 터미널
- 동적 프로그래밍 방법
- 순차탐색
- zsh theme
- 인프런
- VI
- spring boot
- Less
- table status
- 분할정복 방법
- 네트워킹데이
- 이진탐색
- 맥
- 스터디2기
- mysql 표 출력
- 욕심쟁이 방법
- mycli
- 인프런워밍업클럽
- MySQL
- 티스토리챌린지
- 오블완
- Pager
- 알고리즘
- mysql 표
- 오일러 경로
- zsh
- 데이크스트라
- CS스터디
- oh-my-zsh
Archives
- Today
- Total
Develop
28일차_Spring MVC(동작원리, 처리흐름), Logback, Lombok 본문
안녕하세요!
오늘은 데브코스 28일차 (6주 4일차) 입니다.
Spring MVC 에서 컨트롤러랑 뷰정도 다뤄봤고, 로깅 프레임워크 Logback과 어노테이션 프레임워크 Lombok 을 설치했습니다.
수업중엔 무슨말인지 이해를 못했는데, 정리하다보니 대충 구조가 이해됩니다.
MVC 는 Model, View, Controller 로 이루어진 디자인 패턴이고,
클라이언트의 요청은 Controller가 받아서 처리하고,
필요한 비즈니스 로직은 Model에서 수행한 뒤,
그 결과를 View가 응답을 받아서 클라이언트에게 보여준다.
Spring MVC 동작원리 (기본적인 요청 처리 흐름)
(클라이언트)
|
| HTTP 요청
↓
┌───────────────────┐
│ DispatcherServlet │
└───────────────────┘
|
↓
┌─────────────────────┐
│ Handler Mapping │──> 요청 URI에 따라 핸들러(컨트롤러 메서드)를 찾아냄
└─────────────────────┘
|
↓
┌────────────────────┐
│ Interceptors │──> 요청을 가로채거나 전처리, 후처리
└────────────────────┘
|
↓
┌─────────────────┐
│ Controller │──> 비즈니스 로직 수행, Model에 데이터 저장, 논리 뷰* 이름 반환
└─────────────────┘ (* 논리 뷰 : 컨트롤러에서 반환하는 이름
| 'return welcome;'에서 welcome임)
↓
┌────────────────────┐
│ View Resolver │──> 논리 뷰 이름을 실제 물리적 뷰* 리소스로 변환
└────────────────────┘ (* 물리 뷰 : 리소스 파일 경로
| 'WEB-INF/views/welcome.jsp`)
↓
┌───────────────────────┐
│ View Rendering │──> Model 데이터를 사용하여 최종 응답 생성
└───────────────────────┘
|
↓
(클라이언트)
|
|←─ HTTP 응답 ──
- 요청(HTTP): 클라이언트로부터 HTTP 요청을 받음
- DispatcherServlet: 요청을 받아 핸들러를 매핑하고 적절한 컨트롤러 메서드를 호출
- Interceptors: 요청의 전처리/후처리를 수행(필수적이지 않음)
- Controller: 비즈니스 로직을 처리하거나 뷰로 데이터를 전달
- View Resolver: 뷰 이름을 물리적 뷰 리소스로 변환
- View Rendering: 최종 응답 생성(JSP, JSON 등)
위에서 학습한 내용을 오늘 공부한 내용에서 어떻게 적용되는지 알아봤습니다.
Spring MVC 기반 웹 애플리케이션의 전체 아키텍처 흐름
1. Request
[Client → Server 데이터 전송 방식]
- application/x-www-form-urlencoded
- 기본 form 전송방식 (key = value)
- multipart/form-data
- 파일 업로드용 (enctype="multipart/form-data")
- application/json
- REST API에서 주로 쓰는 포맷
- 클라이언트가 JSON 보내면 스프링이 Jackson으로 파싱
[요청 처리 Annotation]
- @GetMapping/ @PostMapping : HTTP 메서드 매핑
- @PathVariable : URL 경로 변수
- @RequestParam : 쿼리 파라미터 매핑 (우리는 안 씀)
- @ModelAttribute :
- form 데이터 바인딩
- 매개변수 2개 이상부터는 명시적으로 사용
- @SessionAttribute , @HttpSession : 세션 접근
- @CookieValue : 쿠키 접근
- /redirect/... : 리다이렉트 처리
- forward : 내부 요청 전달
2. DispatcherServlet (Front Controller)
- 모든 요청을 받아서 적절한 컨트롤러로 전달
- 반환 결과를 ViewResolver 로 넘겨주거나, JSON 처리
3. Controller
- 요청 파라미터 바인딩
- 암묵적 바인딩 : 필드명 자동 매칭
- 명시적 바인딩 : @RequestParam, @PathVariable, @ModelAttribute
- urlEncodedBinder : 스프링 내부 자동 처리
- 검증
- @Valid, BindingResult : 유효성 검증
- @InitBinder : 커스텀 바인딩 설정 가능
- 예외처리
- @ControllerAdvice , @ExceptionHandler : 전역 예외 핸들링
- SweetAlert2 : alert 으로 사용자에게 알려줌
- 응답
- @RestController : JSON 응답 (REST 전용, 내부에 @ResponseBody 포함)
- @ResponseBody : 객체 → JSON 변환
- @JsonFormat : JSON 응답 포맷 설정 → Spring은 Jackson 사용 (Gson 아님)
4. Service
- @Service : 서비스 선언 (비즈니스 로직 담당)
- DTO → 페이로드 DTO로 가공 (민감정보 제거 목적)
- 검증 로직도 이곳에서 처리
- Validator Bean 직접 주입 X (순환참조 위험)
5. Model and View
- JSP : 동적 HTML 뷰
- REST API : JSON 응답 (@RestController 이용)
6. Response
- JSP : ViewResolver 를 통해 .jsp 반환
- REST API : JSON 변환 후 응답
7. 기타
- Logback
- 공식문서: https://logback.qos.ch/
- logback.xml 설정:
- 로그 레벨 INFO로 조정
- 콘솔 외에 로그 파일로 내보내기
- 언어 영어로 설정
- SLF4J : 로그 표준 라이브러리
- ConsoleAppender, RollingFileAppender 등으로 로그 출력
- → System.out 대신 사용 (레벨별 로그, 코드 비용 ↓)
- Lombok
- 공식문서 : https://projectlombok.org/features/
- @RequiredArgsConstructor : final 필드만 포함한 생성자
- @AllArgsConstructor / @NoArgsConstructor : 모든 필드 / 파라미터 없는 생성자
- @Getter, @Setter, @ToString 등 코드 줄여줌
- @Builder : 빌더 패턴 자동 생성 (사용 전 annotation enable 필요)
- 컨트롤러에서 response body 타입 안 맞으면 문제 생김
- JSON 반환 시 @ResponseBody 또는 @RestController 명시
오늘의 질문
Spring MVC 에서의 Principal 의 의미
- 역할
- Principal 클래스는 클라이언트(사용자)의 신원 정보를 포함하는 Java 객체
- Spring MVC는 Principal 을 사용하여 사용자 인증 상태를 관리하고,
이 정보는 로그인 시 세션에 저장되며 인증이 필요한 요청을 처리할때 사용함
- 특징
- 불변객체이며, Principal 의 정보는 보통 세션 내에 저장되기 때문에, 멀티 스레드 환경에서도 안전하게 사용 가능
- 신원 확인: 클라이언트의 신원 확인
- 접근 제어: 특정 자원 또는 기능에 대한 접근을 제어
- 속성: getName() 메서드를 통해 사용자 이름을 반환
OffsetDateTime 과 LocalDateTime 의 차이점
Offset이란?
UTC 세계 표준시 (혹은 그리니치 평균시, GMT)와 특정 지역의 표준시 사이의 시간차이를 나타내는 값으로,
이 차이는 시간대(Time Zone)와 서머타임 등으로 발생할 수 있으며, 한국은 UTC 보다 9시간 빠르기 때문에 + 9:00 오프셋을 가짐
OffsetDateTime
- 용도
- 데이터베이스, 네트워크 프로토콜에서 날짜/시간 데이터를 정확히 전달
- 오프셋 정보를 포함하여 지역 시간을 명확히 표현
- 구조
- 날짜와 시간 필드(연도, 월, 일, 시, 분, 초, 나노초)와 UTC/Greenwich로부터의 오프셋 정보를 저장
- 예: 2025-04-10T22:21:00+09:00 (한국 표준시 기준).
- Immutable 및 Thread-Safe
- OffsetDateTime 객체는 생성 후 변경할 수 없으며, 멀티스레드 환경에서도 안전하게 사용할 수 있습니다.
- Instant와 ZonedDateTime과의 관계
- Instant: UTC 기준의 특정 시점을 표현.
- OffsetDateTime: UTC 오프셋을 추가하여 지역 날짜 및 시간을 표현.
- ZonedDateTime: 시간대 규칙까지 포함한 날짜 및 시간 표현.
예제
- 현재 시간 가져오기
OffsetDateTime now = OffsetDateTime.now(); System.out.println("현재 OffsetDateTime: " + now);
- 직접 값 지정
ZoneOffset offset = ZoneOffset.of("+09:00"); OffsetDateTime dateTime = OffsetDateTime.of(2025, 4, 10, 22, 21, 0, 0, offset); System.out.println("지정된 OffsetDateTime: " + dateTime);
LocalDateTime
- 용도
- 날짜와 시간 데이터를 간단하게 표현 (지역 ,시간대 고려x)
- 시간대 변환 또는 오프셋 포함 작업에는 zonedDateTime 혹은 OffsetDateTime 을 사용
- 날짜와 시간 데이터를 간단하게 표현 (지역 ,시간대 고려x)
- 구조
- 연도, 월(1-12), 일, 시, 분, 초, 나노초를 포함하며, 무시할 수 있는 모든 필드에 대해 기본값을 제공
- 예: 2023-04-10T21:25:00
- Immutable 및 Thread-Safe
- LocalDateTime 객체는 생성 후 변경할 수 없으며, 멀티스레드 환경에서도 안전하게 사용 가능
- 모든 메서드는 새 인스턴스를 반환
예제
- 현재 시간 가져오기
LocalDateTime now = LocalDateTime.now();
System.out.println("현재 LocalDateTime: " + now);
- 직접 값 지정
LocalDateTime custom = LocalDateTime.of(2025, 4, 10, 22, 50, 59);
Logback (Logging Framework)
Logback
- Java 애플리케이션에서 로그 메시지를 기록하는데 사용되는 로깅 프레임워크
로그 설정
- logback.xml 생성
- appender , logger, root logger 설정
<?xml version="1.0" encoding="UTF-8"?>
<!-- appender -->
<configuration>
<property name="LOG_PATTERN"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- root logger -->
<root level="debug">
<appender-ref ref="CONSOLE"/>
</root>
<!-- logger -->
<logger name="com.grepp.spring" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
</logger>
<logger name="org.apache.ibatis.logging.jdbc.PreparedStatementLogger" level="INFO" additivity="false">
<appender-ref ref="CONSOLE"/>
</logger>
</configuration>
- 로그 사용 (lombok)
- import lombok.extern.slf4j.Slf4j;
- @slf4j
@RestController
@RequestMapping("api")
@Slf4j
public class RestApiController {
@GetMapping("test")
public RestPayload test(RestForm form) {
log.info("form: {}", form);
OffsetDateTime now = OffsetDateTime.now();
return new RestPayload(1, "aaa@aaa.com", now, now.toEpochSecond());
}
}
Log Level
- 종류
- TRACE: 가장 상세한 정보(복잡한 디버깅용)
- DEBUG: 상세 정보(개발 단계 디버깅용)
- INFO: 일반적인 실행 흐름 및 정상 상태 정보(운영 모니터링용)
- WARN: 잠재적 문제나 경고(운영 시 주의 필요)
- ERROR: 심각한 오류와 시스템 장애(운영 시 즉시 조치 필요)
- 특징
- 설정된 레벨 이상의 로그를 출력 (INFO 설정 → INFO, WARN, ERROR 출력)
- 운영 환경에서는 INFO나 WARN 이상을 사용하고, 개발 환경에서는 DEBUG를 주로 사용
하하하 오늘도 수고하셨습니다... 지금은 새벽 2시 17분 ...그래도 조금 이해되서 기분좋다~
바이바이
'백엔드 > KDT_Programmers' 카테고리의 다른 글
| 30일차_Spring-MyBatis 실습 정리: 테스트 코드, 매핑, 회원가입 구현 (0) | 2025.04.16 |
|---|---|
| 29일차_Spring-MyBatis 초기 설정 (0) | 2025.04.12 |
| 27일차_Spring-core(Scope, Bean, DI, AOP), Spring-mvc(Context) (0) | 2025.04.09 |
| 26일차_Design Pattern(Adapter / Strategy / Template Method / Template Callback) (2) | 2025.04.09 |
| 25일차_Servlet, JSP(EL, JSTL) (0) | 2025.04.09 |