λ°λ₯Έμμ΄μ€ κ³΅ν΅ νλ μμν¬
[μλ°] java : 1.8
[μ€νλ§ λΆνΈ] org.springframework.boot : 2.7.12
[μ μμ λΆ νλ μμν¬] org.egovframework : 4.2
[build.gradle
]
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation("org.egovframe.rte:org.egovframe.rte.bat.core:4.2.0") {
exclude group: 'org.egovframe.rte', module: 'org.egovframe.rte.fdl.logging'
}
implementation 'org.apache.commons:commons-collections4:4.4'
implementation 'org.apache.commons:commons-text:1.10.0'
implementation 'org.apache.poi:poi-ooxml:5.2.4'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'io.projectreactor:reactor-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
Nexus
λ₯Ό κ³ λ €νκ³ μμ§λ§ νμ¬λ jar
λ‘ μ 곡
[build.gradle
]
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.12'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
id 'maven-publish'
id 'com.github.johnrengelman.shadow' version '7.1.2'
}
...(μ€λ΅)
shadowJar {
archiveFileName.set('project-base-0.0.1-all.jar')
}
publishing {
publications {
mavenJava(MavenPublication) {
artifact shadowJar
}
}
}
com.github.johnrengelman.shadow
: jar
νμΌ μμ± μ μ 체 μμ‘΄μ±(dependencies
) ν¬ν¨
[jar
νμΌ μμ± λ°©λ²]
./gradlew shadowJar
μμ λͺ
λ Ήμ΄ μ€ν μ, build/libs
κ²½λ‘μ project-base-0.0.1-all.jar
μμ±λλ€.
μμΈν μμ μ½λλ project-sample
μμ μ€λͺ
νλ€.
io.bareun.base.api
μΈλΆ API
λ₯Ό νΈμΆνκΈ° μν λͺ¨λ (λκΈ°, λΉλκΈ° μ§μ)
/**
* {@link WebClient}λ₯Ό μ¬μ©νμ¬ μΉ API νΈμΆμ μννλ ν΄λΌμ΄μΈνΈμ
λλ€.
*/
@Slf4j
@Component
public class WebApiClient {
private final WebClient webClient;
...(μ€λ΅)
/**
* μ£Όμ΄μ§ API μμ²μ λκΈ°μ μΌλ‘ νΈμΆνκ³ μλ΅μ λ°νν©λλ€.
*
* @param <T> μλ΅ λ³Έλ¬Έμ νμ
* @param request νΈμΆν API μμ²
* @return API μμ²μ μλ΅ λ³Έλ¬Έ
*/
public <T> T callReturn(ApiRequest<T> request) {
return retrieve(request).block();
}
/**
* μ£Όμ΄μ§ API μμ²μ λΉλκΈ°μ μΌλ‘ νΈμΆν©λλ€.
*
* @param <T> μλ΅ λ³Έλ¬Έμ νμ
* @param request νΈμΆν API μμ²
*/
public <T> void call(ApiRequest<T> request) {
retrieve(request).subscribe(request::subscribe, request::error);
}
...(μ€λ΅)
}
WebClient
λ₯Ό μ¬μ©νμ¬ API
λ₯Ό νΈμΆνλ©° callReturn(ApiRequest<T> request)
κ³Ό call(ApiRequest<T> request)
λ κ°κ° λκΈ°, λΉλκΈ°λ₯Ό νΈμΆνλ λ©μλμ΄λ€.
/**
* API μμ²μ νννλ μΈν°νμ΄μ€μ
λλ€.
*
* @param <T> μλ΅ νμ
*/
public interface ApiRequest<T> {
/**
* HTTP λ©μλλ₯Ό λ°νν©λλ€.
*
* @return μμ²μ μ¬μ©λ HTTP λ©μλ
*/
HttpMethod getMethod();
/**
* μμ²ν URLμ λ°νν©λλ€.
*
* @return μμ²ν URL
*/
String getUrl();
/**
* μμ² λ³Έλ¬Έμ λ°νν©λλ€.
*
* @return μμ² λ³Έλ¬Έ
*/
Object getBody();
/**
* μλ΅ νμ
μ λ°νν©λλ€.
*
* @return μλ΅ νμ
ν΄λμ€
*/
Class<T> getResponseType();
...(μ€λ΅)
}
API
μμ² μΈν°νμ΄μ€, μΈν°νμ΄μ€ ꡬνν ν΄λμ€λ‘ WebApiClient
μ λ©μλλ₯Ό νΈμΆνλ€.
μΆκ°λ‘, Content-Type: application/json
λ₯Ό μ§μνλ JsonApiRequest
μΈν°νμ΄μ€μ νΈλ¦¬νκ² μΈμ€ν΄μ€λ₯Ό μμ±νλ λΉλ ν΄λμ€ ApiRequestBuilder
λ μ 곡νλ€.
io.bareun.base.common
곡ν΅μΌλ‘ μ¬μ©νλ Map
ν΄λμ€μ κ³΅ν΅ Controller
μλ΅ ν΄λμ€, μμ£Ό μ¬μ©νλ μ νΈ ν΄λμ€
/**
* ν€-κ° μμ 보κ΄νκ³ μ‘°μνλ λ° μ¬μ©λλ DTO 맡 ν΄λμ€μ
λλ€.
* κΈ°λ³Έμ μΌλ‘ ν€λ₯Ό camelCaseλ‘ λ³νν©λλ€.
*/
public class BaseMap extends HashMap<String, Object> {
...(μ€λ΅)
}
곡ν΅μΌλ‘ μ¬μ©νλ Map
ν΄λμ€λ‘, ν€λ camelCase
λ‘ λ³νμ μν΅λλ€. νΈνκ² μ¬μ© ν org.apache.commons.collections4.MapUtils
μ μκ±°ν λ©μλλ μΆκ°νμμ΅λλ€.
/**
* BaseMap ν΄λμ€μ λν ν
μ€νΈ ν΄λμ€μ
λλ€.
*/
class BaseMapTest {
/**
* JSON λ¬Έμμ΄ νμ±μ ν
μ€νΈνλ λ©μλμ
λλ€.
* JSON λ¬Έμμ΄μ BaseMap κ°μ²΄λ‘ λ³ννκ³ ,
* λ³νλ BaseMap κ°μ²΄μ κ°μ νμΈν©λλ€.
*/
@Test
void jsonParsing() {
String json = "{\n" +
" \"search_map\": {\n" +
" \"string_value\": \"formal_contents\",\n" +
" \"long_value\": 1203405603,\n" +
" \"double_value\": 1.2,\n" +
" \"integer_value\": 10,\n" +
" \"map_value\" : {\n" +
" \"hello_world\" : \"I'm project base\"\n" +
" },\n" +
" \"list_string_value\": [\n" +
" \"one\",\n" +
" \"two\"\n" +
" ],\n" +
" \"list_map_value\": [\n" +
" {\n" +
" \"key\": \"value\"\n" +
" }\n" +
" ]\n" +
" }\n" +
"}";
BaseMap baseMap = BaseMap.of(json);
System.out.println("baseMap = " + baseMap);
assertThat(baseMap).isNotNull();
assertThat(baseMap.getMap("searchMap")).isNotNull();
assertThat(baseMap.getMap("searchMap").getString("stringValue")).isEqualTo("formal_contents");
assertThat(baseMap.getMap("searchMap").getLong("longValue")).isEqualTo(1203405603);
assertThat(baseMap.getMap("searchMap").getDouble("doubleValue")).isEqualTo(1.2);
assertThat(baseMap.getMap("searchMap").getInteger("integerValue")).isEqualTo(10);
assertThat(baseMap.getMapByKeys("searchMap", "mapValue").getString("helloWorld")).isEqualTo("I'm project base");
assertThat(baseMap.getMap("searchMap").getList("listStringValue").get(0)).isEqualTo("one");
List<BaseMap> list = baseMap.getMap("searchMap").getMapList("listMapValue");
assertThat(list.size()).isEqualTo(1);
BaseMap item = list.get(0);
assertThat(item.getString("key")).isEqualTo("value");
}
}
json
λ¬Έμμ΄μ BaseMap
μΌλ‘ λ³ννκ³ Key
κ°μ μ΄μ©νμ¬ Value
κ°μ μ°Ύλ ν
μ€νΈ μ½λ μ
λλ€. μ¬μ© μμ λ‘ μ°Έκ³
/**
* API μλ΅μ μν ν΄λμ€μ
λλ€.
* <p>
* μ΄ ν΄λμ€λ API μμ²μ λν΄ λ°νν λ°μ΄ν° κ·κ²©μ μ μν©λλ€.
*/
@Data
@Builder
@JsonInclude(NON_NULL)
public class ApiResponse<T> {
/**
* μλ΅ μ½λ
*/
private final int code;
/**
* μλ΅ λ©μμ§
*/
private final String message;
/**
* API μλ΅μ κ²°κ³Ό λ°μ΄ν°λ₯Ό ν¬ν¨
*/
private final T result;
/**
* μ€ν¨ μλ΅μ μμ±νλ λ©μλ.
*
* @param code μλ΅ μ½λ
* @param message μλ΅ λ©μμ§
*/
public static ApiResponse<?> fail(int code, String message) {
return ApiResponse.builder()
.code(code)
.message(message)
.build();
}
/**
* μ±κ³΅ μλ΅μ μμ±νλ λ©μλ.
*
* @param result κ²°κ³Ό λ°μ΄ν°
*/
public static <T> ApiResponse<T> success(T result) {
return ApiResponse.<T>builder()
.code(HttpStatus.OK.value())
.message(HttpStatus.OK.getReasonPhrase())
.result(result)
.build();
}
/**
* κ²°κ³Ό λ°μ΄ν° μλ μ±κ³΅ μλ΅μ μμ±νλ λ©μλ.
*/
public static <T> ApiResponse<T> success() {
return ApiResponse.<T>builder()
.code(HttpStatus.OK.value())
.message(HttpStatus.OK.getReasonPhrase())
.build();
}
}
λ€μκ³Ό κ°μ json
κ²°κ³Ό κ°μ κ³΅ν΅ μ²λ¦¬ νλ€. μ μ μλ΅μ success
λ©μλλ₯Ό μ΄μ©νμ¬ λ¦¬ν΄νλ©΄ λλ€.
{
"code" : (int),
"message" : (String),
"result" : (T)
}
μ νΈ ν΄λμ€
ObjectMapperUtils
:JSON
κ°μ²΄λ₯Ό λ³ννλ μ νΈ ν΄λμ€ (String
-T
/Object
-T
)RequestUtils
:HttpServletRequest
λ°HttpSession
μ²λ¦¬νλ μ νΈ ν΄λμ€ResponseUtils
:HttpServletResponse
μ νΈ ν΄λμ€SecurityUtils
:Spring Security
μ νΈ ν΄λμ€
io.bareun.base.exception
κΈ°λ³Έμ μΌλ‘ μμΈ μ²λ¦¬μ μ¬μ©νλ μλ¬ μ½λ λ° Exception
μ μ, μμΈ νΈλ€λ¬ ν΄λμ€κ° μ 곡
public interface ErrorCode {
int getCode();
String getMessage();
}
κΈ°λ³Έ μλ¬ μ½λ μΈν°νμ΄μ€μ΄λ€. κ° νλ‘μ νΈμμ ErrorCode
λ₯Ό ꡬνν΄μ μ¬μ©νλ©΄ λλ€. κΈ°λ³ΈμΌλ‘ ErrorCode
λ₯Ό ꡬνν μλ¬μ½λλ λ€μκ³Ό κ°λ€.
/**
* ErrorCodeλ μμΈ μ²λ¦¬μ μ¬μ©λλ μ€λ₯ μ½λλ₯Ό μ μνλ μ΄κ±°ν ν΄λμ€μ
λλ€.
* κ° μ΄κ±° μμλ μ€λ₯ μ½λμ λ©μμ§λ₯Ό κ°μ§κ³ μμ΅λλ€.
*/
@Getter
@RequiredArgsConstructor
public enum BaseErrorCode implements ErrorCode {
/**
* HTTP 40x μ½λ κΈ°λ° 5μ리
*/
BAD_REQUEST(40000, "μλͺ»λ μμ² κ° μ
λλ€."),
REQUIRED(40001, "%s κ°μ νμμ
λλ€."),
VALIDATE(40002, "%s κ°μ΄ μ¬λ°λ₯΄μ§ μμ΅λλ€."),
/**
* HTTP 50x μ½λ κΈ°λ° 5μ리
*/
UNKNOWN(50000, "μ μ μλ μλ¬μ
λλ€."),
;
private final int code;
private final String message;
}
μμ 3μ리λ HTTP Status Code μ½λλ‘ κ΅¬μ±νλ©°, λ€μ 2μ리λ 컀μ€ν μ½λμ΄λ€.
/**
* BusinessExceptionμ λΉμ¦λμ€ λ‘μ§μμ λ°μν μ μλ μμΈλ₯Ό λνλ΄λ ν΄λμ€μ
λλ€.
* RuntimeExceptionμ μμλ°μ unchecked μμΈλ‘ μ μλμ΄ μμ΅λλ€.
*/
@Getter
public class BusinessException extends RuntimeException {
private final ErrorCode errorCode;
/**
* μ£Όμ΄μ§ λ©μμ§λ₯Ό κ°μ§κ³ κΈ°λ³Έμ μΈ UNKNOWN μλ¬ μ½λλ‘ BusinessExceptionμ μμ±ν©λλ€.
*
* @param message μμΈ λ©μμ§
*/
public BusinessException(String message) {
super(message);
this.errorCode = BaseErrorCode.UNKNOWN;
}
/**
* μ£Όμ΄μ§ μλ¬ μ½λλ‘ BusinessExceptionμ μμ±ν©λλ€.
*
* @param errorCode μλ¬ μ½λ
*/
public BusinessException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.errorCode = errorCode;
}
/**
* μ£Όμ΄μ§ μλ¬ μ½λμ μΆκ°μ μΈ μΈμλ₯Ό μ¬μ©νμ¬ BusinessExceptionμ μμ±ν©λλ€.
* μλ¬ λ©μμ§λ ν¬λ§·ν
λ ννλ‘ μ 곡λ©λλ€.
*
* @param errorCode μλ¬ μ½λ
* @param args ν¬λ§·ν
μ μ¬μ©λ μΈμλ€
*/
public BusinessException(ErrorCode errorCode, Object... args) {
super(String.format(errorCode.getMessage(), args));
this.errorCode = errorCode;
}
}
μμ ErrorCode
λ₯Ό κΈ°λ°μΌλ‘ νλ μμΈ ν΄λμ€μ΄λ€. ν΄λΉ μμΈ ν΄λμ€λ μ
무κ΄λ ¨λ μ¬μ©μ μλ¬λ©μΈμ§λ₯Ό μ²λ¦¬νλ€.
/**
* ApiExceptionHandlerλ Spring Web MVCμμ λ°μνλ μμΈλ₯Ό μ²λ¦¬νλ ν΄λμ€μ
λλ€.
* RestControllerAdvice μ λ
Έν
μ΄μ
μ μ¬μ©νμ¬ λͺ¨λ @RestControllerμμ λ°μνλ μμΈλ₯Ό μ²λ¦¬ν©λλ€.
* κ° μμΈμ λ°λΌ μ μ ν HTTP μν μ½λμ λ©μμ§λ₯Ό λ°νν©λλ€.
*/
@Slf4j
@RestControllerAdvice(annotations = RestController.class)
public class ApiExceptionHandler {
/**
* BusinessExceptionμ μ²λ¦¬νλ λ©μλμ
λλ€.
*
* @param e λ°μν BusinessException κ°μ²΄
* @return ApiResponse κ°μ²΄ (μ€ν¨ μλ΅)
*/
@ExceptionHandler(BusinessException.class)
public ApiResponse<?> buisnessException(BusinessException e) {
log.error("ApiException buisnessException", e);
return ApiResponse.fail(e.getErrorCode().getCode(), e.getMessage());
}
...(μ€λ΅)
}
μμ μμΈ ν΄λμ€λ₯Ό νΈλ€λ¬νλ ν΄λμ€μ΄λ€. ApiResponse
μ fail()
λ©μλλ₯Ό λ°ννλ€.
io.bareun.base.file
μ²¨λΆ νμΌ λ° μμ νμΌ μ λ‘λ, λ€μ΄λ‘λ μ§μνλ λͺ¨λ
/**
* FileManager μΈν°νμ΄μ€λ νμΌ κ΄λ¦¬ κΈ°λ₯μ μ μνλ μΈν°νμ΄μ€μ
λλ€.
* ꡬν ν΄λμ€μμ νμΌ μ
λ‘λ, λ€μ΄λ‘λ, νμΌλͺ
μμ± λ±μ κΈ°λ₯μ μ 곡ν©λλ€.
*/
public interface FileManager {
/**
* νμΌμ΄ μ μ₯λ λλ ν 리 κ²½λ‘λ₯Ό λ°νν©λλ€.
*
* @return νμΌμ΄ μ μ₯λ λλ ν 리 κ²½λ‘
*/
String getDirectory();
...(μ€λ΅)
/**
* μ£Όμ΄μ§ MultipartFileμ μ
λ‘λνκ³ AttachUploadFile κ°μ²΄λ‘ λ°νν©λλ€.
*
* @param file μ
λ‘λν MultipartFile κ°μ²΄
* @return AttachUploadFile κ°μ²΄
*/
default AttachUploadFile upload(MultipartFile file) {
validate(file);
String originalFileName = file.getOriginalFilename();
String storedFileName = createStoredFileName(originalFileName);
FileUtils.upload(file, getFullPath(storedFileName));
return AttachUploadFile.of(originalFileName, storedFileName);
}
/**
* DownloadFile κ°μ²΄λ₯Ό μ¬μ©νμ¬ νμΌμ λ€μ΄λ‘λν©λλ€.
*
* @param downloadFile λ€μ΄λ‘λν νμΌ μ 보λ₯Ό ν¬ν¨ν DownloadFile κ°μ²΄
* @param <T> μλ΅ λ°λ νμ
* @return ResponseEntity κ°μ²΄λ‘ κ°μΌ λ€μ΄λ‘λ κ²°κ³Ό
*/
default <T> ResponseEntity<T> download(DownloadFile<T> downloadFile) {
return ResponseEntity.ok().headers(downloadFile.getHeaders()).body(downloadFile.getBody());
}
}
νμΌμ κ΄λ¦¬νλ μΈν°νμ΄μ€λ‘, μ μ₯ λλ ν 리λ₯Ό κ°μ Έμ€λ getDirectory()
λ₯Ό νμλ‘ κ΅¬νν΄μΌνλ€. μ
λ‘λμ λ€μ΄λ‘λ κΈ°λ₯μ κΈ°λ³Έ μ 곡νλ€.
/**
* UploadFile μΈν°νμ΄μ€λ μ
λ‘λλ νμΌμ μλ³Έ νμΌλͺ
κ³Ό μ μ₯λ νμΌλͺ
μ μ 곡νλ λ©μλλ₯Ό μ μν©λλ€.
*/
public interface UploadFile {
/**
* μ
λ‘λλ νμΌμ μλ³Έ νμΌλͺ
μ λ°νν©λλ€.
*
* @return μλ³Έ νμΌλͺ
*/
String getOriginalFileName();
/**
* μ
λ‘λλ νμΌμ μ μ₯λ νμΌλͺ
μ λ°νν©λλ€.
*
* @return μ μ₯λ νμΌλͺ
*/
String getStoredFileName();
}
μ
λ‘λ νμΌ μΈν°νμ΄μ€λ‘, μΈν°νμ΄μ€ ꡬνμ²΄λ‘ AttachUploadFile
μ ExcelUploadFile<T>
λ κ°κ° 첨λΆνμΌ, μμ
νμΌ μ
λ‘λ ν΄λμ€μ΄λ€. μ
λ‘λν μ λ³΄λ‘ DB
μμ κ΄λ¦¬λ μ μλ€.
/**
* DownloadFile μΈν°νμ΄μ€λ νμΌ λ€μ΄λ‘λ μ 보λ₯Ό μ μνλ μΈν°νμ΄μ€μ
λλ€.
* ꡬν ν΄λμ€μμλ λ€μ΄λ‘λν νμΌλͺ
, HTTP ν€λ, μλ΅ λ°λλ₯Ό μ 곡ν΄μΌ ν©λλ€.
*
* @param <T> λ€μ΄λ‘λν λ°μ΄ν°μ νμ
*/
public interface DownloadFile<T> {
/**
* λ€μ΄λ‘λν νμΌλͺ
μ λ°νν©λλ€.
*
* @return λ€μ΄λ‘λν νμΌλͺ
*/
String getDownloadFileName();
/**
* λ€μ΄λ‘λν νμΌμ λν HTTP ν€λλ₯Ό λ°νν©λλ€.
*
* @return HTTP ν€λ κ°μ²΄
*/
HttpHeaders getHeaders();
/**
* λ€μ΄λ‘λν λ°μ΄ν°μ λ³Έλ¬Έμ λ°νν©λλ€.
*
* @return λ€μ΄λ‘λν λ°μ΄ν°μ λ³Έλ¬Έ
*/
T getBody();
}
λ€μ΄λ‘λ νμΌ μΈν°νμ΄μ€λ‘, μΈν°νμ΄μ€ ꡬνμ²΄λ‘ AttachDownloadFile
μ ExcelDownloadFile
λ κ°κ° 첨λΆνμΌ, μμ
νμΌ λ€μ΄λ‘λ ν΄λμ€μ΄λ€.
ꡬν ν΄λμ€λ₯Ό μΈμ€ν΄μ€νμ¬ FileManager
μ download
λ©μλλ₯Ό νΈμΆνλ©΄ μλ΅ κ°μΌλ‘ νμΌ λ€μ΄λ‘λκ° μ€νλλ€.
/**
* ExcelWriter μΈν°νμ΄μ€λ Excel νμΌ μμ±μ μν κΈ°λ₯μ μ μν©λλ€.
* <p>
* ꡬν체λ Excel νμΌμ ν€λ μ€νμΌ, ν€λ μ΄λ¦ λ° κ°μ μμ±νκΈ° μν λ©μλλ₯Ό ν¬ν¨ν©λλ€.
* </p>
*
* @param <T> Excel νμΌμ μμ±ν κ°μ²΄μ νμ
*/
public interface ExcelWriter<T> {
/**
* Excel νμΌμ μμ±ν λ°μ΄ν° 리μ€νΈλ₯Ό λ°νν©λλ€.
*
* @return Excel νμΌμ μμ±ν λ°μ΄ν° 리μ€νΈ
*/
List<?> getList();
/**
* Excel νμΌμ μμ±ν κ°μ²΄μ ν΄λμ€ νμ
μ λ°νν©λλ€.
*
* @return Excel νμΌμ μμ±ν κ°μ²΄μ ν΄λμ€ νμ
*/
Class<T> getType();
...(μ€λ΅)
}
μμ
λ€μ΄λ‘λ μ, List<?>
μ λ°μ΄ν°λ₯Ό μμ
λ‘ μ°λ μΈν°νμ΄μ€μ΄λ€. κΈ°λ³Έ ꡬν ν΄λμ€λ‘ DefaultExcelWriter
μ 곡
νμΌ μ νΈ ν΄λμ€
FileUtils
: κΈ°λ³Έ μ²¨λΆ νμΌ μ νΈ ν΄λμ€ExcelFileUtils
: μμ νμΌ κ΄λ ¨ μ νΈ ν΄λ μ€
io.bareun.base.log
@RestController
μ λν HTTP λ‘κΉ
μ 곡ν΅μΌλ‘ μ 곡νλ€.
/**
* ApiLoggingAspectλ REST 컨νΈλ‘€λ¬μ HTTP μμ²μ λ‘κΉ
νκΈ° μν Aspectμ
λλ€.
* <p>
* μ΄ ν΄λμ€λ @RestController μ΄λ
Έν
μ΄μ
μ΄ λΆμ ν΄λμ€ λ΄μμ λ©μλ νΈμΆ μ μ HTTP μμ²μ λ‘κΉ
ν©λλ€.
* λ‘κΉ
ν μ 보λ‘λ IP μ£Όμ, HTTP λ©μλ, μμ² URL, 쿼리 μ€νΈλ§, μμ² λ°λκ° ν¬ν¨λ©λλ€.
*/
@Slf4j
@Aspect
@Component
public class ApiLoggingAspect {
/**
* {@link org.springframework.web.bind.annotation.RestController} μ΄λ
Έν
μ΄μ
μ΄ λΆμ ν΄λμ€
* λ΄μ λͺ¨λ λ©μλλ₯Ό ν¬μΈνΈμ»·μΌλ‘ μ€μ ν©λλ€.
*/
@Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
public void restController() {
}
/**
* ν¬μΈνΈμ»·μμ μ§μ ν λ©μλ νΈμΆ μ μ HTTP μμ²μ λ‘κΉ
νλ λ©μλμ
λλ€.
*
* @param joinPoint μ‘°μΈ ν¬μΈνΈ κ°μ²΄λ‘, νΈμΆλ λ©μλμ κ·Έ νλΌλ―Έν° λ±μ μΆμΆνλ λ° μ¬μ©λ©λλ€.
*/
@Before("restController()")
public void httpLogging(JoinPoint joinPoint) {
String remoteAddr = getRemoteAddr();
String method = getMethod();
String requestURL = getRequestURL();
String queryString = getQueryString();
String requestBody = getRequestBody(joinPoint);
log.info("HTTP Logging IP : {} | Method : {} | URL : {} | Query : {} | Body {}",
remoteAddr, method, requestURL, queryString, requestBody);
}
...(μ€λ΅)
}
AOP
λ₯Ό μ΄μ©νμ¬ HTTP
μ μ 보λ₯Ό λ‘κΉ
νλ€.
[λ‘κ·Έ ν¬λ§·]
HTTP Logging IP : {} | Method : {} | URL : {} | Query : {} | Body {}
https://github.com/bareunio/project-sample
μ΄μ λ° κ°μ μ¬νμ μλμ λ§ν¬λ₯Ό ν΅ν΄ λ±λ‘ ν΄μ£ΌμΈμ