疫情加劇糧食危機 美農業部:北韓6成國民處於挨餓困境

摘錄自2020年8月13日自由時報報導

美國農業部(USDA)今(13)日發布報告指出,武漢肺炎(COVID-19)疫情加劇北韓糧食危機,該國現有約六成國民,即1530萬人口面臨挨餓困境。

美國農業部經濟研究中心在最新發表的《國際糧食安全評估報告》中表示,在未來的10年間,北韓約有1530萬人口處於「糧食不安全(Food Insecurity)」狀態,這些人無法確保每日獲取的食物量高於飢餓線。

北韓近年受旱災、洪災等天災影響,農產品生產量下降,國民面臨長期糧食短缺困境,是國際人道組織長期關注的問題,聯合國食品援助組織「世界糧食計劃署(World Food Programme)」此前預估,約有1000萬北韓人民遭受10年來最嚴重的糧食短缺之苦。

土地利用
氣候變遷
國際新聞
北韓
糧食危機
疫情下的食衣住行
疫情下的社會衝突

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※別再煩惱如何寫文案,掌握八大原則!

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※超省錢租車方案

※教你寫出一流的銷售文案?

網頁設計最專業,超強功能平台可客製化

※產品缺大量曝光嗎?你需要的是一流包裝設計!

磚頭也能變電池?儲能研究揭最新奈米科技 關鍵因素在「多孔」

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

格陵蘭冰融已難挽回 全球海平面恐升6公尺

摘錄自2020年08月16日中央通訊社格陵蘭報導

新研究顯示,格陵蘭(Greenland)冰層可能已經融化到無法挽回的地步,無論全球以多快的速度降低溫室氣體排放,冰層仍可能繼續融化。如果格陵蘭的冰全部融化,全球海平面平均將上升6公尺。

路透社報導,科學家研究橫跨北極234個冰川截至2018年的34年數據發現,年降雪量已經不足以補充冰川在夏季融化而流失的雪和冰。冰川融化已造成全球海平面每年平均上升1公釐。如果格陵蘭的冰全部融化,足以淹沒全球許多沿海城市,不過這個過程將花上數十年。

過去30年來,北極暖化的速度比起全球其他區域至少快兩倍,此現象被稱為「北極放大」效應,而極地海冰在今年7月創下40年來最低點。科學家表示,全球仍能透過降低碳排來減緩氣候變遷,即使格陵蘭難再累積覆蓋其200萬平方公里的冰層,遏制全球氣溫上升也能放慢冰層流失的速度。

氣候變遷
國際新聞
格陵蘭
冰川融化
海平面上升

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

疫情成保育契機 威尼斯潟湖重生

摘錄自2020年08月16日台灣醒報報導

疫情使威尼斯觀光停擺,在地人趁機復甦生態!義大利威尼斯潟湖曾因為人口眾多及排水污染,湖中鹽分提高,導致大量蘆葦消失,生態環境被破壞。然而,因為疫情期間人口稀少,科學家及當地農夫藉此發起潟湖復甦計劃,以運河系統引進淡水、移植海草、種植蘆葦,以恢復原有生態。

鹽沼是沿海潮間帶和陸地間的一種生態系統,海水或鹹水會規律地湧入流出該地區。據《今日泰倫加納》報導,人工的運河系統將思樂河的淡水導入潟湖。能培養豐富生態的鹽沼如今只剩下34公頃。

威尼斯福斯卡里宮大學研究員亞瑞安娜指出,潟湖的一半以上曾經是蘆葦床和鹽沼,約1萬7000公頃並擁有豐富生態,「健康的潟湖鹽分應介於0到15鹽度,但現在威尼斯的鹽度是30,已與海水相去不遠。」計劃發起人布魯薩則表示:「我們的重整計劃將從其他地方導入乾淨的淡水,來沖淡鹽分,還它原始的樣貌。」

污染治理
國際新聞
義大利
威尼斯
潟湖
武漢肺炎
動物與大環境變遷

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

溫室效應越來越嚴重 《魔戒》名場景將不復存在

摘錄自2020年8月16日自由時報報導

隨著地球的溫室效應越來越嚴重,世界各地的冰川都出現融化危機,其中包括曾在知名奇幻電影《魔戒》及《哈比人》電影中出現的紐西蘭南阿爾卑斯山(Southern Alps)的冰川,未來《魔戒》中的「迷霧山脈」可能美景不再。

