9.1.3 .net framework通過業務邏輯層自動生成WebApi的做法

来源:http://www.cnblogs.com/BenDan2002/archive/2016/11/17/6072631.html
-Advertisement-
Play Games

首先需要說明的是這是.net framework的一個組件,而不是針對.net core的。目前工作比較忙,因此.net core的轉換正在編寫過程中,有了實現會第一時間貼出來。 接下來進入正題。對於大型的分層系統,會有一個應用程式層,應用程式層的主要作用是封裝業務領域層的業務邏輯層,並對界面展示層 ...


首先需要說明的是這是.net framework的一個組件,而不是針對.net core的。目前工作比較忙,因此.net core的轉換正在編寫過程中,有了實現會第一時間貼出來。

接下來進入正題。對於大型的分層系統,會有一個應用程式層,應用程式層的主要作用是封裝業務領域層的業務邏輯層,並對界面展示層提供服務。界面展示層例如有Web網站、移動應用、WPF等等,例如下圖。

很多情況下,業務領域層中間的業務邏輯層方法和應用服務層的服務介面幾乎是一致的。在業務邏輯方法編寫完成後,編程人員,也會重覆性的編寫應用服務層。該層難度不大,但是屬於重覆性勞動並且工作量不小。對於一個有敬業精神的程式員來說,問題就來了,寫一大堆不加思考的、工作量大的代碼,還不如寫一個框架自動通過業務邏輯層生成WebApi。

為了簡化編程人員的工作量,減少錯誤的出現,我們編寫了這個框架,就是通過業務邏輯層的方法自動生成應用服務層的服務。

 

其實ABP也有這個東西,但是發現ABP中的實現與Castle Windsor結合太緊密了,用了些Castle Windsor的特性。我等用Unity作為DI/IoC的無法借鑒。

 

要瞭解這個自動生成WebApi的框架,我們得簡要的講解下.net framework下webapi的請求處理過程。

Web API是微軟的主導的一種面向服務的實現方式,已經集成在visual studio的模板中,是一種比較成熟的SOA數據服務方式。Web API的服務提供方式實現過程由三個步驟組成:路由匹配階段;控制器選擇和構建階段;執行器選擇和執行階段。

 

 

 

 

 

 

 

 

 

 

預設情況下,一個mvc項目包含webapi,會在app_start目錄下有一個webapiconfig.cs文件。這個文件是webapi路由的設置,我們假設按照controller和action的名稱進行路由,寫法見下(尤其是routetemplate行): 

 1         public static void Register(HttpConfiguration config)
 2         {
 3             // Web API 配置和服務
 4 
 5             // Web API 路由
 6             config.MapHttpAttributeRoutes();
 7 
 8             config.Routes.MapHttpRoute(
 9                 name: "DefaultApi",
10                 routeTemplate: "api/{controller}/{action}/{id}",
11                 defaults: new { id = RouteParameter.Optional }
12             );
13         }

  

系統運行過程中,如果框架發現了URI的一個匹配,它會創建一個包含了每個占位符適用的值的字典集合。鍵是不包含大括弧的占位符名稱,例如controller、action。值是提取自URI路徑或者表單提交的數據。該字典被存儲在IHttpRouteData對象中。

在路由匹配階段,"{controller}"和"{action}"占位符會被像其他占位符一樣對待。它們被同其他值一起簡單地存儲在字典中。http://[server]/[appName]/api/user/get/1,路由字典將包含:

  • Controller: user
  • Action: get
  • Id: 1

 

控制器選擇和構建階段

在一個路徑匹配路由規則後,可以獲得到Controller和Action,並存放與路由字典中。Web API的消息處理管道由一組HttpMessageHandler經過"首尾相連"而成。WebApi 最終會引導到預設的HttpControllerDispatcher處理,其中HttpControllerDispatcher實現了HttpMessageHandler介面。HttpControllerDispatcher實現了目標HttpController對象的激活、執行。

  • HttpControllerDispatcher接收請求之後,會獲取IHttpControllerSelector的實現(預設是DefaultHttpControllerSelector),然後調用SelectController方法,創建HttpController的描述類HttpControllerDescriptor。
  • HttpControllerDispatcher接下來調用HttpControllerDescriptor對象的CreateController方法得到激活的HttpController對象。對於這個HttpControllerDescriptor對象來說,當它的CreateController方法被調用之後,它會獲取註冊的IHttpControllerActivator對象(預設是DefaultHttpControllerActivator),並調用其Create方法實現針對目標HttpController對象的激活並將激活的對象返回。
  • DefaultHttpControllerActivator對象根據HttpController類型去獲取代表目標HttpController實例的對象。如果後者返回一個具體的HttpController對象,該對象將直接作為方法的返回值,否則DefaultHttpControllerActivator直接採用反射的形式創建目標HttpController對象並返回。

 

