1. 程式人生 > >MVC系列——MVC原始碼學習:打造自己的MVC框架(三:自定義路由規則)

MVC系列——MVC原始碼學習:打造自己的MVC框架(三:自定義路由規則)

前言:上篇介紹了下自己的MVC框架前兩個版本,經過兩天的整理,版本三基本已經完成,今天還是發出來供大家參考和學習。雖然微軟的Routing功能已經非常強大,完全沒有必要再“重複造輪子”了,但博主還是覺得自己動手寫一遍印象要深刻許多,希望想深入學習MVC的童鞋自己動手寫寫。好了,廢話就此打住。

MVC原始碼學習系列文章目錄:

一、版本三功能介紹

在版本三裡面,為了更加透徹理解UrlRoutingModule裡面的路由功能,博主自己寫了一遍路由的讀取和配置過程,完成之後整個框架的程式碼目錄結構如下:

主要還是分為兩大塊:MVC目錄裡面的對應著MvcHandler的邏輯,Routing目錄物件對應的UrlRoutingModule的邏輯。整個呼叫過程如下:

看到這個圖,你可能仍然是懵比狀態。沒關係,如果你有興趣,且往下看。

二、UrlRoutingModule的實現

在整個UrlRoutingModule裡面,我們所有的路由相關邏輯都和System.Web.Routing這個元件沒有任何聯絡,完全是一塊獨立的區域。為了方便理解,這些檔案的命名在原來System.Web.Routing元件裡面的類前面都加上一個“Swift”。UrlRoutingModule的主要邏輯都在以下這些檔案裡面:

1、SwiftRouteTable.cs程式碼

namespace Swift.MVC.Routing
{
    public class
SwiftRouteTable { //靜態建構函式,約束這個靜態物件是一個不被釋放的全域性變數 static SwiftRouteTable() { routes = new SwiftRouteCollection(); } private static SwiftRouteCollection routes; public static SwiftRouteCollection Routes { get {
return routes; } } } }

這個類主要作用就是定義一個靜態全域性的SwiftRoutingCollection物件,在Global.asax裡面可以配置這個路由集合。為什麼是一個靜態全域性變數呢?靜態是為了保證物件不被釋放(GC回收);全域性是為了保證整個應用程式都可以訪問得到。

2、SwiftRouteCollection.cs程式碼

上文在SwiftRouteTable裡面定義一個靜態全域性的SwiftRoutingCollection變數,我們來看這個裡面到底有些什麼東西。

namespace Swift.MVC.Routing
{
    public class SwiftRouteCollection
    {
        public SwiftRoute SwiftRoute { get; set; }

        public string Name { get; set; }

        //Global.asax裡面配置路由規則和預設路由
        public void Add(string name, SwiftRoute route)
        {
            SwiftRoute = route;
            Name = name;
        }

        //通過上下文物件得到當前請求的路由表
        public SwiftRouteData GetRouteData(HttpContextBase context)
        {
            var swiftRouteData = new SwiftRouteData();
            //1.配置RouteHandler例項,這裡的RouteHandler是在全域性配置裡面寫進來的
            swiftRouteData.RouteHandler = SwiftRoute.RouteHandler;

            //2.獲取當前請求的虛擬路徑和說明
            var virtualPath = context.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + context.Request.PathInfo;

            //3.先將預設路由配置寫入當前請求的路由表
            //每次請求只能讀取預設值,而不能覆蓋預設值
            swiftRouteData.RouteValue = new Dictionary<string, object>() ;
            foreach (var key in this.SwiftRoute.DefaultPath)
            {
                swiftRouteData.RouteValue[key.Key] = key.Value;
            }

            //4.如果當前請求虛擬路徑為空,則訪問預設路由表。否則從當前請求的url裡面去取當前的controller和action的名稱
            if (!string.IsNullOrEmpty(virtualPath))
            {
                var arrTemplatePath = this.SwiftRoute.TemplateUrl.Split("{}/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                var arrRealPath = virtualPath.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                for (var i = 0; i < arrTemplatePath.Length; i++)
                {
                    var realPath = arrRealPath.Length > i ? arrRealPath[i] : null;
                    if (realPath == null)
                    {
                        break;
                    }
                    swiftRouteData.RouteValue[arrTemplatePath[i]] = realPath;
                }
            }
            //5.去讀當前請求的引數列表
            var querystring = context.Request.QueryString.ToString();
            if (string.IsNullOrEmpty(querystring))
            {
                return swiftRouteData;
            }
            var parameters = querystring.Split("&".ToArray(), StringSplitOptions.RemoveEmptyEntries) ;
            var oparam = new Dictionary<string, string>();
            foreach (var parameter in parameters)
            {
                var keyvalue = parameter.Split("=".ToArray());
                oparam[keyvalue[0]] = keyvalue[1];
            }
            swiftRouteData.RouteValue["parameters"] = oparam;
            return swiftRouteData;
        }
    }
}

這個類的結構也不復雜,兩個屬性,兩個方法。方法Add()用來給兩個屬性賦值,方法GetRouteData()主要作用註釋中已經註明。要詳細瞭解GetRouteData()方法的邏輯,我們有必要先看看SwiftRoute這個型別。

3、SwiftRoute.cs程式碼

namespace Swift.MVC.Routing
{
    public class SwiftRoute
    {
        public SwiftRoute()
        { }

