一帶一路又惹議 中國在克什米爾建水電廠引大規模示威_貨運

※評比南投搬家公司費用收費行情懶人包大公開

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式

摘錄自2020年7月7日中央社報導

國際亞洲新聞社(ANI)等印度媒體今(7日)報導,巴基斯坦控制克什米爾首府穆薩法拉巴德(Muzaffarabad)居民昨天舉行示威活動,譴責中國財團在尼肋姆河和吉魯姆河興建尼肋姆-吉魯姆(Neelum-Jhelum)水力發電廠和柯哈拉(Kohala)水力發電廠工程是非法建設,且嚴重破壞當地環境生態。

當地居民指控,水力發電廠營運後,會把尼肋姆河90%的河水轉移到發電廠,導致養活穆薩法拉巴德50萬人口的尼肋姆河流量和水位下降,影響當地居民生計,且引發當地氣溫升高。

※回頭車貨運收費標準

宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念

尼肋姆-吉魯姆水力發電廠和柯哈特水力發電廠興建項目,都是中國「一帶一路」下「中巴經濟走廊」的項目。其中,尼肋姆-吉魯姆水力發電廠從2008年開始興建,2018年8月完成;柯哈特水力發電廠工程則於2015年由中國長江三峽集團得標,於2018年起也引發當地居民抗議迄今。

生物多樣性
生態保育
國際新聞
中國新聞
巴基斯坦
水力發電廠
一帶一路
集水區

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

※智慧手機時代的來臨,RWD網頁設計為架站首選

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

真相難辨 日本政府涉放射線不實教材 15萬公民連署要求撤回_包裝設計

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

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

文:宋瑞文(媽媽監督核電廠聯盟特約撰述)

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

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

網動廣告出品的網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上她。

OPPO Find X3 Lite 完整實機開箱照洩漏!只是外觀有點眼熟?_網頁設計公司

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

台中景泰電動車行只是一個單純的理由,將來台灣的環境,出門可以自由放心的深呼吸,讓空氣回歸自然的乾淨,減少污染,留給我們下一代有好品質無空污的優質環境

前段時間 OPPO 正式在台灣推出 Reno5 系列新機,在 2021 年也傳聞將在第一季 Find X 系列就會推出最新的 Find X3 系列新機。不過在稍早有一款 OPPO Find X3 Lite 的實機外觀提前被曝光!從這些提前被洩漏的完整盒裝配件和標籤,都能肯定這就是 Find X3 Lite 國外市售版的實機。不過眼尖的人可能會發現,這款手機其實有些眼熟。

▲圖片來源:Sudhanshu(Twitter/@Sudhanshu1414)

OPPO Find X3 Lite 完整實機開箱照洩漏!只是外觀有點眼熟?

稍早在 Twitter 由 Sudhanshu 釋出了一批 OPPO Find X3 Lite 的完整實機開箱照片,從中我們可見到 Find X3 Lite 採用四鏡頭主相機、支持螢幕指紋辨識並附贈了軟質保護套和 SuperVOOC 快速充電器。

▲圖片來源:Sudhanshu(Twitter/@Sudhanshu1414)

從其他張照片能清楚看到 Find X3 Lite 的機身正反面,其螢幕採用平面的 OLED 挖孔全螢幕,在機身背面配備四鏡頭主相機。從這些照片各位想必已經覺得它有些眼熟吧?其實這款 OPPO Find X3 Lite 5G 應是針對特定市場推出的更名機型,而它的「本體」正是兩週前才剛在台灣正式發表的 OPPO Reno5 。

▲圖片來源:Sudhanshu(Twitter/@Sudhanshu1414)

OPPO Reno5(Find X3 Lite)與 Reno5 Pro 單從機身背面很難分辨,但從機身正面的螢幕則可區分兩者之間的不同。首先, OPPO Reno5 配備 6.43 吋 FHD+ 解析度 OLED 螢幕,螢幕為平面。至於 Reno5 Pro 則配備更大的 6.55 吋 FHD+ 解析度 OLED 曲面螢幕,兩者皆支援 90Hz 螢幕更新率和 180Hz 觸控採樣率。

▲Reno5(圖左)|Reno5 Pro(圖右)

然而,其實最早提出這則爆料的事 Evan Blass(@evleaks),他在兩週前就已經於 Voice 預告 OPPO 將以 Reno5 推出換名在其他市場上市的 Find X3 Lite ,當時也釋出官方渲染圖(如下):

▲圖片來源:Evan Blass(Voice/@evleaks)

這類將同款產品,針對不同銷售市場更換新的名稱在當地上市是相當常見的。例如之前部分 Redmi 和小米的手機、智慧手錶在引進台灣後,可能會採用不同的名稱。另外,前陣子 realme 在中國市場推出 realme V15 ,近期也將在印度市場更名為 realme X7 在印度上市。

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

網站的第一印象網頁設計,決定了客戶是否繼續瀏覽的意願。台北網動廣告製作的RWD網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上它。

消息來源:Sudhanshu(Twitter/@Sudhanshu1414)|Evan Blass(Voice/@evleaks)

延伸閱讀:
OPPO Reno5 、Reno5 Pro 正式在台發表:全新升級 AI 錄影、獨家 Reno Glow 2.0 星鑽工藝打造精緻外觀

realme Watch 2 智慧手錶通過 FCC 認證,外觀、規格提前曝光!電池容量增加、續航翻倍

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

以設計的實用美學觀點,規劃出舒適、美觀的視覺畫面,有效提昇使用者的心理期待,營造出輕鬆、愉悅的網站瀏覽體驗。

專業的才看的到!美國白宮新官網暗藏玄機 原始碼竟然有「招募啟示」_網頁設計公司

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

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

美國新任總統拜登於20日正式宣布就職,而美國白宮網站也在當天進行了改版。這次的改版除了新增時下流行的「深色模式」外,同時也有字體放大、縮小的功能。而有媒體發現,其實在網站的原始碼中,竟然暗藏一個不為人知的彩蛋。

有國外媒體發現,在白宮官方網站的原始碼中,竟然暗藏了一個非常特別的彩蛋,如果仔細鑽研這些原始碼,可以發現工程師在原始碼中寫下「If you’re reading this, we need your help building back better. 」(如果你正在閱讀這段文字,我們需要你的協助來進行更好的重建),同時還附上一個網址「https://usds.gov/apply」 ,而這段網址則是指向「美國數位服務小組(U.S. Digital Service,USDS)」的官方網站。這個非常特別的招募啟示,真的不是專業的高手根本不會注意到。

 

美國數位服務小組成立於2014年,在歐巴馬任期內成立的單位。由於當時美國政府各個單位、各地方政府都在進行數位化,觀念與知識彼此之間有嚴重落差不說,彼此之間的資料甚至還無法共通,於是歐巴馬就成立數為服務小組,主要工作就是由小組內經驗老道的工程師領導,協助美國政府的各個部門進行數位化的工作。

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

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

 

就過往來講,這次白宮網頁在原始碼中藏彩蛋,也並非是首例,就過往來講,也有非常多案例可以查詢,只是為何工程師們都習慣在原始罵內搞鬼呢?小編曾經詢問過業界相關人員,就有工程師朋友表示,其實身為一個專業的工程師,平時真的會習慣動不動就打開原始碼頁面來觀看,所以對於一般民眾覺得很難發現的原始碼,其實工程師們真的天天打開,一點都不困難,對他們就跟吃飯喝水一樣簡單。

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

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

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

