|
@@ -1,14 +1,246 @@
|
|
|
package com.fs.common.utils;
|
|
package com.fs.common.utils;
|
|
|
|
|
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
|
|
+import cn.hutool.http.HttpException;
|
|
|
|
|
+import cn.hutool.http.HttpRequest;
|
|
|
|
|
+import cn.hutool.json.JSONUtil;
|
|
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
+import com.fs.common.core.domain.AjaxResult;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
|
|
|
|
|
+import static com.fs.common.core.domain.AjaxResult.CODE_TAG;
|
|
|
|
|
+import static com.fs.common.core.domain.AjaxResult.DATA_TAG;
|
|
|
|
|
+
|
|
|
|
|
+@Slf4j
|
|
|
public class PhoneUtils {
|
|
public class PhoneUtils {
|
|
|
- public static String getLastFourNum(String phone) {
|
|
|
|
|
|
|
|
|
|
- String lastFourNumber = phone;
|
|
|
|
|
- if (lastFourNumber.length() == 11) {
|
|
|
|
|
- lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 解密
|
|
|
|
|
+ */
|
|
|
|
|
+ public static String decryptPhone(String encryptedText) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ String text=null;
|
|
|
|
|
+ String url= "http://42.194.147.226:8000/app/common/genDecryption";
|
|
|
|
|
+ // 构建请求体 JSON
|
|
|
|
|
+ JSONObject jsonBody = new JSONObject();
|
|
|
|
|
+ jsonBody.put("content", encryptedText);
|
|
|
|
|
+
|
|
|
|
|
+ String result = HttpRequest.post(url)
|
|
|
|
|
+ .body(jsonBody.toString())
|
|
|
|
|
+ .execute()
|
|
|
|
|
+ .body();
|
|
|
|
|
+ //解析返回
|
|
|
|
|
+ AjaxResult ajaxResult = JSONUtil.toBean(result, AjaxResult.class);
|
|
|
|
|
+
|
|
|
|
|
+ //取值返回参数
|
|
|
|
|
+ Object codeValue = ajaxResult.get(CODE_TAG);
|
|
|
|
|
+ Object dataValue = ajaxResult.get(DATA_TAG);
|
|
|
|
|
+
|
|
|
|
|
+ //判断是否成功
|
|
|
|
|
+ if ("200".equals(String.valueOf(codeValue))) {
|
|
|
|
|
+ text = String.valueOf(dataValue);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ log.error("请求失败,状态码: " + codeValue);
|
|
|
|
|
+ return "";
|
|
|
}
|
|
}
|
|
|
- return lastFourNumber;
|
|
|
|
|
|
|
+
|
|
|
|
|
+ return text;
|
|
|
|
|
+ } catch (HttpException e) {
|
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 加密
|
|
|
|
|
+ */
|
|
|
|
|
+ public static String encryptPhone(String text) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ String encryptedText=null;
|
|
|
|
|
+ String url= "http://42.194.147.226:8000/app/common/genEncryption";
|
|
|
|
|
+ // 构建请求体 JSON
|
|
|
|
|
+ JSONObject jsonBody = new JSONObject();
|
|
|
|
|
+ jsonBody.put("content", text);
|
|
|
|
|
+
|
|
|
|
|
+ String result = HttpRequest.post(url)
|
|
|
|
|
+ .body(jsonBody.toString())
|
|
|
|
|
+ .execute()
|
|
|
|
|
+ .body();
|
|
|
|
|
+ //解析返回
|
|
|
|
|
+ AjaxResult ajaxResult = JSONUtil.toBean(result, AjaxResult.class);
|
|
|
|
|
+
|
|
|
|
|
+ //取值返回参数
|
|
|
|
|
+ Object codeValue = ajaxResult.get(CODE_TAG);
|
|
|
|
|
+ Object dataValue = ajaxResult.get(DATA_TAG);
|
|
|
|
|
+
|
|
|
|
|
+ //判断是否成功
|
|
|
|
|
+ if ("200".equals(String.valueOf(codeValue))) {
|
|
|
|
|
+ encryptedText = String.valueOf(dataValue);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ log.error("请求失败,状态码: " + codeValue);
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return encryptedText;
|
|
|
|
|
+ } catch (HttpException e) {
|
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 是否为11位明文手机号(纯数字)
|
|
|
|
|
+ */
|
|
|
|
|
+ public static boolean isPlainMobile11(String phone) {
|
|
|
|
|
+ return StrUtil.isNotBlank(phone) && phone.matches("^1\\d{10}$");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 是否为脱敏展示格式(如 177****5248)
|
|
|
|
|
+ */
|
|
|
|
|
+ public static boolean isMaskedPhone(String phone) {
|
|
|
|
|
+ return StrUtil.isNotBlank(phone) && phone.contains("****");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 解析为11位明文:已是明文直接返回;密文则解密;脱敏格式返回 null(需业务侧先解析)
|
|
|
|
|
+ */
|
|
|
|
|
+ public static String resolveToPlainPhone(String phone) {
|
|
|
|
|
+ if (StrUtil.isBlank(phone)) {
|
|
|
|
|
+ return phone;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isPlainMobile11(phone)) {
|
|
|
|
|
+ return phone;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isMaskedPhone(phone)) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ return tryDecryptToPlain(phone);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将库中/用户表中的手机号转为脱敏格式,用于与前端传入的脱敏号比对
|
|
|
|
|
+ */
|
|
|
|
|
+ public static String toMaskedPhone(String phone) {
|
|
|
|
|
+ if (StrUtil.isBlank(phone)) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isMaskedPhone(phone)) {
|
|
|
|
|
+ return phone;
|
|
|
|
|
+ }
|
|
|
|
|
+ String plain = resolveToPlainPhone(phone);
|
|
|
|
|
+ if (isPlainMobile11(plain)) {
|
|
|
|
|
+ return ParseUtils.parsePhone(plain);
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 入库前统一处理:明文/外部密文 → 统一加密接口密文
|
|
|
|
|
+ */
|
|
|
|
|
+ public static String normalizePhoneForStorage(String phone) {
|
|
|
|
|
+ if (StrUtil.isBlank(phone)) {
|
|
|
|
|
+ return phone;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isMaskedPhone(phone)) {
|
|
|
|
|
+ log.warn("入库前仍为脱敏手机号,请先解析为明文: {}", phone);
|
|
|
|
|
+ return phone;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isPlainMobile11(phone)) {
|
|
|
|
|
+ return encryptPlainOrKeep(phone);
|
|
|
|
|
+ }
|
|
|
|
|
+ String plain = tryDecryptToPlain(phone);
|
|
|
|
|
+ if (isPlainMobile11(plain)) {
|
|
|
|
|
+ return encryptPlainOrKeep(plain);
|
|
|
|
|
+ }
|
|
|
|
|
+ return phone;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 无权限查看时:先解为明文再脱敏展示
|
|
|
|
|
+ */
|
|
|
|
|
+ public static String normalizePhoneForDisplay(String phone) {
|
|
|
|
|
+ if (StrUtil.isBlank(phone)) {
|
|
|
|
|
+ return phone;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isMaskedPhone(phone)) {
|
|
|
|
|
+ return phone;
|
|
|
|
|
+ }
|
|
|
|
|
+ String plain = resolveToPlainPhone(phone);
|
|
|
|
|
+ if (isPlainMobile11(plain)) {
|
|
|
|
|
+ return ParseUtils.parsePhone(plain);
|
|
|
|
|
+ }
|
|
|
|
|
+ return ParseUtils.parsePhone(phone);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * ERP 上传用手机号:仅明文直传,其余解密为明文
|
|
|
|
|
+ */
|
|
|
|
|
+ public static String resolvePhoneForErp(String phone) {
|
|
|
|
|
+ if (StrUtil.isBlank(phone)) {
|
|
|
|
|
+ return phone;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isPlainMobile11(phone)) {
|
|
|
|
|
+ return phone;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isMaskedPhone(phone)) {
|
|
|
|
|
+ log.warn("ERP上传遇到脱敏手机号: {}", phone);
|
|
|
|
|
+ return phone;
|
|
|
|
|
+ }
|
|
|
|
|
+ String plain = tryDecryptToPlain(phone);
|
|
|
|
|
+ return StrUtil.isNotBlank(plain) ? plain : phone;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 从 ErpOrder 取收件人手机号并解析为 ERP 可上传的明文
|
|
|
|
|
+ */
|
|
|
|
|
+ public static String resolveErpOrderReceiverPhone(String receiverMobile, String receiverPhone) {
|
|
|
|
|
+ if (StrUtil.isNotBlank(receiverMobile)) {
|
|
|
|
|
+ return resolvePhoneForErp(receiverMobile);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (StrUtil.isNotBlank(receiverPhone)) {
|
|
|
|
|
+ return resolvePhoneForErp(receiverPhone);
|
|
|
|
|
+ }
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 快递查询用手机号后四位(顺丰/中通等)
|
|
|
|
|
+ */
|
|
|
|
|
+ public static String getLastFourNum(String phone) {
|
|
|
|
|
+ if (StrUtil.isBlank(phone)) {
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+ String plain = resolveToPlainPhone(phone);
|
|
|
|
|
+ if (isPlainMobile11(plain)) {
|
|
|
|
|
+ return plain.substring(plain.length() - 4);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isMaskedPhone(phone) && phone.length() >= 4) {
|
|
|
|
|
+ return phone.substring(phone.length() - 4);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (phone.length() >= 4) {
|
|
|
|
|
+ return phone.substring(phone.length() - 4);
|
|
|
|
|
+ }
|
|
|
|
|
+ return phone;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static String tryDecryptToPlain(String phone) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ String decrypted = decryptPhone(phone);
|
|
|
|
|
+ return isPlainMobile11(decrypted) ? decrypted : "";
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("手机号解密失败", e);
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static String encryptPlainOrKeep(String plain) {
|
|
|
|
|
+ try {
|
|
|
|
|
+// return plain;
|
|
|
|
|
+ String encrypted = encryptPhone(plain);
|
|
|
|
|
+ return StrUtil.isNotBlank(encrypted) ? encrypted : plain;
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("手机号加密失败", e);
|
|
|
|
|
+ return plain;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|