常用工具类

19 阅读19分钟

常用工具类总结

HTTP Client工具类

public class HttpClientUtil {
    /**
     * 证书工厂算法
     */
    static String                                                      ALGORITHM            = "SunX509";

    protected final static Logger                                      ERROR_LOGGER         = LoggerFactory
        .getLogger(LogbackConfig.GATEWAY_ERROR);

    /**
     * 读取超时时间
     */
    private static final int                                           READ_TIMEOUT         = 20000;

    private static final int                                           CONNECT_TIMEOUT      = 10000;

    /**
     * 缓存HttpClient
     * key:域名
     * value:HttpClient
     */
    private static final Map<String, CloseableHttpClient>              HTTP_CLIENT_CACHE    = new ConcurrentHashMap<>();


    public static final Map<String, Function<String, HttpRequestBase>> HTTP_REQUEST_CREATOR = new HashMap<>();

    static {
        HTTP_REQUEST_CREATOR.put(HttpPost.METHOD_NAME, HttpPost::new);
        HTTP_REQUEST_CREATOR.put(HttpGet.METHOD_NAME, HttpGet::new);
        HTTP_REQUEST_CREATOR.put(HttpPut.METHOD_NAME, HttpPut::new);
        HTTP_REQUEST_CREATOR.put(HttpPatch.METHOD_NAME, HttpPatch::new);
    }

    // public static void main(String[] args) throws Exception {
    //     long startTime = System.currentTimeMillis();
    //     SSLContext sslContext = createSSLContext("TLSv1.2",
    //             "/Library/Java/JavaVirtualMachines/jdk-21.jdk/Contents/Home/lib/security/certificate.crt");
    //     HttpClientConnectionManager connectionManager = createHttpClientConnectionManager(
    //             sslContext, 200, 10000);
    //     CloseableHttpClient httpClient = createHttpClient(connectionManager, 200, 10000, 2000);
    //     System.out
    //             .println("Time createHttpClient: " + (System.currentTimeMillis() - startTime) + "ms");
    //     Map<String, String> headers = new HashMap<>();
    //     headers.put("Content-Type", "application/json");
    //     headers.put("client-id", "305Y955W2Y58SM01051");
    //     Map<String, String> params = new HashMap<>();
    //     params.put("client-id", "305Y955W2Y58SM01051");
    //     execute(httpClient, "https://open-sea.alipayplus.com/aps/api/transfer/inquiryQuote",
    //             HttpPost.METHOD_NAME, headers, params, "XSTTT", "UTF-8", "UTF-8", 10000, 2000);
    // }