        //在全域性配置裡面寫入路由規則以及預設配置
        public SwiftRoute(string url, Dictionary<string, object> defaultPath, IRouteHandler routeHandler)
        {
            TemplateUrl = url;
            DefaultPath = defaultPath;
            RouteHandler = routeHandler;
        }
        public string TemplateUrl { get; set; }

        public IRouteHandler RouteHandler { get; set; }

        public Dictionary<string, object> DefaultPath { get; set; }
    }
}

在SwiftRoutingCollection的Add方法裡面,我們需要傳入一個SwiftRoute物件,這裡的SwiftRoute物件就包含了路由規則的url、預設路由地址、IRouteHandler介面物件三個重要資訊,這三個資訊都是在Global.asax裡面寫入的,待會我們測試的再來詳細說明。

4、SwiftRouteData.cs程式碼

在上文SwiftRouteCollection的GetRouteData()裡面,返回了一個SwiftRouteData物件,這個物件的定義更加簡單,僅僅包含兩個屬性:

namespace Swift.MVC.Routing
{
    public class SwiftRouteData
    {
        public IRouteHandler RouteHandler { get; set; }

        public Dictionary<string, object> RouteValue { get; set; }
    }
}

RouteHandler屬性用來儲存當前的IRouteHandler物件;

RouteValue屬性用來儲存當前請求的路由表。

5、IRouteHandler.cs程式碼

上文多次提到了IRouteHandler介面,我們來看看那這個介面內容:

namespace Swift.MVC.Routing
{
    public interface IRouteHandler
    {
        System.Web.IHttpHandler GetHttpHandler(SwiftRouteData routeData, HttpContextBase context);
    }
}

這個介面的意義很簡單,只有一個方法,用來返回處理當前Http請求的HttpHandler物件。既然這裡定義了這個介面,那我們順便也提一下這個介面的實現類,在當前專案的MVC目錄下面,有一個MvcRouteHandler型別:

using Swift.MVC.Routing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace Swift.MVC
{
    public class MvcRouteHandler:IRouteHandler
    {
        /// <summary>
        /// 返回處理當前請求的HttpHandler物件
        /// </summary>
        /// <param name="routeData">當前的請求的路由物件</param>
        /// <param name="context">當前請求的下文物件</param>
        /// <returns>處理請求的HttpHandler物件</returns>
        public System.Web.IHttpHandler GetHttpHandler(SwiftRouteData routeData, HttpContextBase context)
        {
            return new MvcHandler(routeData, context) ;
        }
    }
}

這個實現類作用更加明確,返回一個具體的HttpHandler物件。

6、UrlRoutingModule.cs程式碼

有了上文的幾個型別做支撐,最後我們統籌排程的UrlRoutingModule閃亮登場了。

namespace Swift.MVC.Routing
{
    public class UrlRoutingModule : IHttpModule
    {
        #region Property
        private SwiftRouteCollection _swiftRouteCollection;

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly",
            Justification = "This needs to be settable for unit tests.")]
        public SwiftRouteCollection SwiftRouteCollection
        {
            get
            {
                if (_swiftRouteCollection == null)
                {
                    _swiftRouteCollection = SwiftRouteTable.Routes;
                }
                return _swiftRouteCollection;
            }
            set
            {
                _swiftRouteCollection = value;
            }
        }
        #endregion

        public void Dispose()
        {
            //throw new NotImplementedException();
        }

        public void Init(HttpApplication app)
        {
            app.PostResolveRequestCache += app_PostResolveRequestCache;
        }

