「2020 新手必備 」極速入門 Retrofit + OkHttp 網路框架到實戰,這一篇就夠了!
老生常談
- 什麼是
Retrofit
? Retrofit
早已不是什麼新技術了,想必看到這篇部落格的大家都早已熟知,這裡就不囉嗦了,簡單介紹下:
- Retrofit 是一個針對 Java 和 Android 的設計的
REST
客戶機。它通過基於REST
的 web 服務檢索和上傳 JSON (或其他結構化資料)變得相對容易。在使用中,您可以配置用於資料序列化的轉換器。對於 JSON ,通常使用Gson
,但是可以新增自定義轉換器來處理XML
或其他協議。Retrofit 對 HTTP 請求使用OkHttp
庫。
A type-safe HTTP client for Android and Java
- 好了介紹結束,想必大家的大刀都飢渴難耐了,那麼我們直接開始吧
本文流程
依賴注入
- so Easy 不用說了吧
- 在 app module 下的
build.gradle
中新增以下依賴:
// OkHttp3 api 'com.squareup.okhttp3:okhttp:3.10.0' api 'com.squareup.okio:okio:1.8.0' // Retrofit api 'com.squareup.retrofit2:retrofit:2.7.0' // Gson 伺服器資料互動 api 'com.google.code.gson:gson:2.8.6'
依賴注入很簡單, Retrofit 一直是結合
OkHttp
和 Gson(無所謂什麼 JSON 解析器都行,這裡就用Gson
了)
我這裡專門找了最新的版本庫,so~ 大家直接用即可
- 別急,前面也說了
Retrofit
是結合OkHttp
做網路請求用的,所以悉心提醒記得開下網路許可權:
<uses-permission android:name="android.permission.INTERNET" />
全面進擊
- 網上關於
Retrofit
的教程可謂琳瑯滿目,但是總給人一種雲裡霧裡的感覺 - 所以本文的亮點就在於,我會通過我自己實際專案的程式碼來給大家介紹 Retrofit 到底牛在哪
Retrofit 開始之前
- 這裡我將以我的一個開源專案 FIWKeepApp 的登入模組舉例
- 在
Retrofit
出現之前,原始社會的我們一般是這樣進行網路請求的:
public void login2() {
OkHttpClient okHttpClient = new OkHttpClient();
//Form表單格式的引數傳遞
FormBody formBody = new FormBody
.Builder()
//設定引數名稱和引數值
.add("username",mAccountEdit.getText().toString())
.add("password",mPasswordEdit.getText().toString())
.build();
Request request = new Request
.Builder()
//Post請求的引數傳遞
.post(formBody)
.url("http://hyh.hljdx.net:8080/SitUpWebServer/login")
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(okhttp3.Call call, IOException e) {
Log.d("my_Test", e.getMessage());
}
@Override
public void onResponse(okhttp3.Call call, Response response) throws IOException {
String result = response.body().toString();
UserBean userBean = JSON.parseObject(result, UserBean.class);
Log.d("my_Test",userBean.getUser_head_img());
response.body().close();
}
});
}
- 有沒有一種雲裡霧裡的感覺?
- 首先你得先將要傳送的表單資訊封裝為
Post
請求的Body
物件,那麼有的同學會問什麼是POST
,什麼是Body
?這個問題建議大家Google
下,這裡我建議大家學一些後端或者計網的知識,很簡單也很有必要 - 接著你需要再封裝一個
Request
物件,也就是我們的請求體,在這裡設定資訊要提交到哪去 - 最後呼叫
okHttpClient
的相應方法,將前面實現的東西組合傳送,並在回撥裡接收 - 所以,這一步步,又是封裝
FormBody
又是封裝Request
,搞了半天還要用okHttpClient
傳送,一套下來頭暈眼花,那麼如何解決呢? - 那麼
Retrofit
救世主就出現了
Retrofit 實現
- 還是我專案中的登入模組,我將其改為
Retrofit
的形式 - 同樣完成上面的功能,如果用
Retrofit
實現只需要:
// baseUrl() 設定路由地址
Retrofit retrofit = new Retrofit
.Builder()
.baseUrl(ApiUtils.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
// 設定引數
Call<UserBean> call = retrofit.create(UserMgrService.class)
.login( mAccountEdit.getText().toString(),
mPasswordEdit.getText().toString());
// 回撥
call.enqueue(new Callback<UserBean>() {
@Override
public void onResponse(Call<UserBean> call, Response<UserBean> response) {
Log.d("123123", "msg--" + response.body().getUser_head_img());
}
@Override
public void onFailure(Call<UserBean> call, Throwable t) {
// 失敗時做處理
}
});
- 如上就實現了和純
okHttp
程式碼一樣的功能 - 大家可能會覺得,這也沒簡單多少啊 ?但細心觀察發現,第一步
Retrofit
的例項化過程,只要伺服器不換程式碼幾乎是不變的,所以我們完全可以將它封裝
- 而且大家有沒有發現,如果單單使用
OkHttp
我們的返回值是一個Response
物件,我們還需要在其中提取相應JSON
物件,進行型別轉換,而在Retrofit
中,由於使用了資料解析器,所以這一大塊程式碼都省略了 - 還有很多優點,這裡就不嘮叨了,我們直接開始學習使用之路吧!
實現流程
- 那麼現在就給大家解釋下使用的每個步驟
建立介面
- 首先我們要建立 UserMgrService 介面
/**
* @author fishinwater-1999
* @version 2019-12-21
*/
public interface UserMgrService {
/**
* GET 用 Query
*/
@GET("login")
Call<UserBean> login(@Query("username") String username, @Query("password") String password);
}
- 從
@GET()
註解就可以猜到,這將會是一個Get
請求 - 我們在看方法體,返回值會是一個封裝了
UserBean
的Call<>
物件 - 引數有兩個,分別是
String username
和String password
- 與平常方法不同的是,這兩個引數各自帶上了
@Query("...")
註解 - 通過
@Query("...")
裡的引數我們發現,這與okHttp
建立FormBody
時,add
的引數不謀而合
看到這裡想必大家都明白了,如果大家還不明白什麼是 Get 請求,以及 @Query("...") 裡的 username 和 password 是怎麼的話,我這裡簡單說下
比如說我們現在隨便開啟一個網頁,就拿百度圖片裡搜尋 Github 頁面為例:
- 後端寫伺服器的同學會通過這些引數,像
HashMap get(“key”)
方法取值一樣拿出來
POST
- 這樣解釋,想必大家就明白了
- 除了
GET
方法之外 還有一種POST
方法,相比於使用GET
,使用POST
有很多其他的優點,這裡就不多說了 - 他使用和
GET
的思路一樣,如果用POST
那麼我們的程式碼將會是這樣的:
public interface UserMgrService {
/**
* POST 用 Field
*/
@POST("login")
@FormUrlEncoded
Call<UserBean> login(@Field("username") String username, @Field("password") String password);
}
- 就是把註解換了套名字,然後在
@POST("...")
下再加上一個@FormUrlEncoded
註解 - 這裡就不多說了,我們直接進入下一步
生成 Retrofit 物件
- 我們先看下怎麼建立和設定的:
// baseUrl() 設定路由地址
Retrofit retrofit = new Retrofit
.Builder()
.baseUrl(ApiUtils.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
- 這裡主要是兩步,設定
baseUrl
、設定資料解析器 - 老樣子什麼是
baseUrl
?就拿我之前用OkHttp
設定的那個 url 為例
http://hyh.hljdx.net:8080/SitUpWebServer/login
- 大家可以這麼理解:上面的這個
url = baseurl + @GET("...")
註解裡傳入的字串 - 如果我們前面設定的是
@GET("login")
那這裡baseurl
就是:http://hyh.hljdx.net:8080/SitUpWebServer/
是不是一下子就明白了,但是其他部落格不照顧新人,從沒說清楚 - 然後就是資料解析器,大家應該還記得剛開始的時候我們匯入了一個三方庫:
// Gson 伺服器資料互動
api 'com.google.code.gson:gson:2.8.6'
- 我們和伺服器的資料,都是以
JSON
的形式互動的,比如Bing
每日桌布介面
- 設定了這個資料解析器,就可以把返回的資訊自動封裝為相應的物件,明白了吧
具體這個物件怎麼獲得,大家可以聯絡後端,或者百度搜下 JsonFormat 外掛使用或者 JSON 物件生成器,門路很多這裡都告訴你們啦
生成介面物件
- 老樣子,先看看程式碼
UserMgrService service = retrofit.create(UserMgrService.class);
- 過於簡單,呼叫前面
retrofit
物件的create()
方法傳入介面的class
檔案即可
獲得 Call 物件
- 由剛開始的程式碼我們知道
- 我們向伺服器傳送請求需要呼叫
call
物件的enqueue()
方法 - 那麼
Call
物件怎麼獲得呢?其實很簡單:
Call<UserBean> call = service.login( mAccountEdit.getText().toString(), mPasswordEdit.getText().toString());
- 說白了就是,直接呼叫介面的相應方法,他返回的直接就是一個
Call
物件
傳送請求
- 請求分兩種 同步的和非同步的
- 由於請求是耗時的,假設我們傳送同步請求 ,在請求就過返回之前,應用介面會進去阻塞狀態
- 說白了就是會卡,甚至卡死。。。所以說這種請求很少用到
- 雖然不用,但負責的我還是也給大家程式碼:
Response<UserBean> response = call.execute();
Log.d("123123", "msg--" + response.body().getUser_head_img());
- 具體就不說了,就是呼叫
call
的execute()
會返回一個值 - 這個值就是請求結果,大家直接用就是( 但是在這個只沒返回,比如網速慢時,手機會卡在那動不了甚至
ANR
) - 這裡我介紹下非同步請求:
// 回撥
call.enqueue(new Callback<UserBean>() {
@Override
public void onResponse(Call<UserBean> call, Response<UserBean> response) {
Log.d("123123", "msg--" + response.body().getUser_head_img());
}
@Override
public void onFailure(Call<UserBean> call, Throwable t) {
// 失敗時做處理
}
});
- 這就是非同步方法,直接呼叫
call
的enqueue
方法,傳入一個Callback
介面即可 - 呼叫後系統自動釋放資源,不會阻塞,等到請求結果返回時
- 就會自動呼叫
onResponse
方法,方法 裡的response
就是處理好的結果 - 本文程式碼執行後結果 Demo Example 是不是特別簡單!
登入功能實戰
- 到這裡想必大家都已經學會了
Retrofit
的使用 - 那麼現在我就拿登入功能舉例,看看如何在專案中引用
Retrofit
- 實戰部分先置條件是
MVP
+ButterKnife
,大家很容易在網上找到資料,這就不贅述了
搭建 Model 層
- 建立介面
ILoginModel
- 介面對外暴露 username password 和 一個監聽回撥介面 (介面通過泛型傳入)
/**
* @author fishinwater-1999
* @version 2019-11-12
*/
public interface IBaseLog<L> {
/**
* 登入 Api
* @param userAccount
* @param mPassword
* @param loginCallback
*/
void login(String userAccount, String mPassword, L loginCallback);
}
- 實現回撥介面
- 觀察者模式,當請求資訊返回後動態通知 P 層
/**
* @author fishinwater-1999
* @version 2019-12-23
*/
public interface IBaseRetCallback<T> {
void onSucceed(Response<T> response);
void onFailed(Throwable t);
}
- 建立
LoginModel
實現ILoginModel
介面 - 實現
login
方法,請求成功後回撥IBaseRetCallback
監聽
/**
* @author fishinwater-1999
* @version 2019-11-12
*/
public class LogViewModel implements IBaseLog<IBaseRetCallback<UserBean>> {
private final String TAG = "LogViewModel";
@Override
public void login(String userAccount, String userPassword, final IBaseRetCallback<UserBean> retCallback) {
// baseUrl() 設定路由地址
Retrofit retrofit = new Retrofit
.Builder()
.baseUrl(ApiUtils.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
// 設定引數
UserMgrService service = retrofit.create(UserMgrService.class);
retrofit2.Call<UserBean> call = service.login( userAccount, userPassword);
// 回撥
call.enqueue(new Callback<UserBean>() {
@Override
public void onResponse(retrofit2.Call<UserBean> call, Response<UserBean> response) {
retCallback.onSucceed(response);
}
@Override
public void onFailure(retrofit2.Call<UserBean> call, Throwable t) {
// 失敗時做處理
retCallback.onFailed(t);
}
});
}
}
搭建 Presenter 層
- 首先實現
Presenter
層基類 - 同樣的,要搭建
Presenter
層基類,首先要實現器介面
/**
* @author fishinwater-1999
* @version 2019-11-12
*/
public interface IBasePresenter<V> {
/**
* 繫結
* @param mLogView
*/
void attachView(V mLogView);
/**
* 解綁
*/
void detachView();
/**
* 登入
* @param userName
* @param userPassword
* @param resultListener
*/
void login(String userName, String userPassword, V resultListener);
}
- 編寫抽象類
BasePresenter
實現IBasePresenter
介面
/**
* @author fishinwater-1999
* @version 2019-11-12
*/
public abstract class BasePresenter<V> implements IBasePresenter<V> {
private V view;
@Override
public void attachView(V mLogView) {
this.view = mLogView;
}
@Override
public void detachView() {
this.view = null;
}
@Override
public V getLoginVew() {
return this.view;
}
}
- 然後就到了我們具體的
LogPresenter
類的實現 LogPresenter
類需要持有 View 層和 Model 層介面
/**
* @author fishinwater-1999
* @version 2019-11-12
*/
public class LogPresenter extends BasePresenter<ILoginView> {
private IBaseLog logViewModel;
public LogPresenter(IBaseLog logViewModel) {
this.logViewModel = logViewModel;
}
@Override
public void login(String userName, String userPassword, final ILoginView iLoginView) {
logViewModel.login(userName, userPassword, new IBaseRetCallback<UserBean>() {
@Override
public void onSucceed(Response<UserBean> response) {
UserBean userBean = response.body();
if (userBean != null) {
String user_id = userBean.getUser_id();
iLoginView.showLoginSuccess(user_id);
}
}
@Override
public void onFailed(Throwable t) {
iLoginView.showLoginFailed(ILoginView.ErrCode.WRONG_NET_WORK);
}
});
}
}
- 上面的程式碼中,構造方法 LogPresenter 持有了 Model 層
- 同時暴露了 login(..., ..., Listener) 介面,可供呼叫者呼叫
View 層實現
View
層負責例項化Model
層,並與Presenter
層繫結- 老樣子,建立
BaseFragment<V , P extends IBasePresenter<V>>
基類
/**
* @author fishinwater-1999
* @version 2019-11-12
*/
public abstract class BaseFragment<V , P extends IBasePresenter<V>> extends Fragment {
/**
* Presenter 層
*/
private P mBaseResister;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 自動繫結
if (mBaseResister == null) {
mBaseResister = createProsenter();
}
}
/**
* 在這裡確定要生成的 Presenter 物件型別
* @return
*/
public abstract P createProsenter();
/**
* 獲得 Presenter 物件
* @return
*/
public P getPresenter() {
if (mBaseResister == null) {
createProsenter();
}
return mBaseResister;
}
/**
* 碎片銷燬時解綁
*/
@Override
public void onStop() {
super.onStop();
mBaseResister = null;
}
}
- 實現
View
層邏輯 - View 層只負責使用者介面響應
/**
* @author fishinwater-1999
*/
public class LoginFragment extends BaseFragment<ILoginView, LogPresenter> implements ILoginView {
private static final String TAG = "LoginFragment";
private LogViewModel mLogViewModel;
private LoginFragmentBinding binding;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
binding = DataBindingUtil.inflate(inflater, R.layout.login_fragment, container, false);
View view = binding.getRoot();
binding.setLogCallback(getLogActivity());
binding.setFragment(this);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (mLogViewModel == null) {
mLogViewModel = new LogViewModel();
}
}
public void login(View v) {
getPresenter().login(
getUserName(),
getUserPwd(),
this);
}
@Override
public LogPresenter createPresenter() {
if (mLogViewModel == null) {
mLogViewModel = new LogViewModel();
}
return new LogPresenter(mLogViewModel);
}
@Override
public String getUserName() {
return binding.userAccount.getText().toString();
}
@Override
public String getUserPwd() {
return binding.userPassword.getText().toString();
}
@Override
public void showLoginSuccess(String response) {
Toast.makeText(getActivity(), "登入成功", Toast.LENGTH_LONG).show();
SharedPreferencesUtil.putString(getActivity(), SharedPreferencesUtil.PRE_NAME_SITUP, SharedPreferencesUtil.USER_ID, response);
ARouter.getInstance().build(RouteUtils.MainActivity).navigation();
getActivity().finish();
}
@Override
public void showLoginFailed(ErrCode errCode) {
if (errCode == ErrCode.WRONG_USER_NAME) {
Toast.makeText(getActivity(), "使用者名稱錯誤", Toast.LENGTH_LONG).show();
}else if (errCode == ErrCode.WRONG_USER_PWD){
Toast.makeText(getActivity(), "密碼錯誤", Toast.LENGTH_LONG).show();
}else if (errCode == ErrCode.WRONG_NET_WORK) {
Toast.makeText(getActivity(), "未知,請檢查網路", Toast.LENGTH_LONG).show();
}
}
}
- 這裡我使用了 DataBinding 的形式,對資料進行繫結
- 當然,你也可以選用 ButterKnife 等優秀的三方庫
- 那麼為什麼我選 DataBinding 呢?親兒子 懂吧? /壞笑
執行
- 關於 測序的大致便是如此了
- 至於細枝末節的東西大家可以直接到這個庫裡面看,地址在文末
更多模組實戰 FIWKeepApp
這裡我將上述過程寫在我的
Demo
裡,地址在GitHub
大家可以直接檢視改倉庫原始碼,記得給我點個star
哦~:Demo
地址:FIWKeepApp - LoginFragment
總結
- 想必看到這兒的讀者對 Retrofit 的使用都已近有了一定的瞭解,但 Retrofit 的好處並不只是這些,還有很多跟深入的只是需要了解,但本文限於篇幅,無法向大家一一介紹
- 對於我前面的 FIWKeepApp 這個倉庫,我將一步步轉換到 Retrofit + OkHttp 的形式下,歡迎大家關注我的 這個倉庫,進行學習,也歡迎各位老鐵給個 star
- 後面我還會對
Android
的各種知識點、Framework
層原始碼,三方庫等進行解析,歡迎大家關注 _yuanhao 部落格園 及時接收更多優質博文!
相關推薦
「2020 新手必備 」極速入門 Retrofit + OkHttp 網路框架到實戰,這一篇就夠了!
老生常談 什麼是 Retrofit ? Retrofit 早已不是什麼新技術了,想必看到這篇部落格的大家都早已熟知,這裡就不囉嗦了,簡單介紹下: Retrofit 是一個針對 Java 和 Android 的設計的 REST 客戶機。它通過基於 REST 的 web 服務檢索和上傳 JSON (或其他結
張小龍 4 小時演講沒時間看?看這一篇就夠了!「附贈張小龍歷年演講實錄 PDF」
本文是首次微信 8 年完整發展史的闡述精選和深入分析。2019 年 01 月 09 日晚 19 點 30 分,微信本年度最重要的演講開始了。現場正式演講前,播放的是 In My Secret Life 這首歌。這首歌就是微信 7.0 版本首次啟動的那首歌,據說也是張小龍最喜歡的一首歌。開場前一直在迴圈播放,隨
Elasticsearch入門,這一篇就夠了
search 語義 瀏覽器 三種 http請求 機制 說明 pro .net 實時搜索引擎Elasticsearch Elasticsearch(簡稱ES)是一個基於Apache Lucene(TM)的開源搜索引擎,無論在開源還是專有領域,Lucene可以
JVM和垃圾回收面試入門,這一篇就夠了
前些天在 google 上搜索了一些JVM的參考資料,偶然發現了一篇文章,如獲至寶,簡單易懂而且相對全面的JVM和垃圾回收介紹寫得非常的棒,因此一直儲存著,今天有時間特意翻譯了一下。本人水平有限,但是遇到好文章希望可以與更多的人分享,特此釋出此文。 英文OK的話
Mybatis使用入門,這一篇就夠了
mybatis中,封裝了一個sqlsession 物件(裡面封裝有connection物件),由此物件來對資料庫進行CRUD操作。 執行流程 mybatis有一個配置的xml,用於配置資料來源、對映Mapping,xml的檔名可以任取,為了方便,我們還是起mybatis-config.xml 我們讀取此配置的
高效解決「SQLite」資料庫併發訪問安全問題,只這一篇就夠了
Concurrent database access 本文譯自:https://dmytrodanylyk.com/articles/concurrent-database/ 對於 Android Dev 而言,有關 SQLite 的操作再經常不過了,相比你一定經歷過控制檯一片爆紅的情況,這不禁讓我們疑
JSON入門看這一篇就夠了
jsb cart 開發包 fonts 數據 長度 gmv lock 在哪裏 什麽是JSON JSON:JavaScript Object Notation 【JavaScript 對象表示法】 JSON 是存儲和交換文本信息的語法。類似 XML。 JSON采用完全獨立於任何
Struts2入門這一篇就夠了
and win ioe 了解 指正 屬性 內容 servlet 優雅 前言 這是Strtus的開山篇,主要是引入struts框架...為什麽要引入struts,引入struts的好處是什麽,以及對Struts2一個簡單的入門.... 為什麽要引入struts? 既然Serv
易學筆記--Servlet和JSP--入門就看這一篇就夠了
第4章:作為Servlet:請求和響應/4.1 Servlet載入過程 第4章:作為Servlet:請求和響應/4.2 請求 第4章:作為Servlet:請求和響應/4.3 響應 第4章:作為Servlet:請求和響應/4.4 資源下載例項 第4章:作為Servlet:
Maven教程--入門就看這一篇就夠了
第1章:Maven概述/1.1 Maven的概念 第1章:Maven概述/1.2 Maven的功能 第1章:Maven概述/1.3 與其它構建相比/1.3.1 Make 第1章:Maven概述/1.3 與其它構建相比/1.3.2 Ant 第2章:Maven的安裝/2.1
C語言從入門到精通,看這一篇就夠了
影響 內容 當前 位置 replace 雙精度 下標 寄存器變量 一個 No.1 計算機與程序設計語言的關系 計算機系統由硬件系統和軟件系統構成,硬件相當於人類的肉體,而軟件相當於人類的靈魂,如果脫離了靈魂,人類就是一具行屍走肉 No.2 C語言的特點 代碼簡潔,靈活性高
【看這一篇就夠了】kubernetes入門命令列操作(例項演示)
寫在前面:網上找了好久終於找到了期盼已久的、一個一眼就能理解的kubernetes“整體全過程”文章。 建議看這篇文章可以結合kubernetes官網(www.kubernetes.io)的Tutorial進行演練,效果很好。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GC學習入門 看這一篇就夠了(基於Oracle JDK 8)
目錄 垃圾收集 (Garbage Collection) 機制是 Java 的一大優勢特性, 為充分榨取 JVM 效能, 避免系統因垃圾收集不及時導致的 OOM (OutOfMemory, 記憶體溢位)問題, 或記憶體飽和出現無法響應使用者請求的情況, 就需要根據伺服器配置及應用複雜度對 GC 策略進行優化
易學筆記--python教程--入門就看這一篇就夠了
易學筆記 十年IT經驗個人學習筆記分享: 開發語言:C/C++/JAVA/PYTHON/GO/JSP WEB架構:Servlets/springMVC/springBoot/springClound 容器架構:Docker容器/Docker叢集/Docker與微服務整合/
Spring入門看這一篇就夠了
前言 前面已經學習了Struts2和Hibernate框架了。接下來學習的是Spring框架…本博文主要是引入Spring框架… Spring介紹 Spring誕生: 建立Spring的目的就是用來替代更加重量級的的企業級Java技術 簡化Java
關於Kaggle入門,看這一篇就夠了
這次醞釀了很久想給大家講一些關於Kaggle那點兒事,幫助對資料科學(Data Science)有興趣的同學們更好的瞭解這個專案,最好能親身參與進來,體會一下學校所學的東西和想要解決一個實際的問題所需要的能力的差距。雖然不是Data Science出身,但本著嚴謹的科研態
看這一篇就夠啦!微信小程式入門與實戰,橫掃常用元件API開發技巧(完整版包含全部原始碼)
第1章:什麼是微信小程式? 1 開篇及課程特色介紹 2 直觀感受一下微信小程式 3 小程式適合做什麼樣的應用 4 對開發者的影響 5 學習基礎 6 小作業 第2章:小程式環境大件與開發工具介紹 1 開篇介紹及下載工具 2 小程式目前情況及限制 3 小程式開發
maven 入門 看這一篇就夠了
地址 span con sys 圖片 program 自動 tor ngs 一、maven是什麽 推薦一篇博客寫的非常不錯! 二、maven安裝與配置步驟: 1.下載maven 2.將maven解壓到你想安裝到的文件夾目錄下,這裏示例解壓到 D:\s
Tomcat入門這一篇就夠了
Tomcat,從這裡開始 如何將我們的 Java 程式碼,執行在網路上,初學時,首先接觸到的一般都是Servlet以及Jsp(或
MongoDB 上手開發實踐(入門上手開發這一篇就夠了)
前言 MongoDB是一個介於 關係資料庫 和非關係資料庫之間的產品,是非關係資料庫當中功能最豐富,最像關係資料庫的。它支援的資料結構非常鬆散,是類似 json 的 bson 格式,因此可以儲存比較複雜的資料型別。Mongo最大的特點是它支援的查詢語言非常強大,其語法有點類似於面向物件的查詢語言,幾乎可以