執行器選擇和調用階段

ApiController是HttpController的基類。ApiController中的ExecuteAsync方法實現了Action的選擇和執行。

  • 首先執行GetActionSelector()方法,獲取IHttpActionSelector的實現ApiControllerActionSelector,ApiControllerActionSelector調用SelectAction方法,構建用來描述HttpAction的HttpActionDescriptor..
  • 然後創建Action的上下文,HttpActionContext。
  • 最後執行GetActionInvoker方法,獲取IHttpActionInvoker。緊接著調用ActionInvoker的InvokeActionAsync方法,執行Action並反饋HttpResponseMessage格式的數據。

至此,整個從路由到執行並返回結果的整個流程就結束了。

 

上面洋洋灑灑介紹了整個WeApi的路由和執行過程,下麵我們就根據這個流程來確定如何加入我們修改的內容,以通過業務邏輯層的方法自動實現WebApi。業務邏輯層是一個個的邏輯實現類,類中包含了一個個的業務邏輯方法,例如UserService類包含了GetUser方法。我們最終的實現就是生成http://[server]/[appName]/User/GetUser的WebApi調用方式。做法是:

  • 替換IHttpControllerSelector的實現DefaultHttpControllerSelector,將Controller的查找重定向到邏輯層的邏輯類
  • 替換IHttpActionSelector的實現ApiControllerActionSelector,將Action的查找重定向到邏輯類的方法
  • 替換IHttpActionInvoker的實現ApiControllerActionInvoker,將Action執行重定向到方法的執行

 

在替換之前,我們預先做了部分處理,在所有程式集中查找所有以AppService結尾的邏輯類,並將邏輯類生成為DynamicApiControllerInfo,註冊進DynamicApiControllerManager中,邏輯類中的GetUser等方法生成為DynamicApiActionInfo,存放在DynamicApiControllerInfo的Actions屬性中。該方式可以避免每次查找Controller和Action都要做反射的做法,提高系統執行效率。

這裡,我們約定所有以AppService結尾的邏輯類都要自動生成WebApi,也可以根據情況寫成繼承IApplicationService介面的類自動生成WebApi。

 1     public static class DynamicApiBuilder
 2     {
 3         public static void Build()
 4         {
 5             IEnumerable<Type> types = ReflectionHelper.GetSubTypes<object>().Where(type => !type.IsAbstract && type.IsPublic && type.FullName.EndsWith("AppService"));
 6 
 7             foreach (Type type in types)
 8             {
 9                 DynamicApiControllerInfo controllerInfo = GenerateApiControllerInfo(type);
10 
11                 DynamicApiControllerManager.Register(controllerInfo);
12             }
13         }
14 
15         private static DynamicApiController GenerateApiController()
16         {
17             DynamicApiController controller = new DynamicApiController();
18 
19             return controller;
20         }
21 
22         private static DynamicApiControllerInfo GenerateApiControllerInfo(Type type)
23         {
24             //10位是AppService
25             DynamicApiControllerInfo controllerInfo = new DynamicApiControllerInfo(type);
26 
27             foreach (MethodInfo methodInfo in GetMethodsOfType(type))
28             {
29                 DynamicApiActionInfo actionInfo = new DynamicApiActionInfo(methodInfo.Name, GetNormalizedVerb(methodInfo), methodInfo);
30 
31                 controllerInfo.Actions.Add(actionInfo.ActionName, actionInfo);
32             }
33 
34             return controllerInfo;
35         }
36 
37         private static IEnumerable<MethodInfo> GetMethodsOfType(Type type)
38         {
39             var allMethods = new List<MethodInfo>();
40 
41             FillMethodsRecursively(type, BindingFlags.Public | BindingFlags.Instance, allMethods);
42             //method.DeclaringType != typeof(ApplicationService) &&
43             return allMethods.Where(method => method.DeclaringType != typeof(object) && !IsPropertyAccessor(method));
44         }
45 
46         private static void FillMethodsRecursively(Type type, BindingFlags flags, List<MethodInfo> members)
47         {
48             members.AddRange(type.GetMethods(flags).Where(m => !members.Exists(mm => m.Name == mm.Name)));
49 
50             foreach (var interfaceType in type.GetInterfaces())
51             {
52                 FillMethodsRecursively(interfaceType, flags, members);
53             }
54         }
55 
56         private static bool IsPropertyAccessor(MethodInfo method)
57         {
58             return method.IsSpecialName && (method.Attributes & MethodAttributes.HideBySig) != 0;
59         }
60     }

 