api.versioning 版本控制 自動識別最高版本_網頁設計公司

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

以設計的實用美學觀點,規劃出舒適、美觀的視覺畫面,有效提昇使用者的心理期待,營造出輕鬆、愉悅的網站瀏覽體驗。

Microsoft.AspNetCore.Mvc.Versioning //引入程序集

.net core 下面api的版本控製作用不需要多說,可以查閱https://www.cnblogs.com/dc20181010/p/11313738.html

普通的版本控制一般是通過鏈接、header此類方法進行控制,對ApiVersionReader進行設置,例如

services.AddApiVersioning(o => {
                //o.ReportApiVersions = true;//返回版本可使用的版本
                o.ApiVersionReader = ApiVersionReader.Combine(new HeaderApiVersionReader("api-version"), new QueryStringApiVersionReader("api-version"));//通過Header或QueryString進行傳值來判斷api的版本
//o.DefaultApiVersion
= new ApiVersion(1, 0);//默認版本號
});

或者使用https://www.cnblogs.com/tdfblog/p/asp-net-core-api-versioning.html這種方式

這兩種方式都需要傳遞api的版本信息,如果不傳遞將會報錯

{"error":{"code":"ApiVersionUnspecified","message":"An API version is required, but was not specified.","innerError":null}}

如果我們不想傳遞api的版本信息時,可以將

o.AssumeDefaultVersionWhenUnspecified = true; //此選項將用於在沒有版本的情況下提供請求
o.DefaultApiVersion = new ApiVersion(1, 0); //設置默認Api版本是1.0

打開,這個我們每次請求如果不傳遞版本信息也不會報錯了,但我們的請求將會指向1.0版本,那麼我想讓默認版本指向我寫的api裏面的最高版本怎麼做?

我們將默認版本修改為最高版本可以嗎?

這裏將會出現一個問題,我的api版本可能由於各種各樣原因造成最高版本不一致的問題

所以我們不能採用指定默認版本是最高版本的方法來解決,這個最高版本還必須要是動態的,通過翻閱https://github.com/microsoft/aspnet-api-versioning/wiki/API-Version-Selector#current-implementation-api-selector可以得知

The CurrentImplementationApiVersionSelector selects the maximum API version available which does not have a version status. 
If no match is found, it falls back to the configured DefaultApiVersion. For example, if the versions "1.0", "2.0", and "3.0-Alpha" are available,
then "2.0" will be selected because it's the highest, implemented or released API version. CurrentImplementationApiVersionSelector選擇不具有版本狀態的最大可用API版本。 如果找不到匹配項,它將回退到配置的DefaultApiVersion。
例如,如果提供版本“
1.0”,“ 2.0”和“ 3.0-Alpha”,則將選擇“ 2.0”,因為它是最高,已實施或已發布的API版本。

services.AddApiVersioning( options => options.ApiVersionSelector = new CurrentImplementationApiVersionSelector( options ) );

通過這個版本選擇器,我們可以將最大版本得出,修改上面services.AddApiVersioning

services.AddApiVersioning(o => {
                o.ReportApiVersions = true;//返回版本可使用的版本
                //o.ApiVersionReader = new UrlSegmentApiVersionReader();
                //o.ApiVersionReader = ApiVersionReader.Combine(new HeaderApiVersionReader("api-version"), new QueryStringApiVersionReader("api-version"));
                //o.ApiVersionReader = ApiVersionReader.Combine(new QueryStringApiVersionReader("api-version"));
                o.ApiVersionReader = ApiVersionReader.Combine(new HeaderApiVersionReader("api-version"));//版本號以什麼形式,什麼字段傳遞
                o.AssumeDefaultVersionWhenUnspecified = true;//此選項將用於在沒有版本的情況下提供請求
                o.DefaultApiVersion = new ApiVersion(1, 0);//默認版本號
                o.ApiVersionSelector = new CurrentImplementationApiVersionSelector(o);//默認以當前最高版本進行訪問
            });

舉個栗子

namespace Default.v1.Controllers
{
    [ApiVersion("1.0")]
    [Route("[controller]/[action]")]
    [ApiController]
    public class HomeController : Controller, IBaseController
    {
        private readonly ILogger<HomeController> _logger;

        public HomeController (ILogger<HomeController> logger)
        {
            _logger = logger;
        }

        public JsonResult GetJson()
        {
            return Json("Home 1.0");
        }
}

Default.v1.Controllers.Home

namespace Default.v2.Controllers
{
    [ApiVersion("2.0")]
    [Route("[controller]/[action]")]
    [ApiController]
    public class HomeController : Controller, IBaseController
    {
        private readonly ILogger<HomeController> _logger;

        public HomeController (ILogger<HomeController> logger)
        {
            _logger = logger;
        }

        public JsonResult GetJson()
        {
            return Json("Home 2.0");
        }
}

Default.v2.Controllers.Home

namespace Default.v1.Controllers
{
    [ApiVersion("1.0")]
    [Route("[controller]/[action]")]
    [ApiController]
    public class TestController : Controller, IBaseController
    {
        private readonly ILogger<HomeController> _logger;

        public TestController (ILogger<HomeController> logger)
        {
            _logger = logger;
        }

        public JsonResult GetJson()
        {
            return Json("Test 1.0");
        }
}

Default.v1.Controllers.Test

 

 

 

 我們在

請求/home/getjson 時返回“Home 2.0”

請求/test/getjson 時返回“Test 1.0”

這樣就可以動態的請求最高版本了

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

台中景泰電動車行只是一個單純的理由,將來台灣的環境,出門可以自由放心的深呼吸,讓空氣回歸自然的乾淨,減少污染,留給我們下一代有好品質無空污的優質環境

 

但是還是會有問題的,比如,在我添加了Area和User區域下的HomeController,且User區域下的HomeController增加了1.0和3.0版本之後,神奇的一幕出現了

我的HomeController進不去了。。。

{"error":{"code":"UnsupportedApiVersion","message":"The HTTP resource that matches the request URI 'https://localhost:44311/home/getjson' is not supported.","innerError":null}}

這個時候去google都查不到原因。。。

查看api-supported-versions,返回的是1.0,2.0,3.0。。。我的api版本控制被污染了3.0版本從哪裡來的哪?第一反應是從User區域來的

我現在在User區域下添加一個除了Home和Test以外Name的Controller就可以請求成功,這個讓我懷疑到是不是api.versioning本身的問題,首先懷疑的是Controller的Name問題,源碼拉取下來,從添加版本控制的地方(services.AddApiVersioning)開始找

 

 

 

最後終於在ApiVersionCollator中找到了蛛絲馬跡

///https://github.com/microsoft/aspnet-api-versioning/blob/master/src/Microsoft.AspNetCore.Mvc.Versioning/Versioning/ApiVersionCollator.cs

namespace Microsoft.AspNetCore.Mvc.Versioning
{
    using Microsoft.AspNetCore.Mvc.Abstractions;
    using Microsoft.AspNetCore.Mvc.Controllers;
    using Microsoft.Extensions.Options;
    using System;
    using System.Collections.Generic;
    using System.Linq;

