add slf4j examples
This commit is contained in:
@@ -1,215 +1,229 @@
|
|||||||
# ModelMapper 소개
|
### ModelMapper 소개 및 사용 방법
|
||||||
|
|
||||||
ModelMapper는 Java 객체 간의 매핑을 쉽게 해주는 라이브러리입니다. 복잡한 객체 변환 코드를 작성할 필요 없이 객체의 속성들을 자동으로 매핑해주어 개발 시간을 단축하고 코드의 가독성을 높여줍니다.
|
ModelMapper는 자바에서 객체 간 매핑을 간편하게 처리할 수 있도록 도와주는 오픈소스 라이브러리입니다. DTO(Data Transfer Object)와 엔티티(Entity) 간의 변환 작업을 수동으로 작성하는 대신, ModelMapper를 사용하면 코드의 중복을 줄이고 가독성을 높일 수 있습니다. 이 라이브러리는 객체의 필드 이름과 타입을 기반으로 자동 매핑을 수행하며, 필요에 따라 사용자 정의 매핑 규칙을 추가할 수도 있습니다.
|
||||||
|
|
||||||
## ModelMapper의 주요 특징
|
ModelMapper의 주요 특징은 다음과 같습니다:
|
||||||
|
|
||||||
- **타입 안전성**: 컴파일 시점에서 타입 오류를 확인할 수 있습니다.
|
- **자동 매핑**: 필드 이름이 동일하면 별도의 설정 없이 매핑 가능.
|
||||||
- **자동 매핑**: 이름과 타입이 일치하는 속성들을 자동으로 매핑합니다.
|
- **유연성**: 복잡한 매핑 요구사항을 커스터마이징 가능.
|
||||||
- **커스텀 매핑**: 복잡한 매핑 로직을 위한 커스텀 컨버터 지원
|
- **간결함**: boilerplate 코드를 줄여 개발 생산성 향상.
|
||||||
- **깊은 매핑**: 중첩된 객체 구조도 쉽게 매핑 가능
|
|
||||||
- **설정 유연성**: 다양한 매핑 전략 및 설정 제공
|
|
||||||
|
|
||||||
## ModelMapper 사용 방법
|
---
|
||||||
|
|
||||||
### 1. 의존성 추가
|
### 의존성 추가
|
||||||
|
|
||||||
Maven을 사용한다면 pom.xml에 다음 의존성을 추가합니다:
|
ModelMapper를 사용하려면 먼저 프로젝트에 의존성을 추가해야 합니다. Maven을 사용하는 경우 `pom.xml`에 다음 코드를 추가하세요:
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.modelmapper</groupId>
|
<groupId>org.modelmapper</groupId>
|
||||||
<artifactId>modelmapper</artifactId>
|
<artifactId>modelmapper</artifactId>
|
||||||
<version>3.0.0</version>
|
<version>3.2.0</version> <!-- 최신 버전 확인 필요 -->
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
Gradle을 사용한다면 build.gradle에 다음을 추가합니다:
|
Gradle을 사용하는 경우 `build.gradle`에 아래를 추가합니다:
|
||||||
|
|
||||||
```groovy
|
```gradle
|
||||||
implementation 'org.modelmapper:modelmapper:3.0.0'
|
implementation 'org.modelmapper:modelmapper:3.2.0' // 최신 버전 확인 필요
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. 기본 사용법
|
---
|
||||||
|
|
||||||
```java
|
### 기본 사용 예시
|
||||||
// ModelMapper 인스턴스 생성
|
|
||||||
ModelMapper modelMapper = new ModelMapper();
|
|
||||||
|
|
||||||
// 소스 객체에서 대상 객체로 매핑
|
아래는 ModelMapper를 사용해 간단한 객체 간 매핑을 수행하는 예제입니다.
|
||||||
DestinationType destination = modelMapper.map(source, DestinationType.class);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 실제 사용 예시
|
#### 1. 엔티티와 DTO 클래스 정의
|
||||||
|
|
||||||
다음은 사용자 정보를 담은 엔티티와 DTO 간의 변환 예시입니다:
|
먼저 매핑할 두 클래스를 정의합니다:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
// 엔티티 클래스
|
// 엔티티 클래스
|
||||||
public class User {
|
public class User {
|
||||||
private Long id;
|
private Long id;
|
||||||
|
private String name;
|
||||||
private String email;
|
private String email;
|
||||||
private String password;
|
|
||||||
private String firstName;
|
|
||||||
private String lastName;
|
|
||||||
private Address address;
|
|
||||||
|
|
||||||
// 생성자, getter, setter 생략
|
// Getter와 Setter
|
||||||
}
|
public Long getId() { return id; }
|
||||||
|
public void setId(Long id) { this.id = id; }
|
||||||
public class Address {
|
public String getName() { return name; }
|
||||||
private String street;
|
public void setName(String name) { this.name = name; }
|
||||||
private String city;
|
public String getEmail() { return email; }
|
||||||
private String country;
|
public void setEmail(String email) { this.email = email; }
|
||||||
private String zipCode;
|
|
||||||
|
|
||||||
// 생성자, getter, setter 생략
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DTO 클래스
|
// DTO 클래스
|
||||||
public class UserDTO {
|
public class UserDTO {
|
||||||
private Long id;
|
private Long id;
|
||||||
|
private String name;
|
||||||
private String email;
|
private String email;
|
||||||
private String fullName;
|
|
||||||
private AddressDTO address;
|
|
||||||
|
|
||||||
// 생성자, getter, setter 생략
|
// Getter와 Setter
|
||||||
}
|
public Long getId() { return id; }
|
||||||
|
public void setId(Long id) { this.id = id; }
|
||||||
public class AddressDTO {
|
public String getName() { return name; }
|
||||||
private String street;
|
public void setName(String name) { this.name = name; }
|
||||||
private String city;
|
public String getEmail() { return email; }
|
||||||
private String country;
|
public void setEmail(String email) { this.email = email; }
|
||||||
private String zipCode;
|
|
||||||
|
|
||||||
// 생성자, getter, setter 생략
|
|
||||||
}
|
|
||||||
|
|
||||||
// 매핑 예시
|
|
||||||
public class UserService {
|
|
||||||
private final ModelMapper modelMapper;
|
|
||||||
|
|
||||||
public UserService() {
|
|
||||||
this.modelMapper = new ModelMapper();
|
|
||||||
|
|
||||||
// firstName과 lastName을 fullName으로 매핑하는 커스텀 설정
|
|
||||||
modelMapper.createTypeMap(User.class, UserDTO.class)
|
|
||||||
.addMappings(mapper -> {
|
|
||||||
mapper.map(src -> src.getFirstName() + " " + src.getLastName(),
|
|
||||||
UserDTO::setFullName);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserDTO convertToDTO(User user) {
|
|
||||||
return modelMapper.map(user, UserDTO.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public User convertToEntity(UserDTO userDTO) {
|
|
||||||
return modelMapper.map(userDTO, User.class);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. 고급 매핑 기능
|
#### 2. ModelMapper로 매핑
|
||||||
|
|
||||||
#### 커스텀 매핑 설정
|
이제 ModelMapper를 사용해 `User` 객체를 `UserDTO`로 변환해봅시다:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
// 속성 이름이 다른 경우 명시적 매핑
|
import org.modelmapper.ModelMapper;
|
||||||
modelMapper.createTypeMap(Source.class, Destination.class)
|
|
||||||
.addMapping(Source::getSourceProperty, Destination::setTargetProperty);
|
|
||||||
|
|
||||||
// 조건부 매핑
|
public class Main {
|
||||||
modelMapper.getConfiguration().setPropertyCondition(context -> {
|
public static void main(String[] args) {
|
||||||
// 조건에 따라 true/false 반환
|
// ModelMapper 인스턴스 생성
|
||||||
return context.getSource() != null;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 타입 변환 매핑
|
|
||||||
Converter<String, Date> stringToDateConverter =
|
|
||||||
ctx -> ctx.getSource() == null ? null : new SimpleDateFormat("yyyy-MM-dd").parse(ctx.getSource());
|
|
||||||
|
|
||||||
modelMapper.createTypeMap(Source.class, Destination.class)
|
|
||||||
.addMappings(mapper -> mapper.using(stringToDateConverter)
|
|
||||||
.map(Source::getDateAsString, Destination::setDate));
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 매핑 전략 설정
|
|
||||||
|
|
||||||
```java
|
|
||||||
// 필드 매핑 전략 (필드 이름 기준 매핑)
|
|
||||||
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
|
|
||||||
|
|
||||||
// 접근 방식 설정 (필드 직접 접근)
|
|
||||||
modelMapper.getConfiguration().setFieldAccessLevel(AccessLevel.PRIVATE);
|
|
||||||
modelMapper.getConfiguration().setFieldMatchingEnabled(true);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. 컬렉션 매핑
|
|
||||||
|
|
||||||
```java
|
|
||||||
// List 매핑
|
|
||||||
List<UserDTO> userDTOs = users.stream()
|
|
||||||
.map(user -> modelMapper.map(user, UserDTO.class))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
// Type Token 사용하여 컬렉션 매핑
|
|
||||||
Type listType = new TypeToken<List<UserDTO>>() {}.getType();
|
|
||||||
List<UserDTO> userDTOs = modelMapper.map(users, listType);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 실제 사용 사례
|
|
||||||
|
|
||||||
Spring Boot 애플리케이션에서 ModelMapper를 빈으로 등록하여 사용하는 예시:
|
|
||||||
|
|
||||||
```java
|
|
||||||
@Configuration
|
|
||||||
public class ApplicationConfig {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ModelMapper modelMapper() {
|
|
||||||
ModelMapper modelMapper = new ModelMapper();
|
ModelMapper modelMapper = new ModelMapper();
|
||||||
|
|
||||||
// 엄격한 매핑 전략 설정
|
// User 객체 생성 및 데이터 설정
|
||||||
modelMapper.getConfiguration()
|
User user = new User();
|
||||||
.setMatchingStrategy(MatchingStrategies.STRICT)
|
user.setId(1L);
|
||||||
.setSkipNullEnabled(true)
|
user.setName("홍길동");
|
||||||
.setFieldMatchingEnabled(true)
|
user.setEmail("hong@example.com");
|
||||||
.setFieldAccessLevel(AccessLevel.PRIVATE);
|
|
||||||
|
|
||||||
return modelMapper;
|
// User -> UserDTO로 매핑
|
||||||
}
|
UserDTO userDTO = modelMapper.map(user, UserDTO.class);
|
||||||
}
|
|
||||||
|
|
||||||
@Service
|
// 결과 출력
|
||||||
public class ProductService {
|
System.out.println("ID: " + userDTO.getId());
|
||||||
|
System.out.println("Name: " + userDTO.getName());
|
||||||
private final ProductRepository productRepository;
|
System.out.println("Email: " + userDTO.getEmail());
|
||||||
private final ModelMapper modelMapper;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public ProductService(ProductRepository productRepository, ModelMapper modelMapper) {
|
|
||||||
this.productRepository = productRepository;
|
|
||||||
this.modelMapper = modelMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProductDTO getProduct(Long id) {
|
|
||||||
Product product = productRepository.findById(id)
|
|
||||||
.orElseThrow(() -> new EntityNotFoundException("Product not found"));
|
|
||||||
|
|
||||||
return modelMapper.map(product, ProductDTO.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ProductDTO> getAllProducts() {
|
|
||||||
List<Product> products = productRepository.findAll();
|
|
||||||
|
|
||||||
return products.stream()
|
|
||||||
.map(product -> modelMapper.map(product, ProductDTO.class))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 결론
|
**출력 결과:**
|
||||||
|
|
||||||
ModelMapper는 Java 애플리케이션에서 객체 간 매핑을 간소화하는 강력한 도구입니다. 자동 매핑 기능으로 반복적인 코드를 줄이고, 커스텀 매핑 설정으로 복잡한 변환 로직도 깔끔하게 처리할 수 있습니다. 특히 엔티티와 DTO 간의 변환이 많은 웹 애플리케이션에서 유용하게 활용할 수 있습니다.
|
```
|
||||||
|
ID: 1
|
||||||
|
Name: 홍길동
|
||||||
|
Email: hong@example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
위 예제에서 `modelMapper.map()` 메서드는 `User` 객체의 필드를 `UserDTO`로 자동으로 매핑합니다. 필드 이름과 타입이 동일하기 때문에 별도의 설정 없이도 동작합니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 고급 사용 예시: 커스터마이징 매핑
|
||||||
|
|
||||||
|
필드 이름이 다르거나 특정 변환 로직이 필요한 경우, ModelMapper의 설정을 커스터마이징할 수 있습니다.
|
||||||
|
|
||||||
|
#### 1. 필드 이름이 다른 경우
|
||||||
|
|
||||||
|
예를 들어, `User` 클래스의 `email` 필드를 `UserDTO`의 `emailAddress`로 매핑한다고 가정해봅시다.
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 수정된 UserDTO 클래스
|
||||||
|
public class UserDTO {
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
private String emailAddress; // 필드 이름 변경
|
||||||
|
|
||||||
|
// Getter와 Setter
|
||||||
|
public Long getId() { return id; }
|
||||||
|
public void setId(Long id) { this.id = id; }
|
||||||
|
public String getName() { return name; }
|
||||||
|
public void setName(String name) { this.name = name; }
|
||||||
|
public String getEmailAddress() { return emailAddress; }
|
||||||
|
public void setEmailAddress(String emailAddress) { this.emailAddress = emailAddress; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. 커스터마이징 매핑 설정
|
||||||
|
|
||||||
|
ModelMapper에 매핑 규칙을 추가합니다:
|
||||||
|
|
||||||
|
```java
|
||||||
|
import org.modelmapper.ModelMapper;
|
||||||
|
import org.modelmapper.PropertyMap;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// ModelMapper 인스턴스 생성
|
||||||
|
ModelMapper modelMapper = new ModelMapper();
|
||||||
|
|
||||||
|
// 커스터마이징 매핑 규칙 추가
|
||||||
|
modelMapper.addMappings(new PropertyMap<User, UserDTO>() {
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
map().setEmailAddress(source.getEmail()); // email -> emailAddress
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// User 객체 생성
|
||||||
|
User user = new User();
|
||||||
|
user.setId(1L);
|
||||||
|
user.setName("홍길동");
|
||||||
|
user.setEmail("hong@example.com");
|
||||||
|
|
||||||
|
// 매핑 수행
|
||||||
|
UserDTO userDTO = modelMapper.map(user, UserDTO.class);
|
||||||
|
|
||||||
|
// 결과 출력
|
||||||
|
System.out.println("ID: " + userDTO.getId());
|
||||||
|
System.out.println("Name: " + userDTO.getName());
|
||||||
|
System.out.println("Email Address: " + userDTO.getEmailAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**출력 결과:**
|
||||||
|
|
||||||
|
```
|
||||||
|
ID: 1
|
||||||
|
Name: 홍길동
|
||||||
|
Email Address: hong@example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 추가 기능: 리스트 매핑
|
||||||
|
|
||||||
|
여러 객체를 포함한 리스트를 매핑할 수도 있습니다:
|
||||||
|
|
||||||
|
```java
|
||||||
|
import org.modelmapper.ModelMapper;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ModelMapper modelMapper = new ModelMapper();
|
||||||
|
|
||||||
|
// User 리스트 생성
|
||||||
|
List<User> users = Arrays.asList(
|
||||||
|
new User(1L, "홍길동", "hong@example.com"),
|
||||||
|
new User(2L, "김영희", "kim@example.com")
|
||||||
|
);
|
||||||
|
|
||||||
|
// 리스트 매핑
|
||||||
|
List<UserDTO> userDTOs = users.stream()
|
||||||
|
.map(user -> modelMapper.map(user, UserDTO.class))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 결과 출력
|
||||||
|
userDTOs.forEach(dto -> System.out.println(dto.getName() + ": " + dto.getEmail()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**출력 결과:**
|
||||||
|
|
||||||
|
```
|
||||||
|
홍길동: hong@example.com
|
||||||
|
김영희: kim@example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 결론
|
||||||
|
|
||||||
|
ModelMapper는 객체 간 매핑을 단순화하고 개발자의 시간을 절약해주는 강력한 도구입니다. 기본적인 자동 매핑부터 복잡한 커스터마이징까지 지원하므로, 프로젝트 요구사항에 따라 적절히 활용할 수 있습니다. 위 예제를 참고하여 실제 프로젝트에 적용해보세요! 추가 질문이 있다면 언제든 물어보세요.
|
||||||
@@ -16,6 +16,6 @@ include(
|
|||||||
"properties", "serial-io",
|
"properties", "serial-io",
|
||||||
"mustache", "thymeleaf", "locale", "quartz", "sysinfo",
|
"mustache", "thymeleaf", "locale", "quartz", "sysinfo",
|
||||||
"imaging", "stream", "sound", "midi", "gson", "security",
|
"imaging", "stream", "sound", "midi", "gson", "security",
|
||||||
"model-mapper"
|
"model-mapper", "slf4j"
|
||||||
)
|
)
|
||||||
include("feed")
|
include("feed")
|
||||||
|
|||||||
182
slf4j/README.md
Normal file
182
slf4j/README.md
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
Slf4j(Simple Logging Facade for Java)는 자바 애플리케이션에서 로깅을 위한 표준 인터페이스를 제공하는 라이브러리입니다. Slf4j와 호환되는 로거를 만드는 방법은 크게 두 가지로 나눌 수 있습니다: 1) Slf4j를 직접 사용하는 방법, 2) Slf4j를 기존 로깅 프레임워크와 연결하는 방법입니다. 아래에서 단계별로 설명하겠습니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1. Slf4j 직접 사용하기 (기본 설정)
|
||||||
|
Slf4j는 자체적으로 로깅 구현체를 제공하지 않으므로, Slf4j API와 함께 실제 로깅을 처리할 백엔드(예: Logback, Log4j 등)를 설정해야 합니다. 가장 일반적인 방법은 **Logback**과 함께 사용하는 것입니다.
|
||||||
|
|
||||||
|
#### 단계별 설정:
|
||||||
|
1. **의존성 추가 (Maven 사용 예시)**
|
||||||
|
`pom.xml`에 Slf4j와 Logback 의존성을 추가합니다:
|
||||||
|
```xml
|
||||||
|
<dependencies>
|
||||||
|
<!-- Slf4j API -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>2.0.12</version> <!-- 최신 버전 확인 필요 -->
|
||||||
|
</dependency>
|
||||||
|
<!-- Logback (Slf4j의 기본 구현체) -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>1.5.3</version> <!-- 최신 버전 확인 필요 -->
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **로거 인스턴스 생성**
|
||||||
|
코드에서 Slf4j의 `Logger`와 `LoggerFactory`를 사용해 로거를 생성합니다:
|
||||||
|
```java
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class MyClass {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(MyClass.class);
|
||||||
|
|
||||||
|
public void doSomething() {
|
||||||
|
logger.debug("디버그 메시지");
|
||||||
|
logger.info("정보 메시지");
|
||||||
|
logger.warn("경고 메시지");
|
||||||
|
logger.error("에러 메시지");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Logback 설정 파일 추가 (선택)**
|
||||||
|
기본적으로 Logback은 설정 없이도 동작하지만, 로그 출력 형식이나 레벨을 커스터마이징하려면 `src/main/resources` 디렉토리에 `logback.xml` 파일을 추가합니다:
|
||||||
|
```xml
|
||||||
|
<configuration>
|
||||||
|
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<root level="info">
|
||||||
|
<appender-ref ref="CONSOLE" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
||||||
|
```
|
||||||
|
- 위 설정은 콘솔에 로그를 출력하며, 로그 레벨은 `INFO` 이상으로 설정합니다.
|
||||||
|
|
||||||
|
4. **실행 확인**
|
||||||
|
`doSomething()` 메서드를 호출하면 로그가 콘솔에 출력됩니다:
|
||||||
|
```
|
||||||
|
2025-03-01 12:00:00 INFO [main] com.example.MyClass - 정보 메시지
|
||||||
|
2025-03-01 12:00:00 WARN [main] com.example.MyClass - 경고 메시지
|
||||||
|
2025-03-01 12:00:00 ERROR [main] com.example.MyClass - 에러 메시지
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. 기존 로깅 프레임워크와 Slf4j 연결하기
|
||||||
|
만약 프로젝트에서 Log4j, JUL(java.util.logging) 등 다른 로깅 프레임워크를 이미 사용 중이라면, Slf4j를 브릿지(bridge)로 활용해 통합할 수 있습니다.
|
||||||
|
|
||||||
|
#### Log4j와 연결 예시:
|
||||||
|
1. **의존성 추가**
|
||||||
|
Log4j를 Slf4j에 연결하려면 `log4j-slf4j-impl`을 추가합니다:
|
||||||
|
```xml
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-slf4j-impl</artifactId>
|
||||||
|
<version>2.23.1</version> <!-- 최신 버전 확인 필요 -->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-core</artifactId>
|
||||||
|
<version>2.23.1</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Log4j 설정 파일 추가**
|
||||||
|
`log4j2.xml` 파일을 `src/main/resources`에 추가합니다:
|
||||||
|
```xml
|
||||||
|
<Configuration status="WARN">
|
||||||
|
<Appenders>
|
||||||
|
<Console name="Console" target="SYSTEM_OUT">
|
||||||
|
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
|
||||||
|
</Console>
|
||||||
|
</Appenders>
|
||||||
|
<Loggers>
|
||||||
|
<Root level="info">
|
||||||
|
<AppenderRef ref="Console"/>
|
||||||
|
</Root>
|
||||||
|
</Loggers>
|
||||||
|
</Configuration>
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **코드에서 Slf4j 사용**
|
||||||
|
Log4j가 백엔드로 동작하더라도, 코드에서는 여전히 Slf4j API를 사용합니다:
|
||||||
|
```java
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class MyClass {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(MyClass.class);
|
||||||
|
|
||||||
|
public void doSomething() {
|
||||||
|
logger.info("Log4j를 통한 정보 메시지");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. 커스텀 로거 구현 (직접 만드는 경우)
|
||||||
|
Slf4j와 완전히 독립적인 커스텀 로거를 만들고 싶다면, Slf4j의 `ILoggerFactory`와 `Logger` 인터페이스를 구현할 수 있습니다. 하지만 이 방법은 복잡하므로, 일반적으로는 Logback이나 Log4j 같은 기존 구현체를 사용하는 것이 권장됩니다.
|
||||||
|
|
||||||
|
#### 간단한 커스텀 로거 예시:
|
||||||
|
1. `Logger` 인터페이스 구현:
|
||||||
|
```java
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
public class CustomLogger implements Logger {
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public CustomLogger(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInfoEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String msg) {
|
||||||
|
System.out.println("[INFO] " + name + " - " + msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 나머지 메서드 (debug, warn, error 등) 구현 생략
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. `ILoggerFactory` 구현:
|
||||||
|
```java
|
||||||
|
import org.slf4j.ILoggerFactory;
|
||||||
|
|
||||||
|
public class CustomLoggerFactory implements ILoggerFactory {
|
||||||
|
@Override
|
||||||
|
public Logger getLogger(String name) {
|
||||||
|
return new CustomLogger(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Slf4j에 커스텀 로거 연결:
|
||||||
|
Slf4j는 기본적으로 클래스패스에서 첫 번째로 발견된 구현체를 사용하므로, 위 구현체를 빌드 경로에 포함시키고 다른 구현체(Logback, Log4j 등)를 제거하면 됩니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 결론
|
||||||
|
- **추천 방법**: Slf4j + Logback 조합을 사용하는 것이 가장 간단하고 널리 사용됩니다.
|
||||||
|
- **기존 시스템 통합**: Log4j나 JUL을 사용 중이라면 브릿지 모듈을 활용하세요.
|
||||||
|
- **커스텀 필요 시**: Slf4j 인터페이스를 직접 구현할 수 있지만 유지보수와 성능을 고려해 기존 구현체를 사용하는 것이 낫습니다.
|
||||||
|
|
||||||
|
추가 질문이 있으면 언제든 물어보세요!
|
||||||
14
slf4j/build.gradle.kts
Normal file
14
slf4j/build.gradle.kts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* Examples for Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021. Elex. All Rights Reserved.
|
||||||
|
* https://www.elex-project.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("elex-java")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
}
|
||||||
20
slf4j/logback.xml
Normal file
20
slf4j/logback.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ Examples for Java
|
||||||
|
~
|
||||||
|
~ Copyright (c) 2021. Elex. All Rights Reserved.
|
||||||
|
~ https://www.elex-project.com/
|
||||||
|
-->
|
||||||
|
|
||||||
|
<configuration>
|
||||||
|
|
||||||
|
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<root level="TRACE">
|
||||||
|
<appender-ref ref="CONSOLE" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
||||||
345
slf4j/src/main/java/kr/pe/elex/examples/AbstractLogger.java
Normal file
345
slf4j/src/main/java/kr/pe/elex/examples/AbstractLogger.java
Normal file
@@ -0,0 +1,345 @@
|
|||||||
|
package kr.pe.elex.examples;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.Marker;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public abstract class AbstractLogger implements Logger {
|
||||||
|
@Getter
|
||||||
|
private final String name;
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private Level level = Level.INFO;
|
||||||
|
|
||||||
|
protected abstract void log(String s);
|
||||||
|
|
||||||
|
protected abstract void log(String s, Object o);
|
||||||
|
|
||||||
|
protected abstract void log(String s, Object o1, Object o2);
|
||||||
|
|
||||||
|
protected abstract void log(String s, Object... objects);
|
||||||
|
|
||||||
|
protected abstract void log(String s, Throwable throwable);
|
||||||
|
|
||||||
|
protected abstract void log(Marker marker, String s);
|
||||||
|
|
||||||
|
protected abstract void log(Marker marker, String s, Object o);
|
||||||
|
|
||||||
|
protected abstract void log(Marker marker, String s, Object o1, Object o2);
|
||||||
|
|
||||||
|
protected abstract void log(Marker marker, String s, Object... objects);
|
||||||
|
|
||||||
|
protected abstract void log(Marker marker, String s, Throwable throwable);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTraceEnabled() {
|
||||||
|
return Level.TRACE.ordinal() >= this.level.ordinal();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTraceEnabled(Marker marker) {
|
||||||
|
return isTraceEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDebugEnabled() {
|
||||||
|
return Level.DEBUG.ordinal() >= this.level.ordinal();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDebugEnabled(Marker marker) {
|
||||||
|
return isDebugEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInfoEnabled() {
|
||||||
|
return Level.INFO.ordinal() >= this.level.ordinal();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInfoEnabled(Marker marker) {
|
||||||
|
return isInfoEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWarnEnabled() {
|
||||||
|
return Level.WARN.ordinal() >= this.level.ordinal();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWarnEnabled(Marker marker) {
|
||||||
|
return isWarnEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isErrorEnabled() {
|
||||||
|
return Level.ERROR.ordinal() >= this.level.ordinal();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isErrorEnabled(Marker marker) {
|
||||||
|
return isErrorEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(String s) {
|
||||||
|
log(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(String s, Object o) {
|
||||||
|
log(s, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(String s, Object o, Object o1) {
|
||||||
|
log(s, o, o1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(String s, Object... objects) {
|
||||||
|
log(s, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(String s, Throwable throwable) {
|
||||||
|
log(s, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(Marker marker, String s) {
|
||||||
|
log(marker, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(Marker marker, String s, Object o) {
|
||||||
|
log(marker, s, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(Marker marker, String s, Object o, Object o1) {
|
||||||
|
log(marker, s, o, o1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(Marker marker, String s, Object... objects) {
|
||||||
|
log(marker, s, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(Marker marker, String s, Throwable throwable) {
|
||||||
|
log(marker, s, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(String s) {
|
||||||
|
log(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(String s, Object o) {
|
||||||
|
log(s, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(String s, Object o, Object o1) {
|
||||||
|
log(s, o, o1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(String s, Object... objects) {
|
||||||
|
log(s, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(String s, Throwable throwable) {
|
||||||
|
log(s, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(Marker marker, String s) {
|
||||||
|
log(marker, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(Marker marker, String s, Object o) {
|
||||||
|
log(marker, s, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(Marker marker, String s, Object o, Object o1) {
|
||||||
|
log(marker, s, o, o1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(Marker marker, String s, Object... objects) {
|
||||||
|
log(marker, s, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(Marker marker, String s, Throwable throwable) {
|
||||||
|
log(marker, s, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String s) {
|
||||||
|
log(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String s, Object o) {
|
||||||
|
log(s, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String s, Object o, Object o1) {
|
||||||
|
log(s, o, o1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String s, Object... objects) {
|
||||||
|
log(s, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String s, Throwable throwable) {
|
||||||
|
log(s, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(Marker marker, String s) {
|
||||||
|
log(marker, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(Marker marker, String s, Object o) {
|
||||||
|
log(marker, s, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(Marker marker, String s, Object o, Object o1) {
|
||||||
|
log(marker, s, o, o1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(Marker marker, String s, Object... objects) {
|
||||||
|
log(marker, s, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(Marker marker, String s, Throwable throwable) {
|
||||||
|
log(marker, s, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(String s) {
|
||||||
|
log(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(String s, Object o) {
|
||||||
|
log(s, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(String s, Object o, Object o1) {
|
||||||
|
log(s, o, o1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(String s, Object... objects) {
|
||||||
|
log(s, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(String s, Throwable throwable) {
|
||||||
|
log(s, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(Marker marker, String s) {
|
||||||
|
log(marker, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(Marker marker, String s, Object o) {
|
||||||
|
log(marker, s, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(Marker marker, String s, Object o, Object o1) {
|
||||||
|
log(marker, s, o, o1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(Marker marker, String s, Object... objects) {
|
||||||
|
log(marker, s, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(Marker marker, String s, Throwable throwable) {
|
||||||
|
log(marker, s, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String s) {
|
||||||
|
log(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String s, Object o) {
|
||||||
|
log(s, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String s, Object o, Object o1) {
|
||||||
|
log(s, o, o1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String s, Object... objects) {
|
||||||
|
log(s, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String s, Throwable throwable) {
|
||||||
|
log(s, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(Marker marker, String s) {
|
||||||
|
log(marker, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(Marker marker, String s, Object o) {
|
||||||
|
log(marker, s, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(Marker marker, String s, Object o, Object o1) {
|
||||||
|
log(marker, s, o, o1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(Marker marker, String s, Object... objects) {
|
||||||
|
log(marker, s, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(Marker marker, String s, Throwable throwable) {
|
||||||
|
log(marker, s, throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
5
slf4j/src/main/java/kr/pe/elex/examples/Level.java
Normal file
5
slf4j/src/main/java/kr/pe/elex/examples/Level.java
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package kr.pe.elex.examples;
|
||||||
|
|
||||||
|
public enum Level {
|
||||||
|
TRACE, DEBUG, INFO, WARN, ERROR;
|
||||||
|
}
|
||||||
64
slf4j/src/main/java/kr/pe/elex/examples/MyLogger.java
Normal file
64
slf4j/src/main/java/kr/pe/elex/examples/MyLogger.java
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package kr.pe.elex.examples;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.Marker;
|
||||||
|
|
||||||
|
|
||||||
|
public class MyLogger extends AbstractLogger implements Logger {
|
||||||
|
|
||||||
|
public MyLogger(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void log(String s) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void log(String s, Object o) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void log(String s, Object o1, Object o2) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void log(String s, Object... objects) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void log(String s, Throwable throwable) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void log(Marker marker, String s) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void log(Marker marker, String s, Object o) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void log(Marker marker, String s, Object o1, Object o2) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void log(Marker marker, String s, Object... objects) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void log(Marker marker, String s, Throwable throwable) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
11
slf4j/src/main/java/kr/pe/elex/examples/MyLoggerFactory.java
Normal file
11
slf4j/src/main/java/kr/pe/elex/examples/MyLoggerFactory.java
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package kr.pe.elex.examples;
|
||||||
|
|
||||||
|
import org.slf4j.ILoggerFactory;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
public class MyLoggerFactory implements ILoggerFactory {
|
||||||
|
@Override
|
||||||
|
public Logger getLogger(String s) {
|
||||||
|
return new MyLogger(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user