        void app_PostResolveRequestCache(object sender, EventArgs e)
        {
            var app = (HttpApplication)sender;
            //0.將HttpContext轉換為HttpContextWrapper物件(HttpContextWrapper繼承HttpContextBase)
            var contextbase = new HttpContextWrapper(app.Context);
            PostResolveRequestCache(contextbase);
        }

        public virtual void PostResolveRequestCache(HttpContextBase context)
        {
            //1.傳入當前上下文物件,得到與當前請求匹配的SwiftRouteData物件
            SwiftRouteData routeData = this.SwiftRouteCollection.GetRouteData(context);
            if (routeData == null)
            {
                return;
            }
            //2.從SwiftRouteData物件裡面得到當前的RouteHandler物件。
            IRouteHandler routeHandler = routeData.RouteHandler;
            if (routeHandler == null)
            {
                return;
            }

            //3.根據RequestContext物件得到處理當前請求的HttpHandler(MvcHandler)。
            IHttpHandler httpHandler = routeHandler.GetHttpHandler(routeData, context);
            if (httpHandler == null)
            {
                return;
            }

            //4.請求轉到HttpHandler進行處理(進入到ProcessRequest方法)。這一步很重要,由這一步開始,請求才由UrlRoutingModule轉到了MvcHandler裡面
            context.RemapHandler(httpHandler);
        }
    }
}

 和版本二里面的區別不大,很多屬性名和方法名都採用和版本二相同的規則,最大的區別就是在版本三裡面,不再有RequestContext物件。UrlRoutingModule和MvcHandler兩者打交道的橋樑在版本二里面是RequestContext物件,在版本三裡面變成了直接將當前的路由物件和上下文傳到MvcHandler裡面。

三、MvcHandler的實現

在MvcHandler裡面變化比較大的只有兩個:MvcHandler.cs和Controller.cs

1、MvcHandler.cs

namespace Swift.MVC
{
    public class MvcHandler : IHttpHandler
    {
        public MvcHandler()
        { }

        public HttpContextBase SwiftContext { get; set; }
        public SwiftRouteData SwiftRouteData { get; set; }
        //通過建構函式將兩個物件傳過來,替代了原來RequestContext的作用
        public MvcHandler(SwiftRouteData routeData, HttpContextBase context)
        {
            SwiftRouteData = routeData;
            SwiftContext = context;
        }

        public virtual bool IsReusable
        {
            get { return false; }
        }

        public virtual void ProcessRequest(HttpContext context)
        {
            //寫入MVC的版本到HttpHeader裡面
            //AddVersionHeader(httpContext);
            //移除引數
            //RemoveOptionalRoutingParameters();

            //1.從當前的RouteData裡面得到請求的控制器名稱
            string controllerName = SwiftRouteData.RouteValue["controller"].ToString();

            //2.得到控制器工廠
            IControllerFactory factory = new SwiftControllerFactory();

            //3.通過預設控制器工廠得到當前請求的控制器物件
            IController controller = factory.CreateController(SwiftRouteData, controllerName);
            if (controller == null)
            {
                return;
            }

            try
            {
                //4.執行控制器的Action
                controller.Execute(SwiftRouteData);
            }
            catch
            {}
            finally
            {
                //5.釋放當前的控制器物件
                factory.ReleaseController(controller);
            }

        }
    }
}

相比版本二,這個類多了一個有兩個引數的建構函式,用來將routeData和context傳進來。然後再ProcessRequest方法裡面直接通過傳進來的物件去取當前請求的相關資訊。

2、Controller.cs

namespace Swift.MVC
{
    public abstract class Controller:ControllerBase,IDisposable
    {
        public override void Execute(SwiftRouteData routeData)
        {
            //1.得到當前控制器的型別
            Type type = this.GetType();

            //2.從路由表中取到當前請求的action名稱
            string actionName = routeData.RouteValue["action"].ToString();

            //3.從路由表中取到當前請求的Url引數
            object parameter = null;
            if (routeData.RouteValue.ContainsKey("parameters"))
            {
                parameter = routeData.RouteValue["parameters"];
            }
            var paramTypes = new List<Type>();
            List<object> parameters = new List<object>();
            if (parameter != null)
            {
                var dicParam = (Dictionary<string, string>)parameter;
                foreach (var pair in dicParam)
                {
                    parameters.Add(pair.Value);
                    paramTypes.Add(pair.Value.GetType());
                }
            }

            //4.通過action名稱和對應的引數反射對應方法。
            //這裡第二個引數可以不理會action字串的大小寫,第四個引數決定了當前請求的action的過載引數型別
            System.Reflection.MethodInfo mi = type.GetMethod(actionName,
                BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase, null, paramTypes.ToArray(), null);

            //5.執行該Action方法
            mi.Invoke(this, parameters.ToArray());//呼叫方法
        }