    /// <summary>
    /// Represents an object that collates <see cref="ApiVersion">API versions</see> per <see cref="ActionDescriptor">action</see>.
    /// </summary>
    [CLSCompliant( false )]
    public class ApiVersionCollator : IActionDescriptorProvider
    {
        readonly IOptions<ApiVersioningOptions> options;

        /// <summary>
        /// Initializes a new instance of the <see cref="ApiVersionCollator"/> class.
        /// </summary>
        /// <param name="options">The current <see cref="ApiVersioningOptions">API versioning options</see>.</param>
        public ApiVersionCollator( IOptions<ApiVersioningOptions> options ) => this.options = options;

        /// <summary>
        /// Gets the API versioning options associated with the collator.
        /// </summary>
        /// <value>The current <see cref="ApiVersioningOptions">API versioning options</see>.</value>
        protected ApiVersioningOptions Options => options.Value;

        /// <inheritdoc />
        public int Order { get; protected set; }

        /// <inheritdoc />
        public virtual void OnProvidersExecuted( ActionDescriptorProviderContext context )
        {
            if ( context == null )
            {
                throw new ArgumentNullException( nameof( context ) );
            }

            foreach ( var actions in GroupActionsByController( context.Results ) )
            {
                var collatedModel = CollateModel( actions );

                foreach ( var action in actions )
                {
                    var model = action.GetProperty<ApiVersionModel>();

                    if ( model != null && !model.IsApiVersionNeutral )
                    {
                        action.SetProperty( model.Aggregate( collatedModel ) );
                    }
                }
            }
        }

        /// <inheritdoc />
        public virtual void OnProvidersExecuting( ActionDescriptorProviderContext context ) { }

        /// <summary>
        /// Resolves and returns the logical controller name for the specified action.
        /// </summary>
        /// <param name="action">The <see cref="ActionDescriptor">action</see> to get the controller name from.</param>
        /// <returns>The logical name of the associated controller.</returns>
        /// <remarks>
        /// <para>
        /// The logical controller name is used to collate actions together and aggregate API versions. The
        /// default implementation uses the "controller" route parameter and falls back to the
        /// <see cref="ControllerActionDescriptor.ControllerName"/> property when available.
        /// </para>
        /// <para>
        /// The default implementation will also trim trailing numbers in the controller name by convention. For example,
        /// the type "Values2Controller" will have the controller name "Values2", which will be trimmed to just "Values".
        /// This behavior can be changed by using the <see cref="ControllerNameAttribute"/> or overriding the default
        /// implementation.
        /// </para>
        /// </remarks>
        protected virtual string GetControllerName( ActionDescriptor action )
        {
            if ( action == null )
            {
                throw new ArgumentNullException( nameof( action ) );
            }

            if ( !action.RouteValues.TryGetValue( "controller", out var key ) )
            {
                if ( action is ControllerActionDescriptor controllerAction )
                {
                    key = controllerAction.ControllerName;
                }
            }

            return TrimTrailingNumbers( key );
        }

        IEnumerable<IEnumerable<ActionDescriptor>> GroupActionsByController( IEnumerable<ActionDescriptor> actions )
        {
            var groups = new Dictionary<string, List<ActionDescriptor>>( StringComparer.OrdinalIgnoreCase );

            foreach ( var action in actions )
            {
                var key = GetControllerName( action );

                if ( string.IsNullOrEmpty( key ) )
                {
                    continue;
                }

                if ( !groups.TryGetValue( key, out var values ) )
                {
                    groups.Add( key, values = new List<ActionDescriptor>() );
                }

                values.Add( action );
            }

            foreach ( var value in groups.Values )
            {
                yield return value;
            }
        }

        static string TrimTrailingNumbers( string? name )
        {
            if ( string.IsNullOrEmpty( name ) )
            {
                return string.Empty;
            }

            var last = name!.Length - 1;

            for ( var i = last; i >= 0; i-- )
            {
                if ( !char.IsNumber( name[i] ) )
                {
                    if ( i < last )
                    {
                        return name.Substring( 0, i + 1 );
                    }

                    return name;
                }
            }

            return name;
        }

