摘要:時(shí)間年月日星期六說明本文部分內(nèi)容均來自慕課網(wǎng)。慕課網(wǎng)教學(xué)源碼學(xué)習(xí)源碼第一章課程介紹課程簡(jiǎn)介是啥讀音是輕量級(jí)的依賴注入框架說明一個(gè)的框架需要有基礎(chǔ)什么是剝離注入輕量級(jí)代碼少易維護(hù)性能優(yōu)異,跟比較。
時(shí)間:2017年10月14日星期六
說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com
教學(xué)源碼:https://github.com/zccodere/s...
學(xué)習(xí)源碼:https://github.com/zccodere/s...
Google Guice:Guice是啥
Guice讀音:juice Guice is a lightweight dependency injection framework for java Guice 是輕量級(jí)的依賴注入框架
Google Guice:說明
Java:一個(gè)java的框架、需要有java基礎(chǔ) dependency injection:什么是dependency、剝離dependency、注入dependency lightweight:輕量級(jí)(代碼少、易維護(hù)、性能優(yōu)異),跟Spring比較。 但是:學(xué)習(xí)曲線陡峭、對(duì)開發(fā)者的要求太高了
課程目標(biāo)
理解、重新理解dependency injection 掌握Guice的語法,更要掌握Guice的設(shè)計(jì)理念 開始在你的下一個(gè)項(xiàng)目中使用Guice
課程要點(diǎn)
什么是Guice dependency injection:改造Hello World程序 注入(Injection) 綁定(Binding) 作用域或生命周期(Scope) Guice AOP 使用Guice和SpringBoot協(xié)作搭建一個(gè)簡(jiǎn)單的Web應(yīng)用 Guice vs Spring1-2 產(chǎn)生原因
Spring的不足
手動(dòng)配置:使用xml進(jìn)行配置,配置太過龐大 自動(dòng)配置:Spring提供了自動(dòng)配置,復(fù)雜項(xiàng)目無法實(shí)現(xiàn)
Guice不同于Spring
取消xml 取消bean的概念 使用Constructor來注入 泛型支持 一個(gè)專注于Dependency Injection的框架
參考資料
https://github.com/google/guice/wiki/Motivation https://github.com/google/guice/wiki/ExternalDocumentation 更多利用英文資料,如Stackoverflow第二章:理解依賴 2-1 基礎(chǔ)配置
Hello Guice
配置Guice環(huán)境 Dependency Injection基礎(chǔ) 改造Hello World
創(chuàng)建名為guicedemo的maven工程pom如下
2-2 依賴分析4.0.0 com.myimooc guicedemo 0.0.1-SNAPSHOT jar guicedemo http://maven.apache.org UTF-8 1.8 1.8 1.8 com.google.inject guice 4.1.0 com.google.inject.extensions guice-multibindings 4.1.0 junit junit 4.12 test
經(jīng)典Hello World分析
核心算法:將指定內(nèi)容輸出至指定目標(biāo)
改造Hello World程序
面向?qū)ο蠡?消除Dependency 用Guice來配置Dependency2-3 面向?qū)ο?/b>
代碼編寫
1.編寫MyApplet類
package com.myimooc.guicedemo; /** * @title Applet類 * @describe 提供run()方法 * @author zc * @version 1.0 2017-10-15 */ public interface MyApplet extends Runnable{ }
2.編寫HelloWorldPrinter類
package com.myimooc.guicedemo.helloworlddemo; import com.myimooc.guicedemo.MyApplet; /** * @title HelloWorldPrinter類 * @describe 提供打印HelloWorld的功能 * @author zc * @version 1.0 2017-10-15 */ public class HelloWorldPrinter implements MyApplet { private void printHelloWorld() { System.out.println("Hello World!"); } @Override public void run() { printHelloWorld(); } }
3.編寫Configuration類
package com.myimooc.guicedemo; import com.myimooc.guicedemo.helloworlddemo.HelloWorldPrinter; /** * @title Configuration類 * @describe 程序啟動(dòng)配置類 * @author zc * @version 1.0 2017-10-15 */ public class Configuration { public static MyApplet getMainApplet() { return new HelloWorldPrinter(); } }
4.編寫App類
package com.myimooc.guicedemo; /** * @title 啟動(dòng)類 * @describe 改造HelloWorld類 * @author zc * @version 1.0 2017-10-15 */ public class App { /** * main方法的作用 * bootstrap: * parse command line:解析命令行參數(shù) * set up environment:配置環(huán)境參數(shù) * kick off main logic:?jiǎn)?dòng)程序邏輯 * @param args */ public static void main(String[] args) { MyApplet mainApplet = Configuration.getMainApplet(); mainApplet.run(); } }
面向?qū)ο蠡〗Y(jié)
善于運(yùn)用IDE提供的重構(gòu)能力 Ctrl + 1:猜測(cè)下一步動(dòng)作 Ctrl + shift + r:重命名 先寫代碼,再讓其編譯通過 先思考確定需要什么,然后再機(jī)械性勞動(dòng)實(shí)現(xiàn) 函數(shù)命名 從實(shí)現(xiàn)角度:精確描述函數(shù)干什么 從調(diào)用者角度:描述調(diào)用者需求 兩者不匹配:需要進(jìn)行抽象的點(diǎn)2-4 提取依賴
代碼編寫
1.編寫MyApplet類
package com.myimooc.guicedemo.noguice; /** * @title MyApplet類 * @describe 提供run()方法 * @author zc * @version 1.0 2017-10-15 */ public interface MyApplet extends Runnable{ }
2.編寫StringWritingApplet類
package com.myimooc.guicedemo.noguice.helloworlddemo; import com.myimooc.guicedemo.noguice.MyApplet; /** * @title HelloWorldPrinter類 * @describe 提供打印HelloWorld的功能 * @author zc * @version 1.0 2017-10-15 */ public class StringWritingApplet implements MyApplet { private MyDestination destination; private StringProvider stringProvider; public StringWritingApplet(MyDestination destination,StringProvider stringProvider) { super(); this.destination = destination; this.stringProvider = stringProvider; } private void writeString() { destination.write(stringProvider.get()); } @Override public void run() { writeString(); } }
3.編寫StringProvider類
package com.myimooc.guicedemo.noguice.helloworlddemo; /** * @title StringProvider類 * @describe 提供get()方法 * @author zc * @version 1.0 2017-10-15 */ public interface StringProvider { String get(); }
4.編寫MyDestination類
package com.myimooc.guicedemo.noguice.helloworlddemo; /** * @title MyDestination類 * @describe 提供write()方法 * @author zc * @version 1.0 2017-10-15 */ public interface MyDestination { void write(String string); }
5.編寫PrintStreamWriter類
package com.myimooc.guicedemo.noguice.helloworlddemo; import java.io.PrintStream; /** * @title PrintStreamWriter類 * @describe 實(shí)現(xiàn)write()方法 * @author zc * @version 1.0 2017-10-15 */ public class PrintStreamWriter implements MyDestination { private PrintStream destination; public PrintStreamWriter(PrintStream destination) { super(); this.destination = destination; } @Override public void write(String string) { destination = System.out; destination.println(string); } }
6.編寫Configuration類
package com.myimooc.guicedemo.noguice; import com.myimooc.guicedemo.noguice.helloworlddemo.PrintStreamWriter; import com.myimooc.guicedemo.noguice.helloworlddemo.StringProvider; import com.myimooc.guicedemo.noguice.helloworlddemo.StringWritingApplet; /** * @title Configuration類 * @describe 程序啟動(dòng)配置類 * @author zc * @version 1.0 2017-10-15 */ public class Configuration { public static MyApplet getMainApplet() { return new StringWritingApplet( new PrintStreamWriter(System.out), new StringProvider() { @Override public String get() { return "Hello World"; } }); } }
7.編寫App類
package com.myimooc.guicedemo.noguice; /** * @title 啟動(dòng)類 * @describe 改造HelloWorld類 * @author zc * @version 1.0 2017-10-15 */ public class App { /** * main方法的作用 * bootstrap: * parse command line:解析命令行參數(shù) * set up environment:配置環(huán)境參數(shù) * kick off main logic:?jiǎn)?dòng)程序邏輯 * @param args */ public static void main(String[] args) { MyApplet mainApplet = Configuration.getMainApplet(); mainApplet.run(); } }
消除Dependency小結(jié)
2-5 配置依賴代碼編寫
1.編寫MyApplet類
package com.myimooc.guicedemo.useguice; /** * @title MyApplet類 * @describe 提供run()方法 * @author zc * @version 1.0 2017-10-15 */ public interface MyApplet extends Runnable{ }
2.編寫StringWritingApplet類
package com.myimooc.guicedemo.useguice.helloworlddemo; import com.google.inject.Inject; import com.google.inject.Provider; import com.myimooc.guicedemo.useguice.MyApplet; /** * @title HelloWorldPrinter類 * @describe 提供打印HelloWorld的功能 * @author zc * @version 1.0 2017-10-15 */ public class StringWritingApplet implements MyApplet { private MyDestination destination; private ProviderstringProvider; @Inject public StringWritingApplet(MyDestination destination,@Output Provider stringProvider) { super(); this.destination = destination; this.stringProvider = stringProvider; } private void writeString() { destination.write(stringProvider.get()); } @Override public void run() { writeString(); } }
3.編寫MyDestination類
package com.myimooc.guicedemo.useguice.helloworlddemo; /** * @title MyDestination類 * @describe 提供write()方法 * @author zc * @version 1.0 2017-10-15 */ public interface MyDestination { void write(String string); }
4.編寫PrintStreamWriter類
package com.myimooc.guicedemo.useguice.helloworlddemo; import java.io.PrintStream; import javax.inject.Inject; /** * @title PrintStreamWriter類 * @describe 實(shí)現(xiàn)write()方法 * @author zc * @version 1.0 2017-10-15 */ public class PrintStreamWriter implements MyDestination { private PrintStream destination; @Inject public PrintStreamWriter(PrintStream destination) { super(); this.destination = destination; } @Override public void write(String string) { destination = System.out; destination.println(string); } }
5.編寫Output類
package com.myimooc.guicedemo.useguice.helloworlddemo; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import com.google.inject.BindingAnnotation; /** * @title Output注解 * @describe * @author zc * @version 1.0 2017-10-15 */ @Retention(RetentionPolicy.RUNTIME) @BindingAnnotation public @interface Output { }
6.編寫HelloWorldModule類
package com.myimooc.guicedemo.useguice.helloworlddemo; import java.io.PrintStream; import com.google.inject.AbstractModule; import com.myimooc.guicedemo.useguice.MyApplet; /** * @title HelloWorldModule類 * @describe HelloWorld模塊的依賴配置 * @author zc * @version 1.0 2017-10-15 */ public class HelloWorldModule extends AbstractModule{ @Override protected void configure() { bind(MyApplet.class).to(StringWritingApplet.class); bind(MyDestination.class).to(PrintStreamWriter.class); bind(PrintStream.class).toInstance(System.out); bind(String.class).annotatedWith(Output.class).toInstance("Hello World"); } }
7.編寫MainModule類
package com.myimooc.guicedemo.useguice; import com.google.inject.AbstractModule; import com.myimooc.guicedemo.useguice.helloworlddemo.HelloWorldModule; /** * @title MainModule類 * @describe Guice用來配置的類 * @author zc * @version 1.0 2017-10-15 */ public class MainModule extends AbstractModule{ @Override protected void configure() { install(new HelloWorldModule()); } }
8.編寫App類
package com.myimooc.guicedemo.useguice; import com.google.inject.Guice; /** * @title 啟動(dòng)類 * @describe 改造HelloWorld類 * @author zc * @version 1.0 2017-10-15 */ public class App { /** * main方法的作用 * bootstrap: * parse command line:解析命令行參數(shù) * set up environment:配置環(huán)境參數(shù) * kick off main logic:?jiǎn)?dòng)程序邏輯 * @param args */ public static void main(String[] args) { MyApplet mainApplet = Guice .createInjector(new MainModule()) .getInstance(MyApplet.class); mainApplet.run(); } }
Guice配置Dependency小結(jié)
第三章:注入依賴 3-1 基本注入注入圖解
注入(Injection)
構(gòu)造函數(shù)注入 使用final來區(qū)分dependency和狀態(tài) 注入時(shí)不考慮如何實(shí)現(xiàn)或綁定 成員變量注入 用于測(cè)試 使用injectMembers來注入測(cè)試用例
代碼編寫
1.編寫OrderService類
2.編寫PaymentService類
3.編寫PriceService類
4.編寫OrderServiceImpl類
5.編寫PaymentServiceImpl類
6.編寫PriceServiceImpl類
7.編寫SessionManager類
8.編寫ServerModule類
9.編寫OrderServiceTest類
受篇幅限制,源碼請(qǐng)到我的github地址查看
3-2 其他注入注入Provider
如何注入Provider
DatabaseConnection dbConn Provider< DatabaseConnection > dbConnProvider Guice會(huì)考慮對(duì)象生命周期 需要時(shí)可以自己實(shí)現(xiàn)Provider
命名注入
@Inject @Named(“dbSpec”) private String dbSpec; @Inject @LogFileName private String logFileName; 使用@Named:參數(shù)來自配置文件或命令行、或者為了開發(fā)方便 使用屬性:通常采用此方法
代碼編寫
1.修改SessionManager類
package com.myimooc.guicedemo.server.impl; import javax.inject.Inject; import com.google.inject.Provider; /** * @title session管理類 * @describe 模擬訂單系統(tǒng) * @author zc * @version 1.0 2017-10-15 */ public class SessionManager { private final ProvidersessionIdProvider; @Inject public SessionManager(@SessionId Provider sessionIdProvider) { super(); this.sessionIdProvider = sessionIdProvider; } public Long getSessionId() { return sessionIdProvider.get(); } }
2.修改ServerModule類
package com.myimooc.guicedemo.server.impl; import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.myimooc.guicedemo.server.OrderService; import com.myimooc.guicedemo.server.PaymentService; import com.myimooc.guicedemo.server.PriceService; /** * @title ServerModule類 * @describe 綁定依賴 * @author zc * @version 1.0 2017-10-15 */ public class ServerModule extends AbstractModule{ @Override protected void configure() { bind(OrderService.class).to(OrderServiceImpl.class); bind(PaymentService.class).to(PaymentServiceImpl.class); bind(PriceService.class).to(PriceServiceImpl.class); } @Provides @SessionId Long generateSessionId(){ return System.currentTimeMillis(); } }
3.編寫SessionId類
package com.myimooc.guicedemo.server.impl; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import com.google.inject.BindingAnnotation; /** * @title SessionId注解 * @describe 用來綁定數(shù)據(jù) * @author zc * @version 1.0 2017-10-15 */ @Retention(RetentionPolicy.RUNTIME) @BindingAnnotation public @interface SessionId { }
4.編寫SessionManagerTest類
package com.myimooc.guicedemo.server.impl; import static org.junit.Assert.assertNotEquals; import javax.inject.Inject; import org.junit.Before; import org.junit.Test; import com.google.inject.Guice; /** * @title 測(cè)試類 * @describe 測(cè)試@Provides * @author zc * @version 1.0 2017-10-15 */ public class SessionManagerTest { @Inject SessionManager sessionManager; @Before public void setUp(){ Guice.createInjector(new ServerModule()) .injectMembers(this); } @Test public void testGetSessionId() throws InterruptedException{ Long sessionId1 = sessionManager.getSessionId(); Thread.sleep(1000); Long sessionId2 = sessionManager.getSessionId(); assertNotEquals(sessionId1.longValue(), sessionId2.longValue()); } }第四章:綁定依賴 4-1 綁定詳解
綁定圖解
綁定
類名綁定 實(shí)例綁定 連接綁定 Provider綁定 命名綁定 泛型綁定 集合綁定4-2 模塊組織
Module的相互關(guān)系
并列:Guice.createInjector(module1,module2,…) 嵌套:install(module) 覆蓋:Modules.override(module1).with(module2)
Module何時(shí)被運(yùn)行
Module里存放了很多表達(dá)式 Module不被“運(yùn)行” Guice.createInjector()時(shí)記錄所有表達(dá)式
系統(tǒng)何時(shí)初始化
沒有“初始化”概念,沒有Spring的Configuration Time injector.getInstance()時(shí)根據(jù)表達(dá)式調(diào)用構(gòu)造函數(shù)4-3 綁定示例
案例:HelloWorld與命令行
讓HelloWorld打印命令行參數(shù) 讓HelloWorld通過命令行決定啟動(dòng)哪個(gè)Applet
代碼編寫
1.編寫MyApplet類
2.編寫Applets類
3.編寫StringWritingApplet類
4.編寫PrintLineApplet類
5.編寫MyDestination類
6.編寫PrintStreamWriter類
7.編寫Output類
8.編寫Args類
9.編寫HelloWorldModule類
10.編寫PrintLineModule類
11.編寫CommandLineModule類
12.編寫MainModule類
13.編寫App類
受篇幅限制,源碼請(qǐng)到我的github地址查看
第五章:生命周期 5-1 基本介紹生命周期或作用域
選擇作用域
默認(rèn):適用于:一般實(shí)例,stateless,構(gòu)造速度快 如:Parser、PriceCalulator Singleton:適用于:stateful的實(shí)例,構(gòu)造速度慢的實(shí)例,必須線程安全 如:數(shù)據(jù)庫(kù)、網(wǎng)絡(luò)連接 Session/Request:含有session/request信息的實(shí)例、stateful的實(shí)例 如:SessionSate5-2 使用介紹
作用域的使用
作為類或者@Provides方法的屬性 在綁定時(shí)使用In語句 @Singleton的線程安全性第六章:切面編程 6-1 面向切面
Guice AOP
符合AOP Alliance的MethodInterceptor接口 MethodInterceptor可用于“Aspects” 獲取函數(shù)調(diào)用類、方法、參數(shù) 控制是否執(zhí)行函數(shù)調(diào)用
實(shí)現(xiàn)AOP
綁定MethodInterceptor 實(shí)現(xiàn)MethodInterceptor 在MethodInterceptor中注入Dependency
代碼編寫
1.編寫Logged類
package com.myimooc.guicedemo.aop; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * @title Logged注解 * @describe 用于標(biāo)識(shí)需要記錄日志的方法 * @author zc * @version 1.0 2017-10-15 */ @Retention(RetentionPolicy.RUNTIME) public @interface Logged { }
2.編寫LoggedInterceptor類
package com.myimooc.guicedemo.aop; import java.lang.reflect.Method; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import com.google.common.base.Joiner; /** * @title LoggedMethodInterceptor類 * @describe 切面類,用于處理被攔截的方法,實(shí)現(xiàn)日志記錄 * @author zc * @version 1.0 2017-10-15 */ public class LoggedInterceptor implements MethodInterceptor{ @Override public Object invoke(MethodInvocation invocation) throws Throwable { // 獲得調(diào)用參數(shù) invocation.getArguments(); // 獲得調(diào)用對(duì)象 invocation.getClass(); // 獲得調(diào)用方法 Method method = invocation.getMethod(); // 記錄日志 System.out.println(String.format("Calling %s#%s(%s)", method.getDeclaringClass().getName(), method.getName(), Joiner.on(",").join(invocation.getArguments()))); // 執(zhí)行調(diào)用方法 Object result = invocation.proceed(); // 返回調(diào)用結(jié)果 return result; } }
3.編寫LoggedModule類
package com.myimooc.guicedemo.aop; import com.google.inject.AbstractModule; import com.google.inject.matcher.Matchers; /** * @title LoggedModule類 * @describe 用于配置依賴綁定 * @author zc * @version 1.0 2017-10-15 */ public class LoggedModule extends AbstractModule{ @Override protected void configure() { // 配置攔截任意類,帶有@Logged注解修飾的方法 bindInterceptor( Matchers.any(), Matchers.annotatedWith(Logged.class), new LoggedInterceptor()); } }第七章:框架集成 7-1 協(xié)作框架
使用Guice與SpringBoot協(xié)作搭建Web應(yīng)用
使用SpringBoot搭建簡(jiǎn)單的Web應(yīng)用 使用Guice搭建業(yè)務(wù)邏輯
協(xié)作框架
7-2 案例實(shí)戰(zhàn)創(chuàng)建名為guicespring的maven工程
完成后的項(xiàng)目結(jié)構(gòu)如下
受篇幅限制,源碼請(qǐng)到我的github地址查看
協(xié)作小結(jié)
SpringBoot進(jìn)行總控 各自綁定Guice Injector和Spring ApplicationContext 注意對(duì)象生命周期第八章:課程總結(jié) 8-1 適用場(chǎng)景
Guice與Spring
Guice不是Spring的重制版 Spring綁定 配置文件體現(xiàn)完整裝配結(jié)構(gòu) 大量使用字符串:實(shí)例名:屬性名 在Config Time完成組裝 Guice綁定 Java代碼描述綁定規(guī)則 每個(gè)注入和綁定僅描述局部依賴 沒有Config Time
Guice的優(yōu)點(diǎn)
代碼量少 性能優(yōu)異 支持泛型 Constructor綁定:Immutable objects,不再需要getter/setter 強(qiáng)類型 易于重構(gòu)
Guice的缺點(diǎn)
Module和綁定規(guī)則不易理解 文檔教程少,社區(qū)資源少 無法方便搭出特殊結(jié)構(gòu):如循環(huán)依賴 Guice僅僅是依賴注入框架,而Spring涵蓋較多
從Spring遷移到Guice
不建議 Spring與Guice整合
新項(xiàng)目需要選擇Dependency Injection方案
不妨嘗試Guice 與其它組件或解決方案整合:注意對(duì)象生命周期8-2 課程回顧
課程回顧
什么是Guce Dependency Injection:改造Hello World程序 注入(Injection) 綁定(Binding) 作用域或生命周期(Scope) Guice AOP 使用Guice與SpringBoot協(xié)作搭建Web應(yīng)用
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/67793.html
摘要:入門篇學(xué)習(xí)總結(jié)時(shí)間年月日星期三說明本文部分內(nèi)容均來自慕課網(wǎng)。主要的功能是日志記錄,性能統(tǒng)計(jì),安全控制,事務(wù)處理,異常處理等等。 《Spring入門篇》學(xué)習(xí)總結(jié) 時(shí)間:2017年1月18日星期三說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學(xué)示例源碼:https://github.com/zccodere/s...個(gè)人學(xué)習(xí)源碼:https://git...
摘要:攔截器學(xué)習(xí)總結(jié)時(shí)間年月日星期六說明本文部分內(nèi)容均來自慕課網(wǎng)。慕課網(wǎng)教學(xué)示例源碼暫無。攔截器不依賴與容器,過濾器依賴與容器。攔截器只能對(duì)請(qǐng)求起作用,而過濾器則可以對(duì)幾乎所有的請(qǐng)求起作用。共性問題在攔截器中處理,可以減少重復(fù)代碼,便于維護(hù)。 《SpringMVC攔截器》學(xué)習(xí)總結(jié) 時(shí)間:2017年2月18日星期六說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.co...
摘要:時(shí)間年月日星期一說明本文部分內(nèi)容均來自慕課網(wǎng)。多用于網(wǎng)絡(luò)加密。散列函數(shù)函數(shù)或消息摘要函數(shù)主要作用散列函數(shù)用來驗(yàn)證數(shù)據(jù)的完整性。 時(shí)間:2017年4月10日星期一說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學(xué)示例源碼:https://github.com/zccodere/s...個(gè)人學(xué)習(xí)源碼:https://github.com/zccodere...
摘要:時(shí)間年月日星期日說明本文部分內(nèi)容均來自慕課網(wǎng)。這對(duì)所有形態(tài)的工廠模式都是重要的這個(gè)系統(tǒng)的產(chǎn)品有至少一個(gè)的產(chǎn)品族同屬于一個(gè)產(chǎn)品族的產(chǎn)品是設(shè)計(jì)成在一起使用的。 時(shí)間:2017年08月27日星期日說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學(xué)源碼:https://github.com/zccodere/s...學(xué)習(xí)源碼:https://github.c...
摘要:時(shí)間年月日星期日說明本文部分內(nèi)容均來自慕課網(wǎng)。慕課網(wǎng)教學(xué)示例源碼無個(gè)人學(xué)習(xí)源碼第一章課程概述課程介紹課程須知本課程面向所有使用語言進(jìn)行開發(fā)的小伙伴。 時(shí)間:2017年05月21日星期日說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學(xué)示例源碼:無個(gè)人學(xué)習(xí)源碼:https://github.com/zccodere/s... 第一章:課程概述 1-1 ...
閱讀 2769·2021-11-17 09:33
閱讀 3091·2021-10-25 09:44
閱讀 1199·2021-10-11 10:59
閱讀 2394·2021-09-27 13:34
閱讀 2904·2021-09-07 10:19
閱讀 2132·2019-08-29 18:46
閱讀 1534·2019-08-29 12:55
閱讀 927·2019-08-23 17:11