        public void Dispose()
        {
            //throw new NotImplementedException();
        }
    }
}

在Execute()方法裡面,對基礎型別的Action方法引數過載提供了支援。

四、測試以及程式碼釋疑

上文介紹了這麼多,可能並不直觀,很多類之間如何聯絡的看得並不清晰,反正如果是博主,別人這麼介紹一個類又一個類,看完肯定還是蒙的的。那麼我們來測試看下吧。

 首先,還是配置全域性配置檔案Global.asax

  public class Global : System.Web.HttpApplication
    {

        protected void Application_Start(object sender, EventArgs e)
        {
            var defaultPath = new Dictionary<string, object>();
            defaultPath.Add("controller", "Home");
            defaultPath.Add("action", "Index");
            defaultPath.Add("id", null);
            defaultPath.Add("namespaces", "MyTestMVC.Controllers");
            defaultPath.Add("assembly", "MyTestMVC");

            SwiftRouteTable.Routes.Add("defaultRoute", new SwiftRoute("{controller}/{action}/{id}", defaultPath, new MvcRouteHandler()));
        }
    }

看到這裡應該知道上文中 SwiftRouteTable 、 SwiftRouteCollection 、 SwiftRoute 三個類的用處了吧,原來在這裡。IRouteHandler的例項new MvcRouteHandler()也是在這裡寫入的。

然後啟動專案,我們預設訪問http://localhost:16792/Home/bootstrapTest這個地址,我們來看具體的過程:

1、啟動專案,首先進到全域性配置檔案的Application_Start()方法

這裡告訴我們在SwiftRouteTable.Routes這個全域性靜態變數裡面,已經儲存了路由規則、預設路由、RouteHandler物件三個重要的資訊。這三個資訊後面都會用到。

2、然後請求進到UrlRoutingModule裡面,取SwiftRouteCollection的值:

我們看到,這裡的SwiftRouteCollection的值就是在全域性配置檔案裡面配置的型別。

3、然後請求進到SwiftRouteCollection類的GetRouteData()方法裡面。這個方法的作用很明顯,就是解析當前的請求的url,從中獲取當前的controller、action、引數等資訊。這個方法執行完之後得到的SwiftRouteData物件,結果如下:

這個物件包含兩個屬性,RouteHandler和當前請求的路由表。

4、通過步驟3知道,當前的swiftRouteData物件包含了RouteHandler物件, IRouteHandler routeHandler = routeData.RouteHandler; 結果如下:

5、得到RouteHandler物件之後,就是從該物件的GetHttpHandler()方法裡面得到當前的HttpHandler。

這個應該不難理解,將routeData和context傳入MvcHandler裡面。這就是為什麼之前MvcHandler裡面有一個兩個引數的建構函式的原因。

6、然後就是執行 context.RemapHandler(httpHandler); 將請求正式交給MvcHandler。

7、在MvcHandler的ProcessRequest方法裡面,首先從當前請求的路由表裡面去控制器名稱,如下圖,得到”Home“:

8、然後就是建立控制器工廠、從工廠裡面得到當前請求的控制器的物件,這部分和之前變化不大。

9、得到控制器物件之後,執行對應的當前請求的action方法,請求盡到Controller這個父類的Execute()方法裡面

10、通過反射,最終執行BootstrapTest()方法。

11、BootstrapTest()方法執行完成之後,釋放當前的控制器物件: factory.ReleaseController(controller); 。請求結束。

五、支援方法的過載

 博主對Swift.MVC框架進行了簡單的擴充套件,使得框架支援action方法的過載。比如我們在HomeController裡面定義瞭如下方法

    public class HomeController : Controller
    {
        public void Index()
        {
            HttpContext.Current.Response.Write("Hello MVC");
        }

        public void Index(string id)
        {
            HttpContext.Current.Response.Write("Hello MVC  引數" + id);
        }

        public void Index(string aa, string bb)
        {
            HttpContext.Current.Response.Write("Hello MVC  兩個引數");
        }

        public void BootstrapTest()
        {
            .....
        }

        public void BootstrapTest(int id)
        {
            .....
        }
    }

1、請求預設路由地址:http://localhost:16792/

2、請求地址:http://localhost:16792/Home/index?id=1