        static ApiVersionModel CollateModel( IEnumerable<ActionDescriptor> actions ) => actions.Select( a => a.GetApiVersionModel() ).Aggregate();
    }
}

View Code

 

其中GroupActionsByController將Controller按照Controller的名字進行分組,再看看內部,分組的時候將GetControllerName( action )作為key,那麼GetControllerName是幹嘛的,

protected virtual string GetControllerName( ActionDescriptor action )
        {
            if ( action == null )
            {
                throw new ArgumentNullException( nameof( action ) );
            }

            if ( !action.RouteValues.TryGetValue( "controller", out var key ) )
            {
                if ( action is ControllerActionDescriptor controllerAction )
                {
                    key = controllerAction.ControllerName;
                }
            }

            return TrimTrailingNumbers( key );
        }

這個方法原本是沒有問題的,但是牽扯到Area的時候就會出問題了。。它將根目錄下的HomeController和User.HomeController視為同一類的Controller然後去做版本的屬性注入,造成CurrentImplementationApiVersionSelector選擇器選不到正確的版本,所以返回了上面的錯誤,我們將GetControllerName內部修改為

protected virtual string GetControllerName( ActionDescriptor action )
        {
            if ( action == null )
            {
                throw new ArgumentNullException( nameof( action ) );
            }

            if ( !action.RouteValues.TryGetValue( "controller", out var key ) )
            {
                if ( action is ControllerActionDescriptor controllerAction )
                {
                    key = controllerAction.ControllerName;
                }
            }

            if ( !action.RouteValues.TryGetValue( "area", out var area ) )
            {
            }

            return TrimTrailingNumbers( area + key );
        }

這樣就可以走通了

 

我們有兩種解決辦法,一個是把源碼拉取下來,方法修改掉,項目的依賴項替換為自己修改的Microsoft.AspNetCore.Mvc.Versioning,另一種辦法是將services.AddApiVersioning重寫。。。請相信我,拉取修改替換依賴比重寫services.AddApiVersioning快且簡便。。。

issue:https://github.com/microsoft/aspnet-api-versioning/issues/630

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

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

網站的第一印象網頁設計,決定了客戶是否繼續瀏覽的意願。台北網動廣告製作的RWD網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上它。

踏上嵌入式之路,一去不復返!_網頁設計公司

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

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

大家好,昨天又有一批新的小夥伴加入,這裏重新簡單介紹一下自己的情況。和很多應屆生一樣,剛畢業有着找工作的迷茫和擔憂(這裏不包含已經工作的前輩),這是我去年也有過這樣的經歷;今天有一個網友加我微信,說在b站上看了我的介紹(b站ID:TXP嵌入式),學習經歷很像他,說到這裏,我也不由噓噓的感慨以前的時光,確實我大學裏面不是本專業的,是學汽車的,在學校里的時光,和朋友搞過一年多的汽車保養和維修的創業(其實也不算創業,當時想着提高自己的技術,這算是第一次體驗過如何去經營一個組織的經驗,確實當老闆沒有想象的那麼簡單,要有各方面的抗壓技能等等!),下面我就簡單說一下,我是如何從零基礎到linux開發崗位的一個經驗介紹:

 

正如上面所說,我是跨專業來學电子的,在幹了一年左右的汽車保養和維修,我果斷的放棄了汽車行業(其實最為直接的原因,就是出來上班工資太低,而且以我的體質不適合干汽車維修,為啥這樣說:舉個簡單,在進學院的實驗室管理員,這個過程中要經過大概三個月的魔鬼訓練,每天跑步大概6公里左右,然後跑完做各種難度的動作,到後面舉汽車的輪胎也是有的,說實話,這個我真舉不起,有些輪胎太大了,實在沒有力氣舉(我本身人又瘦小,所以你懂的當時是有多麼難的),後面我挺過來了,進了實驗室(這裏我很羡慕學电子或者計算機的網友能夠進入本學院的實驗室,順便再插一句,我學歷沒有很多大佬那麼高,我只是一名非常普通的大專生),這個過程我不展開詳細講了,今天的核心內容是如何從零基礎到linux開發崗位。

 

我是大二下學期快要結束的時候開始正式學編程(其實大二也有學,但是中途參加過兩次國家行業大賽:汽車新能源服務大賽和智能交通大賽,其中一次獲得三等獎(這裏非常感謝當時學院和老師的指導以及搭檔老王,這兩次比賽經歷算是我大學裏面最難忘的記憶了)。其實我學編程說實話,我的大學班主任算是我的啟蒙老師(這裏真的非常感謝,不然現在我自己也不知道做啥行業,沒有方向感),他給我推薦了一本c語言書籍和野火的開發板來學習,後面我就一發不可收拾了,一直自學堅持到現在,這其中走的彎路太多,比如:在我自己建的一個交流群裏面,經常有網友問,到底學哪個好,其實當初我也是這樣,在入門嵌入式過程中,會發現真的太多東西要學,苦於當時身邊沒有人指導一下方向(我的班主任他是研究生畢業,一出來就來到我們學校當老師了,當時也有找老師談過,但是自己還是沒有找到方向),所以學的過程中非常累,抓不住重點,看到那樣好,就馬上跟風去學,其實自己內心沒有去真正思考過這個技術到底是不是自己喜歡和以後吃飯的傢伙(這是站在我今天已經工作的角度簡單分析的。),因為嵌入式太廣了,甚至很多人連嵌入式到底是啥也不知道(所謂“嵌入式”,名如其文,指在很多芯片中,其所包含的處理器就像嵌入在裏面不為人知一樣,嵌入式領域的應用非常之廣泛,是處理器除了服務器和PC領域之外的主要應用領域:實時(Real Time)嵌入式領域(也就是我們常說的RTOS)、移動(Mobile)領域(比如要搞複雜的系統:linux、安卓等)、傳統嵌入式領域(一般就是單片機裸機了)),其實這段話,我是在網絡上看到一個前輩總結出的,結合自身體驗,確實是分為這三大領域。

 

回到剛才學嵌入式過程的哪個話題,其實在過程中最大的難處在於:缺乏鋼鐵一般的毅力(如果真喜歡嵌入式這個行業的話,一定要堅持下去,會有意想不到的結果)、良好的學術氛圍(我指的是自學的人沒有好學習的環境和交流,全靠一個人走“夜路”,走到哪裡算哪裡,也不知道到底是對還是錯)、缺乏項目經驗;第三點是很多人最為缺乏的(包括我自己也是這樣,其實有的網友說,學校做的畢設和企業裏面做的項目差別太大了,要考慮到很多方面,這個說的確實是這樣,但是我要說的是,先把學校畢設和一些小項目,認真做好,技術經驗和解決問題的能力就是在一個一個的小項目中成長的,帶領你如何走進嵌入式開發的大門,所以在學校裏面的實戰,一定要認真做好,有機會和對嵌入式感興趣的,可以去實驗室,不是說非要進入實驗室,只是說實驗室的環境稍微可能要好一點;把學校裏面的項目做好,後面有機會可以擴展到企業項目,只要你有能力,機會總會來的,就怕你沒有實力和準備,不然就算有機會來的,你也只能幹瞪眼和干著急,沒啥用啊,因為你不會啊,這就是現實;以後出來上班也是這樣,你憑什麼拿高薪,只有有能力給公司產生利潤,老闆就願意給你高薪,因為你有能力,值得這個價。)這裏可能又扯外了,哈哈,不過現實就是如此,只有自己有能力,資源和一切等,你都有機會得到。

 

這學習嵌入式過程,我自己走的彎路確實走的太多,而且很多東西又沒有學會,比如說一開始學過51單片機,後面看到別人玩pic、avr單片機,我也跟着去玩,最後發現自己還是沒有學會pic和avr,就是因為自己學的雜亂無比,其實這裏我建議在學的過程中,最好去網絡上找小項目練手,這樣會學的比較好,不要只看視頻教程學,這樣是學不到啥東西的,只是說帶你走了一個過程,熟悉了一下這種類型的開發以及一些協議和外設等等,實際你自己真要動手去做的話,你會發現不知道從哪裡下手,所以說要多練,養成一個良好的編程習慣以及當拿到一個小項目的時候,我該怎麼去入手,做好大體規劃,然後再去深入細節(這裏模塊化思維很重要,真的);然後後面,發現python和opencv好火,又去跟風學這個,又走了彎路,又沒有學會,這裏你可以發現我,不知道自己真正要學什麼,以後往哪裡走,只是一味的跟風(說的難聽一點,就是在裝逼);後面臨近畢業我真正開始意識到這一點,我得先深入一個方向去學,然後再去擴展,於是乎,我最開始是從pcb去深入的,我報了一個培訓班,認真學了三個月,確實出去能夠幹活了,這裏非常感謝凡億的鄭老師很助教的辛苦付出。在我學完pcb就直接去了一個非常小的公司裏面實習,軟件和硬件都要做,那時候我軟件很差勁,就畫板好一點,畫兩層板和四層還行,六層的不行,沒有實戰過,學的時候,跟實戰還是有差別的,而且小公司裏面不做那麼高層的板子,六層板的話,成本還是蠻高的,更別說8層、12層那種板子了。

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

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

 

那我是如何接觸到linux的呢?沒錯,我在那家小公司實習了兩個月,我就走了,為啥,因為我認識到了自己到底要啥了,這個時候我無意之間買了朱有鵬老師的嵌入式linux核心課程,對於我這種小白來說,這課程可以改變了我職業發展,這是我真心話,因為我出來上班,直接跳過做單片機,直接上手linux,其實這裏我也是比較幸運的,自己也比較大膽,在今天特殊情況下,一來深圳就辭職了上家公司(我正式上班的第一家公司是做手機屏幕,不算是驅動,只是簡單調試显示和觸摸,也不是我喜歡的;當然這裏我是有準備跳槽的。)在上家公司我又待了兩個月左右,這兩個月,我也不知道自己是怎麼走過來的,我拼了命在學朱老師課程,從最基本的linux命令(之前在學校的時候我接觸過,但是太零散了。)、以及基本的c語言基礎、c語言提高、linux應用編程,到現在的linux內核和驅動,在那兩個月里,我每天下班都會去看課程去學(晚上下班7:30.有時候晚一點,早上上班9點,然後周末是單休),每天晚上我都學到凌晨兩點左右,這和我學習pcb的時候,一樣,這種感覺現在回憶起來,讓人噓噓。期間我也開始寫公眾號了(把自己學的知識點,總結出來,並分享出去,讀者也可以發現,我寫的文章並不好,沒有深度,但是這是一個人成長的過程),就是我現在這個公眾號,這期間,我改變了自己的學習方式,養成了喜歡和別人交流技術,也認識了很多前輩和網友,這裏他們的幫助對我影響也非常大(過程中得到了很多指導以及一些網友提的不足之處,讓我糾正了很多誤區。)。

 

其實我去找linux崗位的時候,內心也是非常害怕,怕找不到工作的,因為我linux應用,只是學完了課程內容知識,並沒去找項目練手,只是想快點上手linux;於是乎,我在過年期間就開始頭簡歷,這過程確實難了,和現在有網友找工作的感受一樣;我投了很多簡歷,但是只收到的回復不是很多,因為缺乏項目經驗以及學歷的原因,沒有達到要求,但是我明白,這個過程是自己成長的過程,並沒有放棄對linux崗位的追求,終於後面經過在假期的磨鍊,我又投了幾家,終於收到了offer(這其中我自己又去認真的把課程中的一個網絡編程小項目又熟悉了一邊,以及c語言的基礎,即使是到現在我依然會去買一些書籍,繼續去鞏固基礎):

 

 

後面通過了面試,就順利拿到了linux崗位開發了。這裏我可能我沒有說的很具體,但是這其中的艱辛只有我自己知道,多少次想過放棄從事這個行業,但是又一次次我跌倒了,又重新站起來了,因為我奶奶經常告誡我:年輕的時候要多吃點苦,先苦后甜的道理,我聽過我奶奶講她以前的故事,那時候的苦,我的苦比起她吃的苦,簡直不能比)。

 

好了,今天就分享到這裏了,這就是我的簡單故事,平常和普通,只有靠自己的努力和行動才能得到你想要的。後面我會繼續分享技術文章;如果有網友想進交流群的話,可以加我微信,回復技術,我會拉您進群,之所以這樣,是為了防止有些人,進了交流群裏面,老是發一些與技術無關的鏈接和廣告,這樣的話,就失去了交流群的意義了。最後,說一句:感謝各位網友的支持。

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

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

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

面試問題—JAVA程序CPU佔用過高怎麼定位_網頁設計

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

擁有專業的維修技術團隊,同時聘請資深iphone手機維修專家,現場說明手機問題,快速修理,沒修好不收錢

今天一個電話面試問了這個問題。回來查了下答案,自己也順帶操作一遍,做個記錄。之前只知道jstack工具可以查看線程狀態這些。比如死鎖這些,主要是之前不知道top -H -p pid這個命令的使用,這命令可以看到進程下麵線程信息,拿到線程ID,然後再結合jstack命令使用就可以解決這個問題了。下面記錄一下具體的操作步驟:

1.打個jar包丟到機器上運行

package com.nijunyang.test;



public class TestApplication {

    public static void main(String[] args) {
        for (int i = 0; i < 50; i++) {
            new Thread(()->test()).start();
        }

    }

    public static void test() {
        while (true) {
            int a = 1  + 6;
            System.out.println(a);
        }
    }
}

使用這個maven插件 打包jar

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.nijunyang.test.TestApplication</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

2. java -jar test-0.0.1-SNAPSHOT-jar-with-dependencies.jar  運行程序

 

 一直在輸出

3.top |grep java  或者 jps指令找到java進程的pid(6167)

 

 

4. top -H -p pid   以線程的形式查看該進程 top -H -p 6167

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

窩窩以「數位行銷」「品牌經營」「網站與應用程式」「印刷品設計」等四大主軸,為每一位客戶客製建立行銷脈絡及洞燭市場先機。

 

 因為我們程序是起了50個線程 所以這裏就會展示這個進程中的所有線程呢

5.前面的線程ID是10進制的,,需要轉換成16進制,,因為等下在jstack命令取出來的線程ID是16進制的:這裏就隨便選一個線程ID 去轉換了,真實環境肯定是選擇CPU佔用率最高的那個線程,echo “obase=16;6219” | bc

 

 

6.jstack 6167 >threadInfo.txt   信息輸出到文件 然後查看。也可以直接在命令裏面查看

 

7.文件中查找184b的線程ID信息,就可以找到是哪個線程導致的內存佔用過高,同時也能看到具體的代碼位置

 

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

台北網頁設計公司這麼多該如何選擇?

網動是一群專業、熱情、向前行的工作團隊,我們擁有靈活的組織與溝通的能力,能傾聽客戶聲音,激發創意的火花,呈現完美的作品

SpringSecurity(1)—認證+授權代碼實現_貨運

※評比南投搬家公司費用收費行情懶人包大公開

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式

認證+授權代碼實現

Spring Security是 一種基於 Spring AOP 和 Servlet 過濾器的安全框架。它提供全面的安全性解決方案,同時在 Web 請求級和方法調用級處理身份確認和授權。

有關認證和授權的理論知識,之前有寫過相關博客。了解權限管理

一、SpringSceurity工作流程

網上找一張圖,覺得畫的挺好的,比較容易理解。不然換的是源碼流程圖很難去理解。

圖片地址 : 地址 可以單機放大看更加清楚

要想理解這張圖建議看下這篇博客,因為這張圖中需要自定義的My…類,在文章中都有說明,所以更好理解點。

Spring Boot Security 詳解

二、認證+授權代碼

這裏只展示一些核心代碼,具體完整代碼放在github上。

1、UserDetails接口

Security 中的用戶接口,我們自定義用戶類要實現該接口, 用於向security中注入當前用戶的姓名密碼,和擁有的角色。同時也包含一些其它信息,比如當前用戶是否過期,

賬號是否鎖定等等。

自己定義User實現這個接口

public class User implements UserDetails {
    private String username;
    private String password;
    private List<Role> roles;
    /**
     * 獲取用戶名
     */
    @Override
    public String getUsername() {
        return username;
    }
    /**
     * 獲取密碼
     */
    @Override
    public String getPassword() {
        return password;
    }
    /**
     * 用戶的權限集, 默認需要添加ROLE_ 前綴
     */
    @Override
    @JsonIgnore
    public List<GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> authorities = new ArrayList<>();
        for (Role role : roles) {
            authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
        }
        return authorities;
    }
    /**
     * 賬戶是否過期
     */
    @Override
    @JsonIgnore
    public boolean isAccountNonExpired() {
        return true;
    }
    /**
     * 賬戶是否鎖定
     */
    @Override
    @JsonIgnore
    public boolean isAccountNonLocked() {
        return true;
    }
    /**
     * 憑證是否過期
     */
    @Override
    @JsonIgnore
    public boolean isCredentialsNonExpired() {
        return true;
    }
    /**
     * 用戶是否可用
     */
    @Override
    public boolean isEnabled() {
        return true;
    }  
}

2、UserDetailsService

Security 中的用戶 Service,自定義用戶服務類需要實現該接口。這個接口只有一個方法需要我們去實現,那就是通過用戶名去獲取用戶信息。這裏也是和數據庫交互獲取

用戶認證和授權信息的地方。

@Service
@Slf4j
public class UserService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        //TODO 正常應該查詢數據庫獲取用戶和用戶的權限
//        User user = userMapper.loadUserByUsername(userName);
//        List<Role> roles = rolesMapper.getRolesByUid(user.getId());
//        user.setRoles(roles);
        log.info("登陸用戶名: {}", userName);
        //通過用戶名查詢到的密碼 密碼肯定是加密過的 這裏明文密碼是 123456
        String password = "e10adc3949ba59abbe56e057f20f883e";
        //用戶對應權限
        List<Role> roles = Lists.newArrayList(new Role(1L, "教師"), new Role(2L, "學生"));
        User user = new User(userName, password, roles);
        return user;
    }
}

注意 這裏的明文密碼是 123456,也就是用戶輸入這個才能完成認證。授權的話當前用戶有兩個角色 教師學生。在下面測試的時候會用到。

3、WebSecurityConfigurerAdapter

它是Spring Security的Java 配置類。創建類SecurityConfiguration繼承 WebSecurityConfigurerAdapter,來對我們應用中所有的安全相關的事項(

所有url,驗證用戶名密碼,表單重定向等)進行控制。

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 1、配置的是認證信息, AuthenticationManagerBuilder 這個類,就是AuthenticationManager的建造者, 我們只需要向這個類中, 配置用戶信息,
     *    就能生成對應的AuthenticationManager, 這個類也提過,是用戶身份的管理者, 是認證的入口, 因此,我們需要通過這個配置,想security提供真實的用戶身份。
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    }
    /**
     * 2、配置Security的認證策略, 每個模塊配置使用and結尾。這個也是最複雜的
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    }
    /**
     * 3、這個配置方法用於配置靜態資源的處理方式,可使用 Ant 匹配規則。就是可以不用認證就可以直接訪問的接口
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
    }
}

完整示例

※回頭車貨運收費標準

宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService userService;
    /**
     * 密碼驗證器
     */
    @Autowired
    private PassWordEncorder passWordEncorder;
    /**
     * 成功處理器
     */
    @Autowired
    private AuthenctiationSuccessHandler authenctiationSuccessHandler;

    /**
     * 失敗處理器
     */
   @Autowired
   private AuthenctiationFailHandler authenctiationFailHandler;
   /**
    * 向Security注入用戶信息
    */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(passWordEncorder);
    }
    /**
     * 配置規則
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //開啟登陸配置
        http.authorizeRequests()
                // 登錄之後就能訪問
                .antMatchers("/no-authorize").authenticated()
                // 登陸后 需要校長角色權限
                .antMatchers("/need-authorize").hasRole("校長")
                // 其他的路徑都是登錄后即可訪問
                .anyRequest().authenticated()
                .and().formLogin()
                // 定義登錄頁面,未登錄時,訪問一個需要登錄之後才能訪問的接口,會自動跳轉到該頁面
                .loginPage("/login_page")
                //登錄成功的處理器
                .successHandler(authenctiationSuccessHandler)
                //登錄失敗的處理器
                .failureHandler(authenctiationFailHandler)
                // 登錄處理接口
                .loginProcessingUrl("/login")
                // 定義登錄時,用戶名的 key,默認為 username
                .usernameParameter("username")
                //定義登錄時,用戶密碼的 key,默認為 password
                .passwordParameter("password").permitAll()
                .and().logout()
                ////和表單登錄相關的接口統統都直接通過
                .permitAll()
                .and().csrf().disable().exceptionHandling().accessDeniedHandler(getAccessDeniedHandler());
    }

    /**
     * 對於/static/  下的路徑都不用認證
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/no-login");
    }

    /**
     * 用戶未認證異常攔截
     */
    @Bean
    AccessDeniedHandler getAccessDeniedHandler() {
        return new AuthenticationAccessDeniedHandler();
    }
}

