2019年6月13日 星期四

Google App Engine(四)

延續上一章節:



步驟1:新增
先在資料表中 新增一個資料,書名=android,作者=andy,價格=99999
再到GAE資料庫中查詢資料是否新增,查看網頁中Json的格式。

步驟2:修改資料
書名=android→IOS,作者=andy,價格=99999→88888888
再到GAE資料庫中查詢資料是否修改,查看網頁中Json的資料是否新增 。

步驟3:刪除資料表中的資料
再到GAE資料庫中查詢資料是否刪除,查看網頁中的資料是否刪除

本章運用到了:
MVC設計模式
Adapter接配線模式
BaseAdapter
ListView的 ViewHolider概念

本章目的:

1.與App進行互動
2.上一章節說道『查詢』、本章完成『新增』、『變更』、『刪除』功能

APP(前端)

簡述:因為程式碼太過於攏長,所以我們用片段的方法來介紹,
位置:mainActivity

Add_data_Thread 方法

簡述:用來增加資料的執行緒
//Add_data_Thread
   public class Add_data_Thread extends Thread {
       String add_url;
       private String title;
       private String author;
       private String price;

       //建構子,當被使用時 馬上導入這3個參數
       public Add_data_Thread(String title, String author, String price) {
           this.title = title;
           this.author = author;
           this.price = price;
       } 
 // step1.這段程式碼由OKhttp所提供
 // 分析 http 資料結構標準語法
 // Url是再把網址放入 這時候會發送 request方法給伺服器
 // 伺服器根據你要資料把資料用 response 回傳給你

       OkHttpClient client = new OkHttpClient();

       String run(String url) throws IOException {
           Request request = new Request.Builder()
                   .url(url)
                   .build();

           Response response = client.newCall(request).execute();
           return response.body().string();
       }
       Runnable r = new Runnable() {
           @Override
           public void run() {
               Log.d("tag", "add successful");
           }
       };
       @Override
       public void run() {
           try {

               Log.d("tag", "http://pure-meridian-135923.appspot.com/add");

// 寫死的 先註解掉
//  add_url = run("http://pure-meridian-135923.appspot.com/add");

String ur1 =
String.format("http://pure-meridian-135923.appspot.com/add?mtitle=%s&mauthor=%s&mprice=%s", title, author, price);

               add_url = run(ur1);
               runOnUiThread(r);
           } catch (Exception e) {
           }
       }
   }

Updata_data_Thread 方法

簡述:用來變更資料的執行緒
//Updata_data_Thread
public class Updata_data_Thread extends Thread {

   private String add_url;
   private String key;
   private String title;
   private String author;
   private String price;

   // 建構子,因為後端要使用『key』指定改變資料,所以因曾一個參數
   public Updata_data_Thread(String key, String title, String author, String price) {
       this.key = key;
       this.title = title;
       this.author = author;
       this.price = price;
   }

 //OkHttp 
 // step1.這段程式碼由OKhttp所提供
 // 分析 http 資料結構標準語法
 // Url是再把網址放入 這時候會發送 request方法給伺服器
 // 伺服器根據你要資料把資料用 response 回傳給你


   OkHttpClient client = new OkHttpClient();

   String run(String url) throws IOException {
       Request request = new Request.Builder()
               .url(url)
               .build();

       Response response = client.newCall(request).execute();
       return response.body().string();
   }
   Runnable r = new Runnable() {
       @Override
       public void run() {
           Log.d("tag", "updata successful");
           Toast.makeText(context, "updata successful", Toast.LENGTH_SHORT).show();
       }
   };
   @Override
   public void run() {
       try {

           Log.d("tag", "updata_run");

           //這邊比較複雜需要注意一下
           //網址中的 mkey、mtitle、mauthor、mprice 這參數 會對應到 App_cloud_backend
           String url =
                   String.format("http://pure-meridian-135923.appspot.com/updata?
mkey=%s&mtitle=%s&mauthor=%s&mprice=%s", key, title, author, price);

           add_url = run(url);
           runOnUiThread(r);
       } catch (Exception e) {
       }
   }
}


Delete_data_Thread 方法
簡述:用來刪除資料的執行緒
//Delete_data_Thread
public class Delete_data_Thread extends Thread {
   String url_Delete;
   String key;

   public Delete_data_Thread(String key)
   {
       this.key=key;
   } 