綜合外媒報導,英國利茲大學(University of Leeds)紐西蘭國家水與大氣研究所(NIWA)合作,研究人員發現,南阿爾卑斯山的冰川自從小冰河時期結束以來,消失速度已增快2倍,而且近幾十年中,冰川在小冰河時期保有的體積已經融化近77%,其中1978年至2019年間就消失了17%;研究人員強調,全球冰川融化的嚴重性,不僅使依賴冰川融化供水、水力發電與灌溉農田的當地居民未來無水可用,全球高山冰川與冰蓋融化,也造成海平面上升25%。

研究人員認為,南阿爾卑斯山的冰川的「用水高峰(Peak Water)」或稱冰川融化所供應水資源已超過臨界點,未來可用水將越來越少,必須制定計畫以維護當地的水資源供應。

氣候變遷
國際新聞
紐西蘭
溫室效應
冰川融化
阿爾卑斯山

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

※教你寫出一流的銷售文案?

德國國家科學院聲明 德國能源轉型2030:歐洲碳中和路徑

轉載自台大風險社會與政策研究中心;陳喬琪 編譯

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※別再煩惱如何寫文案,掌握八大原則!

※產品缺大量曝光嗎?你需要的是一流包裝設計!

百公里時速「火龍捲」襲擊北加州 美西迎70年來最嚴重熱浪

摘錄自2020年8月17日東森新聞報導

美國國家氣象局(National Weather Service)15日針對北加州發布龍捲風警報,而且這次是稀有的火龍捲警報,由加州洛亞爾頓的野火火源的高溫引起熱空氣與濃煙上升變成「火積雲」(pyrocumulonimbus),形成時速近100公里的火龍捲。

駭人的火龍捲15日在內華達州邊境被發現,是當空氣中的漩渦亂流因為高熱及風向造成的湍流結合而形成,在旋風內有火焰。當這些渦旋空氣繼續收緊至類似龍捲風的結構時,可以吸入燃燒中的碎塊雜物及可燃氣體,從而使旋風點起火焰。龍捲風的存在可以幫助野火更快地傳播。

美國西部各州面臨70年來最嚴重的熱浪侵襲,超過800萬人收到政府的高溫警報,沙加緬度甚至預計達到攝氏43度。加州14日甚至因為溫度過高,電網不堪負荷,導致全州陷入停電。

氣候變遷
國際新聞
美國
熱浪
野火
龍捲風

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※別再煩惱如何寫文案,掌握八大原則!

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※超省錢租車方案

※教你寫出一流的銷售文案?

網頁設計最專業,超強功能平台可客製化

※產品缺大量曝光嗎?你需要的是一流包裝設計!

Asp.Net Core入門之自定義服務註冊

談到服務註冊,首先我們先了解一下服務註冊時使用的三種方式,也代表了不同的服務生命周期

1  AddTransient
 
2  AddScoped
 
3  AddSingleton
AddSingleton生命周期最長,其生命周期範圍描述為:從應用程序啟動到應用程序結束。在第一次請求時會創建一個實例,之後的每次請求都會使用同一個實例。
AddTransient生命周期最短,在服務請求時會創建一個實例,服務請求結束生命周期即結束,之後的每一次請求都會創建不同的實例。
AddSingleton生命周期介於上述兩者之間,這裏用客戶端請求會話的概念來描述比較清晰一點,它也是在服務請求時創建實例,但是在同一個會話周期內,之後的每次請求都會使用同一個實例,直至會話結束才會創建新的實例。
 

ASP.Net Core框架支持我們以如下方式註冊我們自己的服務。

services.AddScoped<ITest, Test>();

其中第一個泛型類型(如:ITest)表示將要從容器中請求的類型(通常是一個接口)。第二個泛型類型(如:Test)表示將由容器實例化並且用於完成這些請求的具體實現類。

具體我們一起看下面的例子:

首先,我們創建一個需要實現查詢功能的服務接口ITest

   public interface ITest
    {
        Task<string> Get();
    }

然後,我們創建功能類Test實現這個接口

 1     public class Test : ITest
 2     {
 3         private readonly ILogger logger;
 4         public Test(ILogger<Test> _logger)
 5         {
 6             logger = _logger;
 7         }
 8         public Task<string> Get()
 9         {
10             logger.LogInformation("自定義服務查詢");
11             return Task.FromResult("Hello World");
12         }
13     }

最後,我們需要我們自己的服務註冊到容器中。

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<ITest, Test>();
        }

以上我們便簡單完成了自定義服務的註冊。