注意 這裏一共配置了三個路徑用於測試。

1、/no-login 接口不需要認證就可以直接訪問
2、/no-authorize 需要認證 但不需要授權就可以訪問
3、/need-authorize 首先需要認證 認證通過還需要授權 這裏需要校長的角色才可以訪問該接口 但是我們測試用戶只有教師和學生所以沒有權限訪問該接口

下面會針對這個個接口分別進行測試。

三、測試

1、接口提供

@RestController
public class TestController {

    /**
     * 1、不需要登陸就可以訪問
     */
    @RequestMapping(value = "/no-login")
    public ServiceResponse noLogin() {
        return ServiceResponse.success("歡迎訪問不需要登陸接口");
    }
    /**
     * 2、只登陸,不許認證接口
     */
    @RequestMapping(value = "/no-authorize")
    public ServiceResponse needAuthorize(){
        return ServiceResponse.success("登陸了 不用授權");
    }
    /**
     * 3、登陸 + 相關認證接口
     */
    @RequestMapping(value = "/need-authorize")
    public ServiceResponse noAuthorize() {
        return ServiceResponse.success("登陸+授權成功");
    }
    /**
     * @Description: 如果自動跳轉到這個頁面,說明用戶未登錄,返回相應的提示即可
     */
    @RequestMapping("/login_page")
    public ServiceResponse loginPage() {
        return  ServiceResponse.failure("001", "尚未登錄,請登錄!");
    }
}