 //OkHttp 
 // step1.這段程式碼由OKhttp所提供
 // 分析 http 資料結構標準語法
 // Url是再把網址放入 這時候會發送 request方法給伺服器
 // 伺服器根據你要資料把資料用 response 回傳給你


  OkHttpClient client = new OkHttpClient();

   String run(String url) throws IOException {
       Request request = new Request.Builder()
               .url(url)
               .build();

       Response response = client.newCall(request).execute();
       return response.body().string();
   }
   Runnable r = new Runnable() {
       @Override
       public void run() {
           Log.d("tag", "Delete_data_Thread scuccessful");
            }
   };
   @Override
   public void run() {

       Log.d("tag", "Delete_data_Thread run");

       url_Delete = String.format
       ("http://pure-meridian-135923.appspot.com/delete?mkey=%s", key);

       try {
           url_Delete = run(url_Delete);
           runOnUiThread(r);
       } catch (Exception e) {
       }
   }
}


Layout  item.xml 為baseadapter所用 上一章已介紹

簡述:當我按下 "CLICK"的時候 我會跳出
add_form』這一個Layout 來新增資料。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">


  <EditText
      android:text=""
      android:hint="請輸入書名"
      android:layout_margin="5dp"
      android:id="@+id/ed_title"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content" />


  <EditText
      android:text=""
      android:hint="請輸入作者"
      android:layout_margin="5dp"
      android:id="@+id/ed_author"
      android:layout_width="match_parent"
      android:layout_height="wrap_content" />


  <EditText
      android:text=""
      android:hint="請輸入價格"
      android:id="@+id/ed_price"
      android:layout_margin="5dp"
      android:layout_width="match_parent"
      android:layout_height="wrap_content" />
</LinearLayout>




當我按下主畫面每一個item的時候就會跳出
updata_from』這一個Layout 來改變資料

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">


  <EditText
      android:enabled="false"
      android:text=""
      android:hint="KEY"
      android:layout_margin="5dp"
      android:id="@+id/ed_key"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content" />
  <EditText
      android:text=""
      android:hint="請輸入書名"
      android:layout_margin="5dp"
      android:id="@+id/ed_title"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content" />


  <EditText
      android:text=""
      android:hint="請輸入作者"
      android:layout_margin="5dp"
      android:id="@+id/ed_author"
      android:layout_width="match_parent"
      android:layout_height="wrap_content" />


  <EditText
      android:text=""
      android:hint="請輸入價格"
      android:id="@+id/ed_price"
      android:layout_margin="5dp"
      android:layout_width="match_parent"
      android:layout_height="wrap_content" />


</LinearLayout>





activity_Main

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:background="@android:color/holo_green_light"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingBottom="5dp"
  android:orientation="vertical"
  android:paddingLeft="5dp"
  android:paddingRight="5dp"
  android:paddingTop="5dp"
  tools:context="com.example.app_cloud.MainActivity">


  <Button
      android:onClick="onclick"
      android:layout_width="wrap_content"
      android:layout_height="match_parent"
      android:text="Click"
      android:id="@+id/button"
      android:layout_weight="9" />


  <ListView
      android:layout_marginTop="20dp"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:layout_weight="2"
      android:id="@+id/listView"
      android:layout_alignBottom="@+id/webView"
      android:layout_alignParentLeft="true"
      android:layout_alignParentStart="true" />


</LinearLayout>

將上述的方法 放入MainActivity 中

      1. 先取得點擊目標的Mybook物件(已經有值)
     再把Mybook的值 設定在Edtext中,之後再做修改
      2. updata的基本概念(參數 要多一個key,後端才能指定修改)
package com.example.app_cloud;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import com.example.app_cloud.po.MyBook;
import com.google.gson.Gson;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import java.io.IOException;

public class MainActivity extends AppCompatActivity {
   //Context
   private Context context;

   //collection
   private MyBook[] collection_mybook;

   //View
   private ListView listView;
   private View add_view, updata_view;

   //adapter
   private ArrayAdapter arrayadapter;
   private BaseAdapter baseAdapter;

//Edittext
private EditText m_updata_ed_key;
private EditText m_ed_title, m_updata_ed_title;
private EditText m_ed_author, m_updata_ed_author;
private EditText m_ed_price, m_updata_ed_price;