隨後我這裏創建了一個Controller用以使用該服務。

 1     [Route("api/[controller]")]
 2     [ApiController]
 3     public class ValuesController : ControllerBase
 4     {
 5         //聲明服務
 6         private readonly ITest service;
 7 
 8         /// <summary>
 9         /// 通過構造函數的方式注入自定義服務類
10         /// </summary>
11         /// <param name="_service"></param>
12         public ValuesController(ITest _service)
13         {
14             service = _service;
15         }
16 
17         /// <summary>
18         /// 調用服務中實現的Get方法
19         /// </summary>
20         /// <returns></returns>
21         [HttpGet]
22         public Task<string> Get()
23         {
24             return service.Get();
25         }
26      }

ASP.Net Core框架默認支持我們以構造函數的方式注入我們的服務以使用。

我想寫到這裏,大家也會有疑問,如果我們有很多service,這樣一個個註冊寫起來代碼很低效,這裏我們簡單給大家介紹一種批量註冊的方式:

這裏我們創建了一個批量註冊服務派生類:

 1 public static class ServiceExtensions
 2     {
 3         /// <summary>
 4         /// 批量註冊程序集下的服務類
 5         /// </summary>
 6         /// <param name="services"></param>
 7         public static IServiceCollection AddBatchServices(this IServiceCollection services)
 8         {
 9             //根據指定程序集名稱獲取待註冊服務
10             var batchServices = GetConfigureClass("WebApiApplication");
11             foreach (var type in batchServices)
12             {
13                 type.Value.ToList().ForEach(i =>
14                 {
15                     //註冊服務類
16                     services.AddScoped(i, type.Key);
17                 });
18             }
19             return services;
20         }
21 
22         /// <summary>
23         /// 根據程序集名稱獲取自定義服務
24         /// </summary>
25         /// <param name="assembly"></param>
26         /// <returns></returns>
27         public static Dictionary<Type, Type[]> GetConfigureClass(string assembly)
28         {
29             Dictionary<Type, Type[]> dic = new Dictionary<Type, Type[]>();
30             if (!string.IsNullOrEmpty(assembly))
31             {
32                 //獲取程序集對應的類型
33                 Assembly dll = Assembly.LoadFrom(assembly);
34                 List<Type> lstType = dll.GetTypes().ToList();
35                 lstType.ForEach(x =>
36                 {
37                     //篩選滿足條件的服務類
38                     if (x.IsClass && x.GetInterfaces().Length > 0)
39                     {
40                         dic.Add(x, x.GetInterfaces());
41                     }
42                 });
43             }
44             return dic;
45         }
46    }

然後我們ConfigureServices方法中註冊:

        public void ConfigureServices(IServiceCollection services)
        {
            //批量註冊
            services.AddBatchServices();
        }

對於批量註冊,ASP.Net Core允許我們更換默認的IOC容器,感興趣的同學可以試試AutoFac容器支持的程序集掃描式註冊。

註冊我們自己的服務,往往在項目開發過程中是必要的,希望以上簡單的分享能給需要的小夥伴們帶來一點收貨。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

重學 Java 設計模式:實戰外觀模式「基於SpringBoot開發門面模式中間件,統一控制接口白名單場景」

作者:小傅哥
博客:https://bugstack.cn

沉澱、分享、成長,讓自己和他人都能有所收穫!

一、前言

你感受到的容易,一定有人為你承擔不容易

這句話更像是描述生活的,許許多多的磕磕絆絆總有人為你提供躲雨的屋檐和避風的港灣。其實編程開發的團隊中也一樣有人只負責CRUD中的簡單調用,去使用團隊中高級程序員開發出來的核心服務和接口。這樣的編程開發對於初期剛進入程序員行業的小夥伴來說鍛煉鍛煉還是不錯的,但隨着開發的日子越來越久一直做這樣的事情就很難得到成長,也想努力的去做一些更有難度的承擔,以此來增強個人的技術能力。

沒有最好的編程語言,語言只是工具

刀槍棍棒、斧鉞鈎叉、包子油條、盒子麻花,是語言。五郎八卦棍、十二路彈腿、洪家鐵線拳,是設計。記得恭弘=叶 恭弘問里有一句台詞是:金山找:今天我北方拳術,輸給你南方拳術了。恭弘=叶 恭弘問:你錯了,不是南北拳的問題,是你的問題。所以當你編程開發寫的久了,就不會再特別在意用的語言,而是為目標服務,用最好的設計能力也就是編程的智慧做出做最完美的服務。這也就是編程人員的價值所在!

