diff --git a/src/main/java/com/eactive/apim/portal/common/util/PhoneNumberUtil.java b/src/main/java/com/eactive/apim/portal/common/util/PhoneNumberUtil.java new file mode 100644 index 0000000..8f00792 --- /dev/null +++ b/src/main/java/com/eactive/apim/portal/common/util/PhoneNumberUtil.java @@ -0,0 +1,80 @@ +package com.eactive.apim.portal.common.util; + +/** + * 한국 전화번호/연락처 정규화 유틸 (portal·admin 공유). + * + * 전화번호 저장은 본 유틸로 하이픈 구분 정규형으로 통일한다. 저장 형식이 경로별로 + * 달라(가입=원본, 초대=하이픈, SSO=숫자만) 휴대폰 기반 조회/초대 매칭이 어긋나는 것을 막는다. + * 암호화 컨버터가 붙은 필드는 {@code @PrePersist}/{@code @PreUpdate} 에서 본 메서드로 평문을 + * 정규화한 뒤 암호화되므로 암복호화에 영향이 없다. + */ +public final class PhoneNumberUtil { + + private PhoneNumberUtil() { + } + + /** + * 한국 전화번호를 하이픈 구분 정규형으로 변환한다. + * 숫자만 추출 후 prefix/길이로 포맷하며, 해당 규칙에 맞지 않는 값은 원본을 그대로 반환한다. + * 멱등(이미 정규형이면 동일 결과)이며 null/blank 는 원본을 반환한다. + * + *
+ * 휴대폰 01X 11자리 → XXX-XXXX-XXXX (010-1234-5678) + * 휴대폰 01X 10자리 → XXX-XXX-XXXX (011-123-4567) + * 서울 02 9자리 → 02-XXX-XXXX (02-123-4567) + * 서울 02 10자리 → 02-XXXX-XXXX (02-1234-5678) + * 지역/070 0XX 10자리 → 0XX-XXX-XXXX (031-234-5678) + * 지역/070 0XX 11자리 → 0XX-XXXX-XXXX (070-1234-5678) + * 안심 050X 12자리 → 0XXX-XXXX-XXXX (0507-1234-5678) + * 대표 15/16/18XX 8자리 → XXXX-XXXX (1588-1234) + * 그 외/null → 원본 그대로 + *+ */ + public static String normalize(String raw) { + if (raw == null) { + return null; + } + String digits = raw.replaceAll("[^0-9]", ""); + int len = digits.length(); + if (len == 0) { + return raw; + } + + // 대표번호 15XX/16XX/18XX (8자리, 지역번호 없음) + if (len == 8 && (digits.startsWith("15") || digits.startsWith("16") || digits.startsWith("18"))) { + return digits.substring(0, 4) + "-" + digits.substring(4); + } + // 안심번호 050X (12자리) + if (len == 12 && digits.startsWith("050")) { + return digits.substring(0, 4) + "-" + digits.substring(4, 8) + "-" + digits.substring(8); + } + // 서울 02 + if (digits.startsWith("02")) { + if (len == 9) { + return "02-" + digits.substring(2, 5) + "-" + digits.substring(5); + } + if (len == 10) { + return "02-" + digits.substring(2, 6) + "-" + digits.substring(6); + } + return raw; + } + // 휴대폰/지역/070 등 0XX + if (digits.startsWith("0")) { + if (len == 10) { + return digits.substring(0, 3) + "-" + digits.substring(3, 6) + "-" + digits.substring(6); + } + if (len == 11) { + return digits.substring(0, 3) + "-" + digits.substring(3, 7) + "-" + digits.substring(7); + } + return raw; + } + return raw; + } + + /** + * 숫자만 추출(발송 게이트웨이 전달·등가 비교용). null 은 그대로 반환. + */ + public static String digitsOnly(String raw) { + return raw == null ? null : raw.replaceAll("[^0-9]", ""); + } +} diff --git a/src/main/java/com/eactive/apim/portal/invitation/entity/UserInvitation.java b/src/main/java/com/eactive/apim/portal/invitation/entity/UserInvitation.java index 7533a2c..0ba2352 100644 --- a/src/main/java/com/eactive/apim/portal/invitation/entity/UserInvitation.java +++ b/src/main/java/com/eactive/apim/portal/invitation/entity/UserInvitation.java @@ -1,5 +1,6 @@ package com.eactive.apim.portal.invitation.entity; +import com.eactive.apim.portal.common.util.PhoneNumberUtil; import com.eactive.apim.portal.invitation.entity.UserInvitationEnums.InvitationStatus; import com.eactive.apim.portal.jpa.PersonalDataEncryptConverter; import com.eactive.eai.data.converter.LocalDateTimeToStringConverter14; @@ -62,4 +63,11 @@ public class UserInvitation { @Comment("만료일시") private LocalDateTime expiresOn; + /** 저장 시 초대 휴대폰을 하이픈 구분 정규형으로 통일 */ + @PrePersist + @PreUpdate + private void normalizePhones() { + this.invitationMobile = PhoneNumberUtil.normalize(this.invitationMobile); + } + } diff --git a/src/main/java/com/eactive/apim/portal/portalorg/entity/PortalOrg.java b/src/main/java/com/eactive/apim/portal/portalorg/entity/PortalOrg.java index 90d06ae..4d5eeca 100644 --- a/src/main/java/com/eactive/apim/portal/portalorg/entity/PortalOrg.java +++ b/src/main/java/com/eactive/apim/portal/portalorg/entity/PortalOrg.java @@ -1,6 +1,7 @@ package com.eactive.apim.portal.portalorg.entity; import com.eactive.apim.portal.common.entity.Auditable; +import com.eactive.apim.portal.common.util.PhoneNumberUtil; import com.eactive.apim.portal.portalorg.entity.PortalOrgEnums.ApprovalStatus; import com.eactive.apim.portal.portalorg.entity.PortalOrgEnums.OrgStatus; import lombok.Data; @@ -95,4 +96,12 @@ public class PortalOrg extends Auditable implements Serializable, com.eactive.ea @Column(name = "reverse_proxy_path", length = 255) @Comment("리버스 프록시 경로") private String reverseProxyPath; + + /** 저장 시 전화번호를 하이픈 구분 정규형으로 통일 */ + @PrePersist + @PreUpdate + private void normalizePhones() { + this.orgPhoneNumber = PhoneNumberUtil.normalize(this.orgPhoneNumber); + this.scPhoneNumber = PhoneNumberUtil.normalize(this.scPhoneNumber); + } } diff --git a/src/main/java/com/eactive/apim/portal/portaluser/entity/PortalUser.java b/src/main/java/com/eactive/apim/portal/portaluser/entity/PortalUser.java index ad7bf25..c8df0a9 100644 --- a/src/main/java/com/eactive/apim/portal/portaluser/entity/PortalUser.java +++ b/src/main/java/com/eactive/apim/portal/portaluser/entity/PortalUser.java @@ -1,6 +1,7 @@ package com.eactive.apim.portal.portaluser.entity; import com.eactive.apim.portal.common.entity.Auditable; +import com.eactive.apim.portal.common.util.PhoneNumberUtil; import com.eactive.apim.portal.jpa.PersonalDataEncryptConverter;import com.eactive.apim.portal.portalorg.entity.PortalOrg; import com.eactive.apim.portal.portaluser.entity.PortalUserEnums.ApprovalStatus; import com.eactive.apim.portal.portaluser.entity.PortalUserEnums.RoleCode; @@ -98,4 +99,12 @@ public class PortalUser extends Auditable implements Serializable, com.eactive.e @Column(name = "withdrawal_reason", length=200) @Comment("회원탈퇴사유") private String withdrawalReason; + + /** 저장 시 전화번호를 하이픈 구분 정규형으로 통일 */ + @PrePersist + @PreUpdate + private void normalizePhones() { + this.phoneNumber = PhoneNumberUtil.normalize(this.phoneNumber); + this.mobileNumber = PhoneNumberUtil.normalize(this.mobileNumber); + } } diff --git a/src/main/java/com/eactive/apim/portal/user/entity/UserInfo.java b/src/main/java/com/eactive/apim/portal/user/entity/UserInfo.java index a4a6740..9fb82ae 100644 --- a/src/main/java/com/eactive/apim/portal/user/entity/UserInfo.java +++ b/src/main/java/com/eactive/apim/portal/user/entity/UserInfo.java @@ -1,5 +1,6 @@ package com.eactive.apim.portal.user.entity; +import com.eactive.apim.portal.common.util.PhoneNumberUtil; import com.eactive.apim.portal.jpa.PersonalDataEncryptConverter; import com.eactive.eai.data.converter.LocalDateTimeToStringConverter14; import com.eactive.eai.data.converter.StringTrimConverter; @@ -139,4 +140,12 @@ public class UserInfo extends AbstractEntity