   private Handler handler = new Handler();

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

       //findViewID
       finId();

       //3second run→ Show_data_Thread
       Runnable r = new Runnable() {
           @Override
           public void run() {

               //  執行查詢
               new Show_data_Thread().start();

               // 3秒鐘執行一次
               handler.postDelayed(this, 3000);
           }
       };

       handler = new Handler();
       handler.post(r);

       //避免程式碼過於肥大,我們將點擊item寫在這一個方法中
       onclick_itwm_view();
   }
   public void finId() {
       context = this;
       listView = (ListView) findViewById(R.id.listView);
   }
   public void add_view_finId() {

       add_view = View.inflate(context, R.layout.add_form, null);
       m_ed_title = (EditText) add_view.findViewById(R.id.ed_title);
       m_ed_author = (EditText) add_view.findViewById(R.id.ed_author);
       m_ed_price = (EditText) add_view.findViewById(R.id.ed_price);
   }
public void updata_view_findId() {

   updata_view = View.inflate(context, R.layout.updata_form, null);
   m_updata_ed_key = (EditText) updata_view.findViewById(R.id.ed_updata_key);
   m_updata_ed_title = (EditText) updata_view.findViewById(R.id.ed_updata_title);
   m_updata_ed_author = (EditText) updata_view.findViewById(R.id.ed_updata_author);
   m_updata_ed_price = (EditText) updata_view.findViewById(R.id.ed_updata_price);
}

  //onclick →Add_Mybook_Data (當我按下按鈕的時候 我就執行新增資料)
   public void onclick(View view) {

   add_view_finID();

       AlertDialog.Builder dialog = new AlertDialog.Builder(context);

       dialog.setTitle("新增 Book")
               .setView(add_view)
               .setNegativeButton("取消", null)
               .setPositiveButton("新增", new DialogInterface.OnClickListener() {
                   @Override
                   public void onClick(DialogInterface dialogInterface, int i) {

                       //用Log檢查一下打印出來的數據
                       Log.d("tag", "m_ed_title= " + m_ed_title.getText().toString());
                       Log.d("tag", "m_ed_author= " + m_ed_author.getText().toString());
                       Log.d("tag", "m_ed_price= " + m_ed_price.getText().toString());

                       //設定要帶入的參數,(從Edtext中取得)
                       new Add_data_Thread(
                               m_ed_title.getText().toString(),
                               m_ed_author.getText().toString(),
                               m_ed_price.getText().toString()
                       ).start();

                       // 寫死的RunAddWork() 先註解掉
                       // new Add_data_Thread().start();
                   }
               }).show();
   }
   public void onclick_itwm_view() {

       //點擊每一個item中會發師的事情 setOnItemClickListener
       listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
           @Override
           public void onItemClick(AdapterView adapterView, View view, int postion, long long) {

               //我們製作的Adapter的型別是 ,所以我們可利用型別去對應
               //再利用.getItemAtPosition(i) 去找到相對應的位置
               MyBook myBook = (MyBook) adapterView.getItemAtPosition(i);

               //Toast確認該筆的資料
               Toast.makeText(context, "" + myBook, Toast.LENGTH_SHORT).show();

               //findViewById
               View updata_view = View.inflate(context, R.layout.updata_form, null);
               updata_view_findId();

               //step1,取得原有資料,在Dialog對話框 開啟前並設定到Dialog Edtext中
               m_updata_ed_key.setText(myBook.getKey() + "");
               m_updata_ed_title.setText(myBook.getTitle());
               m_updata_ed_author.setText(myBook.getAuthor());
               m_updata_ed_price.setText(myBook.getPrice() + "");

               //顯示 Dialog 對話框
               AlertDialog alert = new AlertDialog.Builder(context)
                       .setTitle("修改標題")
                       .setView(updata_view)

                       //修改的選項(Positive)
                       .setPositiveButton("修改", new DialogInterface.OnClickListener() {
                           @Override
                           public void onClick(DialogInterface dialogInterface, int i) {

                               //使用者輸入資料後,再取得資料 並送出→ Updata_data_Thread
                               new Updata_data_Thread(
                                       m_updata_ed_key.getText().toString(),
                                       m_updata_ed_title.getText().toString(),
                                       m_updata_ed_author.getText().toString(),
                                       m_updata_ed_price.getText().toString()

                               ).start();
                           }
                       })

                       //取消的選項(Negative)
                       .setNegativeButton("取消", null)

                       //刪除的選項(Neutral)
                       .setNeutralButton("刪除", new DialogInterface.OnClickListener() {
                           @Override
                           public void onClick(DialogInterface dialogInterface, int i) {
                               new Delete_data_Thread( m_updata_ed_key.getText().toString()).start();
                           }
                       }).show();
           }
       });
   }
   //Show_data_Thread
   public class Show_data_Thread extends Thread { }
   //Add_data_Thread
   public class Add_data_Thread extends Thread { }
   //Updata_data_Thread
   public class Updata_data_Thread extends Thread { }
   //Delete_data_Thread
   public class Delete_data_Thread extends Thread { }
   }
}