    protected static void execute(CloseableHttpClient httpClient, String url, String httpMethod,
                                  Map<String, String> headers, Map<String, String> params,
                                  String body, String requestCharset, String responseCharset,
                                  int readTimeout, int connectTimeout) {
        HttpRequestBase httpRequestBase = createHttpMethod(httpMethod, url, readTimeout,
            connectTimeout);
        constructParams(httpRequestBase, headers, params, body, requestCharset, MediaType.APPLICATION_JSON_VALUE);
        // 使用try-with-resources来确保资源的自动关闭
        try (CloseableHttpResponse httpResponse = httpClient.execute(httpRequestBase)) {
//            int statusCode = httpResponse.getStatusLine().getStatusCode();
            // 读取并打印响应体
            try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(httpResponse.getEntity().getContent(), responseCharset))) {
                StringBuilder stringBuilder = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    stringBuilder.append(line);
                }
                System.out.println("Response Body: " + stringBuilder.toString());
            } catch (IOException e) {
                System.err.println("Error reading response body: " + e.getMessage());
            }
        } catch (IOException e) {
            System.err.println("Request failed: " + e.getMessage());
        }
    }


    /**
     * 根据域名 domain 获取HttpClient
     * @param domainConfig
     * @return
     */
    public static CloseableHttpClient getHttpClient(GwDomainConfig domainConfig, GwCertConfig gwCertConfig) {
        return HTTP_CLIENT_CACHE.computeIfAbsent(domainConfig.getDomain(), key -> {
            try {
                int readTimeout = Optional.ofNullable(domainConfig.getReadTimeOut()).map(Integer::parseInt).orElse(READ_TIMEOUT);
                int connectTimeout = Optional.ofNullable(domainConfig.getConnectTimeOut()).map(Integer::parseInt).orElse(CONNECT_TIMEOUT);
                SSLContext sslContext = HttpClientUtil.createSSLContext(domainConfig.getSslProtocol(), gwCertConfig);
                HttpClientConnectionManager connectionManager = HttpClientUtil.createHttpClientConnectionManager(sslContext,
                        domainConfig.getSinglePoolLimit(), readTimeout);
                return HttpClientUtil.createHttpClient(connectionManager, domainConfig.getSinglePoolLimit(), readTimeout, connectTimeout);
            } catch (Exception e) {
                ERROR_LOGGER.error(MessageFormat.format("create http client for domain [{0}]", domainConfig.getDomain()), e);
                return null;
            }
        });
    }

    public static CloseableHttpClient createHttpClient(HttpClientConnectionManager manager,
                                                       int maxTotal, int readTimeout,
                                                       int connectTimeout) {
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        httpClientBuilder.setConnectionManager(manager);
        RequestConfig requestConfig = RequestConfig.custom()
            .setConnectionRequestTimeout(connectTimeout).setConnectTimeout(readTimeout)
            .setSocketTimeout(readTimeout).build();
        httpClientBuilder.setDefaultRequestConfig(requestConfig);
        HttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler(0, false);
        httpClientBuilder.setRetryHandler(retryHandler);
        httpClientBuilder.setMaxConnTotal(maxTotal);
        return httpClientBuilder.build();
    }

    /**
     * 根据本地cert文件和协议创建SSLContext
     *
     * @param protocol
     * @param fileName
     * @return
     * @throws Exception
     */
    public static SSLContext createSSLContext(String protocol, String fileName) throws Exception {
        X509TrustManager customTrustManager = (X509TrustManager) createCustomTrustManager(fileName);
        X509TrustManager defaultTrustManagerInner = (X509TrustManager) createDefaultTrustManagerInner();
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return ArrayUtils.addAll(customTrustManager.getAcceptedIssuers(),
                    defaultTrustManagerInner.getAcceptedIssuers());
            }

            public void checkClientTrusted(X509Certificate[] certs, String authType) {
            }

            public void checkServerTrusted(X509Certificate[] certs,
                                           String authType) throws CertificateException {

                if (customTrustManager != null) {
                    try {
                        // 先使用自定义的
                        customTrustManager.checkServerTrusted(certs, authType);
                    } catch (CertificateException e) {
                        // 如果自定义的检验失败,使用默认的
                        if (defaultTrustManagerInner != null) {
                            defaultTrustManagerInner.checkServerTrusted(certs, authType);
                        }
                    }
                } else if (defaultTrustManagerInner != null) {
                    defaultTrustManagerInner.checkServerTrusted(certs, authType);
                }
            }
        } };
        // 初始化SSLContext以使用自定义的TrustManager
        SSLContext sslContext = SSLContext.getInstance(protocol);
        sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
        return sslContext;
    }

    /**
     * 根据 protocol 以及 gwConfig 创建SSLContext
     * @param protocol
     * @param gwCertConfig
     * @return
     */
    public static SSLContext createSSLContext(String protocol,
                                              GwCertConfig gwCertConfig) throws Exception {
        X509TrustManager customTrustManager = (X509TrustManager) createCustomTrustManagerByCertConfig(
            gwCertConfig);
        X509TrustManager defaultManager = (X509TrustManager) createDefaultTrustManagerInner();

        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return ArrayUtils.addAll(
                    customTrustManager != null ? customTrustManager.getAcceptedIssuers()
                        : new X509Certificate[0],
                    defaultManager != null ? defaultManager.getAcceptedIssuers()
                        : new X509Certificate[0]);
            }

            public void checkClientTrusted(X509Certificate[] chain, String authType) {
                // 客户端证书验证逻辑(可选)
            }

            public void checkServerTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
                if (customTrustManager != null) {
                    try {
                        customTrustManager.checkServerTrusted(chain, authType);
                    } catch (CertificateException e) {
                        if (defaultManager != null) {
                            defaultManager.checkServerTrusted(chain, authType);
                        } else {
                            throw e;
                        }
                    }
                } else if (defaultManager != null) {
                    defaultManager.checkServerTrusted(chain, authType);
                }
            }
        } };
        SSLContext sslContext = SSLContext.getInstance(protocol);
        sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
        return sslContext;
    }

    /**
     * 根据 gwCertConfig 创建TrustManager
     * @param gwCertConfig
     * @return
     */
    private static TrustManager createCustomTrustManagerByCertConfig(GwCertConfig gwCertConfig) {
        if (gwCertConfig == null || gwCertConfig.getCertStoreValue() == null) {
            return null;
        }
        switch (gwCertConfig.getCertStoreType()) {
            case DATABASE:
                return createCustomTrustManagerByDBCert(gwCertConfig.getCertStoreValue(),
                    gwCertConfig.getCertAlias());
            case GCP_KMS:
                return createCustomTrustManagerByGCPSecret(gwCertConfig);
            default:
                return null;
        }
    }

    /**
     * 从 gcp_kms中获取证书并创建自定义TrustManager
     * @param gwCertConfig
     * @return
     */
    private static TrustManager createCustomTrustManagerByGCPSecret(GwCertConfig gwCertConfig) {
        return null;
    }

    /**
     * 根据 certContent 创建TrustManager
     * @param certContent
     * @param certAlias
     * @return
     */
    private static TrustManager createCustomTrustManagerByDBCert(String certContent,
                                                                 String certAlias) {
        try {

            // 1. 将字符串转换为字节数组(certStoreValue 是 PEM 格式)
            byte[] certBytes = certContent.getBytes(StandardCharsets.UTF_8);

            // 2. 使用 ByteArrayInputStream 模拟文件输入流
            Certificate certificate = CertificateFactory.getInstance("X.509")
                .generateCertificate(new ByteArrayInputStream(certBytes));

            // 3. 创建 KeyStore 并添加证书
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null, null);
            keyStore.setCertificateEntry(certAlias, certificate);

            // 4. 创建 TrustManagerFactory 并使用自定义证书初始化
            TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(ALGORITHM);
            trustFactory.init(keyStore);

            // 5. 返回 TrustManager
            return trustFactory.getTrustManagers()[0];
        } catch (Exception e) {
            ERROR_LOGGER.error("createCustomTrustManagerByDBCert error, certAlias:{}", certAlias, e);
            return null;
        }
    }

    public static HttpClientConnectionManager createHttpClientConnectionManager(SSLContext sslContext,
                                                                                int maxTotal,
                                                                                int readTimeout) {
        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
            sslContext, new DefaultHostnameVerifier());
        RegistryBuilder<ConnectionSocketFactory> registryBuilder = createRegistryBuilderBySSLConnectionSocketFactory(
            sslConnectionSocketFactory);
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(
            registryBuilder.build());
        // 连接最大线程数
        connectionManager.setMaxTotal(maxTotal);
        // 设置每个路由的默认最大连接数
        connectionManager.setDefaultMaxPerRoute(maxTotal);
        SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(readTimeout).build();
        connectionManager.setDefaultSocketConfig(socketConfig);
        return connectionManager;
    }

    public static HttpRequestBase createHttpMethod(String httpReqType, String requestUrl,
                                                   int readTimeout, int connectTimeout) {
        Function<String, HttpRequestBase> requestBaseFunction = HTTP_REQUEST_CREATOR
            .get(StringUtils.upperCase(httpReqType));

        HttpRequestBase httpRequestBase = requestBaseFunction.apply(requestUrl);

        // 动态设置传输超时时间(优先使用接口实例上的超时时间,否则用通讯点上的超时时间)
        RequestConfig.Builder requestConfigBuilder = RequestConfig.custom()
            .setCookieSpec(CookieSpecs.IGNORE_COOKIES).setConnectTimeout(connectTimeout)
            .setConnectionRequestTimeout(connectTimeout).setSocketTimeout(readTimeout);
        httpRequestBase.setConfig(requestConfigBuilder.build());
        return httpRequestBase;
    }

    public static void constructParams(HttpRequestBase httpMethod, Map<String, String> headers,
                                       Map<String, String> params, String content,
                                       String requestCharset, String contentType) {
        addRequestHeader(headers, httpMethod);
        addParameter(httpMethod, params, requestCharset);
        // 只有POST请求才添加报文正文
        if (httpMethod instanceof HttpEntityEnclosingRequestBase) {
            addContent(content, (HttpEntityEnclosingRequestBase) httpMethod, requestCharset, contentType);
        }
    }

    /**
     * 添加请求参数,对post,添加到parameter中(form表单),对于其他,直接添加到queryString
     *
     * @param method
     */
    public static void addParameter(HttpRequestBase method, Map<String, String> params,
                                    String requestCharset) {
        if (CollectionUtils.isEmpty(params)) {
            return;
        }
        // 对于支持
        List<NameValuePair> valuePairs = new ArrayList<>(params.size());
        for (Map.Entry<String, String> entry : params.entrySet()) {
            NameValuePair nameValuePair = new BasicNameValuePair(entry.getKey(),
                String.valueOf(entry.getValue()));
            valuePairs.add(nameValuePair);
        }
        HttpEntity formEntity;
        try {
            formEntity = new NoUrlEncodedFormEntity(valuePairs, Charset.forName(requestCharset));
            AtomicBoolean hasQuery = new AtomicBoolean(
                StringUtils.isNotEmpty(method.getURI().getQuery()));
            StringBuilder fullUrlBuilder = new StringBuilder(method.getURI().toString());
            String param = EntityUtils.toString(formEntity, Charset.forName("UTF-8"));
            //build get uri with params
            fullUrlBuilder.append(hasQuery.get() ? "&" : "?").append(param);
            hasQuery.set(true);
            method.setURI(new URI(fullUrlBuilder.toString()));
        } catch (Exception e) {
        }
    }

    public static void addRequestHeader(Map<String, String> headers, HttpRequestBase method) {
        if (CollectionUtils.isEmpty(headers)) {
            return;
        }

        Set<Map.Entry<String, String>> entries = headers.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            method.addHeader(entry.getKey(), entry.getValue());
        }

    }

    /**
     * 添加请求内容
     *
     * @param content
     * @param method
     * @param contentType
     */
    public static void addContent(String content, HttpEntityEnclosingRequestBase method,
                                  String requestCharset, String contentType) {
        if (StringUtils.isBlank(content)) {
            return;
        }
        // 根据请求体 contentType,构造请求体并将其封装到HttpEntityEnclosingRequestBase中
        try {
            switch (contentType) {
                case MediaType.APPLICATION_JSON_VALUE:
                    StringEntity jsonEntity = new StringEntity(content, Charset.forName(requestCharset));
                    jsonEntity.setContentType(MediaType.APPLICATION_JSON_VALUE);
                    method.setEntity(jsonEntity);
                    break;
                case MediaType.APPLICATION_FORM_URLENCODED_VALUE:
                    Map<String, Object> paramMap = JSON.parseObject(content,
                            new TypeReference<Map<String, Object>>(){});

                    List<NameValuePair> formParams = new ArrayList<>();
                    for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
                        if (entry.getValue() != null) {
                            formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
                        }
                    }
                    HttpEntity formEntity = new org.apache.http.client.entity.UrlEncodedFormEntity(
                            formParams, Charset.forName(requestCharset));
                    method.setEntity(formEntity);
                    break;
                default:
                    // 默认情况下,将内容作为纯文本处理
                    StringEntity defaultEntity = new StringEntity(content, Charset.forName(requestCharset));
                    method.setEntity(defaultEntity);
                    break;
            }
        } catch (Exception e) {
            ERROR_LOGGER.error("Error adding content to request body, contentType: {}", contentType, e);
            throw new IorpCommonException(IorpCommonResultCodeEnum.UNKNOWN_EXCEPTION, "Error adding content to request body");
        }
    }

    /**
     * createRegistryBuilder
     * @param socketFactory
     * @return
     */
    private static RegistryBuilder<ConnectionSocketFactory> createRegistryBuilderBySSLConnectionSocketFactory(SSLConnectionSocketFactory socketFactory) {
        RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder
            .<ConnectionSocketFactory> create()
            .register("http", PlainConnectionSocketFactory.INSTANCE)
            .register("https", socketFactory);
        return registryBuilder;
    }

    private static TrustManager createDefaultTrustManagerInner() {
        TrustManagerFactory defaultTrustFactory = null;
        try {
            defaultTrustFactory = TrustManagerFactory.getInstance(ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
        try {
            defaultTrustFactory.init((KeyStore) null);
        } catch (KeyStoreException e) {
            throw new RuntimeException(e);
        }
        return defaultTrustFactory.getTrustManagers()[0];
    }

    private static TrustManager createCustomTrustManager(String fileName) {
        if (StringUtils.isBlank(fileName))
            return null;
        try {
            // 加载自签名证书
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            FileInputStream fis = new FileInputStream(fileName);
            X509Certificate cert = (X509Certificate) cf.generateCertificate(fis);
            fis.close();
            // 创建一个 KeyStore 并添加证书
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null, null);
            keyStore.setCertificateEntry("mycert", cert);
            // 创建自定义的trustManager
            TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(ALGORITHM);
            trustFactory.init(keyStore);
            return trustFactory.getTrustManagers()[0];
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

JSON 工具类

public class JSONUtil extends JSON {
    private static final String            NEST_JSON_SPLIT                    = ">";
    private static final String            ARRAY_MARK                         = "[]";
    private static final String            EMPTY_STRING                       = "";
    private static final SerializeFilter[] emptyObjectAndBigDecimalAndNoneStringValueFilters;
    private static final SerializeFilter[] emptyObjectAndNoneStringValueFilters;
    private static final SerializeFilter   noneObjectFilters;
    private static final SerializeFilter   bigDecimalToDoubleFilters;
    private static final SerializeFilter   nonStringValueToStringFilters;

    // 过滤value为空string的json
    private static final SerializeFilter   emptyStringFilters;
    private static final SerializeFilter[] emptyStringSerializeFilters;

    // fastjson autotype白名单
    private static final String            FASTJSON_AUTOTYPE_ALIPAY_WHITELIST = "com.alipay.";
    private static final String            FASTJSON_AUTOTYPE_IPAY_WHITELIST   = "com.ipay.";

    // 方括号包含.的正则,防止['a.b']被getValueByPath分割
    public static final Pattern            PATTER_BRACKETS_CONTAIN_DOT        = Pattern
        .compile("^.*((\\[)+.*(\\.)+.*(\\])+)+.*$");
    public static final Pattern            START_WITH_NUMBER                  = Pattern
        .compile("^[0-9]+.*$");

    protected final static Logger          ERROR_LOGGER                       = LoggerFactory
        .getLogger(LogbackConfig.GATEWAY_ERROR);

    static {
        JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();
        JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.MapSortField.getMask();
        // 为了安全性,fastjson限制了autotype功能,所以自动反序列化会被禁止,需要加白名单:https://github.com/alibaba/fastjson/wiki/enable_autotype

        ParserConfig.getGlobalInstance().addAccept(FASTJSON_AUTOTYPE_ALIPAY_WHITELIST);
        ParserConfig.getGlobalInstance().addAccept(FASTJSON_AUTOTYPE_IPAY_WHITELIST);

        // 过滤器一: 过滤空对象
        noneObjectFilters = (PropertyFilter) (object, name,
                                              value) -> null != value
                                                        && (!(value instanceof JSONArray)
                                                            || !((JSONArray) value).isEmpty())
                                                        && (!(value instanceof JSONObject)
                                                            || !((JSONObject) value).isEmpty());

        // 过滤器二: 将BigDecimal转为Double,原因是兼容老网关代码
        bigDecimalToDoubleFilters = (ValueFilter) (object, name, value) -> {
            if ((value instanceof BigDecimal)) {
                return ((BigDecimal) value).doubleValue();
            }
            return value;
        };

        // 过滤器三: 将非string类型转为string
        nonStringValueToStringFilters = (ValueFilter) (object, name, value) -> {
            if ((null != value) && (value instanceof Number || value instanceof Boolean)) {
                return value.toString();
            }
            return value;
        };

        // 过滤器四: 过滤空值并自动替换为闭合,注意仅提供给xml场景使用
        emptyStringFilters = (ValueFilter) (object, name, value) -> {
            if (null != value && value instanceof String) {
                if (StringUtils.isNotBlank((String) value)) {
                    return value.toString();
                } else if (StringUtils.isEmpty((String) value) && object instanceof JSONObject) {
                    ((JSONObject) object).remove(name);
                    JSONObject jsonObject = (JSONObject) JSON.parse("{\"-self-closing\":\"true\"}");
                    ((JSONObject) object).put(name, jsonObject);
                    return jsonObject;
                }
            }

            return value;

        };

        // 过滤链:过滤空对象和bigdecimal到double和非string字段值到string
        emptyObjectAndBigDecimalAndNoneStringValueFilters = new SerializeFilter[3];
        emptyObjectAndBigDecimalAndNoneStringValueFilters[0] = noneObjectFilters;
        emptyObjectAndBigDecimalAndNoneStringValueFilters[1] = bigDecimalToDoubleFilters;
        emptyObjectAndBigDecimalAndNoneStringValueFilters[2] = nonStringValueToStringFilters;

        emptyStringSerializeFilters = new SerializeFilter[1];
        emptyStringSerializeFilters[0] = emptyStringFilters;

        emptyObjectAndNoneStringValueFilters = new SerializeFilter[1];
        emptyObjectAndNoneStringValueFilters[0] = nonStringValueToStringFilters;

    }

    /**
     * 空实现,在启动后调用,可以初始化JSON上面的很多全局变量
     */
    public static void init() {
    }

    /**
     * 获取json对象上指定路径的值,支持嵌套json
     *
     * rootObject= {"1a":"{\"b\":\"{\\\"c\\\":12}\"}"}
     * path = 1a>b>c
     * =>
     * result = 12
     *
     * @param rootObject 根对象
     * @param path 路径,如果有嵌套的json,用" ",比如 "1a>b>c"
     * @return 结果
     */
    public static Object getValueByPath(Object rootObject, String path) {
        try {
            List<String> split = Splitter.on(NEST_JSON_SPLIT).trimResults().omitEmptyStrings()
                .splitToList(path.replaceAll("\\.", NEST_JSON_SPLIT));
            Object eval = null;
            int lastIndex = split.size() - 1;
            for (int i = 0; i < split.size(); i++) {
                String s = split.get(i);
                eval = JSONPath.eval(rootObject, s);
                if (eval == null) {
                    return null;
                }
                if (i < lastIndex) {
                    if (eval instanceof String) {
                        rootObject = JSONUtil.parseJSONObjectWithExceptionNull((String) eval);
                        if (null == rootObject) {
                            return null;
                        }
                    } else {
                        rootObject = JSON.toJSON(eval);
                    }
                } else if (i == lastIndex && path.endsWith(NEST_JSON_SPLIT)
                           && eval instanceof String) {
                    eval = JSON.parse((String) eval);
                }
            }
            return eval;
        } catch (Exception e) {
            //LogUtil.warn(loggerWarn, e,"getValueByPath fail, path=", path);

            return null;
        }
    }

    /**
     * 获取对象的时候进行深度copy
     * @param rootObject
     * @param path
     * @return
     */
    public static Object deepCloneGetValueByPath(Object rootObject, String path) {
        return getValueByPath(rootObject, path);
    }

    /**
     * 反序列化text,且不改变里面的字段顺序
     * @param text
     * @return
     */
    public static JSONObject parseObjectOrder(String text) {
        return JSON.parseObject(text, Feature.OrderedField);
    }

    /**
     * fastjson 深拷贝对象
     * @param object
     * @return
     */
    public static Object deepCloneObject(Object object) {
        if (null == object) {
            return null;
        }
        return JSON.parse(JSON.toJSONString(object, SerializerFeature.WriteClassName),
            Feature.OrderedField);
    }

    /**
     * 设置值到json对象,支持嵌套json
     * rootObject = {}
     * path = 1a>b>c
     * value = 12
     * =>
     * rootObject = {"1a":"{\"b\":\"{\\\"c\\\":12}\"}"}
     *
     * @param rootObject 根JSON对象
     * @param path 路径,如果有嵌套的json,用">",比如 "1a>b>c"
     * @param value 要设置的值
     */
    public static void setValueByPath(Object rootObject, String path, Object value) {
        if (rootObject == null || StringUtils.isBlank(path)) {
            return;
        }
        if (!StringUtils.contains(path, NEST_JSON_SPLIT)) {
            try {
                setValue(rootObject, path, value);
            } catch (Exception e) {
                ERROR_LOGGER.warn("rootObject={},path={},value={}", rootObject, path, value, e);
            }
            return;
        }
        String[] paths = path.split(NEST_JSON_SPLIT, 2);
        String firstPath = paths[0];
        Object eval = JSONPath.eval(rootObject, firstPath);
        if (eval == null) {
            eval = new JSONObject();
        } else {
            eval = JSON.parse(eval.toString());
        }
        String subPath = paths[1];
        if (StringUtils.isBlank(subPath)) {
            setValue(rootObject, firstPath, JSON.toJSONString(value));
        } else {
            setValueByPath(eval, subPath, value);
            setValue(rootObject, firstPath, JSON.toJSONString(eval));
        }
    }

    public static void setValue(Object rootObject, String path, Object value) {
        if (value != null) {
            JSONPath.set(rootObject, path, value);
        }
    }

    public static void map(Object source, Object dest, String sourcePath, String destPath) {
        map(source, dest, sourcePath, destPath, a -> a);
    }

    /**
     * 将源对象的属性设置到目标对象的属性,支持list
     *
     * @param source     源对象
     * @param dest       目标对象
     * @param sourcePath 源路径
     * @param destPath   目标路径
     */
    public static void map(Object source, Object dest, String sourcePath, String destPath,
                           Function<Object, Object> function) {
        map(source, dest, sourcePath, null, destPath, function, false);
    }

    /**
     * 将源对象的属性设置到目标对象的属性,支持list
     * 且支持多个输入的复杂mapping,目前主要用于mapArray表达式
     * @param source
     * @param dest
     * @param sourcePath
     * @param sourcePathMap
     * @param destPath
     * @param function
     */
    public static void map(Object source, Object dest, String sourcePath,
                           Map<String, String> sourcePathMap, String destPath,
                           Function<Object, Object> function) {
        map(source, dest, sourcePath, sourcePathMap, destPath, function, true);
    }

    /**
     * mapping父类
     * @param source
     * @param dest
     * @param sourcePath
     * @param sourcePathMap
     * @param destPath
     * @param function
     * @param multiInputMapping
     */
    public static void map(Object source, Object dest, String sourcePath,
                           Map<String, String> sourcePathMap, String destPath,
                           Function<Object, Object> function, boolean multiInputMapping) {
        try {
            // multiInputMapping场景下sourcePathMap不能为空,但是sourcePath可能为空
            if (source == null || dest == null
                || (CollectionUtils.isEmpty(sourcePathMap) && multiInputMapping)
                || StringUtils.isBlank(destPath)
                || (StringUtils.isBlank(sourcePath) && !multiInputMapping)) {
                return;
            }
            if (!sourcePath.contains(ARRAY_MARK)) {
                Object sourceParameter = getMappingFunctionInputParameter(source, sourcePath,
                    sourcePathMap, multiInputMapping);
                JSONUtil.setValueByPath(dest, destPath, function.apply(sourceParameter));
                return;
            }
            String sourcePath1 = StringUtils.substringBefore(sourcePath, "[]");
            String sourcePath2 = StringUtils.substringAfter(sourcePath, "[]");
            String destPath1 = StringUtils.substringBefore(destPath, "[]");
            String destPath2 = StringUtils.substringAfter(destPath, "[]");
            JSONArray sourceArray = (JSONArray) JSONUtil.deepCloneGetValueByPath(source,
                sourcePath1);
            if (sourceArray == null) {
                return;
            }
            JSONArray destArray = new JSONArray();
            for (int i = 0; i < sourceArray.size(); i++) {
                Object dest1 = JSONUtil.getValueByPath(dest, destPath1 + "[" + i + "]");
                if (dest1 == null) {
                    dest1 = new JSONObject();
                }
                destArray.add(i, dest1);
                map(sourceArray.get(i), dest1, sourcePath2, sourcePathMap, destPath2, function,
                    multiInputMapping);
            }
            JSONUtil.setValueByPath(dest, destPath1, destArray);
        } catch (Exception e) {
            //LogUtil.warn(LOGGER, e, "map路径出错,源路径:", sourcePath, ",目的路径:", destPath);
            throw e;
        }
    }

    /**
     * 获取map的function mapping的入参
     * @param source
     * @param sourcePath
     * @param sourcePathMap
     * @param multiInputMapping
     * @return
     */
    private static Object getMappingFunctionInputParameter(Object source, String sourcePath,
                                                           Map<String, String> sourcePathMap,
                                                           boolean multiInputMapping) {
        Object sourceParameter;
        if (multiInputMapping) {
            sourceParameter = buildSourceValueMap(source, sourcePathMap);
        } else {
            sourceParameter = JSONUtil.deepCloneGetValueByPath(source, sourcePath);
        }
        return sourceParameter;
    }

    /**
     * 目前用在mapArray表达式中
     * @param source 源object
     * @param sourcePathMap: key:表达式占位符,value,路径
     * @return destValueMap: key:表达式占位符,value,值
     */
    private static Map<String, Object> buildSourceValueMap(Object source,
                                                           Map<String, String> sourcePathMap) {
        Map<String, Object> resultMap = new HashMap<>();
        sourcePathMap.forEach(
            (key, value) -> resultMap.put(key, JSONUtil.deepCloneGetValueByPath(source, value)));
        return resultMap;

    }

    /**
     * 如果不是json结构,返回原值
     *
     * @param jsonStr jsonStr
     * @return 是否为json
     */
    public static Object defaultIfNotJson(String jsonStr) {
        try {
            return JSON.parseObject(jsonStr);
        } catch (Exception e) {
            return jsonStr;
        }
    }

    /**
     * 对象序列化成json字符串,出现任何异常空字符串兜底
     *
     * @param obj
     * @return
     */
    public static String defaultIfToJSONStringFail(Object obj) {
        try {
            return JSON.toJSONString(obj);
        } catch (Throwable e) {
            return EMPTY_STRING;
        }
    }

    /**
     * @param json1 json1
     * @param json2 json2
     * @return 一致返回true, 不一致返回false
     * @function 比较两个JSONObject元素内容是否一致---忽略顺序
     */
    public static boolean isEquals(JSONObject json1, JSONObject json2) {
        if (json1 == null || json2 == null) {
            return ObjectUtil.equals(json1, json2);
        } else if (json1.size() != json2.size()) {
            return false;
        }
        boolean result = true;
        for (String key : json1.keySet()) {
            if (isJson(json1.getString(key))) {
                result = isEquals(json1.getJSONObject(key), json2.getJSONObject(key));
            } else {
                result = StringUtils.equals(json1.getString(key), json2.getString(key));
            }
            if (!result) {
                return false;
            }
        }

        return result;
    }

    /**
     * 是否为json结构
     *
     * @param jsonStr jsonStr
     * @return 是否为json
     */
    public static boolean isJson(String jsonStr) {
        try {
            if (StringUtils.isBlank(jsonStr)) {
                return false;
            }
            JSON.parseObject(jsonStr);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 将jsonStr转为json object,如果转换失败(比如格式不是json的),那么返回null
     * @param jsonStr
     * @return
     */
    public static JSONObject parseJSONObjectWithExceptionNull(String jsonStr) {
        try {
            if (StringUtils.isBlank(jsonStr)) {
                return null;
            } else {
                return JSON.parseObject(jsonStr);
            }
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取兼容JSONPath的path,如果key中包含-,则将key用'包起来
     * @param key
     * @return
     */
    public static String getJsonPath(String key) {
        if (StringUtils.contains(key, "-")) {
            return "['" + key + "']";
        }
        return key;
    }

    /**
     * 判断str是否是json path的特殊字符,包括
     * 1. 是数字开头,且没有用[]包起来
     * 2. 包含-,且没有使用\-转义,或者用[]包起来
     * @param str
     * @return
     */
    private static boolean containJsonPathSpecialChar(String str) {
        return (START_WITH_NUMBER.matcher(str).matches()
                || (StringUtils.contains(str, "-") && !StringUtils.contains(str, "\\-")))
               && !StringUtils.contains(str, "[");
    }

    /**
     * JSONPath在路径中有-或者一些特殊字符的场景,需要加上[]转义
     * 1. 当key有[]时,如rish[3],不进行转义
     * 2. 如果包含-,且不包含\-,不进行转义
     * 2. 在1之外,如果包含非AlphaSpace或者-,需要转义
     * @param key
     * @return
     */
    public static String getFullJsonPath(String key) {

        String result = Arrays.stream(StringUtils.split(key, ".")).map(str -> {
            if (containJsonPathSpecialChar(str)) {
                return "['" + str + "']";
            } else {
                return "." + str;
            }
        }).collect(Collectors.joining());
        if (result.startsWith(".")) {
            result = result.replaceFirst("\\.", "");
        }
        return result;
    }

    /**
     * 将json对象中的字段做过滤处理
     * 1. 过滤空对象
     * 2. 将BigDecimal对象转为Double对象,兼容isupergw老逻辑
     * 3. 将非string类型值转为string
     * @param jsonObject
     * @return
     */
    public static JSONObject filterEmptyJsonAndBigDecimalAndToStringValueField(JSONObject jsonObject,
                                                                               SerializerFeature... features) {
        // 添加过滤器转换对象
        return JSON.parseObject(JSON.toJSONString(jsonObject,
            emptyObjectAndBigDecimalAndNoneStringValueFilters, features));
    }

    public static JSONObject filterEmptyJsonAndToStringValueField(JSONObject jsonObject,
                                                                  SerializerFeature... features) {
        // 添加过滤器转换对象
        return JSON.parseObject(
            JSON.toJSONString(jsonObject, emptyObjectAndNoneStringValueFilters, features),
            Feature.OrderedField);
    }

    /**
     * 将json对象中的value为空string的过滤掉
     *
     * @param jsonObject jsonObject
     * @param features   features
     * @return 结果
     */
    public static JSONObject filterEmptyStringValueField(JSONObject jsonObject,
                                                         SerializerFeature... features) {
        // 添加过滤器转换对象
        return JSON.parseObject(
            JSON.toJSONString(jsonObject, emptyStringSerializeFilters, features),
            Feature.OrderedField);
    }

    public static String objToJsonString(Object object) {
        if (null == object || object instanceof String) {
            return (String) object;
        } else {
            return JSON.toJSONString(object);
        }
    }

    public static <T> T parseObject(String text, Class<T> clazz) {
        return JSON.parseObject(text, clazz);
    }

    /**
     * 使用Gson拍平json字符串,即当有多层json嵌套时,可以把多层的json拍平为一层
     */
    public static void parseJson2keySet(Set<String> allFullFields, String json, String parentKey) {
        JsonElement jsonElement = new JsonParser().parse(json);
        if (jsonElement.isJsonObject()) {
            JsonObject jsonObject = jsonElement.getAsJsonObject();
            parseJson2keySet(allFullFields, jsonObject, parentKey);
            //传入的还是一个json数组
        } else if (jsonElement.isJsonArray()) {
            JsonArray jsonArray = jsonElement.getAsJsonArray();
            for (JsonElement element : jsonArray) {
                parseJson2keySet(allFullFields, element.getAsJsonObject(), parentKey);
            }
        }
    }

    /**
     * 递归遍历JsonObject,找出所有叶子节点的全路径,加入 allFullFields set中.
     * 支持list类型的对象
     */
    public static void parseJson2keySet(Set<String> allFullFields, JsonObject jsonObject,
                                        String parentKey) {
        for (Map.Entry<String, JsonElement> object : jsonObject.entrySet()) {
            String key = object.getKey();
            JsonElement value = object.getValue();
            String fullKey = (null == parentKey || parentKey.trim().equals("")) ? key
                : parentKey.trim() + "." + key;
            if (value.isJsonNull() || value.isJsonPrimitive()) {
                //对象为空了就是叶子节点,直接加上.JSON基本类型同理
                //对于判断出是基本类型,但是实际是一个String 类型的JSONObjet场景则忽略,超网解析是强类型.对象就是对象,String就是String
                allFullFields.add(fullKey);
            } else if (value.isJsonObject()) {
                //如果是JsonObject对象则递归处理
                parseJson2keySet(allFullFields, value.getAsJsonObject(), fullKey);
            } else if (value.isJsonArray()) {
                //如果是JsonArray数组则迭代,然后进行递归
                JsonArray jsonArray = value.getAsJsonArray();
                for (JsonElement jsonElement1 : jsonArray) {
                    parseJson2keySet(allFullFields, jsonElement1.getAsJsonObject(), fullKey);
                }
            }
        }
    }

    public static String getLastPathKey(String fullPath) {
        String lastPath = fullPath;
        if (StringUtils.isNotBlank(fullPath)) {
            if (fullPath.endsWith("]")) {
                String lastParam = StringUtils.substringAfterLast(fullPath, "['");
                lastPath = StringUtils.substringBeforeLast(lastParam, "']");
            } else if (fullPath.contains(".")) {
                lastPath = StringUtils.substringAfterLast(fullPath, ".");
            }
        }
        return lastPath;
    }

    public static String objToStringWithMapNullValue(JSONObject jsonObject) {
        if (null == jsonObject) {
            return null;
        } else {
            return JSON.toJSONString(jsonObject, SerializerFeature.WriteMapNullValue);
        }
    }

    /**
     * 合并两个JSONObject对象
     */
    public static JSONObject merge(JSONObject jsonObject, JSONObject mergeJsonObject) {
        try {
            jsonObject.putAll(mergeJsonObject);
            return jsonObject;
        } catch (Exception e) {
            //            LogUtil.warn(loggerWarn, e,"An exception occurred when merge two jsonObject.jsonObject=",
            //                    jsonObject , ",mergeJsonObject=" ,mergeJsonObject);
            return null;
        }
    }

    /**
     * 返回简单json结构中特定路径下的值 如:
     * resutlInfo{
     *     resultCode:IPAY_RS_10020,
     *     resultStatus:S
     * }
     */
    public static String getStringBySimplePath(JSONObject jsonObject, String path) {
        Object value;
        try {
            value = JSONPath.eval(jsonObject, "$." + path);
            return value != null ? value.toString() : EMPTY_STRING;
        } catch (Exception e) {
            return EMPTY_STRING;
        }
    }

    /**
     * 将JSONObject对象转换为Map<String, Object>
     *
     * @param jsonObject
     * @return
     */
    public static Map<String, Object> convertToMap(JSONObject jsonObject) {
        Map<String, Object> map = new HashMap<>();
        for (String key : jsonObject.keySet()) {
            Object value = jsonObject.get(key);
            if (value instanceof JSONObject) {
                map.put(key, convertToMap((JSONObject) value)); // 递归处理嵌套对象
            } else {
                map.put(key, value);
            }
        }
        return map;
    }
}

日期工具


@Slf4j
public class DateUtils {

    /**
     * Date Format定义
     */
    public final static String  shortFormat            = "yyyyMMdd";
    public final static String  shortFormat2            = "yyMMdd";
    public final static String  longFormat             = "yyyyMMddHHmmss";
    public final static String  webFormat              = "yyyy-MM-dd";
    public final static String  webFormat2             = "yyyy/MM/dd";
    public final static String  webFormat3             = "yyyy/M/d";
    public final static String  webFormat4             = "yy/MM/dd";
    public final static String  timeFormat             = "HHmmss";
    public final static String  monthFormat            = "yyyyMM";
    public final static String  monthFormat2           = "M月";
    public final static String  chineseDtFormat        = "yyyy年MM月dd日";
    public final static String  chineseDtFormat2       = "yyyy年M月d日";
    public final static String  chineseDtFormat3       = "M月d日";

    public final static String  newFormat              = "yyyy-MM-dd HH:mm:ss";
    public final static String  noSecondFormat         = "yyyy-MM-dd HH:mm";

    public static final String  DATE_FORMAT_MMDD       = "MMdd";

    /**
     * 常量:UTC时区
     */
    public final static String  TZ_UTC                 = "UTC";
    /**
     * 常量:GMT8
     */
    public final static String  TZ_GMT8                = "GMT+08:00";

    /**
     * 常量:UTC9
     */
    public final static String  TZ_UTC9                = "UTC+9";
    /**
    * 常量:GMT9
    */
    public final static String  TZ_GMT9                = "GMT+09:00";

    /**
     * 缺省时间格式字符串<br>
     * <p>
     * 时间格式是:"年-月-日 时:分:秒.毫秒",比如: "2013-01-01 19:20:31.789"
     */
    public final static String  DEFAULT_DATE_FORMAT    = "yyyy-MM-dd HH:mm:ss.SSS";

    /**
     * 24小时制一天的秒数,毫秒数常量
     */
    public final static long    ONE_DAY_SECONDS        = 86400;
    public final static long    ONE_DAY_MILL_SECONDS   = 86400000;

    /**
     * 时区间隔符
     */
    private final static String TIMEZONE_INTERVAL      = "|";

    /**
     * ISO datetime最小长度,必须带有时区,可能还有微秒
     */
    private final static int    ISO_DATE_LENGTH        = 25;

    /**
     * UTC 0时区的ISO datetime最小长度,时区信息是字符Z,不是+00:00格式
     */
    private final static int    UTC_0_ISO_DATE_LENGTH  = 20;

    /**
     * UTC 0时区的timezone标识
     */
    private final static String UTC_0_TIMEZONE         = "Z";


    /**
     * 获取utc的ISO的时间字符串
     *
     * @param date 日期
     * @return ISO的时间字符串
     */
    public static String getUtcISODateTimeStr(Date date) {
        return getISODateTimeStr(date, TimeZone.getTimeZone(TZ_UTC));
    }

    /**
     * 获取北京时区的ISO的时间字符串
     *
     * @param date 日期
     * @return ISO的时间字符串
     */
    public static String getGMT8ISODateTimeStr(Date date) {
        return getISODateTimeStr(date, TimeZone.getTimeZone(TZ_GMT8));
    }

    /**
     * 获取指定时区的ISO的时间字符串
     *
     * @param date 日期
     * @param tz
     * @return ISO的时间字符串
     */
    public static String getISODateTimeStrWithTZ(Date date, String tz) {
        return getISODateTimeStr(date, TimeZone.getTimeZone(tz));
    }

    /**
     * 获取指定时区的ISO的时间字符串
     *
     * @param date 日期
     * @return ISO的时间字符串
     */
    public static String getISODateTimeStr(Date date, String timeZone) {
        return getISODateTimeStr(date, TimeZone.getTimeZone(timeZone));
    }

    /**
     * 获取指定时区的ISO的时间字符串
     *
     * @param date     日期
     * @param timeZone 时区
     * @return ISO的时间字符串
     */
    public static String getISODateTimeStr(Date date, TimeZone timeZone) {
        if (date == null) {
            return null;
        }

        // 将毫秒数设置为000
        // 注意不能使用cal.set(Calendar.MILLISECOND, 0)方式来设置, 会导致时区跳变时的前一个小时时间都不正确.
        date.setTime(date.getTime() / 1000L * 1000L);

        Calendar cal = new GregorianCalendar();
        if (timeZone != null) {
            cal.setTimeZone(timeZone);
        }
        cal.setTime(date);
        return DatatypeConverter.printDateTime(cal);
    }

    /**
     * 解析ISO的时间字符串
     *
     * @param isoDateStr
     * @return ISO的时间字符串
     */
    public static Date parseISODateTimeStr(String isoDateStr) {
        if (StringUtils.isBlank(isoDateStr)) {
            return null;
        }

        int minDateStrLength;
        // UTC 0时区字符串,时区标识是字符Z,不是+00:00
        if (isoDateStr.endsWith(UTC_0_TIMEZONE)) {
            minDateStrLength = UTC_0_ISO_DATE_LENGTH;

        } else {
            minDateStrLength = ISO_DATE_LENGTH;
        }

        if (isoDateStr.length() < minDateStrLength) {
            return null;
        }

        try {
            Calendar cal = DatatypeConverter.parseDate(isoDateStr);
            return cal.getTime();
        } catch (IllegalArgumentException e) {

            log.error("DateUtils.parseXSDate exception,isoDatetime:{0} {}", isoDateStr, e);

            return null;
        }
    }

    /**
     * 日期格式化
     * @param date
     * @param format
     * @return
     */
    public static String dateFormat(Date date, String format) {
        return org.apache.commons.lang3.time.DateFormatUtils.format(date, format);
    }

    /**
     * 日期格式化
     * @param dateStr
     * @param format
     * @return
     */
    public static Date parseDate(String dateStr, String format) {
        try {
            return org.apache.commons.lang3.time.DateUtils.parseDate(dateStr, format);
        } catch (ParseException e) {
            throw new IorpCommonException(IorpCommonResultCodeEnum.UNKNOWN_EXCEPTION,
                "parse date error:" + e.getMessage());
        }
    }

    /**
     * 计算下一天的日期
     * @param currentDay 当前日期,格式为yyyy-MM-dd
     * @return 下一天的日期,格式为yyyy-MM-dd
     */
    public static String calculateNextDay(String currentDay) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(webFormat);
        LocalDate date = LocalDate.parse(currentDay, formatter);
        LocalDate newDate = date.plusDays(1);
        return newDate.format(formatter);
    }


    /**
     * 根据日、小时、分钟获取具体的时间点
     * @param day 格式为yyyy-MM-dd
     * @param hour 时
     * @param minute 分
     * @return Date类型的时间点
     */
    public static Date parseDate(String day, int hour, int minute) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(webFormat);
        LocalDate date = LocalDate.parse(day, formatter);
        LocalDateTime localDateTime = date.atTime(hour, minute);
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }


}

Money 工具类

/**
 * 金额工具类
 * @author sunny
 * @version : MoneyUtils.java, v 0.1 2025年07月10日 20:22 sunny Exp $
 */
public class MoneyUtil {

    /**
     * 转换为Money对象
     * @param amount
     * @param currency
     * @return
     */
    public static Money convertToMoney(String amount, String currency) {
        // 创建货币单位
        CurrencyUnit currencyUnit = Monetary.getCurrency(currency);

        return Money.of(new BigDecimal(amount), currencyUnit);
    }

    /**
     * 转换为Money对象
     * @param amount BigDecimal对象
     * @param currency 货币代码
     * @return Money对象
     */
    public static Money convertToMoney(BigDecimal amount, String currency) {
        if(currency == null){
            return null;
        }
        if (amount == null) {
            return Money.of(new BigDecimal(0), currency );
        }
        // 创建货币单位
        CurrencyUnit currencyUnit = Monetary.getCurrency(currency);

        return Money.of(amount, currencyUnit);
    }

    /**
     * 转换为BigDecimal对象
     * @param money Money对象
     * @return BigDecimal对象
     */
    public static BigDecimal convertToAmount(Money money) {
        if(money == null){
            return null;
        }
        return money.getNumberStripped();
    }

    /**
     * 转换为String对象
     * @param money Money对象
     * @return String对象
     */
    public static String convertToCurrency(Money money) {
        if(money == null){
            return null;
        }
        CurrencyUnit currency = money.getCurrency();
        if (currency == null) {
            return null;
        }
        return currency.getCurrencyCode();
    }

    /**
     * 转换为Money对象
     * @param amount
     * @param currency
     * @return
     */
    public static Money convertToMoney(Long amount, String currency) {
        // 创建货币单位
        CurrencyUnit currencyUnit = Monetary.getCurrency(currency);

        return Money.of(amount, currencyUnit);
    }

    /**
     * 获取金额
     * @param money
     * @return
     */
    public static String getMoneyAmount(Money money) {
        if (Objects.isNull(money)) {
            return null;
        }
        return Optional.of(money.getNumber()).map(String::valueOf).orElse(null);
    }

    /**
     * 获取金额(long类型)
     * @param money
     * @return
     */
    public static Long getMoneyLongAmount(Money money) {
        if (Objects.isNull(money)) {
            return null;
        }
        return money.getNumber().longValue();
    }

    /**
     * 获取币种
     * @param money
     * @return
     */
    public static String getMoneyCurrencyCode(Money money) {
        if (Objects.isNull(money)) {
            return null;
        }
        return Optional.ofNullable(money.getCurrency()).map(CurrencyUnit::getCurrencyCode)
            .orElse(null);
    }

    /**
     * 校验金额大于0
     * @param money
     * @return
     */
    public static boolean isGreaterThanZero(Money money) {
        return money.getNumberStripped().compareTo(BigDecimal.ZERO) > 0;
    }



    /**
     * 构造0
     * @param currency
     * @return
     */
    public static Money buildZero(String currency) {
        return convertToMoney("0", currency);
    }

    /**
     * 将金额转换为对应币种的最小单位
     * @param money  金额
     * @return 最小单位的值
     */
    public static Long toMinorUnit(Money money) {
        if(money == null){
            return null;
        }
        // 获取货币单位
        CurrencyUnit currency = money.getCurrency();
        // 获取小数位数(fraction digits)
        int fractionDigits = currency.getDefaultFractionDigits();
        // 若币种无小数位定义,默认按 0 处理
        if (fractionDigits < 0) {
            fractionDigits = 0;
        }
        // 将金额转换为BigDecimal
        BigDecimal majorAmount = money.getNumberStripped();
        // 根据小数位数计算最小单位对应的值
        BigDecimal minorAmount = majorAmount.movePointRight(fractionDigits);
        //(最小单位)四舍五入到最接近的整数
        minorAmount = minorAmount.setScale(0, RoundingMode.HALF_UP);
        // 返回长整型值(最小单位)
        return minorAmount.longValueExact();
    }

    /**
     * 将最小单位的值转换为对应币种的金额
     * @param minorUnit 最小单位的值
     * @param currency 币种
     * @return 金额
     */
    public static Money fromMinorUnit(Long minorUnit, String currency) {
        if(currency == null){
            return null;
        }
        if(minorUnit == null){
            minorUnit = 0L;
        }
        // 创建货币单位
        CurrencyUnit currencyUnit = Monetary.getCurrency(currency);
        // 获取小数位数(fraction digits)
        int fractionDigits = currencyUnit.getDefaultFractionDigits();
        // 若币种无小数位定义,默认按 0 处理
        if (fractionDigits < 0) {
            fractionDigits = 0;
        }
        // 将最小单位的值转换为BigDecimal
        BigDecimal amount = BigDecimal.valueOf(minorUnit, fractionDigits);
        // 返回Money对象
        return convertToMoney(amount, currency);
    }

}

断言工具类

/**
 * 断言工具类。
 *
 * <p><b>使用方法:</b>
 * <ul>
 * <li>在本地定义AssertUtil的匿名bean。
 * <li>给匿名bean注入属性exceptionClassName的值。
 * <li>exceptionClass必须是CommonException的子类,且实现带错误描述参数的构造方法。
 * </ul>
 *
 */

public class AssertUtil {

    /**
     * 断言表达式的值为true,否则抛出指定错误信息。
     *
     * @param expValue          断言表达式
     * @param resultCode        错误码
     * @param objs              任意个异常描述信息的参数
     */
    public static void isTrue(final boolean expValue, final CommonResultCodeEnum resultCode,
                              final Object... objs) {

        if (!expValue) {
            String logString = getLogString(objs);
            String resultMsg = StringUtils.isBlank(logString) ? resultCode.getMessage() : logString;
            throw new CommonException(resultCode, resultMsg);
        }
    }

    /**
     * 断言表达式的值为true,否则抛出指定错误信息。
     *
     * @param expValue 断言表达式
     * @param resultCode 错误码
     */
    public static void isTrue(final boolean expValue, final IorpCommonResultCodeEnum resultCode) {
        if (!expValue) {
            throw new CommonException(resultCode, resultCode.getMessage());
        }
    }

    /**
     * 断言表达式的值为false,否则抛出指定错误信息。
     *
     * @param expValue          断言表达式
     * @param resultCode        错误码
     * @param objs              任意个异常描述信息的参数
     */
    public static void isFalse(final boolean expValue, final CommonResultCodeEnum resultCode,
                               final Object... objs) {
        isTrue(!expValue, resultCode, objs);
    }

    public static void isFalse(final boolean expValue, final CommonResultCodeEnum resultCode) {
        isTrue(!expValue, resultCode);
    }

    /**
     * 断言两个对象相等,否则抛出指定错误信息。
     *
     * @param obj1              待比较对象
     * @param obj2              待比较对象
     * @param resultCode        错误码
     * @param objs              任意个异常描述信息的参数
     */
    public static void equals(final Object obj1, final Object obj2,
                              final CommonResultCodeEnum resultCode, final Object... objs) {

        isTrue(obj1 == null ? obj2 == null : obj1.equals(obj2), resultCode, objs);
    }

    /**
     * 断言两个对象不等,否则抛出指定错误信息。
     *
     * @param obj1              待比较对象
     * @param obj2              待比较对象
     * @param resultCode        错误码
     * @param objs              任意个异常描述信息的参数
     */
    public static void notEquals(final Object obj1, final Object obj2,
                                 final CommonResultCodeEnum resultCode, final Object... objs) {

        isTrue(obj1 == null ? obj2 != null : !obj1.equals(obj2), resultCode, objs);
    }

    /**
     * 断言两个对象相同,否则抛出指定错误信息。
     *
     * @param base          待比较对象
     * @param target        待比较对象
     * @param resultCode    错误码
     * @param objs          任意个异常描述信息的参数
     */
    public static void is(final Object base, final Object target,
                          final CommonResultCodeEnum resultCode, final Object... objs) {

        isTrue(base == target, resultCode, objs);
    }

    /**
     * 断言两个对象不相同,否则抛出指定错误信息。
     *
     * @param base          待比较对象
     * @param target        待比较对象
     * @param resultCode    错误码
     * @param objs          任意个异常描述信息的参数
     */
    public static void isNot(final Object base, final Object target,
                             final CommonResultCodeEnum resultCode, final Object... objs) {

        isTrue(base != target, resultCode, objs);
    }

    /**
     * 断言指定对象在容器中。否则抛出指定错误信息。
     *
     * <p>注意:这里的"在"是指"equals",不是指对象=。
     *
     * @param base              待查对象
     * @param collection        容器集合
     * @param resultCode        错误码
     * @param objs              任意个异常描述信息的参数
     */
    public static void contains(final Object base, final Collection<?> collection,
                                final CommonResultCodeEnum resultCode, final Object... objs) {
        notEmpty(collection, resultCode, objs);
        isTrue(collection.contains(base), resultCode, objs);
    }

    /**
     * 断言指定对象不在容器中。否则抛出指定错误信息。
     *
     * <p>注意:这里的"在"是指"=",不是指对象equals。
     *
     * @param base          待查对象
     * @param collection    容器集合
     * @param resultCode    错误码
     * @param objs          任意个异常描述信息的参数
     */
    public static void notIn(final Object base, final Object[] collection,
                             final CommonResultCodeEnum resultCode, final Object... objs) {

        if (null == collection) {
            return;
        }

        for (Object obj2 : collection) {
            isTrue(base != obj2, resultCode, objs);
        }
    }

    /**
     * 断言对象为空,否则抛出指定错误信息。
     *
     * @param str               断言字符串
     * @param resultCode        错误码
     * @param objs              任意个异常描述信息的参数
     */
    public static void blank(final String str, final CommonResultCodeEnum resultCode,
                             final Object... objs) {

        isTrue(StringUtils.isBlank(str), resultCode, objs);
    }

    public static void blank(final String str, final CommonResultCodeEnum resultCode) {

        isTrue(StringUtils.isBlank(str), resultCode);
    }

    /**
     * 断言对象为非空,否则抛出指定错误信息。
     *
     * @param str               断言字符串
     * @param resultCode        错误码
     * @param objs              任意个异常描述信息的参数
     */
    public static void notBlank(final String str, final IorpCommonResultCodeEnum resultCode,
                                final Object... objs) {

        isTrue(StringUtils.isNotBlank(str), resultCode, objs);
    }

    public static void notBlank(final String str, final IorpCommonResultCodeEnum resultCode) {

        isTrue(StringUtils.isNotBlank(str), resultCode);
    }

    /**
     * 断言对象为null,否则抛出指定错误信息。
     *
     * @param object            待检查对象
     * @param resultCode        错误码
     * @param objs              任意个异常描述信息的参数
     */
    public static void isNull(final Object object, final CommonResultCodeEnum resultCode,
                              final Object... objs) {

        isTrue(object == null, resultCode, objs);
    }

    /**
     * 断言对象非null,否则抛出指定错误信息。
     *
     * @param object            待检查对象
     * @param resultCode        错误码
     * @param objs              任意个异常描述信息的参数
     */
    public static void notNull(final Object object, final CommonResultCodeEnum resultCode,
                               final Object... objs) {

        isTrue(object != null, resultCode, objs);
    }

    /**
     * 断言集合不为空或null,否则抛出指定错误信息。
     *
     * @param collection        待检查集合
     * @param resultCode        错误码
     * @param objs              任意个异常描述信息的参数
     */
    public static void notEmpty(final Collection collection,
                                final CommonResultCodeEnum resultCode, final Object... objs) {

        isTrue(!CollectionUtils.isEmpty(collection), resultCode, objs);
    }

    public static void notEmpty(final Collection collection,
                                final CommonResultCodeEnum resultCode) {

        isTrue(!CollectionUtils.isEmpty(collection), resultCode);
    }

    /**
     * 断言集合为空或null,否则抛出指定错误信息。
     *
     * @param collection        待检查集合
     * @param resultCode        错误码
     * @param objs              任意个异常描述信息的参数
     */
    public static void empty(final Collection collection, final CommonResultCodeEnum resultCode,
                             final Object... objs) {
        isTrue(CollectionUtils.isEmpty(collection), resultCode, objs);
    }

    public static void empty(final Collection collection,
                             final CommonResultCodeEnum resultCode) {
        isTrue(CollectionUtils.isEmpty(collection), resultCode);
    }

    /**
     * 断言map不为空或null,否则抛出指定错误信息。
     *
     * @param map               待检查map
     * @param resultCode        错误码
     * @param objs              任意个异常描述信息的参数
     */
    public static void notEmpty(final Map map, final CommonResultCodeEnum resultCode,
                                final Object... objs) {

        isTrue(!CollectionUtils.isEmpty(map), resultCode, objs);
    }

    /**
     * 断言map为空或null,否则抛出指定错误信息。
     *
     * @param map               待检查map
     * @param resultCode        错误码
     * @param objs              任意个异常描述信息的参数
     */
    public static void empty(final Map map, final CommonResultCodeEnum resultCode,
                             final Object... objs) {

        isTrue(CollectionUtils.isEmpty(map), resultCode, objs);
    }

    /**
     * 推断在条件成立下,str非空。否则抛出指定错误信息。
     *
     * @param condition         推断条件
     * @param str               断言字符串
     * @param resultCode        错误码
     * @param objs              任意个异常描述信息的参数
     */
    public static void deductNotBlank(final boolean condition, final String str,
                                      final CommonResultCodeEnum resultCode,
                                      final Object... objs) {

        if (!condition) {
            return;
        }

        notBlank(str, resultCode, objs);
    }

    /**
     * 推断在条件成立下,expValue为真。否则抛出指定错误信息。
     *
     * @param condition         推断条件
     * @param expValue          断言表达式
     * @param resultCode        错误码
     * @param objs              任意个异常描述信息的参数
     */
    public static void deductTrue(final boolean condition, final boolean expValue,
                                  final CommonResultCodeEnum resultCode, final Object... objs) {

        if (!condition) {

            return;
        }

        isTrue(expValue, resultCode, objs);
    }

    // ~~~ 内部方法

    /**
     * 生成输出到日志的字符串
     *
     * @param objs      任意个要输出到日志的参数
     * @return          日志字符串
     */
    private static String getLogString(Object... objs) {
        StringBuilder log = new StringBuilder();

        for (Object o : objs) {
            log.append(o);
        }
        return log.toString();
    }
}