[공통] util → framework 유틸 (ACM-CM-002)
This commit is contained in:
parent
45406e9974
commit
92c06b9c9b
1 changed files with 507 additions and 0 deletions
|
|
@ -0,0 +1,507 @@
|
||||||
|
package com.klaro.acquirecore.framework.util;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static utility class for message encoding/decoding migrated from legacy/util_msg.c
|
||||||
|
* Uses java.util.Base64 and java.nio.charset for codec operations.
|
||||||
|
*/
|
||||||
|
public final class MessageUtil {
|
||||||
|
|
||||||
|
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
|
||||||
|
public static final Charset EUC_KR_CHARSET = Charset.forName("EUC-KR");
|
||||||
|
public static final Charset ISO_8859_1_CHARSET = StandardCharsets.ISO_8859_1;
|
||||||
|
|
||||||
|
private static final Pattern EMAIL_PATTERN = Pattern.compile(
|
||||||
|
"^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$"
|
||||||
|
);
|
||||||
|
private static final Pattern PHONE_PATTERN = Pattern.compile(
|
||||||
|
"^\\d{2,4}-\\d{3,4}-\\d{4}$|^\\d{10,11}$"
|
||||||
|
);
|
||||||
|
private static final Pattern KOREAN_PHONE_PATTERN = Pattern.compile(
|
||||||
|
"^01[016789]-\\d{3,4}-\\d{4}$"
|
||||||
|
);
|
||||||
|
|
||||||
|
private MessageUtil() {
|
||||||
|
throw new UnsupportedOperationException("Utility class cannot be instantiated");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== Base64 Encoding/Decoding ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes a string to Base64.
|
||||||
|
*
|
||||||
|
* @param input the string to encode
|
||||||
|
* @return the Base64 encoded string
|
||||||
|
*/
|
||||||
|
public static String encodeBase64(String input) {
|
||||||
|
Objects.requireNonNull(input, "input must not be null");
|
||||||
|
return Base64.getEncoder().encodeToString(input.getBytes(DEFAULT_CHARSET));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes a string to Base64 with specified charset.
|
||||||
|
*
|
||||||
|
* @param input the string to encode
|
||||||
|
* @param charset the charset to use
|
||||||
|
* @return the Base64 encoded string
|
||||||
|
*/
|
||||||
|
public static String encodeBase64(String input, Charset charset) {
|
||||||
|
Objects.requireNonNull(input, "input must not be null");
|
||||||
|
Objects.requireNonNull(charset, "charset must not be null");
|
||||||
|
return Base64.getEncoder().encodeToString(input.getBytes(charset));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes bytes to Base64.
|
||||||
|
*
|
||||||
|
* @param bytes the bytes to encode
|
||||||
|
* @return the Base64 encoded string
|
||||||
|
*/
|
||||||
|
public static String encodeBase64(byte[] bytes) {
|
||||||
|
Objects.requireNonNull(bytes, "bytes must not be null");
|
||||||
|
return Base64.getEncoder().encodeToString(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a Base64 string to plain string.
|
||||||
|
*
|
||||||
|
* @param encoded the Base64 encoded string
|
||||||
|
* @return the decoded string
|
||||||
|
*/
|
||||||
|
public static String decodeBase64(String encoded) {
|
||||||
|
Objects.requireNonNull(encoded, "encoded must not be null");
|
||||||
|
byte[] decoded = Base64.getDecoder().decode(encoded);
|
||||||
|
return new String(decoded, DEFAULT_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a Base64 string to plain string with specified charset.
|
||||||
|
*
|
||||||
|
* @param encoded the Base64 encoded string
|
||||||
|
* @param charset the charset to use for decoding
|
||||||
|
* @return the decoded string
|
||||||
|
*/
|
||||||
|
public static String decodeBase64(String encoded, Charset charset) {
|
||||||
|
Objects.requireNonNull(encoded, "encoded must not be null");
|
||||||
|
Objects.requireNonNull(charset, "charset must not be null");
|
||||||
|
byte[] decoded = Base64.getDecoder().decode(encoded);
|
||||||
|
return new String(decoded, charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a Base64 string to bytes.
|
||||||
|
*
|
||||||
|
* @param encoded the Base64 encoded string
|
||||||
|
* @return the decoded bytes
|
||||||
|
*/
|
||||||
|
public static byte[] decodeBase64ToBytes(String encoded) {
|
||||||
|
Objects.requireNonNull(encoded, "encoded must not be null");
|
||||||
|
return Base64.getDecoder().decode(encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes a URL-safe Base64 string.
|
||||||
|
*
|
||||||
|
* @param input the string to encode
|
||||||
|
* @return the URL-safe Base64 encoded string
|
||||||
|
*/
|
||||||
|
public static String encodeBase64Url(String input) {
|
||||||
|
Objects.requireNonNull(input, "input must not be null");
|
||||||
|
return Base64.getUrlEncoder().encodeToString(input.getBytes(DEFAULT_CHARSET));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a URL-safe Base64 string.
|
||||||
|
*
|
||||||
|
* @param encoded the URL-safe Base64 encoded string
|
||||||
|
* @return the decoded string
|
||||||
|
*/
|
||||||
|
public static String decodeBase64Url(String encoded) {
|
||||||
|
Objects.requireNonNull(encoded, "encoded must not be null");
|
||||||
|
byte[] decoded = Base64.getUrlDecoder().decode(encoded);
|
||||||
|
return new String(decoded, DEFAULT_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== Hex Encoding/Decoding ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes bytes to hexadecimal string.
|
||||||
|
*
|
||||||
|
* @param bytes the bytes to encode
|
||||||
|
* @return the hexadecimal string
|
||||||
|
*/
|
||||||
|
public static String encodeHex(byte[] bytes) {
|
||||||
|
Objects.requireNonNull(bytes, "bytes must not be null");
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (byte b : bytes) {
|
||||||
|
sb.append(String.format("%02x", b));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a hexadecimal string to bytes.
|
||||||
|
*
|
||||||
|
* @param hex the hexadecimal string
|
||||||
|
* @return the decoded bytes
|
||||||
|
*/
|
||||||
|
public static byte[] decodeHex(String hex) {
|
||||||
|
Objects.requireNonNull(hex, "hex must not be null");
|
||||||
|
if (hex.length() % 2 != 0) {
|
||||||
|
throw new IllegalArgumentException("Hex string must have even length");
|
||||||
|
}
|
||||||
|
int len = hex.length();
|
||||||
|
byte[] data = new byte[len / 2];
|
||||||
|
for (int i = 0; i < len; i += 2) {
|
||||||
|
data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
|
||||||
|
+ Character.digit(hex.charAt(i + 1), 16));
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== URL Encoding/Decoding ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL encodes a string using UTF-8.
|
||||||
|
*
|
||||||
|
* @param input the string to encode
|
||||||
|
* @return the URL encoded string
|
||||||
|
*/
|
||||||
|
public static String urlEncode(String input) {
|
||||||
|
Objects.requireNonNull(input, "input must not be null");
|
||||||
|
try {
|
||||||
|
return java.net.URLEncoder.encode(input, DEFAULT_CHARSET.name());
|
||||||
|
} catch (java.io.UnsupportedEncodingException e) {
|
||||||
|
throw new RuntimeException("Unsupported encoding", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL decodes a string using UTF-8.
|
||||||
|
*
|
||||||
|
* @param encoded the URL encoded string
|
||||||
|
* @return the decoded string
|
||||||
|
*/
|
||||||
|
public static String urlDecode(String encoded) {
|
||||||
|
Objects.requireNonNull(encoded, "encoded must not be null");
|
||||||
|
try {
|
||||||
|
return java.net.URLDecoder.decode(encoded, DEFAULT_CHARSET.name());
|
||||||
|
} catch (java.io.UnsupportedEncodingException e) {
|
||||||
|
throw new RuntimeException("Unsupported encoding", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== String Manipulation ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Masks a string with asterisks, showing only the first and last characters.
|
||||||
|
*
|
||||||
|
* @param input the string to mask
|
||||||
|
* @return the masked string
|
||||||
|
*/
|
||||||
|
public static String mask(String input) {
|
||||||
|
return mask(input, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Masks a string with asterisks, showing only specified first and last characters.
|
||||||
|
*
|
||||||
|
* @param input the string to mask
|
||||||
|
* @param showFirst number of characters to show at the start
|
||||||
|
* @param showLast number of characters to show at the end
|
||||||
|
* @return the masked string
|
||||||
|
*/
|
||||||
|
public static String mask(String input, int showFirst, int showLast) {
|
||||||
|
if (input == null || input.isEmpty()) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
int length = input.length();
|
||||||
|
if (length <= showFirst + showLast) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(input, 0, showFirst);
|
||||||
|
for (int i = showFirst; i < length - showLast; i++) {
|
||||||
|
sb.append('*');
|
||||||
|
}
|
||||||
|
sb.append(input.substring(length - showLast));
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Masks an email address.
|
||||||
|
*
|
||||||
|
* @param email the email to mask
|
||||||
|
* @return the masked email
|
||||||
|
*/
|
||||||
|
public static String maskEmail(String email) {
|
||||||
|
if (email == null || !email.contains("@")) {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
String[] parts = email.split("@");
|
||||||
|
String localPart = parts[0];
|
||||||
|
String domain = parts[1];
|
||||||
|
if (localPart.length() <= 2) {
|
||||||
|
return mask(localPart, 1, 0) + "@" + domain;
|
||||||
|
}
|
||||||
|
return mask(localPart, 1, 1) + "@" + domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Masks a phone number.
|
||||||
|
*
|
||||||
|
* @param phone the phone number to mask
|
||||||
|
* @return the masked phone number
|
||||||
|
*/
|
||||||
|
public static String maskPhone(String phone) {
|
||||||
|
if (phone == null || phone.isEmpty()) {
|
||||||
|
return phone;
|
||||||
|
}
|
||||||
|
String digitsOnly = phone.replaceAll("[^0-9]", "");
|
||||||
|
if (digitsOnly.length() < 7) {
|
||||||
|
return phone;
|
||||||
|
}
|
||||||
|
int length = digitsOnly.length();
|
||||||
|
String masked = digitsOnly.substring(0, 3) + "****" + digitsOnly.substring(length - 4);
|
||||||
|
if (phone.contains("-")) {
|
||||||
|
return masked.substring(0, 3) + "-" + "****" + "-" + masked.substring(7);
|
||||||
|
}
|
||||||
|
return masked;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== Validation ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates if a string is a valid email address.
|
||||||
|
*
|
||||||
|
* @param email the email to validate
|
||||||
|
* @return true if valid, false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean isValidEmail(String email) {
|
||||||
|
if (email == null || email.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return EMAIL_PATTERN.matcher(email).matches();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates if a string is a valid phone number.
|
||||||
|
*
|
||||||
|
* @param phone the phone number to validate
|
||||||
|
* @return true if valid, false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean isValidPhone(String phone) {
|
||||||
|
if (phone == null || phone.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return PHONE_PATTERN.matcher(phone).matches();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates if a string is a valid Korean phone number.
|
||||||
|
*
|
||||||
|
* @param phone the phone number to validate
|
||||||
|
* @return true if valid, false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean isValidKoreanPhone(String phone) {
|
||||||
|
if (phone == null || phone.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return KOREAN_PHONE_PATTERN.matcher(phone).matches();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a string is null or empty.
|
||||||
|
*
|
||||||
|
* @param input the string to check
|
||||||
|
* @return true if null or empty
|
||||||
|
*/
|
||||||
|
public static boolean isEmpty(String input) {
|
||||||
|
return input == null || input.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a string is null, empty, or whitespace only.
|
||||||
|
*
|
||||||
|
* @param input the string to check
|
||||||
|
* @return true if null, empty, or whitespace only
|
||||||
|
*/
|
||||||
|
public static boolean isBlank(String input) {
|
||||||
|
return input == null || input.trim().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== Charset Conversion ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a string from one charset to another.
|
||||||
|
*
|
||||||
|
* @param input the input string
|
||||||
|
* @param fromCharset the source charset
|
||||||
|
* @param toCharset the target charset
|
||||||
|
* @return the converted string
|
||||||
|
*/
|
||||||
|
public static String convertCharset(String input, Charset fromCharset, Charset toCharset) {
|
||||||
|
Objects.requireNonNull(input, "input must not be null");
|
||||||
|
Objects.requireNonNull(fromCharset, "fromCharset must not be null");
|
||||||
|
Objects.requireNonNull(toCharset, "toCharset must not be null");
|
||||||
|
byte[] bytes = input.getBytes(fromCharset);
|
||||||
|
return new String(bytes, toCharset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts EUC-KR encoded bytes to UTF-8 string.
|
||||||
|
*
|
||||||
|
* @param eucKrBytes the EUC-KR encoded bytes
|
||||||
|
* @return the UTF-8 string
|
||||||
|
*/
|
||||||
|
public static String eucKrToUtf8(byte[] eucKrBytes) {
|
||||||
|
Objects.requireNonNull(eucKrBytes, "eucKrBytes must not be null");
|
||||||
|
return new String(eucKrBytes, EUC_KR_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts UTF-8 string to EUC-KR encoded bytes.
|
||||||
|
*
|
||||||
|
* @param input the UTF-8 string
|
||||||
|
* @return the EUC-KR encoded bytes
|
||||||
|
*/
|
||||||
|
public static byte[] utf8ToEucKr(String input) {
|
||||||
|
Objects.requireNonNull(input, "input must not be null");
|
||||||
|
return input.getBytes(EUC_KR_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== Truncation and Padding ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Truncates a string to the specified length.
|
||||||
|
*
|
||||||
|
* @param input the string to truncate
|
||||||
|
* @param maxLength the maximum length
|
||||||
|
* @return the truncated string
|
||||||
|
*/
|
||||||
|
public static String truncate(String input, int maxLength) {
|
||||||
|
if (input == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (input.length() <= maxLength) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
return input.substring(0, maxLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pads a string on the left with spaces to reach the specified length.
|
||||||
|
*
|
||||||
|
* @param input the string to pad
|
||||||
|
* @param length the target length
|
||||||
|
* @return the padded string
|
||||||
|
*/
|
||||||
|
public static String padLeft(String input, int length) {
|
||||||
|
if (input == null) {
|
||||||
|
input = "";
|
||||||
|
}
|
||||||
|
return String.format("%" + length + "s", input);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pads a string on the right with spaces to reach the specified length.
|
||||||
|
*
|
||||||
|
* @param input the string to pad
|
||||||
|
* @param length the target length
|
||||||
|
* @return the padded string
|
||||||
|
*/
|
||||||
|
public static String padRight(String input, int length) {
|
||||||
|
if (input == null) {
|
||||||
|
input = "";
|
||||||
|
}
|
||||||
|
return String.format("%- " + length + "s", input);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pads a string on the left with zeros to reach the specified length.
|
||||||
|
*
|
||||||
|
* @param input the string to pad
|
||||||
|
* @param length the target length
|
||||||
|
* @return the zero-padded string
|
||||||
|
*/
|
||||||
|
public static String padLeftWithZeros(String input, int length) {
|
||||||
|
if (input == null) {
|
||||||
|
input = "";
|
||||||
|
}
|
||||||
|
return String.format("%0" + length + "d", Long.parseLong(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Left pads a numeric string with zeros.
|
||||||
|
*
|
||||||
|
* @param value the numeric value
|
||||||
|
* @param length the target length
|
||||||
|
* @return the zero-padded string
|
||||||
|
*/
|
||||||
|
public static String zeroPad(long value, int length) {
|
||||||
|
return String.format("%0" + length + "d", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== Byte Array Utilities ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a string to bytes using the default charset.
|
||||||
|
*
|
||||||
|
* @param input the string to convert
|
||||||
|
* @return the bytes
|
||||||
|
*/
|
||||||
|
public static byte[] toBytes(String input) {
|
||||||
|
if (input == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return input.getBytes(DEFAULT_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a string to bytes using the specified charset.
|
||||||
|
*
|
||||||
|
* @param input the string to convert
|
||||||
|
* @param charset the charset to use
|
||||||
|
* @return the bytes
|
||||||
|
*/
|
||||||
|
public static byte[] toBytes(String input, Charset charset) {
|
||||||
|
if (input == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Objects.requireNonNull(charset, "charset must not be null");
|
||||||
|
return input.getBytes(charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts bytes to string using the default charset.
|
||||||
|
*
|
||||||
|
* @param bytes the bytes to convert
|
||||||
|
* @return the string
|
||||||
|
*/
|
||||||
|
public static String toString(byte[] bytes) {
|
||||||
|
if (bytes == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new String(bytes, DEFAULT_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts bytes to string using the specified charset.
|
||||||
|
*
|
||||||
|
* @param bytes the bytes to convert
|
||||||
|
* @param charset the charset to use
|
||||||
|
* @return the string
|
||||||
|
*/
|
||||||
|
public static String toString(byte[] bytes, Charset charset) {
|
||||||
|
if (bytes == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Objects.requireNonNull(charset, "charset must not be null");
|
||||||
|
return new String(bytes, charset);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in a new issue