App_Cloud_backend(後端)

簡述:前端的基本設定已完成,後端的設定開始
新增 關鍵程式碼:
工廠取得:   DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
建立資料表: Entity book = new Entity("資料表名稱");
放入資料:    book.setProperty( "輸入標題","輸入內容")
指定app端輸入的內容:req.getParameter(APP前端的指定參數 )........

AddServlet
package com.example.myapplication.backend;


import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import java.io.IOException;
import java.util.Date;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class AddServlet extends HttpServlet {
  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp)
          throws IOException {


      resp.setContentType("text/plain");


      //使用工廠獲取 DatastoreService
      DatastoreService ds = DatastoreServiceFactory.getDatastoreService();


      //創建一個資料表 name= book
      Entity book = new Entity("Book");


      //資料表 放入資料
      book.setProperty("title", req.getParameter("mtitle"));
      book.setProperty("author", req.getParameter("mauthor"));
      book.setProperty("price", Integer.parseInt(req.getParameter("mprice")));
      book.setProperty("time", new Date().getDate());


      //寫死的資料我們就可以先註解掉
//        book.setProperty("title","android");
//        book.setProperty("author","Vincent");
//        book.setProperty("price", new Random().nextInt(500) + 500);
//        book.setProperty("time",new Date().getDate() );


      //放入資料表
      ds.put(book);


      //DatastoreService對象並調用put方法寫入數據
      resp.getWriter().println("add ok");
  }
}


簡述:
工廠取得:   DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
Key取得指定位置:Key key = KeyFactory.createKey("資料表的名稱",APP前端的指定參數mkey )
記得型別是Long 記得轉型。

UpdataServlet
package com.example.myapplication.backend;


import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import java.io.IOException;
import java.util.Date;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class UpdataServlet extends HttpServlet {
  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp)
          throws IOException {


      resp.setContentType("text/plain");


      ////使用工廠獲取 DatastoreService
      DatastoreService ds = DatastoreServiceFactory.getDatastoreService();


      //取得一個KEY工廠
      Key key = KeyFactory.createKey("Book", Long.parseLong(req.getParameter("mkey")));


      //創建一個資料表才要Entity ,更新資料不用歐
      // Entity book = new Entity("Book");


      try {
          //使用 ds.get(key) 先取得指定資料,再用req.getParameter取得數值
          Entity  book = ds.get(key);
          book.setProperty("title", req.getParameter("mtitle"));
          book.setProperty("author", req.getParameter("mauthor"));
          book.setProperty("price", Integer.parseInt(req.getParameter("mprice")));
          book.setProperty("time", new Date().getTime());


          //放入資料表
          ds.put(book);


      } catch (Exception e) {
      }


      //DatastoreService對象並調用put方法寫入數據,
      resp.getWriter().println("update ok");
  }
}


DeleteServlet
package com.example.myapplication.backend;


import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import java.io.IOException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class DeleteServlet extends HttpServlet {
  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp)
          throws IOException {


      resp.setContentType("text/plain");


      //使用工廠獲取 DatastoreService
      DatastoreService ds = DatastoreServiceFactory.getDatastoreService();


      //取得一個KEY工廠 ,後面參數的型別為lONG 記得轉型!
      Key key = KeyFactory.createKey("Book", Long.parseLong(req.getParameter("mkey")));


      try {
          // 使用ds.delete(Key key),刪除指定資料
          ds.delete(key);
          resp.getWriter().println("delete ok");


      } catch (Exception e) {


      }
  }
}
































沒有留言:

張貼留言