設計與反設計以及過渡設計

設計模式是解決程序中不合理、不易於擴展、不易於維護的問題,也是幹掉大部分ifelse的利器,在我們常用的框架中基本都會用到大量的設計模式來構建組件,這樣也能方便框架的升級和功能的擴展。但!如果不能合理的設計以及亂用設計模式,會導致整個編程變得更加複雜難維護,也就是我們常說的;反設計過渡設計。而這部分設計能力也是從實踐的項目中獲取的經驗,不斷的改造優化摸索出的最合理的方式,應對當前的服務體量。

二、開發環境

  1. JDK 1.8
  2. Idea + Maven
  3. SpringBoot 2.1.2.RELEASE
  4. 涉及工程三個,可以通過關注公眾號bugstack蟲洞棧,回復源碼下載獲取(打開獲取的鏈接,找到序號18)
工程 描述
itstack-demo-design-10-00 場景模擬工程;模擬一個提供接口服務的SpringBoot工程
itstack-demo-design-10-01 使用一坨代碼實現業務需求
itstack-demo-design-10-02 通過設計模式開發為中間件,包裝通用型核心邏輯

三、外觀模式介紹

外觀模式也叫門面模式,主要解決的是降低調用方的使用接口的複雜邏輯組合。這樣調用方與實際的接口提供方提供方提供了一个中間層,用於包裝邏輯提供API接口。有些時候外觀模式也被用在中間件層,對服務中的通用性複雜邏輯進行中間件層包裝,讓使用方可以只關心業務開發。

那麼這樣的模式在我們的所見產品功能中也經常遇到,就像幾年前我們註冊一個網站時候往往要添加很多信息,包括;姓名、昵稱、手機號、QQ、郵箱、住址、單身等等,但現在註冊成為一個網站的用戶只需要一步即可,無論是手機號還是微信也都提供了這樣的登錄服務。而對於服務端應用開發來說以前是提供了一個整套的接口,現在註冊的時候並沒有這些信息,那麼服務端就需要進行接口包裝,在前端調用註冊的時候服務端獲取相應的用戶信息(從各個渠道),如果獲取不到會讓用戶後續進行補全(營銷補全信息給獎勵),以此來拉動用戶的註冊量和活躍度。

四、案例場景模擬

在本案例中我們模擬一個將所有服務接口添加白名單的場景

在項目不斷壯大發展的路上,每一次發版上線都需要進行測試,而這部分測試驗證一般會進行白名單開量或者切量的方式進行驗證。那麼如果在每一個接口中都添加這樣的邏輯,就會非常麻煩且不易維護。另外這是一類具備通用邏輯的共性需求,非常適合開發成組件,以此來治理服務,讓研發人員更多的關心業務功能開發。

一般情況下對於外觀模式的使用通常是用在複雜或多個接口進行包裝統一對外提供服務上,此種使用方式也相對簡單在我們平常的業務開發中也是最常用的。你可能經常聽到把這兩個接口包裝一下,但在本例子中我們把這種設計思路放到中間件層,讓服務變得可以統一控制。

1. 場景模擬工程

itstack-demo-design-10-00
└── src
    ├── main
    │   ├── java
    │   │   └── org.itstack.demo.design
    │   │       ├── domain
    │   │       │	└── UserInfo.java
    │   │       ├── web	
    │   │       │	└── HelloWorldController.java
    │   │       └── HelloWorldApplication.java
    │   └── resources	
    │       └── application.yml	
    └── test
        └── java
            └── org.itstack.demo.test
                └── ApiTest.java
  • 這是一個SpringBootHelloWorld工程,在工程中提供了查詢用戶信息的接口HelloWorldController.queryUserInfo,為後續擴展此接口的白名單過濾做準備。

2. 場景簡述

2.1 定義基礎查詢接口

@RestController
public class HelloWorldController {

    @Value("${server.port}")
    private int port;

    /**
     * key:需要從入參取值的屬性字段,如果是對象則從對象中取值,如果是單個值則直接使用
     * returnJson:預設攔截時返回值,是返回對象的Json
     *
     * http://localhost:8080/api/queryUserInfo?userId=1001
     * http://localhost:8080/api/queryUserInfo?userId=小團團
     */
    @RequestMapping(path = "/api/queryUserInfo", method = RequestMethod.GET)
    public UserInfo queryUserInfo(@RequestParam String userId) {
        return new UserInfo("蟲蟲:" + userId, 19, "天津市南開區旮旯衚衕100號");
    }

}
  • 這裏提供了一個基本的查詢服務,通過入參userId,查詢用戶信息。後續就需要在這裏擴展白名單,只有指定用戶才可以查詢,其他用戶不能查詢。