3、請求地址:http://localhost:16792/Home/index?aa=kate&bb=lucy

當然上文封裝都是隻是通過url傳遞引數的情況,等有時間可以擴充套件下,使得支援通過post請求傳遞引數。

六、總結

通過上一篇和這一篇,我們基本上把MVC的核心原理涉及到的技術都重寫了一遍,等有時間再擴充套件一個自己的”View“,加上模型驗證,資料繫結,我們的Swift.MVC就算是一個相對完整的微型MVC框架了。當然,此框架僅僅是從學習理解MVC的原理層面去實現的,如果要應用於專案,還要考慮很多東西,不論如何,是個好的開始,有時間繼續完善。原始碼地址

如果你覺得本文能夠幫助你,可以右邊隨意 打賞 博主,也可以 推薦 進行精神鼓勵。你的支援是博主繼續堅持的不懈動力。

歡迎各位轉載,但是未經作者本人同意,轉載文章之後必須在文章頁面明顯位置給出作者和原文連線,否則保留追究法律責任的權利

相關推薦

MVC系列——MVC原始碼學習打造自己MVC框架定義路由規則

前言:上篇介紹了下自己的MVC框架前兩個版本,經過兩天的整理,版本三基本已經完成,今天還是發出來供大家參考和學習。雖然微軟的Routing功能已經非常強大,完全沒有必要再“重複造輪子”了,但博主還是覺得自己動手寫一遍印象要深刻許多,希望想深入學習MVC的童鞋自己動手寫寫。好了,廢話就此打住。 MVC原始

Spring原始碼學習之路---IOC實現原理

原文地址:https://blog.csdn.net/zuoxiaolong8810/article/details/8548478          上一章我們已經初步認識了BeanFactory和BeanDefinition,一個是IOC的核心工廠介面,一個是IOC的be

.NET深入解析LINQ框架LINQ優雅的前奏

對話 spa log 有用 強類型 provider 瓶頸 模式 是什麽 閱讀目錄: 1.動態LINQ查詢(動態構建Expression<T>表達式樹) 2.DLR動態語言運行時(基於CLR之上的動態語言運行時) 1】.動態LINQ查詢(動態構建Expres

Vue+ElementUI從零開始搭建自己的網站、元件間的通訊

前面討論了環境的搭建和導航頁面以及路由的配置,今天我們討論下如何開發一個擁有表單和表格功能的頁面。先上開發完的效果圖:  可以看出頁面非常的簡單,其中上半部分是表單搜尋和查詢,下半部分是用於展示資料的表格。如果按照傳統的開發思路,其實非常簡單,只要用兩個div,第一個d

MVC系列——MVC原始碼學習打造自己MVC框架瞭解神奇的檢視引擎

前言:通過之前的三篇介紹,我們基本上完成了從請求發出到路由匹配、再到控制器的啟用,再到Action的執行這些個過程。今天還是趁熱打鐵,將我們的View也來完善下,也讓整個系列相對完整,博主不希望爛尾。對於這個系列,通過學習原始碼,博主也學到了很多東西,在此還是把博主知道的先發出來,供大家參考。 MVC原

MVC系列——MVC原始碼學習打造自己MVC框架核心原理

前言:最近一段時間在學習MVC原始碼,說實話,研讀原始碼真是一個痛苦的過程,好多晦澀的語法搞得人暈暈乎乎。這兩天算是理解了一小部分,這裡先記錄下來,也給需要的園友一個參考,奈何博主技術有限,如有理解不妥之處,還希望大家斧正,博主感激不盡! MVC原始碼學習系列文章目錄: 一、MVC原理解析  最

MVC系列——MVC原始碼學習打造自己MVC框架原始碼

前言:上篇介紹了下 MVC5 的核心原理,整篇文章比較偏理論,所以相對比較枯燥。今天就來根據上篇的理論一步一步進行實踐,通過自己寫的一個簡易MVC框架逐步理解,相信通過這一篇的實踐,你會對MVC有一個更加清晰的認識。 MVC原始碼學習系列文章目錄: 這篇博主打算從零開始一步一步來加上MVC裡面用到

mvc原理打造自己MVC框架1.0

一、MVC的原理 從請求到服務端接受到請求中間這個過程經歷了哪些步驟: 第一步:請求被UrlRoutingModule部件攔截 第二步:封裝請求上下文HttpContext,成為HttpContextWrapper 第三步:根據當前的HttpContext,從Routes集合中得到與

MVC路由學習定義路由參數用戶看不到參數名,重新定義路由規則

route sys 工具 str optional href clas local amp 一,項目有需求將項目地址中的參數名不顯示給用戶看 在MVC定義一個方法:     public ActionResult GetUserInfo(string Name, str

caffe學習系列訓練自己的圖片集超詳細教程

    學習的caffe的目的,不是簡單的做幾個練習,而是最終落實到自己的專案或科研中去。因此,本文介紹一下,從自己的原始圖片到lmdb資料,再到訓練和測試的整個流程。 一、資料的準備     有條件的同學,可以去ImageNet的官網點選開啟連結,下載ImageNet圖片

C#進階系列——一步一步封裝自己的HtmlHelper元件BootstrapHelper原始碼

前言:之前的兩篇封裝了一些基礎的表單元件,這篇繼續來封裝幾個基於bootstrap的其他元件。和上篇不同的是,這篇的有幾個元件需要某些js檔案的支援。 BootstrapHelper系列文章目錄 一、NumberBoxExtensions NumberBoxExtensions是一個基於boot

Asp.net MVC 搭建屬於自己框架

C4D pagedlist del tran 6.0 ext 才有 應該 frame 網址:https://www.cnblogs.com/sggx/p/4555255.html 為什麽要自己搭框架?   大家夥別急,讓我慢慢地告訴你!大家有沒有這種感覺,從一家跳槽到另一家

逆向工程第002篇打造自己的仙劍奇俠

        眾所周知,在國產RPG遊戲裡面,《仙劍奇俠傳》是永恆的經典。釋出近二十年以來,依舊話題不斷。但是鮮有人對其進行逆向分析,只是聽說多年之前曾有人為了探究其是否有隱藏劇情,從而採取了某種逆

菜鳥系列Fabric原始碼學習 — 區塊同步

Fabric 1.4 原始碼分析 區塊同步 本文主要從原始碼層面介紹fabric peer同步區塊過程,peer同步區塊主要有2個過程: 1)peer組織的leader與orderer同步區塊 2)peer組織間peer同步區塊。 1. peer leader和orderer同步區塊 首先,orderer對外

