β λ¬Έμ
@Builderλ₯Ό μ μ©ν μν°ν°μμ @EntityListeners(AuditingEntityListener.class) μ μ© ν @CreatedDateλ‘ μμ±μΌμ μλ μ
λ ₯νλ € νμΌλ κ°μ΄ μ μμ μΌλ‘ μ μ₯λμ§ μμ.@Getter
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
@EntityListeners(AuditingEntityListener.class)
public class ErrorResponse {
@CreatedDate
private final LocalDateTime timestamp;
private final int status;
...
public static ErrorResponse of(ErrorCode errorCode) {
return ErrorResponse.builder()
.status(errorCode.getStatus())
...
.build();
}
...
}
β μμΈ
JPA Auditingμ JPA λΌμ΄νμ¬μ΄ν΄ μ΄λ²€νΈλ₯Ό κΈ°λ°μΌλ‘ ν¨.persist, merge, remove λ±μ μμ
μ μν΄ μ΄λ²€νΈ νΈλ¦¬κ±°κ° λ¨.ErrorResponseλ μν°ν°κ° μλλ―λ‘(@Entity μ΄λ
Έν
μ΄μ
β) JPA λΌμ΄νλΌμ΄ν΄μ λ°λ₯Έ μ΄λ²€νΈ νΈλ¦¬κ±°κ° λ°μνμ§ μλλ€.AuditingEntityListener.class μ΄ λμνμ§ μμμ.β ν΄κ²°
JPA μν°ν°κ° μλλ―λ‘ μΈμ€ν΄μ€μ λν΄νΈ κ°μ μ€μ νλ κ²μΌλ‘ ν΄κ²°.
μμ μ½λμμλ @Builer ν¨ν΄μ μ¬μ©νκ³ μμΌλ―λ‘, @Builder.Defaultλ₯Ό μ¬μ©νμ¬ @Builer λ‘ μμ± μμ λν΄νΈ κ°μΌλ‘ νμ¬ μκ°μ μ μ₯νλλ‘ λ³κ²½νμλ€.
@Builder.Default
private final LocalDateTime timestamp = LocalDateTime.now();
κ·Έ κ²°κ³Ό νμ μ€ν¬νκ° μ μμ μΌλ‘ κΈ°λ‘λλ κ²μ νμΈν μ μλ€.
{
"timestamp": "2025-04-04T02:35:55.5728417",
"status": 400,
"error": "Bad Request",
"code": "U003",
"message": "Email is Duplicated"
}
β λ¬Έμ
Validationμμ message νλΌλ―Έν°λ‘ μ€μ ν μ€λ₯ λ©μΈμ§κ° μ λλ‘ μΆλ ₯λμ§ μμErrorResponse errorResponse = ErrorResponse.of(ErrorCode.INVALID_INPUT_VALUE, e.getMessage());
{
"status": 400,
"error": "Bad Request",
"code": "C001",
"message": "Validation failed for argument [0] in public java.lang.String org.example.scheduleprojectv2.controller.UserController.login(org.example.scheduleprojectv2.dto.LoginRequestDTO,jakarta.servlet.http.HttpServletRequest): [Field error in object 'loginRequestDTO' on field 'email': rejected value [yejin1234]; codes [Email.loginRequestDTO.email,Email.email,Email.java.lang.String,Email]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [loginRequestDTO.email,email]; arguments []; default message [email],[Ljakarta.validation.constraints.Pattern$Flag;@3da63570,.*]; default message [μ¬λ°λ₯Έ νμμ μ΄λ©μΌ μ£Όμμ¬μΌ ν©λλ€]] "
}
β μμΈ
β ν΄κ²°
ErrorResponse errorResponse = ErrorResponse.of(ErrorCode.INVALID_INPUT_VALUE, bindingResult.getFieldErrors().get(0).getDefaultMessage());
{
"status": 400,
"error": "Bad Request",
"code": "C001",
"message": "μ¬λ°λ₯Έ νμμ μ΄λ©μΌ μ£Όμμ¬μΌ ν©λλ€"
}
λ°©λ²1οΈβ£ μν°ν°μ λ©μλ ꡬν
λ°©λ²2οΈβ£ μλΉμ€ λ μ΄μ΄μ ꡬν
λ°©λ²3οΈβ£ DTOμ λ©μλ ꡬν
@Setterλ₯Ό μ¬μ©νμ§ μμ μνλ λλ‘ μμ±μ΄ μλ¨.μΌμ -μ¬μ©μ N:1 μ°κ΄ κ΄κ³μμ, μ¬μ©μκ° μμ λλ©΄(νμ νν΄) ν΄λΉ μ¬μ©μμ μ°κ΄λ μΌμ λ ν¨κ» μμ λ νμκ° μμ.
JPA CASCADEλ₯Ό μ¬μ©νκΈ° μν΄μ @OneToManyλ‘ μλ°©ν₯ μ€μ μ ν΄μ£Όμ΄μΌ ν¨.
μ‘°μ¬ν΄λ³΄λ @OnDelete(action= OnDeleteAction.CASCADE)λ₯Ό μ¬μ©νμ¬ μ¬μ©μκ° μμ λ λ κ΄λ ¨λ μΌμ λ κ°μ΄ μμ λλλ‘ μ€μ ν μ μμ.
μ΄ λμμ JPAκ° μλ DB μΈ‘μμ μ΄λ£¨μ΄μ§λ μμ μ΄λ―λ‘ νλμ μΏΌλ¦¬λ‘ μ²λ¦¬κ° κ°λ₯ν¨.
νμ¬ νλ‘μ νΈμμλ @OnDelete μ΄λ
Έν
μ΄μ
μΌλ‘ μ²λ¦¬νμμΌλ, λ μ€ μ΄λ λ°©μμ΄ λ μ μ ν μ§λ μΆκ° μ‘°μ¬ νμ.