2.2 設置Application啟動類

@SpringBootApplication
@Configuration
public class HelloWorldApplication {

    public static void main(String[] args) {
        SpringApplication.run(HelloWorldApplication.class, args);
    }

}
  • 這裡是通用的SpringBoot啟動類。需要添加的是一個配置註解@Configuration,為了後續可以讀取白名單配置。

五、用一坨坨代碼實現

一般對於此種場景最簡單的做法就是直接修改代碼

累加if塊幾乎是實現需求最快也是最慢的方式,是修改當前內容很快,是如果同類的內容幾百個也都需要如此修改擴展和維護會越來越慢。

1. 工程結構

itstack-demo-design-10-01
└── src
    └── main
        └── java
            └── org.itstack.demo.design
                └── HelloWorldController.java
  • 以上的實現是模擬一個Api接口類,在裏面添加白名單功能,但類似此類的接口會有很多都需要修改,所以這也是不推薦使用此種方式的重要原因。

2. 代碼實現

public class HelloWorldController {

    public UserInfo queryUserInfo(@RequestParam String userId) {

        // 做白名單攔截
        List<String> userList = new ArrayList<String>();
        userList.add("1001");
        userList.add("aaaa");
        userList.add("ccc");
        if (!userList.contains(userId)) {
            return new UserInfo("1111", "非白名單可訪問用戶攔截!");
        }

        return new UserInfo("蟲蟲:" + userId, 19, "天津市南開區旮旯衚衕100號");
    }

}
  • 在這裏白名單的代碼佔據了一大塊,但它又不是業務中的邏輯,而是因為我們上線過程中需要做的開量前測試驗證。
  • 如果你日常對待此類需求經常是這樣開發,那麼可以按照此設計模式進行優化你的處理方式,讓後續的擴展和摘除更加容易。

六、外觀模式重構代碼

接下來使用外觀器模式來進行代碼優化,也算是一次很小的重構。

這次重構的核心是使用外觀模式也可以說門面模式,結合SpringBoot中的自定義starter中間件開發的方式,統一處理所有需要白名單的地方。

後續接下來的實現中,會涉及的知識;

  1. SpringBoot的starter中間件開發方式。
  2. 面向切面編程和自定義註解的使用。
  3. 外部自定義配置信息的透傳,SpringBoot與Spring不同,對於此類方式獲取白名單配置存在差異。

1. 工程結構

itstack-demo-design-10-02
└── src
    ├── main
    │   ├── java
    │   │   └── org.itstack.demo.design.door
    │   │       ├── annotation
    │   │       │	└── DoDoor.java	
    │   │       ├── config
    │   │       │	├── StarterAutoConfigure.java
    │   │       │	├── StarterService.java
    │   │       │	└── StarterServiceProperties.java
    │   │       └── DoJoinPoint.java
    │   └── resources	
    │       └── META_INF
    │           └── spring.factories
    └── test
        └── java
            └── org.itstack.demo.test
                └── ApiTest.java

門面模式模型結構

  • 以上是外觀模式的中間件實現思路,右側是為了獲取配置文件,左側是對於切面的處理。
  • 門面模式可以是對接口的包裝提供出接口服務,也可以是對邏輯的包裝通過自定義註解對接口提供服務能力。

2. 代碼實現

2.1 配置服務類

public class StarterService {

    private String userStr;

    public StarterService(String userStr) {
        this.userStr = userStr;
    }

    public String[] split(String separatorChar) {
        return StringUtils.split(this.userStr, separatorChar);
    }

}
  • 以上類的內容較簡單隻是為了獲取配置信息。

2.2 配置類註解定義

@ConfigurationProperties("itstack.door")
public class StarterServiceProperties {

    private String userStr;

    public String getUserStr() {
        return userStr;
    }

    public void setUserStr(String userStr) {
        this.userStr = userStr;
    }

}
  • 用於定義好後續在 application.yml 中添加 itstack.door 的配置信息。

2.3 自定義配置類信息獲取

@Configuration
@ConditionalOnClass(StarterService.class)
@EnableConfigurationProperties(StarterServiceProperties.class)
public class StarterAutoConfigure {