接下來實現DynamicApiControllerSelector,替換預設的DefaultHttpControllerSelector。這個程式的主要做法是從路由信息RouteData中獲取當前的Controller和Action等信息。根據Controller信息從DynamicApiControllerManager中獲取已註冊的DynamicApiControllerInfo,創建Controller的描述類DynamicApiControllerDescriptor。DynamicApiControllerManager就是預處理部分,將DynamicApiControllerInfo註冊的類。

 1     public class DynamicApiControllerSelector : DefaultHttpControllerSelector
 2     {
 3         private readonly HttpConfiguration _Configuration;
 4 
 5         public DynamicApiControllerSelector(HttpConfiguration configuration)
 6             : base(configuration)
 7         {
 8             _Configuration = configuration;
 9         }
10 
11         public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
12         {
13             if (request == null)
14             {
15                 return base.SelectController(null);
16             }
17 
18             var routeData = request.GetRouteData();
19             if (routeData == null)
20             {
21                 return base.SelectController(request);
22             }
23 
24             //Get Area/Controller/Action from route
25             object objArea;
26             if (!routeData.Values.TryGetValue("area", out objArea))
27             {
28                 return base.SelectController(request);
29             }
30             object objController;
31             if (!routeData.Values.TryGetValue("controller", out objController))
32             {
33                 return base.SelectController(request);
34             }
35             object objAction;
36             if (!routeData.Values.TryGetValue("action", out objAction))
37             {
38                 return base.SelectController(request);
39             }
40 
41             string areaName = (string)objArea;
42             string controllerName = (string)objController;
43             string actionName = (string)objAction;
44 
45             //Normalize serviceNameWithAction
46             if (actionName.EndsWith("/"))
47             {
48                 actionName = actionName.Substring(0, actionName.Length - 1);
49                 routeData.Values["action"] = actionName;
50             }
51 
52             DynamicApiControllerInfo controllerInfo = DynamicApiControllerManager.Get(areaName, controllerName);
53 
54             //Create the controller descriptor
55             var controllerDescriptor = new DynamicApiControllerDescriptor(_Configuration, controllerInfo.AreaName, controllerInfo.ControllerName);
56             controllerDescriptor.Properties["__MicroLibraryDynamicApiControllerInfo"] = controllerInfo;
57             return controllerDescriptor;
58         }
59     }

 

下一步就是實現DynamicApiActionSelector,替換預設的ApiControllerActionSelector。DynamicApiActionSelector重寫了SelectAction方法,主要做法是Controller的上下文HttpControllerContext中獲取當前的DynamicApiControllerInfo,創建Action的描述類DynamicApiActionDescriptor。

 1     public class DynamicApiActionSelector : ApiControllerActionSelector
 2     {
 3        public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
 4         {
 5             object controllerInfoObj;
 6             if (!controllerContext.ControllerDescriptor.Properties.TryGetValue("__MicroLibraryDynamicApiControllerInfo", out controllerInfoObj))
 7             {
 8                 return GetDefaultActionDescriptor(controllerContext);
 9             }
10 
11             //Get controller information which is selected by HttpControllerSelector.
12             var controllerInfo = controllerInfoObj as DynamicApiControllerInfo;
13             MicroLibraryExceptionHelper.IsNull(controllerInfo, this.GetType().FullName, TraceLogType.Error, "DynamicApiControllerInfo in ControllerDescriptor.Properties is not a " + typeof(DynamicApiControllerInfo).FullName + " class.");
14 
15             string areaName = (string)controllerContext.RouteData.Values["area"];
16             string controllerName = (string)controllerContext.RouteData.Values["controller"];
17             string actionName = (string)controllerContext.RouteData.Values["action"];
18 
19             return GetActionDescriptorByActionName(controllerContext, controllerInfo, actionName);
20         }
21 
22         private HttpActionDescriptor GetActionDescriptorByActionName(HttpControllerContext controllerContext, DynamicApiControllerInfo controllerInfo, string actionName)
23         {
24             //Get action information by action name
25             DynamicApiActionInfo actionInfo;
26             MicroLibraryExceptionHelper.FalseThrow(controllerInfo.Actions.TryGetValue(actionName, out actionInfo), this.GetType().FullName, TraceLogType.Error, "在Api Controller:" + controllerInfo.ControllerName + "中,沒有對應的Action:" + actionName);
27             MicroLibraryExceptionHelper.FalseThrow(actionInfo.Verb.IsEqualTo(controllerContext.Request.Method), this.GetType().FullName, TraceLogType.Error, "在Api Controller:" + controllerInfo.ControllerName + "中的Action:" + actionName + "的HttpVerb不正確,應該為:" + actionInfo.Verb);
28 
29             return new DynamicApiActionDescriptor(controllerContext.ControllerDescriptor, actionInfo.Method);
30         }
31 
32         private HttpActionDescriptor GetDefaultActionDescriptor(HttpControllerContext controllerContext)
33         {
34             return base.SelectAction(controllerContext);
35         }
36     }

 