2、未登錄訪問 no-login 和 no-authorize 接口

no-login接口

很明顯沒有登陸 請求該接口成功!

no-authorize接口

沒有登陸訪問失敗,在上面配置了如果用戶沒有認證的話跳轉到login_page接口,所以這裏返回 ‘尚未登錄,請登錄!’

3、登陸后訪問 no-authorize 和 need-authorize 接口

先登陸

根據上面配置登陸的路徑為 /login 請求參數包括 usernamepassword

注意 這裏需要post請求。

no-authorize 接口

登陸就可以訪問了。

need-authorize 接口

雖然登陸成功了,但是因為該接口需要校長角色,之前給該用戶只配置了教師和學生的角色所以訪問失敗。

參考

1、SpringSide 3 中的安全框架

2、Spring Security 工作原理概覽

3、Spring Boot Security 詳解 很贊

別人罵我胖,我會生氣,因為我心裏承認了我胖。別人說我矮,我就會覺得好笑,因為我心裏知道我不可能矮。這就是我們為什麼會對別人的攻擊生氣。
攻我盾者,乃我內心之矛(17)

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

※智慧手機時代的來臨,RWD網頁設計為架站首選

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

結合 AOP 輕鬆處理事件發布處理日誌_包裝設計

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

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

結合 AOP 輕鬆處理事件發布處理日誌

Intro

前段時間,實現了 EventBus 以及 EventQueue 基於 Event 的事件處理,但是沒有做日誌(EventLog)相關的部分,原本想增加兩個接口, 處理事件發布日誌和事件處理日誌,最近用了 AOP 的思想處理了 EntityFramework 的數據變更自動審計,於是想着事件日誌也用 AOP 的思想來實現,而且可能用 AOP 來處理可能會更好一些,最近自己造了一個 AOP 的輪子 —— FluentAspects,下面的示例就以它來演示了,你也可以換成自己喜歡的 AOP 組件,思想是類似的