    @Autowired
    private StarterServiceProperties properties;

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "itstack.door", value = "enabled", havingValue = "true")
    StarterService starterService() {
        return new StarterService(properties.getUserStr());
    }

}
  • 以上代碼是對配置的獲取操作,主要是對註解的定義;@Configuration@ConditionalOnClass@EnableConfigurationProperties,這一部分主要是與SpringBoot的結合使用。

2.4 切面註解定義

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DoDoor {

    String key() default "";

    String returnJson() default "";

}
  • 定義了外觀模式門面註解,後續就是此註解添加到需要擴展白名單的方法上。
  • 這裏提供了兩個入參,key:獲取某個字段例如用戶ID、returnJson:確定白名單攔截后返回的具體內容。

2.5 白名單切面邏輯

@Aspect
@Component
public class DoJoinPoint {

    private Logger logger = LoggerFactory.getLogger(DoJoinPoint.class);

    @Autowired
    private StarterService starterService;

    @Pointcut("@annotation(org.itstack.demo.design.door.annotation.DoDoor)")
    public void aopPoint() {
    }

    @Around("aopPoint()")
    public Object doRouter(ProceedingJoinPoint jp) throws Throwable {
        //獲取內容
        Method method = getMethod(jp);
        DoDoor door = method.getAnnotation(DoDoor.class);
        //獲取字段值
        String keyValue = getFiledValue(door.key(), jp.getArgs());
        logger.info("itstack door handler method:{} value:{}", method.getName(), keyValue);
        if (null == keyValue || "".equals(keyValue)) return jp.proceed();
        //配置內容
        String[] split = starterService.split(",");
        //白名單過濾
        for (String str : split) {
            if (keyValue.equals(str)) {
                return jp.proceed();
            }
        }
        //攔截
        return returnObject(door, method);
    }

    private Method getMethod(JoinPoint jp) throws NoSuchMethodException {
        Signature sig = jp.getSignature();
        MethodSignature methodSignature = (MethodSignature) sig;
        return getClass(jp).getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
    }

    private Class<? extends Object> getClass(JoinPoint jp) throws NoSuchMethodException {
        return jp.getTarget().getClass();
    }

    //返回對象
    private Object returnObject(DoDoor doGate, Method method) throws IllegalAccessException, InstantiationException {
        Class<?> returnType = method.getReturnType();
        String returnJson = doGate.returnJson();
        if ("".equals(returnJson)) {
            return returnType.newInstance();
        }
        return JSON.parseObject(returnJson, returnType);
    }

    //獲取屬性值
    private String getFiledValue(String filed, Object[] args) {
        String filedValue = null;
        for (Object arg : args) {
            try {
                if (null == filedValue || "".equals(filedValue)) {
                    filedValue = BeanUtils.getProperty(arg, filed);
                } else {
                    break;
                }
            } catch (Exception e) {
                if (args.length == 1) {
                    return args[0].toString();
                }
            }
        }
        return filedValue;
    }

}
  • 這裏包括的內容較多,核心邏輯主要是;Object doRouter(ProceedingJoinPoint jp),接下來我們分別介紹。

@Pointcut(“@annotation(org.itstack.demo.design.door.annotation.DoDoor)”)

定義切面,這裏採用的是註解路徑,也就是所有的加入這個註解的方法都會被切面進行管理。

getFiledValue

獲取指定key也就是獲取入參中的某個屬性,這裏主要是獲取用戶ID,通過ID進行攔截校驗。

returnObject

返回攔截后的轉換對象,也就是說當非白名單用戶訪問時則返回一些提示信息。

doRouter

切面核心邏輯,這一部分主要是判斷當前訪問的用戶ID是否白名單用戶,如果是則放行jp.proceed();,否則返回自定義的攔截提示信息。

3. 測試驗證

這裏的測試我們會在工程:itstack-demo-design-10-00中進行操作,通過引入jar包,配置註解的方式進行驗證。

3.1 引入中間件POM配置

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>itstack-demo-design-10-02</artifactId>
</dependency>
  • 打包中間件工程,給外部提供jar包服務

3.2 配置application.yml

# 自定義中間件配置
itstack:
  door:
    enabled: true
    userStr: 1001,aaaa,ccc #白名單用戶ID,多個逗號隔開
  • 這裏主要是加入了白名單的開關和白名單的用戶ID,逗號隔開。

3.3 在Controller中添加自定義註解