需要說明的是,我們只是按照ActionName來確定最終的Action。還可以按照HttpVeb來確定Actin的方式,我們沒有使用該方式,因此沒有實現,可以參照如下代碼實現:

 1         private HttpVerb GetNormalizedVerb(MethodInfo methodInfo)
 2         {
 3             if (methodInfo.IsDefined(typeof(HttpGetAttribute)))
 4             {
 5                 return HttpVerb.Get;
 6             }
 7 
 8             if (methodInfo.IsDefined(typeof(HttpPostAttribute)))
 9             {
10                 return HttpVerb.Post;
11             }
12 
13             if (methodInfo.IsDefined(typeof(HttpPutAttribute)))
14             {
15                 return HttpVerb.Put;
16             }
17 
18             if (methodInfo.IsDefined(typeof(HttpDeleteAttribute)))
19             {
20                 return HttpVerb.Delete;
21             }
22 
23             if (methodInfo.IsDefined(typeof(HttpOptionsAttribute)))
24             {
25                 return HttpVerb.Options;
26             }
27 
28             if (methodInfo.IsDefined(typeof(HttpHeadAttribute)))
29             {
30                 return HttpVerb.Head;
31             }
32 
33             return HttpVerb.Get;
34         }
35 
36         private HttpActionDescriptor GetActionDescriptorByCurrentHttpVerb(HttpControllerContext controllerContext, DynamicApiControllerInfo controllerInfo)
37         {
38             //Check if there is only one action with the current http verb
39             var actionsByVerb = controllerInfo.Actions.Values.Where(action => action.Verb.IsEqualTo(controllerContext.Request.Method));
40 
41             MicroLibraryExceptionHelper.TrueThrow(actionsByVerb.Count() == 0, this.GetType().FullName, TraceLogType.Error, "在Api Controller:" + controllerInfo.ServiceName + "中,沒有HttpVerb: " + controllerContext.Request.Method + "的Action");
42             MicroLibraryExceptionHelper.TrueThrow(actionsByVerb.Count() > 1, this.GetType().FullName, TraceLogType.Error, "在Api Controller:" + controllerInfo.ServiceName + "中,HttpVerb: " + controllerContext.Request.Method + "的Action有多個");
43 
44             //Return the single action by the current http verb
45             return new DynamicApiActionDescriptor(controllerContext.ControllerDescriptor, actionsByVerb.First().Method);
46         }
View Code

 

再下一步就是實現DynamicApiActionInvoker,替換預設的ApiControllerActionInvoker。DynamicApiActionInvoker實現了InvokeActionAsync方法,主要做法是獲取Controller和Action的描述類DynamicApiControllerDescriptor、DynamicApiActionDescriptor。根據Controller的描述類獲取DynamicApiControllerInfo,進一步獲取ControllerInfo的ServiceType,這就是邏輯類的類型信息。通過我們自己的Ioc管理器IocManager,從DI容器中獲取SerivceType的具體實現obj對象。然後從Action描述中獲取MethodInfo,執行方法。返回結果信息,返回前在頭部增加Access-Control-Allow-Origin等信息。

