欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android入門之使用SQLite內(nèi)嵌式數(shù)據(jù)庫(kù)詳解

 更新時(shí)間:2022年12月22日 08:38:56   作者:TGITCIC  
Android內(nèi)帶SQLite內(nèi)嵌式數(shù)據(jù)庫(kù)了。這對(duì)于我們存儲(chǔ)一些更復(fù)雜的結(jié)構(gòu)化數(shù)據(jù)帶來了極大的便利。本文就來和大家聊聊具體的使用方法,希望對(duì)大家有所幫助

介紹

Android內(nèi)帶SQLite內(nèi)嵌式數(shù)據(jù)庫(kù)了。這對(duì)于我們存儲(chǔ)一些更復(fù)雜的結(jié)構(gòu)化數(shù)據(jù)帶來了極大的便利。比如說我們要存儲(chǔ)應(yīng)用內(nèi)的常用聯(lián)系人,購(gòu)物車暫存信息,常量。必竟從xml或者是json里取數(shù)據(jù)都沒有一條Select語句來得簡(jiǎn)單。

SQLite常用有五種數(shù)據(jù)類型:

  • NULL
  • INTEGER
  • REAL(浮點(diǎn)數(shù))
  • TEXT(字符串文本)
  • BLOB(二進(jìn)制對(duì)象)

雖然只有五種,但是對(duì)于varchar,char等其他數(shù)據(jù)類型都是可以保存的,如下create table語句依然是可以生效的:

create table user(name varchar(20))

SQLite常用的三個(gè)類介紹

  • SQLiteOpenHelper:抽象類,我們通過繼承該類,然后重寫數(shù)據(jù)庫(kù)創(chuàng)建以及更新的方法, 我們還可以通過該類的對(duì)象獲得數(shù)據(jù)庫(kù)實(shí)例,或者關(guān)閉數(shù)據(jù)庫(kù);
  • SQLiteDatabase:數(shù)據(jù)庫(kù)訪問類:我們可以通過該類的對(duì)象來對(duì)數(shù)據(jù)庫(kù)做一些增刪改查的操作;
  • Cursor:游標(biāo),有點(diǎn)類似于JDBC里的resultset,結(jié)果集!可以簡(jiǎn)單理解為指向數(shù)據(jù)庫(kù)中某 一個(gè)記錄的指針;

這三個(gè)類我們直接來看下面的Sample代碼各位就知道是什么樣的組合應(yīng)用了。

private SQLiteDatabase db;
private Context context = null;
private DBOpenHelper dbOpenHelper;
private String DB_NAME="user.db";
private static final String DB_TABLE = "t_user_login";
 
dbOpenHelper = new DBOpenHelper(context, DB_NAME, null, DB_VERSION);
try {
     db = dbOpenHelper.getWritableDatabase();
     db.open();
     StringBuilder sqlStr = new StringBuilder();
     sqlStr.append("select loginId,password,user_name from ").append(DB_TABLE);
     Cursor cur = db.rawQuery(sqlStr.toString(), null);
     while (cur.moveToNext()) {
            String loginId = cur.getString(cur.getColumnIndexOrThrow("loginId"));
            String password = cur.getString(cur.getColumnIndexOrThrow("password"));
            String userName = cur.getString(cur.getColumnIndexOrThrow("user_name"));
            UserBean user = new UserBean();
            user.setLoginId(loginId);
            user.setPassword(password);
            user.setUserName(userName);
            userList.add(user);
    }
} catch (SQLiteException ex) {
     Log.e(TAG, ">>>>>>open db error: " + ex.getMessage(), ex);
 
}finally {
         try{
           db.close();
         }catch(Exception e){}
}

使用上和JDBC幾乎一樣,此處的Cursor相當(dāng)于JDBC里的ResultSet。

敲黑板重要提醒-Android中如何正確使用db.open()/db.close()

在我們的例子里我們?cè)诿恳粋€(gè)業(yè)務(wù)方法操作都會(huì)使用db.open一下,在finally塊里db.close一下。

同時(shí)要在Activity的onStop方法中去dbclose()掉它。

記得,它就和水龍頭一樣,用完就要關(guān)。

SQLiteOpenHelper類的使用

這個(gè)類通常我們都要新建一個(gè)其它的類來extends這個(gè)類才能使用,主要的是這個(gè)類里有這么兩個(gè)方法是很有用的。

public void onCreate

方法全簽名:public void onCreate(SQLiteDatabase db)

這個(gè)類的作用就是當(dāng)SQLiteOpenHelper被實(shí)例化時(shí),第一次用來做“初始化數(shù)據(jù)庫(kù)”用的。比如說我們有一個(gè)類如下

