摘要:問題場景有一個工具類用于對支付參數進行簽名其中使用了配置類簽名工具類如下這里的輸出為訪問它將會導致排序參數拼接支付簽名參數拼接簽名并返回這樣是不行的是一個靜態成員容器在初始化過程中如果看到這是一個靜態的成員它會直接跳過這個成員字段處理下一個
問題場景
有一個工具類, 用于對支付參數進行簽名, 其中使用了 @ConfigurationProperties 配置類. 簽名工具類如下:
import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.DigestUtils; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; @Slf4j public class SignUtil { private static PayProperties payProperties; @Autowired public static void setPayProperties(PayProperties payProperties) { SignUtil.payProperties = payProperties; } public static String signParams(PayOrderRequest payOrderRequest, String apiKey) { //////////////////////////////////////////////////////////////////// // 這里 payProperties 的輸出為 null, 訪問它將會導致 NullPointerException //////////////////////////////////////////////////////////////////// log.info("============================: {}", payProperties); // 排序 Mapmap = new TreeMap<>(); map.put("merchantOrderId", payOrderRequest.getMerchantOrderId()); map.put("createdAt", payOrderRequest.getCreatedAt()); ... ... ... List params = new ArrayList<>(); for (String key : map.keySet()) { log.debug("參數: {}", String.format("%s=%s", key, map.get(key))); params.add(map.get(key)); } params.add(apiKey); // 拼接 String plainTextParams = String.join("|", params); log.info("支付簽名參數拼接: {}", plainTextParams); // 簽名并返回 return DigestUtils.md5DigestAsHex(plainTextParams.getBytes()).toUpperCase(); } }
這樣是不行的, PayProperties 是一個靜態成員, Spring 容器在初始化過程中如果看到這是一個靜態的成員, 它會直接跳過這個成員字段, 處理下一個字段.解決辦法
使用一個代理Bean類對靜態成員進行初始化, 這個代理Bean可以叫做 StaticContextInitializer(靜態山下文初始化器)
首先, 這個代理類需要使用 @Component 進行注解
其次, 刪除上述代碼中靜態方法 setPayProperties 的注解 @Autowired,
然后, 創建這個代理類, 并使用PostConstruct 對 SignUtil 工具類的 PayProperties 成員進行手工注入:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; @Component public class StaticContextInitializer { private PayProperties anyiProperties; @Autowired public void setAnyiProperties(PayProperties anyiProperties) { this.anyiProperties = anyiProperties; } @PostConstruct public void init() { SignUtil.setPayProperties(anyiProperties); } }可測試的示例代碼
StaticContextInitializer.java
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; @Component public class StaticContextInitializer { private PayProperties anyiProperties; @Autowired public void setAnyiProperties(PayProperties anyiProperties) { this.anyiProperties = anyiProperties; } @PostConstruct public void init() { SignUtil.setPayProperties(anyiProperties); } }
SignUtil.java
import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.DigestUtils; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; @Slf4j public class SignUtil { private static PayProperties payProperties; @Autowired public static void setPayProperties(PayProperties payProperties) { SignUtil.payProperties = payProperties; } public static String signParams(PayOrderRequest payOrderRequest, String apiKey) { //////////////////////////////////////////////////////////////////// // payProperties 字段已經通 StaticContextInitializer.init() 進行注入 // 不會再出現 NPE 問題 //////////////////////////////////////////////////////////////////// log.info("============================: {}", payProperties); // 排序 Mapmap = new TreeMap<>(); map.put("merchantOrderId", payOrderRequest.getMerchantOrderId()); map.put("createdAt", payOrderRequest.getCreatedAt()); List params = new ArrayList<>(); for (String key : map.keySet()) { log.debug("參數: {}", String.format("%s=%s", key, map.get(key))); params.add(map.get(key)); } params.add(apiKey); // 拼接 String plainTextParams = String.join("|", params); log.info("支付簽名參數拼接: {}", plainTextParams); // 簽名并返回 return DigestUtils.md5DigestAsHex(plainTextParams.getBytes()).toUpperCase(); } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/72318.html
摘要:下面我們來測試一下,訪問我們經過修改后的編寫的接口這里我將返回值統一為,以便數據存入,實際類型應是接口的返回類型。如果沒有返回值的話,那就可以一個對象直接通過構造方法賦值即可。 為什么要統一返回值 在我們做后端應用的時候,前后端分離的情況下,我們經常會定義一個數據格式,通常會包含code,message,data這三個必不可少的信息來方便我們的交流,下面我們直接來看代碼 ReturnV...
摘要:全局異常處理類用于全局返回,如需返回請使用繼承了,對于一些類似于請求方式異常的異常進行捕獲重寫,自定義處理過程這里將異常直接傳給方法進行處理,返回值為保證友好的返回,而不是出現錯誤碼。 前言 異常的處理在我們的日常開發中是一個繞不過去的坎,在Spring Boot 項目中如何優雅的去處理異常,正是我們這一節課需要研究的方向。 異常的分類 在一個Spring Boot項目中,我們可以把異...
摘要:注意,其是在編譯源碼過程中,幫你自動生成的。就是說,將極大減少你的代碼總量。注解和類似,區別在于它會把所有成員變量默認定義為修飾,并且不會生成方法。不同的日志注解總結如下上面是注解,下面是編譯后的代碼參考資料下的安裝以及使用簡介注解介紹 Lombok有什么用 在我們實體Bean中有大量的Getter/Setter方法以及toString, hashCode等可能不會用到,但是某些時候仍...
摘要:但是,一個好的單元測試應該是毫秒級的,否則這會影響的工作方式,這也就是測試驅動開發的思想。在單元測試中,我們可以像這樣來構建一個實例。所以,我們在寫單元測試的時候,應該以一種更簡單的方式去構建。 本文翻譯自:https://reflectoring.io/unit-...原文作者:Tom Hombergs 譯文原地址:https://weyunx.com/2019/02/04... ...
摘要:結構型模式適配器模式橋接模式裝飾模式組合模式外觀模式享元模式代理模式。行為型模式模版方法模式命令模式迭代器模式觀察者模式中介者模式備忘錄模式解釋器模式模式狀態模式策略模式職責鏈模式責任鏈模式訪問者模式。 主要版本 更新時間 備注 v1.0 2015-08-01 首次發布 v1.1 2018-03-12 增加新技術知識、完善知識體系 v2.0 2019-02-19 結構...
閱讀 1113·2021-11-19 09:40
閱讀 969·2021-11-12 10:36
閱讀 1259·2021-09-22 16:04
閱讀 3106·2021-09-09 11:39
閱讀 1266·2019-08-30 10:51
閱讀 1882·2019-08-30 10:48
閱讀 1221·2019-08-29 16:30
閱讀 464·2019-08-29 12:37