還有一點說明的是需要在Web.config中進行修改,modules中移除WebDavModule,handlers中移除WebDav和OPTIONSVerbHandler。

 1     public class DynamicApiActionInvoker : IHttpActionInvoker
 2     {
 3         private bool authenticatedFlag = DynamicApiConfiguration.GetConfig().AuthenticatedFlag;
 4 
 5         public Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
 6         {
 7             DynamicApiActionDescriptor actionDescriptor = actionContext.ActionDescriptor as DynamicApiActionDescriptor;
 8             DynamicApiControllerDescriptor controllerDescriptor = actionContext.ControllerContext.ControllerDescriptor as DynamicApiControllerDescriptor;
 9 
10             DynamicApiControllerInfo controllerInfo = controllerDescriptor.Properties["__MicroLibraryDynamicApiControllerInfo"] as DynamicApiControllerInfo;
11 
12             object obj = IocManager.Instance.Resolve(controllerInfo.ServiceType);
13 
14             MicroLibraryExceptionHelper.FalseThrow(Verify(actionContext), this.GetType().FullName, TraceLogType.Error, "Token驗證不通過!");
15 
16             //todo: 異常處理以及參數順序問題
17             object result = actionDescriptor.MethodInfo.Invoke(obj, actionContext.ActionArguments.Where(kvp => !string.Equals(kvp.Key, "sign", StringComparison.OrdinalIgnoreCase) || !string.Equals(kvp.Key, "appKey", StringComparison.OrdinalIgnoreCase)).Select(kvp => kvp.Value).ToArray());
18 
19             return Task.Run<HttpResponseMessage>(() =>
20              {
21                  string strResult;
22                  if (result is String || result is Char)
23                  {
24                      strResult = obj.ToString();
25                  }
26                  else
27                  {
28                      strResult = SerializerHelper.ToJson(result);
29                  }
30 
31                  var response = new HttpResponseMessage()
32                  {
33                      Content = new StringContent(strResult, Encoding.GetEncoding("UTF-8"), "application/json")
34                  };
35 
36                  //需要在web.config中,system.webServer---modules---remove name="WebDavModule"
37                  //---handlers---remove name="WebDav"和remove name="OPTIONSVerbHandler"
38                  response.Headers.Add("Access-Control-Allow-Origin", "*");
39                  response.Headers.Add("Access-Control-Allow-Headers", "X-Requested-With");
40                  if (actionContext.Request.Method.Method == "Options")
41                  {
42                      response.Headers.Add("Access-Control-Allow-Methods", "*");
43                      response.Headers.Add("Access-Control-Allow-Headers", "*");
44                  }
45                  return response;
46              });
47         }
48 
49         private bool Verify(HttpActionContext actionContext)
50         {
51             if (!authenticatedFlag) return true;
52 
53             var attrs = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>();
54             if (attrs.Any()) return true;
55 
56             string appKey = (string)actionContext.ActionArguments["appCode"];
57 
58             return DynamicApiHelper.ValidAppSecretSign(actionContext.ActionArguments, appKey);
59         }
60     }

 

大家可能還註意到我們有Verify方法。這個方法是判斷對WebApi是否有許可權訪問。在這種Rest形式的服務中,服務介面對外部暴露出來,因此對用戶調用的授權尤為重要。在Dynamic WebAPI的安全實現過程中,使用了JWT(JsonWebToken)技術,這裡就不做贅述了。

 

面向雲的.net core開發框架


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 字元串轉組件名 字元串轉變數名 或 ...
  • EntityFramework 一對一關係映射有很多種,比如主鍵作為關聯,配置比較簡單,示例代碼: 上面代碼表示 Teacher 和 Student 一對一關係,Fluent API 配置如下: 測試代碼: 生成 SQL 代碼: 另一種 Fluent API 配置如下: 執行同樣測試代碼,生成 SQ ...
  • ...
  • 本文主要涉及兩個概念: 阿裡雲OSS:對象存儲(Object Storage Service,簡稱OSS),是阿裡雲對外提供的海量、安全和高可靠的雲存儲服務。 bootstrap-fileinput:An enhanced HTML 5 file input for Bootstrap 3.x wi ...
  • 刪除重覆的文件功能 使用方法: 建一個BAT文件,如1.bat,裡面寫入:RemoveDuplicate.exe path1 path2 (或者在命令行下輸入以上內容) 其中path1表示原文件夾,path2表示要檢測和刪除的文件夾 例如文件夾path1中有:1.txt、2.txt、3.txt、4. ...
  • 吃飯的時候翻開推特發現巨硬在開大會,真是後知後覺啊。整理了一下幾個大事分享出來: 1.谷歌雲加入了.NET 基金會的一個小組。 2.三星Tizen系統將整合.NET Core平臺,並於2017年正式推出。這個系統目前貌似主要用在三星電視中,原文描述如下: Tizen’s .NET support w... ...
  • 本演練介紹瞭如何使用新資料庫進行 Code First 開發。我們用類定義一個模型,然後使用該模型創建一個資料庫,然後存儲和檢索數據。資料庫創建之後,我們使用 Code First 遷移將架構更改為我們發展後的模型。此外還介紹瞭如何使用數據註釋和 Fluent API 來配置模型。 ...
  • 在IIS中瀏覽某個網站時,出錯案例現場: 編譯器錯誤消息: CS0016: 未能寫入輸出文件“c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\41c262f4\874fe77f\App_Web_ ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...