private static class DBOpenHelper extends SQLiteOpenHelper {

然后當(dāng)你實(shí)例化這個(gè)類時(shí)

dbOpenHelper = new DBOpenHelper(context, DB_NAME, null, DB_VERSION);

它會(huì)自動(dòng)觸發(fā)這個(gè)onCreate方法,在onCreate方法中我們可以做表創(chuàng)建以及數(shù)據(jù)初始化操作如:

        private static final String DB_CREATE = "create table " +
                DB_TABLE + " (" + KEY_ID + " VARCHAR(20) primary key , " +
                KEY_PASSWORD + " text not null, " + KEY_NAME + " text not null);";
 
        @Override
        public void onCreate(SQLiteDatabase db) {
            Log.i(TAG, ">>>>>>execute create table->" + DB_CREATE);
            db.execSQL(DB_CREATE);
            StringBuilder initDataSql = new StringBuilder();
            initDataSql.append("INSERT INTO ").append(DB_TABLE).
                    append("(").append(KEY_ID).append(",").append(KEY_PASSWORD).
                    append(",").append(KEY_NAME).append(")").append("values(?,?,?)");
            Log.i(TAG, ">>>>>>execute initDataSql->" + initDataSql.toString());
            db.execSQL(initDataSql.toString(), new String[]{"root", "111111", "root"});
            Log.i(TAG, ">>>>>>db init successfully");
        }

public void onUpgrade

方法全簽名:public void onUpgrade(SQLiteDatabase db, int _oldVersion, int _newVersion)

它有一個(gè)_newVersion這么一個(gè)參數(shù),這個(gè)參數(shù)也很有意思。當(dāng)你在實(shí)例化SQLiteOpenHelper類傳入的DB_VERSION參數(shù)>就近一次實(shí)例化這個(gè)類傳入的DB_VERSION參數(shù)時(shí),它就會(huì)觸發(fā)這個(gè)onUpgrade()方法,在這個(gè)方法里我們一般是根據(jù)業(yè)務(wù)場(chǎng)景的需要,沒有一概而論該怎么辦,通用的做法有:

  • 重新執(zhí)行一遍onCreate();此時(shí)所有的數(shù)據(jù)會(huì)被清空并初始化;
  • 有些Android發(fā)版時(shí)不需要做全數(shù)據(jù)庫(kù)清除,往往太過危險(xiǎn),而是會(huì)執(zhí)行alter更改表結(jié)構(gòu)、新建表、新插入-insert一些數(shù)據(jù)或者是稍帶著update一些數(shù)據(jù);

因此我才說,不一概而論而是需要依賴于你的實(shí)際業(yè)務(wù)場(chǎng)景來做操作。在我們的例子里我們會(huì)在onUpgrade里再執(zhí)行一下onCreate()。

使用SQLite操作數(shù)據(jù)庫(kù)方法介紹

這一塊在使用上分兩塊。它類似Hibernate一樣,也有API和原生SQL之分。

API的使用

即不需要書寫SQL,如下樣例:

    public long addItem(UserBean user) throws Exception {
        try {
            ContentValues newValues = new ContentValues();
            newValues.put(KEY_ID, user.getLoginId());
            newValues.put(KEY_PASSWORD, user.getPassword());
            newValues.put(KEY_NAME, user.getUserName());
            Log.i(TAG, "addItem successfully with loginId->" + user.getLoginId() + " password->" + user.getPassword());
            return db.insert(DB_TABLE, null, newValues);
        } catch (Exception e) {
            Log.e(TAG, "addItem error: " + e.getMessage(), e);
            throw new Exception("addItem error: " + e.getMessage(), e);
        }
    }

我們可以看到全程沒有使用SQL。

原生SQL的使用

    public List<UserBean> queryAll() {
        List<UserBean> userList = new ArrayList<UserBean>();
        try {
            StringBuilder sqlStr = new StringBuilder();
            sqlStr.append("select loginId,password,user_name from ").append(DB_TABLE);
            Cursor cur = db.rawQuery(sqlStr.toString(), null);
            while (cur.moveToNext()) {
                String loginId = cur.getString(cur.getColumnIndexOrThrow("loginId"));
                String password = cur.getString(cur.getColumnIndexOrThrow("password"));
                String userName = cur.getString(cur.getColumnIndexOrThrow("user_name"));
                UserBean user = new UserBean();
                user.setLoginId(loginId);
                user.setPassword(password);
                user.setUserName(userName);
                userList.add(user);
            }
        } catch (Exception e) {
            Log.e(TAG, ">>>>>>queryAll error: " + e.getMessage(), e);
        }
        return userList;
    }

區(qū)分何時(shí)使用API何時(shí)使用原生SQL

如何區(qū)分呢?

答案很簡(jiǎn)單,以下是最佳實(shí)踐 :

