目錄html
我(夢在旅途,http://zuowj.cnblogs.com; http://www.zuowenjun.cn)最近發表的一篇文章《.NET CORE與Spring Boot編寫控制檯程序應有的優雅姿式》看到都上48小時閱讀排行榜(固然以前發表的文章也有哦!),說明關注.NET CORE及Spring Boot的人不少,也是目前的主流方向,因而我便決定系統性的總結一下C# 與JAVA 、ASP.NET CORE 與 Spring Boot MVC,讓更多的人瞭解它們,消除以前可能存在的對.NET或JAVA的誤解。java
本文目的是經過全面簡述C# 與JAVA 在基礎語法以及ASP.NET CORE 與 Spring Boot MVC的在框架規範、部署、運行的殊途同歸的實現方式,讓你們更多的瞭解C#與JAVA,本文不會刻意說哪門語言好,我認爲這是沒有意義的,更多的是瞭解每種語言的特色、優勢以及不一樣語言的共性,掌握編程內功(如:面向對象、DI、AOP、設計模式、算法),這樣才能讓本身更能適應社會及將來的變化。web
本文主要以示例代碼爲主,輔以簡單文字說明,不會細講每一個語法點,只會體現不一樣的實現方式而矣,全文無廢話,全是乾貨,慢慢欣賞吧。算法
(注:本文內容是使用Markdown編輯器進行編輯完成!)spring
#region 1.匿名類 var helloWord = new { CodeBy = "C#匿名類", Output = new Action<string, string>((name, codeBy) => { System.Console.WriteLine($"Welcome:{name},Hello Word! by {codeBy}"); }) }; helloWord.Output("夢在旅途", helloWord.CodeBy); #endregion
//1.匿名類 IHelloWord helloWord=new IHelloWord() { @Override public void output(String name) { System.out.printf("Welcome:%s,Hello Word! by %s\n",name,getCodeBy()); } @Override public String getCodeBy() { return "JAVA匿名類"; } }; helloWord.output("夢在旅途"); public interface IHelloWord { void output(String name); String getCodeBy(); }
#region 2.類型初始化 Dictionary<string, string> map = new Dictionary<string, string> { { "key1","value1" },//(隱式自動調用add方法) { "key2", "value2" }, { "key3", "value3" } }; foreach (var item in map) { System.Console.WriteLine($"key:{item.Key},value:{item.Value}"); } List<string> list = new List<string> { "list-item1",//(隱式自動調用add方法) "list-item2", "list-item3" }; foreach (string item in list) { System.Console.WriteLine(item); } String[] strArr = { "arr1", "arr2", "arr3" }; foreach (string item in strArr) { System.Console.WriteLine(item); } Person person = new Person { Name = "夢在旅途", Age = 23, Sex = "男" }; string json = JsonConvert.SerializeObject(person); System.Console.WriteLine("Person json:" + json); #endregion
//2.類型初始化 Map<String,String> map=new HashMap(){ { put("key1","value1"); put("key2","value2"); put("key3","value3"); } }; for (Map.Entry<String, String> item:map.entrySet()) { System.out.printf("key:%1$s,value:%2$s\n",item.getKey(),item.getValue()); } List<String> list=new ArrayList(){ { add("list-item1"); add("list-item2"); add("list-item3"); } }; for (String item :list) { System.out.printf("%s\n",item); } String[] strArr={"arr1","arr2","arr3"}; for (String item :strArr) { System.out.printf("%s\n",item); } Person person=new Person(){ { setName("zwj"); setAge(32); setSex("男"); } }; ObjectMapper jsonMapper=new ObjectMapper(); String json= jsonMapper.writeValueAsString(person); System.out.println("Person json:" + json);
#region 3.委託 delegate void HelloDelegate(string name);//定義委託類型(重點是方法簽名) //常規普通自定義委託類型及委託相應的方法 HelloWord helloWordObj = new HelloWord(); HelloDelegate helloDelegate = helloWordObj.Output; //委託實例方法 helloDelegate.Invoke("夢在旅途");// OR helloDelegate("夢在旅途"); HelloDelegate helloDelegate2 = HelloWord.OutputForStatic; //委託類的靜態方法 helloDelegate2.Invoke("zuowenjun"); // OR helloDelegate2("zuowenjun"); //使用通用的已封裝好的委託類型(如:Func、Action)並實例化 Func<int, int, int> multiplyFunc = new Func<int, int, int>(delegate (int a, int b) { return a * b; }); int x = 12, y = 25; int multiplyResult = multiplyFunc.Invoke(x, y); //OR multiplyFunc(x,y); System.Console.WriteLine($"{x}乘以{y}等於:{multiplyResult}"); Action<string> helloAction = new Action<string>(delegate (string name) { System.Console.WriteLine($"hello,{name},how are you!"); System.Console.WriteLine("learning keep moving!"); }); helloAction.Invoke("www.zuowenjun.cn"); #endregion
//3.委託 HelloWord helloWordObj = new HelloWord(); HelloWordDelegate helloWordDelegate = helloWordObj::output; helloWordDelegate.invoke("夢在旅途"); HelloWordDelegate helloWordDelegate2 = HelloWord::outputForStatic; helloWordDelegate2.invoke("zuowenjun"); //使用已封裝好的委託方法(JAVA這邊稱:函數式接口,有不少詳見:https://www.runoob.com/java/java8-functional-interfaces.html) BiFunction<Integer, Integer, Integer> multiplyFunc = new BiFunction<Integer, Integer, Integer>() { @Override public Integer apply(Integer i, Integer i2) { return i * i2; } }; int x = 12, y = 25; int multiplyResult = multiplyFunc.apply(x, y); System.out.printf("%d乘以%d等於:%d%n", x, y, multiplyResult); Consumer<String> helloAction=new Consumer<String>() { @Override public void accept(String s) { System.out.printf("hello,%s,how are you!%n",s); System.out.printf("learning keep moving!%n"); } }; helloAction.accept("www.zuowenjun.cn"); @FunctionalInterface public interface HelloWordDelegate { void invoke(String name); } public class HelloWord implements IHelloWord { @Override public void output(String name) { System.out.printf("Welcome:%s,Hello Word! by %s\n",name,getCodeBy()); } public static void outputForStatic(String name){ System.out.printf("Welcome:%s,Hello Word! by JAVA static\n",name); } @Override public String getCodeBy() { return "JAVA"; } }
#region 4.Lambda Func<int, int, int> multiplyFunc2 = new Func<int, int, int>((a, b) => a * b); int x2 = 12, y2 = 25; int multiplyResult2 = multiplyFunc2.Invoke(x2, y2); //OR multiplyFunc(x,y); System.Console.WriteLine($"{x2}乘以{y2}等於:{multiplyResult2}"); Action<string> helloAction2 = new Action<string>(name => { System.Console.WriteLine($"hello,{name},how are you!"); System.Console.WriteLine("learning keep moving!"); }); helloAction2.Invoke("www.zuowenjun.cn"); int[] intArr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; intArr = intArr.Where(i => i >= 5).ToArray(); foreach (int i in intArr) { System.Console.WriteLine($"int-{i}"); } string msg = "測試外部變量被Lambda引用"; Action testMsgAction = () => { msg += "--改變內容"; System.Console.WriteLine("Lambda方法體中的值:" + msg); }; testMsgAction(); System.Console.WriteLine("原始值:" + msg); #endregion
//4.Lambda BiFunction<Integer, Integer, Integer> multiplyFunc = (i1, i2) -> i1 * i2; int x = 12, y = 25; int multiplyResult = multiplyFunc.apply(x, y); System.out.printf("%d乘以%d等於:%d%n", x, y, multiplyResult); Consumer<String> helloAction= s -> { System.out.printf("hello,%s,how are you!%n",s); System.out.printf("learning keep moving!%n"); }; helloAction.accept("www.zuowenjun.cn"); int[] intArr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; intArr= Arrays.stream(intArr).filter(value -> value>=5).toArray(); for (int n : intArr) { System.out.printf("int-%d%n",n); }
#region 5.泛型 //經常使用泛型集合類型 List<int> intList = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; List<long> longList = new List<long> { 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L }; Dictionary<string, string> dic = new Dictionary<string, string> { { "k1","v1"},{ "k2","v2"},{ "k3","v3"} }; //泛型方法 var demo = new DemoGenericClass(); //demo.DisplayResult("學習永無止境"); 錯誤,由於約束是值類型 demo.DisplayResult(ConsoleColor.DarkGreen); List<YellowPerson> yellowPersonList = new List<YellowPerson> { new YellowPerson(){ Name="zzz",Age=11,Sex="G"}, new YellowPerson(){ Name="xxx",Age=22,Sex="B"} }; //協變(泛型參數子類轉父類) //public interface IEnumerable<out T> IEnumerable<YellowPerson> yellowPersons = yellowPersonList; IEnumerable<Person> persons = yellowPersons;//協變(子類到父類的轉變) ,泛型參數 out標記,通常用於出參,這個正確的 // List<Person> personList = yellowPersonList; 由於List是類,並且泛型參數並無標記out,不適用協變,故這樣轉換是錯誤的 foreach (var p in persons) { System.Console.WriteLine($"item :【Name={p.Name},Age={p.Age},Sex={p.Sex},Color={p.Color}】"); } //逆變(泛型參數父類轉子類) Action<object, object> showPlusResultAction = (d1, d2) => Console.WriteLine($"{d1}+{d2}={d1.ToString() + d2.ToString()}"); Action<string, string> showStrPlusResultAction = showPlusResultAction;//逆變(父類到子類的轉變),泛型參數 in標記,通常用於入參 showPlusResultAction(55, 66); showStrPlusResultAction("你好", "中國"); ShowMsg<Person> showMsg = new ShowMsg<Person>((p) => { System.Console.WriteLine($"ShowMsg :【Name={p.Name},Age={p.Age},Sex={p.Sex},Color={p.Color}】"); }); //ShowMsg<HelloWord> showMsg2 = new ShowMsg<HelloWord>(...); 這樣是不行的,由於泛型約束爲需繼承自Person showMsg.Invoke(new Person() { Name = "zuowenjun", Age = 33, Sex = "B" }); showMsg.Invoke(new YellowPerson() { Name = "zuowenjun2", Age = 33, Sex = "B" }); //綜合演示:入參逆變,出參協變 Func<Person, Person, string> getDataFunc = (x, y) => x.Name + y.Name; Func<YellowPerson, YellowPerson, object> getDataFunc2 = getDataFunc; object dataResult = getDataFunc2(new YellowPerson() { Name = "張三", Age = 33, Sex = "G" }, new YellowPerson() { Name = "趙六", Age = 33, Sex = "B" }); System.Console.WriteLine($"getDataFunc2:{dataResult}"); List<int> a = new List<int>(); List<String> b = new List<string>(); bool isEqual = (a.GetType() == b.GetType()); System.Console.WriteLine($"List<int> 與 List<String> {(isEqual ? "is" : "not")} Equal ");//結果是不相等 #endregion //以上示例須要用到的類 public class BaseClass { /// <summary> /// 必需是用virtual標記的方法(即:虛方法)或abstract標記的方法(即:抽象方法)子類才能使用override進行重寫 /// </summary> /// <param name="name"></param> public virtual void SayHello(string name) { System.Console.WriteLine($"{nameof(BaseClass)} Say:{name},hello!"); } } public class DemoGenericClass : BaseClass, IDisposable { public void DisplayResult<T>(T arg) where T : struct { System.Console.WriteLine($"DemoGenericClass.DisplayResult:{arg}"); } public void Dispose() { System.Console.WriteLine("DemoGenericClass Disposed"); } public override void SayHello(string name) { base.SayHello(name); System.Console.WriteLine($"{nameof(DemoGenericClass)} Say:{name},hello again!"); } } public class Person { public virtual Color Color { get; } public string Name { get; set; } public int Age { get; set; } public string Sex { get; set; } } public class BlackPerson : Person { public override Color Color => Color.Black; } public class YellowPerson : Person { public override Color Color => Color.Yellow; } public class WhitePerson : Person { public override Color Color => Color.White; }
//經常使用泛型集合 List<Integer> intList = new ArrayList(){ { add(1); add(2); add(3); add(4); add(5); } }; Map<String,String> map=new HashMap(){ { put("k1","v1"); put("k2","v2"); put("k3","v3"); } }; //泛型方法 DemoGenericClass demo=new DemoGenericClass(); demo.displayResult(new YellowPerson(){{ setName("zwj");setSex("B");setAge(33); }}); List<Integer> a=new ArrayList<>(); List<String> b=new ArrayList<>(); boolean isEqual =(a.getClass()==b.getClass()); System.out.printf("List<Integer>與List<String> %s Equal %n",isEqual?"is":"not"); //結果是相等,都是同一個List類型,不能使用instanceof判斷泛型類型實例 //協變、逆變(詳見說明:https://www.jianshu.com/p/2bf15c5265c5 ,意義與C#相同) List<? super Person> persons=new ArrayList<>(); //super:限定下邊界,逆變,用於入參 persons.add(new Person(){ { setName("張三"); setAge(25); setSex("B"); } }); persons.add(new YellowPerson(){ { setName("趙六"); setAge(18); setSex("G"); } }); List<? extends Person> result= (List<? extends Person>) persons;//extends:限定上邊界,協變,用於出參 for (Person p:result){ System.out.printf("Person list item:%s %n",p.toString()); } //以上示例須要用到的類 public class DemoGenericClass implements AutoCloseable { @Override public void close() throws Exception { System.out.println("DemoGenericClass closed"); } public <T extends Person> void displayResult(T arg) //泛型約束(泛型參數上邊界,協變) { System.out.printf("DemoGenericClass.DisplayResult:%s %n",arg.toString()); } } public class Person { private String name; private int age; private String sex; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public String toString() { return String.format("Person=[Name:%s,Age:%d,Sex:%s] %n", name, age, sex); } } class YellowPerson extends Person { @Override public String toString() { return "YellowPerson#toString-"+ super.toString(); } }
using (var demo2 = new DemoGenericClass()) //DemoGenericClass實現IDisposable接口 { demo2.DisplayResult(123456); }
try(DemoGenericClass demo=new DemoGenericClass()) { demo.displayResult(new YellowPerson(){ { setName("zuowenjun"); setAge(33); setSex("B"); } }); }
C#全部類的普通方法默認是密封方法(相似JAVA的final方法),是不容許被重寫,能夠理解爲默認是不開放的,須要開放重寫的方法必需使用virtual標記爲虛方法(虛方法至少是protected及以上的訪問權限),若重寫後不想被後續的子類再次重寫,則能夠標記爲sealed,即:密封方法編程
public class BaseClass { /// <summary> /// 必需是用virtual標記的方法(即:虛方法)或abstract標記的方法(即:抽象方法)子類才能使用override進行重寫 /// </summary> /// <param name="name"></param> public virtual void SayHello(string name) { System.Console.WriteLine($"{nameof(BaseClass)} Say:{name},hello!"); } } public class DemoGenericClass : BaseClass { public override void SayHello(string name) { base.SayHello(name); System.Console.WriteLine($"{nameof(DemoGenericClass)} Say:{name},hello again!"); } }
JAVA全部類的普通方法默認是虛方法,都是能夠被重寫,能夠理解爲默認是開放重寫的,若不想被重寫則應標記爲final ,即:最終方法(C#中稱密封方法)json
public class BaseClass{ public void testOutput(String msg){ System.out.println("output Msg:" + msg); } } public class DemoGenericClass extends BaseClass { @Override public void testOutput(String msg){ super.testOutput(msg); System.out.println("output again Msg:" + msg); } }
.NET項目的包是NuGet包,能夠從nuget.org上查找瀏覽所需的包,項目中引用依賴包,除了在csproj文件中使用PackageReference添加編輯外(具體用法參見:項目文件中的包引用 (PackageReference))還可使用package manager控制檯使用包管理命令,如:
Install-Package ExcelEasyUtil -Version 1.0.0
,或者直接使用.NET CLI命令行工具,如:dotnet add package ExcelEasyUtil --version 1.0.0
c#.NET有包、元包、框架 之分,詳細瞭解:包、元包和框架設計模式
<!--包引用--> <ItemGroup> <PackageReference Include="Autofac.Extras.DynamicProxy" Version="4.5.0" /> <PackageReference Include="Autofac" Version="4.9.2" /> <PackageReference Include="Microsoft.AspNetCore.App" /> <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.1" /> <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.4.0" /> </ItemGroup> <!--同一解方案下的項目引用--> <ItemGroup> <ProjectReference Include="..\StandardClassLib2019\StandardClassLib2019.csproj" /> </ItemGroup> <!--本地組件直接引用--> <ItemGroup> <Reference Include="KYExpress.Common"> <HintPath>xxxx\xxxx.dll</HintPath> <Private>true</Private> </Reference> </ItemGroup>
<dependencies> <!--maven包依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!--本地JAR包依賴(scope=system,systemPath=jar包存放目錄)--> <dependency> <groupId>cn.zuowenjun.boot.mybatis.plugin</groupId> <artifactId>cn.zuowenjun.boot.mybatis.plugin</artifactId> <version>1.0</version> <scope>system</scope> <systemPath>${basedir}/src/main/libs/xxxxx.jar</systemPath> </dependency> <!--同一父項目Module之間依賴,注意這個必需先建立基於POM的父項目,而後各子Moudle 的POM 的parent指向父項目--> <dependency> <groupId>cn.zuowenjun.springboot</groupId> <artifactId>springboot-demo1</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
JAVA POM 依賴繼承兩種方式api
經過parent繼承,以下所示:(以下是很是典型的spring boot的parent繼承),項目將繼承spring-boot-starter-parent POM中的全部設置及依賴(如:properties、dependencies等)
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> </parent>
經過dependencyManagement繼承,以下所示:(這是依賴管理,dependencyManagement裏只是聲明依賴,並不實現引入,所以子項目可按需顯式的聲明所需的依賴項。若是不在子項目中聲明依賴,則不會從父項目中繼承依賴,只有在子項目中聲明瞭依賴項,且沒有指定具體版本,纔會從父項目中繼承依賴項,(寫了版本號至關於覆蓋),version和scope都讀取自父pom)
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Greenwich.SR2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
//1.使用ASP.NET CORE默認的DI框架,在Startup文件中ConfigureServices方法中按需註冊依賴 public void ConfigureServices(IServiceCollection services) { //採用ASP.NET CORE默認的IOC容器註冊 services.AddTransient<IOperationTransient, Operation>(); services.AddScoped<IOperationScoped, Operation>(); services.AddSingleton<IOperationSingleton, Operation>(); services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty)); } //2.在Controller中就能夠直接採用構造函數注入或指明從IOC容器中得到實例[FromServices] [ApiController] [Route("api/[controller]")] public class DemoController : Controller { private readonly OperationService operationService; public DemoController(OperationService operationService) { this.operationService = operationService; } [Route("optid")] public object Operation([FromServices]OperationService optSrv){ //TODO:方法體中直接使用operationService 或 入參optSrv都可 } } //如上所需接口及類定義 public interface IOperation { Guid OperationId { get; } } public interface IOperationTransient : IOperation { } public interface IOperationScoped : IOperation { } public interface IOperationSingleton : IOperation { } public interface IOperationSingletonInstance : IOperation { } public class Operation : IOperationTransient, IOperationScoped, IOperationSingleton, IOperationSingletonInstance { public Operation() : this(Guid.NewGuid()) { } public Operation(Guid id) { OperationId = id; } public Guid OperationId { get; private set; } } public class OperationService { public OperationService( IOperationTransient transientOperation, IOperationScoped scopedOperation, IOperationSingleton singletonOperation, IOperationSingletonInstance instanceOperation) { TransientOperation = transientOperation; ScopedOperation = scopedOperation; SingletonOperation = singletonOperation; SingletonInstanceOperation = instanceOperation; } public IOperationTransient TransientOperation { get; } public IOperationScoped ScopedOperation { get; } public IOperationSingleton SingletonOperation { get; } public IOperationSingletonInstance SingletonInstanceOperation { get; } }
C#使用第三方IOC容器,如:autofac,由第三方IOC容器接管並實現DI,示例以下:(autofac支持更多、更靈活的依賴注入場景)
public IServiceProvider ConfigureServices(IServiceCollection services) { //採用ASP.NET CORE默認的IOC容器註冊 services.AddTransient<IOperationTransient, Operation>(); services.AddScoped<IOperationScoped, Operation>(); services.AddSingleton<IOperationSingleton, Operation>(); services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty)); services.AddTransient<OperationService, OperationService>(); var containerBuilder = new ContainerBuilder(); containerBuilder.Populate(services); //交由autofac IOC容器管理 var container = containerBuilder.Build(); return new AutofacServiceProvider(container);//使用utofac IOC容器 }
註解依賴註冊通常能夠經過自定義一個spring統一註冊配置類,如代碼中所示BeansConfig,這種通常對於集中註冊Bean或Bean之間有前後依賴,前後順序時比較有效果;另外一種是直接在Bean上使用@Component註解(或其它專用含義的註解,如:@Repository、@Service,這些註解自己也標記了@Component註解)
//1. 在自定義的spring統一註冊配置類中註冊相關Bean @Configuration public class BeansConfig { @Bean @Scope("prototype") //singleton,request,session @Order(1) //註冊順序 public DemoBean demoBean(){ return new DemoBean(); } @Bean("demo") //定義名稱 @Order(2) public DemoInterface demoInterface(){ return new DemoImplBean(demoBean()); //構造函數注入 } } //2.在Controller中就能夠直接經過屬性注入或構造函數注入得到實例,並在ACTION中使用這些實例對象 @RestController public class DemoController { @Autowired private DemoBean demoBean; @Autowired @Qualifier("demo")//指定從IOC中解析的bean註冊名 private DemoInterface demoInterface; @Autowired private DemoBean2 demoBean2; @RequestMapping(path = "/demo/msg",method = RequestMethod.GET,produces = "application/json;charset=utf-8") public Object testMsg(@RequestParam(value = "m",required = false) String m){ //TODO:可直接使用:demoBean、demoInterface、demoBean2這些私有字段,它們經過屬性注入 return "test msg:" + m; } } //如下是如上所需的類及接口定義 public class DemoBean { } public interface DemoInterface { void showMsg(String msg); } public class DemoImplBean implements DemoInterface { private DemoBean demoBean; public DemoImplBean(DemoBean demoBean){ this.demoBean=demoBean; } @Override public void showMsg(String msg) { System.out.println("show msg:" + msg); } } //經過標記Component,交由spring IOC自動掃描註冊 @Component public class DemoBean2 { }
public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddMvc(opt => opt.Filters.Add<AopFilter>() //第一種:添加過濾器,實現ACTION執行先後記錄耗時 ).SetCompatibilityVersion(CompatibilityVersion.Version_2_1); var containerBuilder = new ContainerBuilder(); containerBuilder.Populate(services); containerBuilder.RegisterType<AopInterceptor>(); containerBuilder.RegisterType<OperationService>().InterceptedBy(typeof(AopInterceptor)).EnableClassInterceptors(); //第二種:啓用autofac的AOP攔截 var container = containerBuilder.Build(); return new AutofacServiceProvider(container); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //第三種:使用一個自定義的中間件,實現AOP的效果 app.Use(async (ctx, next) => { //若是爲示例邏輯 if (!ctx.Request.Query.TryGetValue("token", out var tokenVal) || tokenVal != "zuowenjun") { await ctx.Response.WriteAsync("驗證token失敗,禁止訪問!"); return; } ctx.Request.EnableBuffering();//啓動用buffer,以即可以重置Position var requestReader = new StreamReader(ctx.Request.Body); var requestContent = requestReader.ReadToEnd(); ctx.Request.Body.Position = 0; //須要重置爲流開頭,不然將致使後續的Model Binding失效等各類問題 var originalResponseStream = ctx.Response.Body;//記錄原始請求 using (var ms = new MemoryStream()) { ctx.Response.Body = ms;//因原始請求爲只寫流,故此處用自定義的內存流來接收響應流數據 var watch = Stopwatch.StartNew(); await next.Invoke(); watch.Stop(); ms.Position = 0; var responseReader = new StreamReader(ms); var responseContent = responseReader.ReadToEnd(); string logMsg = $"execedTime:{ watch.ElapsedMilliseconds.ToString() }ms,Request,{requestContent},Response: { responseContent}"; Logger.LogInformation(logMsg); ms.Position = 0;//恢復流位置爲開頭 await ms.CopyToAsync(originalResponseStream); //將當前的流合併到原始流中 ctx.Response.Body = originalResponseStream; //恢復原始響應流 }; }); app.UseMvc(); } /// <summary> /// Filter僅針對接入層(MVC)有效,底層服務若需使用AOP,則必需使用特定的AOP框架 /// </summary> public class AopFilter : IActionFilter { private readonly Stopwatch stopWatch = new Stopwatch(); public void OnActionExecuting(ActionExecutingContext context) { //執行前邏輯 stopWatch.Start(); } public void OnActionExecuted(ActionExecutedContext context) { //執行後邏輯 stopWatch.Stop(); var returnResult = context.Result; if (returnResult is ObjectResult) { var objResult = (returnResult as ObjectResult); objResult.Value = new { Original = objResult.Value, ElapsedTime = stopWatch.ElapsedMilliseconds.ToString() + "ms" }; } else if (returnResult is JsonResult) { var jsonResult = (returnResult as JsonResult); jsonResult.Value = new { Original = jsonResult.Value, ElapsedTime = stopWatch.ElapsedMilliseconds.ToString() + "ms" }; } } }
//最早執行,由servlet攔截請求(適用WEB) @WebFilter(filterName = "demoFilter",urlPatterns = "/*") class DemoFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { //初始化 } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //過濾處理 } @Override public void destroy() { //銷燬以前執行 } } //其次執行,由spring MVC攔截請求(適用Spring MVC) @Component public class DemoHandlerInterceptor implements HandlerInterceptor { //也可繼承自HandlerInterceptorAdapter @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //執行前 return false; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { //執行後,生成視圖以前執行 } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { //在DispatcherServlet徹底處理完請求以後被調用,可用於清理資源 } } //最後執行,攔截方法 @Component class DemoMethodInterceptor implements MethodInterceptor{ @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { return null; } } //方法攔截的另外一種形式 @Component @Aspect class AutoAspectJInterceptor { @Around("execution (*..controller.*.*(..))") public Object around(ProceedingJoinPoint point) throws Throwable{ //執行前 Object object = point.proceed(); //執行後 return object; } }
特別說明:ASP.NET CORE中的Fitler 與Spring MVC中的MethodInterceptor相似,都是控制方法,而ASP.NET CORE中的請求管道中間件與Spring MVC中的Filter、HandlerInterceptor相似,都是控制請求過程。這點要搞清楚。
//Configuration爲IConfiguration實例對象 Configuration.GetValue("key");//適用單個key-value Configuration.Get<TConfig>();//適用整個config文件映射爲一個TConfig類型的對象 Configuration.GetSection("key").GetChildren();//獲取子項集合
//1.經過@value方式獲取配置信息 @Value("${zuowenjun.site}") public String zwjSite; //2.經過建立一個映射配置信息的Bean(ConfigProperties) 方式獲取配置信息 @Component @ConfigurationProperties()//若是有前綴,則能夠設置prefix=XXX public static class Zuowenjun { private String site; private String skills; private String motto; public String getSite() { return site; } public void setSite(String site) { this.site = site; } public String getSkills() { return skills; } public void setSkills(String skills) { this.skills = skills; } public String getMotto() { return motto; } public void setMotto(String motto) { this.motto = motto; } } //3.經過Environment來直接獲取配置信息 environment.getProperty("zuowenjun.site");
C#(ASP.NET CORE:除了以下使用.NET CLI命今進行發佈打包,也可使用VS或VS CODE可視化操做進行發佈操做)
dotnet publish --configuration Release
JAVA(Spring MVC:除了以下使用MAVEN命令進行清理打包,還可使用IDEA來進行打包,具體方法可參見:Springboot項目打包成jar運行2種方式)
mvn clean package;
C#(ASP.NET CORE)、JAVA(Spring MVC)均可以:
都支持WINDOWS服務器、Linux服務器等多種平臺服務器 部署運行
都支持使用命令行啓動運行ASP.NET CORE 或Spring MVC應用,例如:
dotnet aspnetcoreApp.dll --urls="http://*:5001"
java -jar springmvcApp.jar --server.port=5001
都支持Jenkins CI&CD ,Docker、k8s虛擬化部署
都支持在Linux服務器中以守護進程方式運行,例如:
nohup dotnet aspnetcoreApp.dll > aspnetcoreApp.out 2>&1 &
nohup java -jar springmvcApp.jar > springmvcApp.out 2>&1 &
//或者都使用Supervisor來構建守護進程,還提供管理UI,具體請參見網上相關資源
好了,總結到此結束,願能幫助到那些處於.NET 轉JAVA 或JAVA 轉.NET或者想多瞭解一門編程語言的朋友們,祝你們事業有成。從此將分享更多關於分佈式、算法等方面的知識,不侷限.NET或JAVA語言,敬請期待,謝謝!
碼字不易,若需轉載及轉載我以前的文章請註明出處,謝謝。