簽到APP:android入門級小項目,Node.js 提供服務端接口。

###1、項目描述
  實驗室小夥伴們經過APP鏈接實驗室路由器,比對路由器Mac地址進行簽到。此外小夥伴們還可經過APP進行請假,上傳請假理由、日期等信息,便於實驗室平常管理。html

###2、APP截圖 用戶登陸 輸入圖片說明 輸入圖片說明 輸入圖片說明 輸入圖片說明 輸入圖片說明node

###3、相關github開源項目 感謝開源:android

/*卡片佈局*/
compile 'com.android.support:cardview-v7:+'
/*meterial風格對話框*/
compile 'com.afollestad.material-dialogs:core:0.9.1.0'
/*Meterial UI控件*/
compile 'com.github.navasmdc:MaterialDesign:1.5[@aar](https://my.oschina.net/AAR)'
compile 'com.wdullaer:materialdatetimepicker:2.5.0'
/*懸浮按鈕*/
compile 'com.getbase:floatingactionbutton:1.10.1'
/*輸入框*/
compile 'com.rengwuxian.materialedittext:library:2.1.4'
/*訪問網絡工具類*/
compile 'com.lzy.net:okgo:2.0.0'
/*Gson Json轉化成bean工具類*/
compile 'com.google.code.gson:gson:2.3.1'
/*andrroid工具包*/
compile 'com.blankj:utilcode:1.3.3'

###4、數據庫設計   主要設計三個對象:用戶、請假記錄、簽到記錄
  **約束:**一個用戶天天只能有一條簽到記錄,同時用戶簽到過允許再次簽到。
  **解決方法:**給每條簽到記錄經過用戶名加日期生成一個unique_id可預見字段,用戶簽到時查詢數據庫是否存在存在此字段的記錄。
輸入圖片說明
其中版本更新代碼目前並無實現。git

###5、關鍵代碼 5.一、比對路由器Mac地址:github

/*比對路由器的MAC地址*/
    public boolean checkLabMac(){
        //獲取WiFIMac地址
        if(NetworkUtils.isWifiConnected(MainActivity.this)){
            WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
            WifiInfo info = wifi.getConnectionInfo();
            str_mac=info.getBSSID();
            if(!str_mac.equals(Constant.E412_MAC)){
                signSuccess("非實驗室WIFI,沒法簽到!");
                return false;
            }else {
                return true;
            }
        }else{
            signSuccess("WIFI未鏈接,請先鏈接實驗室WIFI!");
            return false;
        }
    }

5.二、訪問網絡與Gson解析數據:
   訪問網絡工具類:compile 'com.lzy.net:okgo:2.0.0'Gson Json, 地址:https://github.com/jeasonlzy/okhttp-OkGo
轉化成bean工具類:compile 'com.google.code.gson:gson:2.3.1' Gson轉換Json到Bean須要創建相應的Bean與Json字段一一對應,否則會出錯。
若是Json和Bean字段對應不上,或者服務端傳過來的字段命名不規範,加一個 @SerializedName,解決方案:http://blog.csdn.net/bzy601638015/article/details/32916281 輸入圖片說明web

經過谷歌瀏覽器插件PostMan模擬登陸 輸入圖片說明chrome

這裏以用戶登陸訪問網絡爲例:
 /*用戶名密碼校驗*/
    public void checkUser(){
        /*構造請求體*/
        HashMap<String, String> params = new HashMap<>();
        params.put("username", str_username);
        params.put("password", str_password);
        JSONObject jsonObject = new JSONObject(params);
        /*發送登陸請求*/
        OkGo.post(Api.LOGIN)//
                .tag(this)//
                .upJson(jsonObject.toString())//
                .execute(new StringCallback() {
                    @Override
                    public void onSuccess(String s, Call call, Response response) {
                        /*關閉提示框*/
                        /* int code = conn.getResponseCode();//返回碼200請求成功,若是請求碼不是200,則提示服務器出錯*/
                        login=new ResponseLogin();
                        login= JsonUtils.fromJson(s,ResponseLogin.class);
                        md.dismiss();
                        if(login.getStatus().equals(Constant.SUCCESS)){
                            /*若是勾選了記住密碼,且登陸成功,就保存用戶名密碼*/
                            if(checkBox.isCheck()){
                              /*記住用戶名密碼*/
                                PreferencesUtils.putString(LoginActivity.this,"username",str_username);
                                PreferencesUtils.putString(LoginActivity.this,"password",str_password);
                            }
                            toActivity(MainActivity.class);
                            Toast.makeText(LoginActivity.this,"登錄成功",Toast.LENGTH_SHORT).show();
                            LoginActivity.this.finish();
                        }else{
                            if(login.getMsg().equals(Constant.ERROR_SYSTEM)){
                                Toast.makeText(LoginActivity.this,"系統錯誤",Toast.LENGTH_SHORT).show();
                                return;
                            }if(login.getMsg().equals(Constant.ERROR_USERNAME)){
                                Toast.makeText(LoginActivity.this,"用戶不存在",Toast.LENGTH_SHORT).show();
                                return;
                            }if(login.getMsg().equals(Constant.ERROR_PASSWORD)){
                                Toast.makeText(LoginActivity.this,"密碼錯誤",Toast.LENGTH_SHORT).show();
                                return;
                            }
                        }
                    }
                });
    }