  • 單表操作,就使用API好了;
  • 跨表(>1個(gè)表)的操作或者是較復(fù)雜的邏輯如果使用API會(huì)產(chǎn)生循環(huán)套來套去不如寫一條長(zhǎng)點(diǎn)的SQL那么請(qǐng)直接使用原生SQL;

在樣例前我們最后要了解一下,SQLite數(shù)據(jù)庫(kù)管理工具。

SQLite數(shù)據(jù)庫(kù)管理

Android里的SQLite一旦生成后它必須導(dǎo)出到AndroidStudio外部才能管理。按照如下步驟來導(dǎo)出SQLite數(shù)據(jù)庫(kù)

先使用Device File Explorer打開data->data->你的包全路徑下/databases,這里面有一個(gè).db文件就是SQLite數(shù)據(jù)庫(kù)文件。另一個(gè).db-journal是Transaction日志,我們后面講SQLite的Transaction時(shí)會(huì)講到。

選擇這個(gè)user.db右鍵選->save as,就可以導(dǎo)出到本地磁盤了。

然后你可以使用如下工具去管理SQLite數(shù)據(jù)庫(kù)文件。

Windows下的SQLite管理工具

請(qǐng)使用SQLite Expert Professional,我使用的是5.4.4。不過這個(gè)是收費(fèi)的,它長(zhǎng)這個(gè)樣但相當(dāng)專業(yè)(收費(fèi)的當(dāng)然專業(yè))。

MAC下的SQLite管理工具

請(qǐng)使用SQLiteManager,完全免費(fèi)并且和Windows的SQLite Expert Professional收費(fèi)的一樣功能全。為什么呢?難道因?yàn)镸AC貴。。。所以。。。有預(yù)收費(fèi)之說:)?

好了,原理介紹完畢,我們要進(jìn)入實(shí)踐課程了。

課程目標(biāo)

1.該APP啟動(dòng)會(huì)創(chuàng)建user.db數(shù)據(jù)庫(kù),新建一張t_user_login表并初始化一條root/111111數(shù)據(jù)進(jìn)入內(nèi)嵌SQLite數(shù)據(jù)庫(kù);

2.用戶名密碼輸入root/111111點(diǎn)【登錄】按鈕可以得到登錄成功,如果輸入其它的不存在的帳戶信息會(huì)以Toast顯示“登錄失敗請(qǐng)校驗(yàn)?zāi)愕挠脩裘兔艽a”;

3.用戶名密碼輸入任意值,點(diǎn)擊【增加一條記錄】按鈕,可以插入一條數(shù)據(jù)到內(nèi)嵌SQLite;

4.點(diǎn)擊【查詢所有記錄】會(huì)以Log和Toast顯示目前所有的相對(duì)應(yīng)的表內(nèi)的數(shù)據(jù)即:select *操作;

5.例子中對(duì)于單表的插入操作我們使用的是Android自帶的SQLiteOpenHelper的原生API;

6.校驗(yàn)登錄和查詢所有記錄我們用的是原生SQL+Cursor;

下面就進(jìn)入代碼部分吧。

前端代碼

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
 
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="用戶登陸" />
 
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="請(qǐng)輸入用戶名" />
 
        <EditText
            android:id="@+id/editLoginid"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="用戶名" />
 
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="請(qǐng)輸入密碼" />
 
        <EditText
            android:id="@+id/editPassword"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="密碼"
            android:inputType="textPassword" />
 
        <Button
            android:id="@+id/buttonLogin"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="登錄" />
 
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#dfdfdf" />
    </LinearLayout>
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <Button
            android:id="@+id/buttonAddItem"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="10dp"
            android:text="增加一條記錄"/>
        <Button
            android:id="@+id/buttonQueryAll"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="查詢所有記錄"/>
    </LinearLayout>
</LinearLayout>

后端代碼

UserBean.java

package org.mk.android.demo.demosimplesqlite;
 
import java.io.Serializable;
 
public class UserBean implements Serializable {
 
    public String getLoginId() {
        return loginId;
    }
 
    public void setLoginId(String loginId) {
        this.loginId = loginId;
    }
 
    private String loginId = "";
 
    public String getPassword() {
        return password;
    }
 
    public void setPassword(String password) {
        this.password = password;
    }
 