事件日誌示例

事件發布日誌

事件發布日誌只需要攔截事件發布的方法調用即可,在發布事件時進行攔截,在攔截器中根據需要進行日誌記錄即可

事件發布者接口定義:

public interface IEventPublisher
{
    /// <summary>
    /// publish an event
    /// </summary>
    /// <typeparam name="TEvent">event type</typeparam>
    /// <param name="event">event data</param>
    /// <returns>whether the operation succeed</returns>
    bool Publish<TEvent>(TEvent @event) where TEvent : class, IEventBase;

    /// <summary>
    /// publish an event async
    /// </summary>
    /// <typeparam name="TEvent">event type</typeparam>
    /// <param name="event">event data</param>
    /// <returns>whether the operation succeed</returns>
    Task<bool> PublishAsync<TEvent>(TEvent @event) where TEvent : class, IEventBase;
}

事件發布日誌攔截器:

public class EventPublishLogInterceptor : AbstractInterceptor
{
    public override async Task Invoke(IInvocation invocation, Func<Task> next)
    {
        Console.WriteLine("-------------------------------");
        Console.WriteLine($"Event publish begin, eventData:{invocation.Arguments.ToJson()}");
        var watch = Stopwatch.StartNew();
        try
        {
            await next();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Event publish exception({ex})");
        }
        finally
        {
            watch.Stop();
            Console.WriteLine($"Event publish complete, elasped:{watch.ElapsedMilliseconds} ms");
        }
        Console.WriteLine("-------------------------------");
    }
}

事件處理日誌

事件處理器接口定義:

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

網動廣告出品的網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上她。

public interface IEventHandler
{
    Task Handle(object eventData);
}

事件處理日誌攔截器定義:

public class EventHandleLogInterceptor : IInterceptor
{
    public async Task Invoke(IInvocation invocation, Func<Task> next)
    {
        Console.WriteLine("-------------------------------");
        Console.WriteLine($"Event handle begin, eventData:{invocation.Arguments.ToJson()}");
        var watch = Stopwatch.StartNew();
        try
        {
            await next();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Event handle exception({ex})");
        }
        finally
        {
            watch.Stop();
            Console.WriteLine($"Event handle complete, elasped:{watch.ElapsedMilliseconds} ms");
        }
        Console.WriteLine("-------------------------------");
    }
}

AOP 配置

Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(builder =>
    {
        builder.UseStartup<Startup>();
    })
    .UseFluentAspectsServiceProviderFactory(options =>
    {
        // 攔截器配置
        
        // 攔截 `IEventPublisher` 日誌,註冊事件發布日誌攔截器
        options
            .InterceptType<IEventPublisher>()
            .With<EventPublishLogInterceptor>();

        // 攔截 `IEventHandler`,註冊事件處理日誌攔截器
        options.InterceptType<IEventHandler>()
            .With<EventHandleLogInterceptor>();
    }, builder =>
    {
        // 默認使用默認實現來生成代理,現在提供了 Castle 和 AspectCore 的擴展,也可以自己擴展實現自定義代理生成方式
        // 取消註釋使用 Castle 來生成代理
        //builder.UseCastleProxy();
    }, t => t.Namespace?.StartsWith("WeihanLi") == false // 要忽略的類型斷言
    )
    .Build()
    .Run();

More

事件發布示例,定義了一個發布事件的中間件:

// pageView middleware
app.Use((context, next) =>
{
    var eventPublisher = context.RequestServices
        .GetRequiredService<IEventPublisher>();
    eventPublisher.Publish(new PageViewEvent()
    {
        Path = context.Request.Path.Value,
    });

    return next();
});

事件處理示例是用一個消息隊列的模式來處理的,示例和前面的事件的文章類似,EventConsumer 是一個後台任務,完整代碼示例如下:

public class EventConsumer : BackgroundService
{
    private readonly IEventQueue _eventQueue;
    private readonly IEventHandlerFactory _eventHandlerFactory;

    public EventConsumer(IEventQueue eventQueue, IEventHandlerFactory eventHandlerFactory)
    {
        _eventQueue = eventQueue;
        _eventHandlerFactory = eventHandlerFactory;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            var queues = await _eventQueue.GetQueuesAsync();
            if (queues.Count > 0)
            {
                await queues.Select(async q =>
                        {
                            var @event = await _eventQueue.DequeueAsync(q);
                            if (null != @event)
                            {
                                var handlers = _eventHandlerFactory.GetHandlers(@event.GetType());
                                if (handlers.Count > 0)
                                {
                                    await handlers
                                            .Select(h => h.Handle(@event))
                                            .WhenAll()
                                        ;
                                }
                            }
                        })
                        .WhenAll()
                    ;
            }

            await Task.Delay(1000, stoppingToken);
        }
    }
}

完整的示例代碼可以從https://github.com/WeihanLi/WeihanLi.Common/blob/dev/samples/AspNetCoreSample 獲取

OverMore

之前在微軟的 EShopOnContainers 項目里又看到類似下面這樣的代碼,在發布事件的時候包裝一層 try … catch 來記錄事件發布日誌,相比之下,本文示例中的這種方式更為簡潔,代碼更清爽

Reference

  • https://www.cnblogs.com/weihanli/p/12941919.html
  • https://www.cnblogs.com/weihanli/p/implement-event-queue.html
  • https://github.com/WeihanLi/WeihanLi.Common
  • https://github.com/WeihanLi/WeihanLi.Common/blob/dev/samples/AspNetCoreSample/Startup.cs

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

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

上新台中搬家公司提供您一套專業有效率且人性化的辦公室搬遷、公司行號搬家及工廠遷廠的搬家服務

月銷2萬!國產SUV又一爆款誕生了!_網頁設計公司

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

網站的第一印象網頁設計,決定了客戶是否繼續瀏覽的意願。台北網動廣告製作的RWD網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上它。

5的最低投訴銷量比奪得第一,大幅超越主流合資產品,成為有口皆碑的A級車“品質王”。榮威360憑藉“藍芯”科技在動力總成上的核心優勢,以榮威RX5和榮威360為代表的產品“量價齊收”,還將持續帶動榮威品牌的快速增長。新能源:獲中國汽車界“諾貝爾”獎,勇奪專業賽道“插混王”10月,上汽新能源不僅在技術、整車性能等方面得到了行業和消費者的認可,市場銷量也在不斷攀升。

在榮威RX5強勁熱銷勢頭的帶動下,上汽乘用車10月銷量破4萬,同比激增147%!榮威品牌更是以245%的增速,蟬聯中國品牌增速王!

10月,榮威RX5月銷量首次突破2萬輛,截至目前訂單量已突破10萬輛。第4.5萬輛榮威RX5已於日前在上汽臨港生產基地下線,南京工廠榮威RX5生產線也如期改造完成並將全面投產。榮威RX5的熱銷還帶動了榮威、MG名爵各款車型的銷售,上汽乘用車10月份總銷量超過4萬輛,同比激增147%。

上汽乘用車堅持中高端發展路線,十年磨一劍,通過品質和技術的提升來打造最好的產品。隨着今年“芯動戰略”成果的集中爆發,上汽也正式駛入“品質+銷量”發展階段的“快車道”,引領中國品牌走進品價比時代。

