Spring Boot 다국어 지원, DB 번역값 처리하기 - 1
이전에 Entity단에서 직접 번역값과 매핑하는 것에 대해,
엔티티마다 Translatable 인터페이스를 구현하고, 번역 필드를 관리하는 코드가 반복되고, 필드가 추가될 때마다 TranslatableField를 함께 추가해주어야 한다는 부분에 대해 번거로움을 느꼈습니다.
따라서 AOP를 사용하여 DTO Response값을 받아와 번역이 요구되는 필드일 경우 번역하는 과정으로 바꾸어보았습니다.
먼저, AOP를 사용하기 때문에 이전처럼 Entity에 Transable을 implements할 이유가 없었습니다. 따라서, 커스텀 어노테이션을 만들어 번역이 필요한 필드에 직접 붙여주는 방식으로 구현했습니다.
Trans Custom Annotation 선언
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Trans {
}
@Data
public class ArtistSearchDto {
private Long contentId;
@Trans
private String artistName;
}
위와 같이 ArtistSearchDto 내 번역이 필요한 artistName에 @Trans 어노테이션을 붙여주었습니다.
Translation Aspect
@Aspect
@Component
@RequiredArgsConstructor
public class TranslationAspect {
private final TranslationService translationService;
@Around("@annotation(org.springframework.web.bind.annotation.GetMapping)")
public Object translateFields(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = joinPoint.proceed();
if (result instanceof ResponseEntity) {
ResponseEntity<?> responseEntity = (ResponseEntity<?>) result;
Object body = responseEntity.getBody();
if (body instanceof Page) {
Page<?> page = (Page<?>) body;
page.getContent().forEach(this::translateObject);
} else {
translateObject(body);
}
return ResponseEntity.status(responseEntity.getStatusCode()).headers(responseEntity.getHeaders()).body(body);
} else {
translateObject(result);
}
return result;
}
private void translateObject(Object obj) {
if (obj == null) return;
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Trans.class)) {
field.setAccessible(true);
try {
String originalValue = (String) field.get(obj);
String translatedValue = translationService.translate(originalValue, Language.ofLocale());
field.set(obj, translatedValue);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
장점
단점
장점
단점
AOP를 사용한 방식은 코드의 간결성과 유지보수 측면에서 큰 장점을 제공합니다. 하지만 @GetMapping 메서드로부터 받은 응답값에 직접 번역을 수행하므로 성능 문제가 발생할 수 있는 단점이 있습니다.
만약 번역이 대부분의 엔드포인트에서 필요하고, 번역 필드가 자주 변경된다면 AOP 방식이 더 적합할 수 있습니다. 반면, 특정 엔드포인트에서만 번역이 필요하거나, 성능이 중요한 경우에는 기존 방식이 더 나을 수 있습니다.
제가 구현중인 서비스의 경우 전자이기 때문에, AOP 방식을 적용하고자 합니다.