    public String getUserName() {
        return userName;
    }
 
    public void setUserName(String userName) {
        this.userName = userName;
    }
 
    private String password = "";
    private String userName = "";
}

SQLite的核心操作-DBAdapter.java

package org.mk.android.demo.demosimplesqlite;
 
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
 
import java.util.ArrayList;
import java.util.List;
 
public class DBAdapter {
    private static final String TAG = "DemoSQLite";
    private static final String DB_NAME = "user.db";
    private static final String DB_TABLE = "t_user_login";
    private static final int DB_VERSION = 2;
 
    public static final String KEY_ID = "loginId";
    public static final String KEY_PASSWORD = "password";
    public static final String KEY_NAME = "user_name";
    private SQLiteDatabase db;
    private Context context = null;
    private DBOpenHelper dbOpenHelper;
 
    public DBAdapter(Context ctx) {
        context = ctx;
    }
 
    public void close() {
        try {
            if (db != null) {
                db.close();
                db = null;
            }
        } catch (Exception e) {
        }
    }
 
    public void open()  {
        dbOpenHelper = new DBOpenHelper(context, DB_NAME, null, DB_VERSION);
        try {
            db = dbOpenHelper.getWritableDatabase();
        } catch (SQLiteException ex) {
            Log.e(TAG, ">>>>>>open db error: " + ex.getMessage(), ex);
 
        }
    }
 
    public long addItem(UserBean user) throws Exception {
        try {
            ContentValues newValues = new ContentValues();
            newValues.put(KEY_ID, user.getLoginId());
            newValues.put(KEY_PASSWORD, user.getPassword());
            newValues.put(KEY_NAME, user.getUserName());
            Log.i(TAG, "addItem successfully with loginId->" + user.getLoginId() + " password->" + user.getPassword());
            return db.insert(DB_TABLE, null, newValues);
        } catch (Exception e) {
            Log.e(TAG, "addItem error: " + e.getMessage(), e);
            throw new Exception("addItem error: " + e.getMessage(), e);
        }
    }
 
    public List<UserBean> queryAll() {
        List<UserBean> userList = new ArrayList<UserBean>();
        try {
            StringBuilder sqlStr = new StringBuilder();
            sqlStr.append("select loginId,password,user_name from ").append(DB_TABLE);
            Cursor cur = db.rawQuery(sqlStr.toString(), null);
            while (cur.moveToNext()) {
                String loginId = cur.getString(cur.getColumnIndexOrThrow("loginId"));
                String password = cur.getString(cur.getColumnIndexOrThrow("password"));
                String userName = cur.getString(cur.getColumnIndexOrThrow("user_name"));
                UserBean user = new UserBean();
                user.setLoginId(loginId);
                user.setPassword(password);
                user.setUserName(userName);
                userList.add(user);
            }
        } catch (Exception e) {
            Log.e(TAG, ">>>>>>queryAll error: " + e.getMessage(), e);
        }
        return userList;
    }
 
    public int checkLogin(String loginId, String pwd) {
        int result = 0;
        StringBuilder sqlStr = new StringBuilder();
        sqlStr.append("SELECT COUNT(*) FROM ").append(DB_TABLE).append(" WHERE ").append(KEY_ID).append("=? AND ").append(KEY_PASSWORD).append("=?");
        Log.i(TAG, ">>>>>>execute checkLogin SQL: " + sqlStr.toString());
        Log.i(TAG, ">>>>>>LoginId->" + loginId + " password->" + pwd);
        try {
            Cursor cur = db.rawQuery(sqlStr.toString(), new String[]{loginId, pwd});
            if (cur != null) {
                cur.moveToFirst();
                result = cur.getInt(0);
            }
        } catch (Exception e) {
            Log.e(TAG, "checkLogin dao error: " + e.getMessage(), e);
        }
        return result;
    }
 
    private static class DBOpenHelper extends SQLiteOpenHelper {
 
        public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
            super(context, name, factory, version);
        }
 
        private static final String DB_CREATE = "create table " +
                DB_TABLE + " (" + KEY_ID + " VARCHAR(20) primary key , " +
                KEY_PASSWORD + " text not null, " + KEY_NAME + " text not null);";
 