/**
 * http://localhost:8080/api/queryUserInfo?userId=1001
 * http://localhost:8080/api/queryUserInfo?userId=小團團
 */
@DoDoor(key = "userId", returnJson = "{\"code\":\"1111\",\"info\":\"非白名單可訪問用戶攔截!\"}")
@RequestMapping(path = "/api/queryUserInfo", method = RequestMethod.GET)
public UserInfo queryUserInfo(@RequestParam String userId) {
    return new UserInfo("蟲蟲:" + userId, 19, "天津市南開區旮旯衚衕100號");
}
  • 這裏核心的內容主要是自定義的註解的添加@DoDoor,也就是我們的外觀模式中間件化實現。
  • key:需要從入參取值的屬性字段,如果是對象則從對象中取值,如果是單個值則直接使用。
  • returnJson:預設攔截時返回值,是返回對象的Json。

3.4 啟動SpringBoot

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.2.RELEASE)

2020-06-11 23:56:55.451  WARN 65228 --- [           main] ion$DefaultTemplateResolverConfiguration : Cannot find template location: classpath:/templates/ (please add some templates or check your Thymeleaf configuration)
2020-06-11 23:56:55.531  INFO 65228 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-06-11 23:56:55.533  INFO 65228 --- [           main] o.i.demo.design.HelloWorldApplication    : Started HelloWorldApplication in 1.688 seconds (JVM running for 2.934)
  • 啟動正常,SpringBoot已經啟動可以對外提供服務。

3.5 訪問接口接口測試

白名單用戶訪問

http://localhost:8080/api/queryUserInfo?userId=1001

{"code":"0000","info":"success","name":"蟲蟲:1001","age":19,"address":"天津市南開區旮旯衚衕100號"}
  • 此時的測試結果正常,可以拿到接口數據。

非白名單用戶訪問

http://localhost:8080/api/queryUserInfo?userId=小團團

{"code":"1111","info":"非白名單可訪問用戶攔截!","name":null,"age":null,"address":null}
  • 這次我們把userId換成小團團,此時返回的信息已經是被攔截的信息。而這個攔截信息正式我們自定義註解中的信息:@DoDoor(key = "userId", returnJson = "{\"code\":\"1111\",\"info\":\"非白名單可訪問用戶攔截!\"}")

七、總結

  • 以上我們通過中間件的方式實現外觀模式,這樣的設計可以很好的增強代碼的隔離性,以及復用性,不僅使用上非常靈活也降低了每一個系統都開發這樣的服務帶來的風險。
  • 可能目前你看這隻是非常簡單的白名單控制,是否需要這樣的處理。但往往一個小小的開始會影響着後續無限的擴展,實際的業務開發往往也要複雜的很多,不可能如此簡單。因而使用設計模式來讓代碼結構更加乾淨整潔。
  • 很多時候不是設計模式沒有用,而是自己編程開發經驗不足導致即使學了設計模式也很難駕馭。畢竟這些知識都是經過一些實際操作提煉出來的精華,但如果你可以按照本系列文章中的案例方式進行學習實操,還是可以增強這部分設計能力的。

八、推薦閱讀

  • 1. 重學 Java 設計模式:實戰工廠方法模式(多種類型商品發獎場景)
  • 2. 重學 Java 設計模式:實戰抽象工廠模式(替換Redis雙集群升級場景)
  • 3. 重學 Java 設計模式:實戰建造者模式(裝修物料組合套餐選配場景)
  • 4. 重學 Java 設計模式:實戰原型模式(多套試每人題目和答案亂序場景)
  • 5. 重學 Java 設計模式:實戰橋接模式(多支付渠道「微信、支付寶」與多支付模式「刷臉、指紋」場景)
  • 6. 重學 Java 設計模式:實戰組合模式(營銷差異化人群發券,決策樹引擎搭建場景)

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

Cypress系列(18)- 可操作類型的命令 之 點擊命令

如果想從頭學起Cypress,可以看下面的系列文章哦

https://www.cnblogs.com/poloyy/category/1768839.html

 

前言

  • 啥是可操作類型?就是可以和 DOM 元素交互的命令,比如:點擊,雙擊…..等等等
  • 這些命令模擬用戶和應用程序交互,Cypress 會觸發瀏覽器事件,進而觸發應用程序綁定的時間

這一篇着重講點擊操作,一共有三個命令

  1. click:單擊
  2. dbclick:雙擊
  3. rightclick:右鍵

 

.click() 的語法和用法