JSON對應Bean,服務端值放回成功或者失敗信息,只有兩個字段。

public class ResponseLogin implements Serializable {
    private String status;
    private String msg;
    public void setStatus(String status) {
        this.status = status;
    }
    public String getStatus() {
        return status;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
    public String getMsg() {
        return msg;
    }
}

5.三、使用時間選擇器問題:
  使用時間選擇器是,樣例代碼是之間經過Activity實現結構,而後重寫方法,若是用這種方式一個Activity中貌似只能用一個Dialog選擇時間(不知道本身理解是否是對的,歡迎指正),而這裏有兩個位置須要選擇時間。因此選擇匿名內部類的方式實現選擇時間功能。數據庫

btn_startTime.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //彈出日期選擇對話框
                Calendar now = Calendar.getInstance();
                DatePickerDialog dialog= DatePickerDialog.newInstance(new DatePickerDialog.OnDateSetListener(){
                  @Override
                  public void onDateSet(DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) {
                      String date =year+"-"+(monthOfYear+1)+"-"+dayOfMonth;
                      startTime.setText(date);
                      }},now.get(Calendar.YEAR),
                        now.get(Calendar.MONTH),
                        now.get(Calendar.DAY_OF_MONTH));
                dialog.show(getFragmentManager(), "Datepickerdialog");
            }
        });
        btn_endTime.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //彈出日期選擇對話框
                Calendar now = Calendar.getInstance();
                DatePickerDialog dialog= DatePickerDialog.newInstance(new DatePickerDialog.OnDateSetListener(){
                      @Override
                      public void onDateSet(DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) {
                      String date =year+"-"+(monthOfYear+1)+"-"+dayOfMonth;
                      endTime.setText(date);
                      }},now.get(Calendar.YEAR),
                        now.get(Calendar.MONTH),
                        now.get(Calendar.DAY_OF_MONTH));
                dialog.show(getFragmentManager(), "Datepickerdialog");
            }
        });

5.四、關於Toolbar菜單字體顏色背景顏色問題:
  使用Toorbar的時候,它的菜單字體爲白色,菜單背景爲灰白色,蠻難看。
  解決方案:http://www.cnblogs.com/oyjt/p/4762640.htmljson

5.五、關於仿知乎懸浮按鈕問題:
  主頁上仿知乎懸浮按鈕,github上例子的佈局是相對佈局,可是本身經常使用的是線性佈局,想着把它用在線性佈局中,給它調位置一直沒成功,只能將就的把主頁改爲相對佈局吧,效果也還不錯。
可給按鈕添加圖標以及顏色:瀏覽器

<com.getbase.floatingactionbutton.FloatingActionButton
            android:id="@+id/action_a"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            fab:fab_colorNormal="@color/blue"
            fab:fab_title="我要請假"
            fab:fab_icon="@drawable/holiday"
            fab:fab_colorPressed="@color/white_pressed"/>

地址:https://github.com/futuresimple/android-floating-action-button

5.六、下拉刷新上拉加載更多:
  下拉刷新再本項目中貌似並無多大意義,由於用戶每次查看本身的記錄的時候,只弄了個上拉分頁加載更多。注意傳入當前頁數出現的問題。 上拉加載更多參考代碼:https://github.com/wangnaiwen/RecyclerViewRefresh

5.七、引入CheckBox時,默認選中不起做用:
  發現materialdesign是代碼提示自動引入的,
輸入圖片說明
須要將其修改成:修改成 xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:materialdesign="http://schemas.android.com/apk/res-auto" 這是自定義屬性引入有問題形成的。
參考個人另外一個小結:http://www.javashuo.com/article/p-hcgxabto-z.html

5.八、本地測試時,Natapp內外網映射工具:
  開機重啓後natapp映射的本地路徑就變了,天天都得修改,若是你沒有關機習慣倒也無所謂。注意用node.js作服務端時須要在www文件中將默認的3000端口改爲80端口。 輸入圖片說明

###6、最後相關網址分享: 阿里狂拽酷炫的圖標庫:地址:http://www.iconfont.cn/plus
**API測試工具PostMan:**下載地址: http://chromecj.com/web-development/2014-09/60/download.html
**內外網映射工具:**作服務端開發時APP需訪問我本地電腦,這是能夠經過免費的內外網映射,不須要經過阿里雲測試(微信公衆號開發也能夠經過此服務 )。 地址:https://natapp.cn/
項目源碼: https://github.com/dpc761218914/SignIn
Node.js服務端源碼: https://github.com/dpc761218914/SignIn_Server

相關文章
相關標籤/搜索