목록 화면에서 개인정보에 해당하는 몇 필드들은 전달받은 규칙에 맞게 마스킹처리를 해야했다.
구글링을 해보니, Jackson을 이용하는 방법이 있었다.
여러 dto 중 일부 개인정보에 해당하는 필드에만 @MaskRequired
라는 어노테이션을 만들어 달아 어떤 필드를 마스킹 해야하는지 정의하도록 한다.
어떤 방식으로 마스킹할지 정의해줄 속성으로 MaskingType
enum을 만든다.
어떻게 마스킹을 처리하는지를 맡는 Masking
클래스가 필요한다. 이 클래스에는 이름, 전화번호, 주소등을 마스킹처리하는 구현 method를 가진다.
@MaskRequired
Annotation 생성public enum MaskingType {
NAME,
CONTACT,
DETAIL_ADDRESS
}
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
public @interface MaskRequired {
MaskingType type();
}
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
: 런타임시에 어노테이션 사용할 수 있음@JacksonAnnotationsInside
: jackson custom annotation 이라고 정의하는 부분public class Masking {
public static String mask(MaskingType type, String value) {
String str = "";
switch (type) {
case NAME:
str = getNameMask(value);
break;
case CONTACT:
str = getContactMask(value);
break;
case DETAIL_ADDRESS:
str = getDetailAddressMask(value);
break;
default:
break;
}
return str;
}
... // 마스킹 메소드들은 필요한 형태로 구현하면 됨
}
처음엔 참고 블로그 내용처럼 interface를 구현하는
XXMasking
클래스를 각각 만들려고 하였으나MaskingPropertySerializer
의createContextual()
에서 instance를 넘기려고 했으나, java에서는 그런 방법이 없어서 enum 속성과 Masking 클래스를 분리했다.
어노테이션이 붙은 필드는 custom serialize 를 사용하도록 설정해야 한다.
public class MaskingPropertySerializer extends StdSerializer<String> implements ContextualSerializer {
MaskingType maskingType;
protected MaskingPropertySerializer() {
super(String.class);
}
protected MaskingPropertySerializer(MaskingType maskingType) {
super(String.class);
this.maskingType = maskingType;
}
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeString(Masking.mask(maskingType, value));
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
MaskingType maskingTypeValue = null;
MaskRequired ann = null;
if (property != null) {
ann = property.getAnnotation(MaskRequired.class);
}
if (ann != null) {
maskingTypeValue = ann.type();
}
return new MaskingPropertySerializer(maskingTypeValue);
}
}
gen.writeString(Masking.mask(maskingType, value));
: 구현한 mask()
메소드를 타도록 한다. 여기까지 작성하면, dto의 해당하는 필드 위에
@JsonSerialize(using = MaskingPropertySerializer.class)
@MaskRequired(type = MaskType.NAME)
private String name;
이렇게 @JsonSerialize(using = MaskingPropertySerializer.class)
을 반복적으로 달아주어야 한다.
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JsonSerialize(using = MaskingPropertySerializer.class) // 추가
public @interface MaskRequired {
MaskingType type();
}
MaskRequired
인터페이스에 두 어노테이션을 더 추가한다.
이렇게 하면 마스킹 처리가 필요한 dto의 필드 위에
@MaskRequired(type = MaskType.NAME)
private String name;
이렇게만 작성해주면 된다.
참고
https://rutesun.github.io/development/annotation-driven-masking/