單擊某個元素

 

六種基礎語法格式

// 單擊某個元素
.click()

// 帶參數的單擊
.click(options)

// 在某個位置點擊
.click(position)

// 在某個位置點擊,且帶參數
.click(position, options)

// 根據頁面坐標點擊
.click(x, y)

// 根據頁面坐標點擊,且帶參數
.click(x, y, options)

 

正確用法

宗旨:先獲取 DOM 元素,再對 DOM 元素操作

 

錯誤用法

 

position 位置參數

每個元素都有九個 position,具體可看下圖

 

坐標 x, y

距離 DOM 元素左上角的坐標,x 是橫軸,y 是豎軸

 

options 可選參數

共有四個

 

 

如何傳 options ?

  •  .click({ multiple: true }) 
  •  .click({ multiple: true , force: true}) 

 

force: true 的作用

背景

  • Cypress 可以通過 Test Runner 的快照找到阻止 DOM 元素交互的情況,但某些情況下可能會阻礙測試的進行
  • 比如:有一個嵌套的導航結構,用戶必須將鼠標 hover 在一個非常特定的模式中,才能拿到所需的鏈接
  • 當測試時,其實我們只是想獲取鏈接而已,前面過多的繁瑣操作可能會導致測試失敗

 

作用

  • 當設置了 force: true 時,Cypress 會強制操作命令的發生,避開前面的所有檢查
  • 你可以傳遞 { force: true } 給大多數操作命令

 

栗子

// 強制點擊,和所有後續事件
// 即使該元素 “不可操作”,也會觸發點擊操作
cy.get('button').click({ force: true })

 

當使用 force 時,將執行這些操作

  • 繼續執行所有默認操作
  • 強制在元素上觸發事件

 

當使用 force 時,將不會執行這些操作

  • 滾動到視圖中
  • 確保可見
  • 確保未禁用
  • 確保沒有分離
  • 確保它不是只讀的
  • 確保它沒有動畫
  • 確保未覆蓋
  • 向後代觸發事件

 

總結

總而言之, { force: true } 跳過檢查,它將始終在所需元素處觸發事件

 

.click() 具體的栗子

.click() 的栗子

測試文件代碼

 

 

測試結果

 

.click(position)

測試文件代碼

 

測試結果

 

.click(x, y)

測試文件代碼

 

測試結果

 

{force: true} 的栗子

.click(options)

 

.click(position, options)

 

.click(x, y, options)

 

{multiple : true } 的栗子

測試文件代碼

 

測試結果

 cy.get(‘ ul > li ‘) 共匹配四個 DOM 元素,他們均觸發單擊操作

 

單擊組合鍵

 .click() 命令還可以與 .type() 命令結合使用修飾符來觸發組合鍵操作,以便在單擊時結合鍵盤操作,例如ALT + click

 

以下修飾符可以和 .click() 結合使用

修飾符 作用 別名
{alt}
等價於 alt 鍵 {option}
{ctrl} 等價於 ctrl 鍵 {control}
{shift} 等價於 shift 鍵  

 

栗子

 

.dblclick()

雙擊,跟 click() 的語法 & 用法一致,只是變成了雙擊

cy.get("#main1").dblclick()
cy.get("#main1").dblclick("top")
cy.get("#main1").dblclick(15, 15)

 

.rightclick()

右鍵,跟 click() 的語法 & 用法一致,只是變成了右鍵點擊

cy.get("#li1").rightclick()
cy.get("#li1").rightclick("top")
cy.get("#li1").rightclick(15, 15)

 

.click() 注意事項

可操作性

執行 .click()  必須是 DOM 元素達到了可操作狀態

 

關於斷言

 .click() 將自動等待元素達到可操作狀態。

 .click() 將自動等待後面鏈接的斷言通過

 

超時時間

 .click() 如果 DOM 元素一直達不到可操作狀態,可能會超時

 .click() 如果後面鏈接的斷言一直不通過,可能會超時

 

.click() 會觸發的鼠標事件

在命令日誌中單擊 click 時,控制台console 將輸出以下鼠標事件

 

結尾

本文是博主基於對蔡超老師的《Cypress 從入門到精通》閱讀理解完后輸出的博文,並附上了自己的理解

對書籍感興趣的,大家可以參考本篇博客:https://www.cnblogs.com/poloyy/p/13052972.html,考慮自身需求進行購買

 

我的博客即將同步至騰訊雲+社區,邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=12vd92hxgwgj1

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化