슈퍼코딩/주특기(JAVA)

2024.05.31(금) 슈퍼코딩 신입연수원 9주차 Day 5 후기 - Lombok, Mapper, 로깅, 문서화

곰돌이볼 2024. 5. 31. 17:31
  • 강의
    • 96강(스프링부트 실정 적용하기 v1) ~ 100강(스프링부트와 무넛화와 로깅 남기기)

Lombok


  • 기능 : 자동 코드 생성
    • Getter, Setter : @Getter, @Setter
    • 생성자 : @NoArgsConstructor, @AllArgsConstructor
    • equals(), hashCode(), toString() : @EqualsAndHashCode(of = "id"), @ToString
    • 빌더 패턴 : @Builder
  • 설치하기
    • 의존성 추가
      • compileOnly 'org.projectlombok:lombok'
        annotationProcessor 'org.projectlombok:lombok'
    • plugin 설치

 


Mapper


  • 객체를 매핑해서 다른 객체로 생성해주는 라이브러리
    • 필드 이름이 같은 경우에는 자동으로 매핑
  • 싱글톤 디자인 패턴을 이용해서 구현 가능
@Mapper
public interface PersonMapper {
	PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class); // 싱글톤 디자인 패턴
    
    @Mapper(source = "name", target = "fullName")
    Person personDtoToPerson(PersonDto personDto);
    // source는 매개변수, target는 반환값
}
  • 조건
    • target의 setter 필요
    • default 값 설정 가능 → @Mapper(target = "color", defaultValue = "White")
    • custom 메서드 실행 가능
@Mapper
public interface PersonMapper {
	PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class); // 싱글톤 디자인 패턴
    
    @Mapper(source = "name", target = "name", qualifiedByName = "toUppder")
    Person personDtoToPerson(PersonDto personDto);
    
    @Named("toUpper")
    static String toUpper(String value) {
    	if (value == null) return null;
        return value.toUpperCase();
    }
}

 

메타 프로그래밍

  • 종류
    • 컴파일 메타프로그래밍
      • Annotation 프로세서가 컴파일 이후에 자동으로 코드 생성
      • Lombok과 Mapstruct 라이브러리의 동작 원리 → 종속성에 annotationProcessor를 선언해야 하는 이유
    • 런타임 메타프로그래밍

로깅


  • 로그
    • 서버의 작업 및 상태에 대한 기록
    • 콘솔 출력의 한계
      • 상세한 기록 X
      • 파일 생성 X
      • 제어 및 필터링 X
  • 로그 레벨 단계
    • FATAL > ERROR > WARN > INFO > DEBUG > TRACE
    • ERROR : 요청 처리 발생하는 오류 로그
    • WARN : 처리 가능한 문제(추후 에러에 대한 원인 경고)
    • INFO : 상태변경과 같은 정보 로그
    • DEBUG : 디버깅 정보 로그
  • Logger(로거)
    • 로깅을 실행하는 주체
    • Root : 최상위 로거
  • 로그 패턴
    • 로그 메세지 출력 형식을 정의한 템플릿
    • 시간, 정보, thread 정보 등과 같은 탐재 가능
  • Log Appender(로그 어펜더)
    • 로그 기록의 목적지
    • console appender : 콘솔에 출력됨
    • file appender : 파일 기록
    • Message appender : 로깅 생성 시 메세지로 송출
  • Slf4j 인터페이스
    • 로깅 구현체 : LOGBack, LOG4J ...
    • 로깅의 인터페이스이고, 로깅 구현체를 이용해서 로깅 구현
  • 설정
    • logback-spring.xml : 설정 파일, resource 폴더에 생성
    • application.yaml : 설정 파일이 무엇인지 선언
      • logging:
            config: classpath:logpack-spring.xml
<!-- logback-spring-local.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <!-- 콘솔 로그 출력 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{36}) - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 루트 로거 설정 -->
    <root level="info">
        <appender-ref ref="CONSOLE" />
    </root>
</configuration>
<!-- logback-spring-dev.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <property name="LOG_PATH" value="logs" />

    <!-- 콘솔 로그 출력 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{36}) - %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>${LOG_PATH}/test.log</file>
        <append>true</append>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{36}) - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 루트 로거 설정 -->
    <root level="info">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" /> <!-- logs 폴더에 test.log 파일 생성됨 -->
    </root>
</configuration>

 

  • 사용
    • this.getClass() 로거 생성 및 선언
private final Logger logger = LoggerFactory.getLogger(this.getClass());

logger.info("TEST1");

문서화


  • API 문서화 도구
    • REST Docs
    • openAPI
    • Swagger 

Swagger

  • 선택한 이유
    • 간단한 사용법
    • 페이지 가독성
    • 간단한 테스트 지원
  • 설정
    • 의존성 추가
      • implementation 'io.springfox:springfox-swagger2:2.9.2'
        implementation 'io.springfox:springfox-swagger-ui:2.9.2'
    • application.yaml 설정 추가
      • spring:
          mvc:
             pathmatch:
                 matching-strategy: ant_path_matcher
    • swagger docket 빈 등록
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket api(){
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.github.supercodingspring.web.controller")) // 등록할 controller 설정
                .paths(PathSelectors.any())
                .build();
    }
}
  • 사용방법
    • http://localhost:8080/swagger-ui.html
  • swagger 커스텀
    • @ApiOperation("") : api 제목
    • @ApiParam : 파라미터 값 설정
    • @ApiModelProperty : dto 값 설정
// controller
@ApiOperation("단일 Item id로 검색")
@GetMapping("/items/{id}")
public Item findItemByPathId(
        @ApiParam(name = "id", value = "item ID", example = "1") @PathVariable String id){
    return electronicStoreItemService.findItemById(id);
}

// dto
public class Item {
    @ApiModelProperty(name = "id", value = "Item Id", example = "1") private String id;
    @ApiModelProperty(name = "name", value = "Item 이름", example = "Dell XPS 15") private String name;
    @ApiModelProperty(name = "type", value = "Item 기기타입", example = "Laptop") private String type;
    @ApiModelProperty(name = "price", value = "Item 가격", example = "125000") private Integer price;
    private Spec spec;
}
  • 실무
    • 로깅 파일
    • 로깅 알람 시스템