        @Override
        public void onCreate(SQLiteDatabase db) {
            Log.i(TAG, ">>>>>>execute create table->" + DB_CREATE);
            db.execSQL(DB_CREATE);
            StringBuilder initDataSql = new StringBuilder();
            initDataSql.append("INSERT INTO ").append(DB_TABLE).
                    append("(").append(KEY_ID).append(",").append(KEY_PASSWORD).
                    append(",").append(KEY_NAME).append(")").append("values(?,?,?)");
            Log.i(TAG, ">>>>>>execute initDataSql->" + initDataSql.toString());
            db.execSQL(initDataSql.toString(), new String[]{"root", "111111", "root"});
            Log.i(TAG, ">>>>>>db init successfully");
        }
 
        @Override
        public void onUpgrade(SQLiteDatabase db, int _oldVersion, int _newVersion) {
            //db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE);
            //onCreate(_db);
            db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE);
            onCreate(db);
 
        }
    }
}

MainActivity.java

這個(gè)就來得相對(duì)簡(jiǎn)單了。

package org.mk.android.demo.demosimplesqlite;
 
import androidx.appcompat.app.AppCompatActivity;
 
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
 
import java.util.ArrayList;
import java.util.List;
 
 
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "DemoSQLite";
 
    private SQLiteDatabase db;
    private Context context;
    private DBAdapter dbAdapter;
 
    private EditText editLoginId;
    private EditText editPassword;
    private Button buttonLogin;
    private Button buttonAddItem;
    private Button buttonQueryAll;
    private String strLoginId;
    private String strPassword;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        context = getApplicationContext();
        buttonLogin = (Button) findViewById(R.id.buttonLogin);
        buttonAddItem = (Button) findViewById(R.id.buttonAddItem);
        buttonQueryAll = (Button) findViewById(R.id.buttonQueryAll);
        editLoginId = (EditText) findViewById(R.id.editLoginid);
        editPassword = (EditText) findViewById(R.id.editPassword);
        dbAdapter = new DBAdapter(context);
 
        buttonLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    dbAdapter.open();
                    strLoginId = editLoginId.getText().toString();
                    strPassword = editPassword.getText().toString();
                    int answer = dbAdapter.checkLogin(strLoginId, strPassword);
                    Log.i(TAG, ">>>>>>checkLogin is->" + answer);
                    if (answer != 1) {
                        Toast.makeText(context, "登錄失敗請(qǐng)校驗(yàn)?zāi)愕挠脩裘兔艽a", Toast.LENGTH_LONG).show();
                    } else {
                        Toast.makeText(context, "登錄成功", Toast.LENGTH_LONG).show();
                    }
                } catch (Exception e) {
                    Log.e(TAG, ">>>>>>checkLogin error: " + e.getMessage(), e);
                } finally {
                    dbAdapter.close();
                }
            }
        });
        buttonAddItem.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    dbAdapter.open();
                    strLoginId = editLoginId.getText().toString();
                    strPassword = editPassword.getText().toString();
                    UserBean user = new UserBean();
                    user.setLoginId(strLoginId);
                    user.setPassword(strPassword);
                    user.setUserName(strLoginId);
 
                    long result = dbAdapter.addItem(user);
                    Toast.makeText(context, "增加一條數(shù)據(jù)成功", Toast.LENGTH_LONG).show();
 
                } catch (Exception e) {
                    Log.e("TAG", ">>>>>>addItem error: " + e.getMessage(), e);
                } finally {
                    dbAdapter.close();
                }
            }
        });
        buttonQueryAll.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    dbAdapter.open();
                    StringBuilder sb = new StringBuilder();
                    List<UserBean> userList = new ArrayList<UserBean>();
                    userList = dbAdapter.queryAll();
                    if (userList != null && userList.size() > 0) {
                        userList.forEach(v -> {
                            sb.append("loginId->").append(v.getLoginId())
                                    .append("  password->").append(v.getPassword())
                                    .append(" userName->").append(v.getUserName())
                                    .append("\n");
                        });
                        Log.i(TAG,sb.toString());
                        Toast.makeText(context, "查詢所有數(shù)據(jù)\n" + sb.toString(), Toast.LENGTH_LONG).show();
 
                    }
                } catch (Exception e) {
                    Log.e(TAG, ">>>>>>queryAll error: " + e.getMessage(), e);
                } finally {
                    dbAdapter.close();
                }
            }
        });
    }
 
    @Override
    protected void onStart(){
        super.onStart();
        dbAdapter.open();
    }
    @Override
    protected void onStop() {
        super.onStop();
        dbAdapter.close();
    }
}

運(yùn)行效果

自己動(dòng)一下手試試吧。

以上就是Android入門之使用SQLite內(nèi)嵌式數(shù)據(jù)庫(kù)詳解的詳細(xì)內(nèi)容,更多關(guān)于Android SQLite內(nèi)嵌式數(shù)據(jù)庫(kù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論