榮威RX5月銷量破2萬 好爸爸聯手領跑市場

10月,榮威RX5銷量突破2萬輛。在榮威RX5熱銷帶動下,上汽榮威品牌從8月同比增長205%,9月增214%,到10月的245%,銷量連續翻番,勢如破竹,帶領上汽乘用車重回發展快車道。爆款SUV榮威RX5上市第三個月銷量即破2萬,還獲得李克強總理親切“接見”,以及工博會工業設計金獎、2017年度德國紅點“中國好設計”榮譽獎、2016“上海市優秀工業設計金獎”等榮譽;榮威360和榮威350組成的“榮威3系”,9月、10月銷量接連破萬,實現了銷量與口碑的雙豐收。

榮威RX5獲工博會工業設計金獎

從上市不到2周互聯網車型訂單破萬,到上市首月交車近萬輛,次月銷量近1.4萬輛,再到第三個月銷量超過2萬輛,榮威RX5的爆款熱銷之勢根本停不下來!作為首款成功突破合資價格區間的中國品牌SUV,真正讓消費者“買得起、用得爽”,成為10-20萬元SUV首選。隨着榮威RX5持續熱賣,勢必將進一步撬動車市格局。

榮威RX5在SUV市場上的大獲全勝,離不開陳虹“爸爸”和馬雲“爸爸”的聯手助攻。在10月的全球首次互聯網汽車拉力賽中,榮威RX5憑藉上汽世界級“藍芯”高效動力科技,以及阿里的互聯網黑科技,創下3.7L/百公里的超低油耗紀錄,刷新SUV節油標準。憑藉互聯網“黑科技”在複雜生活場景中的實際應用,榮威RX5率先開啟了未來交通密碼,為用戶探索追求新生活方式的可能性。

榮威RX5全球首次互聯網汽車拉力賽啟動

不只在SUV市場發力,在家轎市場上,榮威品牌勢頭同樣強勁。上市一周年的榮威360,憑藉全方位高品質和紮實的用戶口碑,累計銷售9萬輛,成為囊括“Carplay車型銷量王”、“品質王”及“A級車節油王”的“三冠王”,更是榮獲德國紅點“中國好設計”唯一汽車類大獎。此前的“千公里一箱油”極限油耗挑戰總決賽中,榮威360一箱油可行駛1496km,創下3.7L/100km的最低油耗紀錄,力證“藍芯”世界級高效動力的領先燃油經濟性。在權威汽車平台《車質網》公布的投訴排行榜中,榮威360以萬分之2.5的最低投訴銷量比奪得第一,大幅超越主流合資產品,成為有口皆碑的A級車“品質王”。

榮威360

憑藉“藍芯”科技在動力總成上的核心優勢,以榮威RX5和榮威360為代表的產品“量價齊收”,

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

以設計的實用美學觀點,規劃出舒適、美觀的視覺畫面,有效提昇使用者的心理期待,營造出輕鬆、愉悅的網站瀏覽體驗。

還將持續帶動榮威品牌的快速增長。

新能源:獲中國汽車界“諾貝爾”獎,勇奪專業賽道“插混王”

10月,上汽新能源不僅在技術、整車性能等方面得到了行業和消費者的認可,市場銷量也在不斷攀升。

10月28日,中國汽車工業科學技術獎揭曉,上汽新能源憑藉在EDU電驅、HCU電控和ESS電池方面的創新,成為今年插電混動領域唯一獲一等獎的車企,這也是上汽時隔5年再次獲得中國汽車界最高榮譽。中國汽車工業科學技術獎是經國家科委批准,業內公認的最能代表中國汽車科技發展水平的獎項,被譽為中國汽車界“諾貝爾獎”。擁有百餘項國內外專利授權和技術認證,上汽插電混動技術突破了混合動力技術的專利壁壘,成為最先進的新能源汽車動力科技。

榮威e550

得益於上汽世界級新能源科技的運用,榮威e550首次參加中國量產車性能大賽(CCpC),便以總成績第一的表現摘得冠軍,並分別在長距離經濟性、制動性、舒適性等方面共斬獲了6個單項冠軍,充分驗證了上汽新能源領先世界的產品性能,大大增強了消費者的購買信心。

截止10月,上汽新能源今年已累計銷售17474輛,同比大增114%。其中,主銷車型榮威e550共銷售了13600輛,同比增長72%,多次獲得新能源中級車“銷量王”稱號。今年上市的中國首款插電混動高級轎車榮威e950,已連續三個月成為上海B級車銷量冠軍,並成為中國首款月銷過千的新能源B級車。

榮威e950

接下來,上汽新能源還將推出SUV車型,豐富消費者選擇,並引領中高端SUV市場消費趨勢,給消費者提供最智能便捷、最節能環保的出行方案。

MG名爵:前10月同比增長30% 名爵銳騰高性能領跑SUV細分市場

MG名爵10月繼續保持穩步攀升的態勢。今年1-10月,MG名爵全系車型銷量達到58797輛,與去年同比勁增27%!“高性能中級SUV”名爵銳騰更是以全面越級的產品力強勢領跑,同比增長30%。

征戰,不是我們的習慣,而是我們的傳統!作為“高性能中級SUV”,名爵銳騰7月從新疆天山開啟征程,以“十項全能 挑戰巔峰”的高性能姿態全面征服嚴苛複雜的山路環境。得益於上汽世界級“藍芯”動力科技與保時捷專業級底盤調校強強聯手,名爵銳騰從絕壁斷崖到5000米海拔全面制霸,並用自己獨有的方式和態度號召更多年輕人加入到征戰的隊伍中,把自己的愛車真正“開出趣”、綻放年輕的魅力。

名爵銳騰

除了SUV產品的出色表現,高性能風尚中級車MG GT名爵銳行勢頭同樣強勁,1-10月銷量同比增長更是高達61%。今年推出2016款MG GT名爵銳行並新增1.5L車型后,其價格下探至7萬區間,幫助更多年輕消費者實現購車夢想。此外,9月起MG GT名爵銳行的智能娛樂行車系統全面升級,可支持百度CarLife,適配手機的型號更寬泛,名爵銳行也成為首款同時兼容蘋果Carplay和百度CarLife的中級車,全面進入“雙Car”時代。

MG名爵與生俱來的競速基因,讓更多的消費者享受駕控樂趣和汽車生活,綻放獨有的個性魅力,將愛車“開出趣”。即將進入年底收官的關鍵,高性能、高智能、高安全的核心優勢,將帶動MG名爵品牌持續高速增長。

隨着品價比時代的到來,上汽始終堅持品質為王,打造符合時代的最好產品。在“芯動戰略”的整體戰略布局下,上汽乘用車以“藍芯”和“綠芯”兩大技術品牌為支撐,搭載互聯網思維,堅持創新發展,突破傳統局限。未來上汽乘用車還將不斷超越創新,為消費者帶來更多高品質的越級之作。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

台中景泰電動車行只是一個單純的理由,將來台灣的環境,出門可以自由放心的深呼吸,讓空氣回歸自然的乾淨,減少污染,留給我們下一代有好品質無空污的優質環境