菜鳥系列Fabric原始碼學習 — committer記賬節點

Fabric 1.4 原始碼分析 committer記賬節點 本文件主要介紹committer記賬節點如何初始化的以及committer記賬節點的功能及其實現。 1. 簡介 記賬節點負責驗證交易和提交賬本,包括公有資料(即區塊資料,包括公共資料和私密資料hash值)與私密資料。在提交賬本前需要驗證交易資料的有

菜鳥系列Fabric原始碼學習 — MVCC驗證

Fabric 1.4 原始碼分析 MVCC驗證 讀本節文件之前建議先檢視[Fabric 1.4 原始碼分析 committer記賬節點]章節。 1. MVCC簡介 Multi-Version Concurrency Control 多版本併發控制,MVCC 是一種併發控制的方法,一般在資料庫管理系統中,實現對

Mvc Api 定義路由

return pic mbo tro val 定義 精確 efi post // [RoutePrefix("api/ssm")]// public class ValuesController : ApiController// {// ///&

機器學習之支持向量機核函數和KKT條件的理解

麻煩 ron 現在 調整 所有 核函數 多項式 err ges 註:關於支持向量機系列文章是借鑒大神的神作,加以自己的理解寫成的;若對原作者有損請告知,我會及時處理。轉載請標明來源。 序: 我在支持向量機系列中主要講支持向量機的公式推導,第一部分講到推出拉格朗日對偶函數的對

FineBI學習系列之淺談FineBI和Tableau對比異同從產品理念和功能對比圖文詳解

研究 簡單 nio 比較 管理 post 企業it 獨立 圖片   不多說,直接上 幹貨!   FineBI和Tableau是比較好的自助式商業智能軟件,功能都很強大,是企業數據可視化不可或缺的利器,但兩款產品還是有非常大的區別的

SpringCloud系列Eureka 服務發現框架定義 Eureka 服務端、Eureka 服務信息、Eureka 發現管理、Eureka 安全配置、Eureka-HA(高可用) 機制、Eureka 服務打包部署

pac elf figure 傳遞 uri rect body 情況 服務組 1、概念:Eureka 服務發現框架 2、具體內容 對於服務發現框架可以簡單的理解為服務的註冊以及使用操作步驟,例如:在 ZooKeeper 組件,這個組件裏面已經明確的描述了一個服務的註冊以及發