新聞中心
隨著移動(dòng)互聯(lián)網(wǎng)的普及,Android作為最為流行的移動(dòng)操作系統(tǒng)之一,其數(shù)據(jù)庫(kù)操作也越來(lái)越受到開發(fā)者的關(guān)注。而在Android應(yīng)用程序開發(fā)中,數(shù)據(jù)的存儲(chǔ)一直是一個(gè)普遍且重要的問(wèn)題。為了解決這個(gè)問(wèn)題,開發(fā)者需要使用一種可靠且高效的數(shù)據(jù)庫(kù)操作方法,以及封裝底層實(shí)現(xiàn)的數(shù)據(jù)庫(kù)基類,以實(shí)現(xiàn)數(shù)據(jù)的快速存儲(chǔ)與調(diào)用。

成都創(chuàng)新互聯(lián)公司提供高防主機(jī)、云服務(wù)器、香港服務(wù)器、綿陽(yáng)主機(jī)托管等
1、數(shù)據(jù)庫(kù)操作方法
在Android應(yīng)用程序開發(fā)中,SQLite是一種全功能、輕量級(jí)的關(guān)系型數(shù)據(jù)庫(kù)引擎。它廣泛應(yīng)用于移動(dòng)設(shè)備,因?yàn)樗欠浅P∏啥指咝У?,并且能夠?qū)崿F(xiàn)快速的CRUD(增、刪、改、查)操作。Android SDK提供了一套SQLite API,使得開發(fā)者可以通過(guò)Java代碼來(lái)與SQLite數(shù)據(jù)庫(kù)進(jìn)行交互。
在進(jìn)行數(shù)據(jù)庫(kù)操作時(shí),開發(fā)者應(yīng)該遵循以下幾個(gè)步驟:
1)打開或創(chuàng)建數(shù)據(jù)庫(kù)
2)創(chuàng)建表
3)插入數(shù)據(jù)
4)查詢數(shù)據(jù)
5)更新數(shù)據(jù)
6)刪除數(shù)據(jù)
7)關(guān)閉數(shù)據(jù)庫(kù)
在實(shí)際開發(fā)過(guò)程中,我們通常會(huì)為每個(gè)數(shù)據(jù)表創(chuàng)建一個(gè)Java Bean類,用于封裝表中的數(shù)據(jù),方便訪問(wèn)和操作。
2、數(shù)據(jù)庫(kù)基類的封裝
封裝數(shù)據(jù)庫(kù)基類的目的是為了提高代碼的復(fù)用性和可維護(hù)性。我們可以將所有公共的數(shù)據(jù)庫(kù)操作封裝到一個(gè)基類中,并提供一些常用的API,以便子類繼承和調(diào)用。這樣可以避免在每個(gè)數(shù)據(jù)表對(duì)應(yīng)的Java Bean類中都寫一遍數(shù)據(jù)庫(kù)操作代碼,代碼重用率將大大提高。
以下是一個(gè)簡(jiǎn)單的數(shù)據(jù)庫(kù)基類的實(shí)現(xiàn):
“`
public abstract class BaseDao {
private SQLiteDatabase mDatabase;
private Class mClazz;
public BaseDao(Context context, Class clazz) {
// 創(chuàng)建或打開數(shù)據(jù)庫(kù)
mDatabase = SQLiteDatabase.openOrCreateDatabase(context.getDatabasePath(“my_db”), null);
mClazz = clazz;
// 創(chuàng)建數(shù)據(jù)表
createTable();
}
private void createTable() {
// 通過(guò)反射獲取Java Bean類中定義的表名和屬性
String tableName = mClazz.getSimpleName();
Field[] fields = mClazz.getDeclaredFields();
StringBuilder = new StringBuilder();
.append(“CREATE TABLE IF NOT EXISTS “);
.append(tableName);
.append(“(“);
for (Field field : fields) {
field.setAccessible(true);
String fieldName = field.getName();
String fieldType = getFieldType(field.getType());
.append(fieldName);
.append(” “);
.append(fieldType);
.append(“,”);
}
.deleteCharAt(.length() – 1);
.append(“)”);
mDatabase.execSQL(.toString());
}
private String getFieldType(Class type) {
if (type == String.class) {
return “TEXT”;
} else if (type == int.class || type == Integer.class) {
return “INTEGER”;
} else if (type == float.class || type == Float.class) {
return “REAL”;
} else if (type == double.class || type == Double.class) {
return “REAL”;
} else {
return “BLOB”;
}
}
public void insert(T entity) {
ContentValues values = new ContentValues();
// 通過(guò)反射獲取實(shí)體類中的屬性并保存到ContentValues中
Field[] fields = mClazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String fieldName = field.getName();
String fieldValue = “”;
try {
Object obj = field.get(entity);
if (obj != null) {
fieldValue = obj.toString();
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
values.put(fieldName, fieldValue);
}
// 將ContentValues中的數(shù)據(jù)插入到數(shù)據(jù)庫(kù)表中
mDatabase.insert(mClazz.getSimpleName(), null, values);
}
// …
}
“`
可以看到,BaseDao類中定義了一個(gè)私有的SQLiteDatabase對(duì)象mDatabase,它在構(gòu)造函數(shù)中被初始化。在構(gòu)造函數(shù)中,我們還通過(guò)反射獲取了子類傳遞進(jìn)來(lái)的Java Bean類的Class對(duì)象,并保存到了mClazz變量中。然后在createTable()方法中,我們通過(guò)反射獲取了Java Bean類中定義的表名和屬性,并拼接成了一個(gè)完整的SQL語(yǔ)句,然后通過(guò)mDatabase.execSQL()方法執(zhí)行這個(gè)SQL語(yǔ)句,從而創(chuàng)建了數(shù)據(jù)表。
在insert()方法中,我們將子類傳遞進(jìn)來(lái)的Java Bean對(duì)象轉(zhuǎn)換成了ContentValues對(duì)象,并插入到了數(shù)據(jù)庫(kù)表中。其他CRUD操作也可以采用類似的方式實(shí)現(xiàn)。
3、數(shù)據(jù)庫(kù)操作的API設(shè)計(jì)
通常情況下,一個(gè)完整的數(shù)據(jù)庫(kù)操作包括表的創(chuàng)建、數(shù)據(jù)的插入、數(shù)據(jù)的查詢、數(shù)據(jù)的更新和數(shù)據(jù)的刪除等。因此,我們可以在數(shù)據(jù)庫(kù)基類中添加一些常用的API,以方便子類進(jìn)行數(shù)據(jù)庫(kù)操作。以下是一個(gè)示例:
“`
public abstract class BaseDao {
// …
public abstract void insert(T entity);
public abstract List query(String selection, String[] selectionArgs);
public abstract void update(T entity, String selection, String[] selectionArgs);
public abstract void delete(String selection, String[] selectionArgs);
protected List cursorToList(Cursor cursor) {
List list = new ArrayList();
if (cursor != null && cursor.moveToFirst()) {
do {
T entity = null;
try {
entity = mClazz.newInstance();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
if (entity != null) {
// 通過(guò)反射將數(shù)據(jù)填充到Java Bean對(duì)象中
Field[] fields = mClazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String fieldName = field.getName();
int columnIndex = cursor.getColumnIndex(fieldName);
if (columnIndex != -1) {
Object value = cursor.getString(columnIndex);
setFieldValue(entity, field, value);
}
}
list.add(entity);
}
} while (cursor.moveToNext());
cursor.close();
}
return list;
}
private void setFieldValue(T entity, Field field, Object value) {
try {
if (value == null) {
return;
}
Class fieldType = field.getType();
if (fieldType == int.class || fieldType == Integer.class) {
field.setInt(entity, Integer.parseInt(value.toString()));
} else if (fieldType == long.class || fieldType == Long.class) {
field.setLong(entity, Long.parseLong(value.toString()));
} else if (fieldType == float.class || fieldType == Float.class) {
field.setFloat(entity, Float.parseFloat(value.toString()));
} else if (fieldType == double.class || fieldType == Double.class) {
field.setDouble(entity, Double.parseDouble(value.toString()));
} else if (fieldType == boolean.class || fieldType == Boolean.class) {
field.setBoolean(entity, Boolean.parseBoolean(value.toString()));
} else {
field.set(entity, value.toString());
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public void close() {
mDatabase.close();
}
}
“`
在這個(gè)示例中,我們定義了insert()、query()、update()、delete()等常用的API,它們的實(shí)現(xiàn)可以調(diào)用父類中的方法。此外,我們還定義了一個(gè)cursorToList()方法,用于將查詢結(jié)果轉(zhuǎn)換成Java Bean對(duì)象的列表。
4、數(shù)據(jù)庫(kù)操作的使用示例
如何在實(shí)際開發(fā)中使用上述的數(shù)據(jù)庫(kù)基類呢?我們可以先創(chuàng)建一個(gè)Java Bean類,定義數(shù)據(jù)表的結(jié)構(gòu):
“`
public class User {
private int id;
private String name;
private int age;
private String address;
// getter/setter
}
“`
然后創(chuàng)建一個(gè)子類繼承自BaseDao,實(shí)現(xiàn)具體的數(shù)據(jù)庫(kù)操作:
“`
public class UserDao extends BaseDao {
public UserDao(Context context) {
super(context, User.class);
}
@Override
public void insert(User entity) {
super.insert(entity);
}
@Override
public List query(String selection, String[] selectionArgs) {
Cursor cursor = mDatabase.query(mClazz.getSimpleName(), null, selection, selectionArgs, null, null, null);
return cursorToList(cursor);
}
@Override
public void update(User entity, String selection, String[] selectionArgs) {
super.update(entity, selection, selectionArgs);
}
@Override
public void delete(String selection, String[] selectionArgs) {
super.delete(selection, selectionArgs);
}
public List queryAll() {
return query(null, null);
}
public User queryById(int id) {
String selection = “id=?”;
String[] selectionArgs = new String[] {String.valueOf(id)};
List list = query(selection, selectionArgs);
return (list != null && list.size() > 0) ? list.get(0) : null;
}
// …
}
“`
在這個(gè)子類中,我們重寫了父類中的API,并調(diào)用了父類中相應(yīng)的方法。此外,我們還實(shí)現(xiàn)了一些特定的查詢方法,如queryAll()和queryById()等。
在實(shí)際開發(fā)中,我們可以使用如下代碼來(lái)進(jìn)行數(shù)據(jù)庫(kù)操作:
“`
UserDao userDao = new UserDao(context);
User user = new User();
user.setName(“張三”);
user.setAge(20);
user.setAddress(“北京市”);
userDao.insert(user);
List userList = userDao.queryAll();
for (User u : userList) {
Log.d(TAG, u.getName() + “, ” + u.getAge() + “, ” + u.getAddress());
}
user.setName(“李四”);
userDao.update(user, “id=?”, new String[] {String.valueOf(user.getId())});
userDao.delete(“id=?”, new String[] {String.valueOf(user.getId())});
User user2 = userDao.queryById(1);
if (user2 != null) {
Log.d(TAG, user2.getName() + “, ” + user2.getAge() + “, ” + user2.getAddress());
}
userDao.close();
“`
相關(guān)問(wèn)題拓展閱讀:
- android SQLite數(shù)據(jù)怎么顯示到UI界面中
android SQLite數(shù)據(jù)怎么顯示到UI界面中
1 sqlite增刪改的例子圖片
2 上面使用的例子來(lái)自android學(xué)習(xí)手冊(cè),例子、源碼、文檔全部搞定,采用androidstudo的目錄結(jié)構(gòu),360手機(jī)助手中下載。。
3 使用SQLite。
現(xiàn)在的主流移動(dòng)設(shè)備像Android、iPhone等都使用SQLite作為復(fù)雜數(shù)據(jù)的存儲(chǔ)引擎,在我們?yōu)橐苿?dòng)設(shè)備開發(fā)應(yīng)用程序時(shí),也許就要使用到SQLite來(lái)存儲(chǔ)我們大量的數(shù)據(jù),所以我們就需要掌握移動(dòng)設(shè)備上做旅的SQLite開發(fā)技巧。對(duì)于Android平臺(tái)來(lái)說(shuō),系統(tǒng)內(nèi)置了豐富的API來(lái)供開發(fā)人員操作SQLite,我們可以輕松的完成對(duì)數(shù)據(jù)的存取。
下面就向大家介紹一下SQLite常用的操作方法,為了方便,我將代碼寫在了Activity的onCreate中:
view plain copy print?
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//打開或創(chuàng)建test.db數(shù)據(jù)庫(kù)
SQLiteDatabase db = openOrCreateDatabase(“test.db”, Context.MODE_PRIVATE, null);
db.execSQL(“DROP TABLE IF EXISTS person”);
//創(chuàng)建person表
db.execSQL(“CREATE TABLE person (_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age ALLINT)”);
Person person = new Person();
person.name = “john”;
person.age = 30;
//插入數(shù)據(jù)
db.execSQL(“INSERT INTO person VALUES (NULL, ?, ?)”, new Object{person.name, person.age});
person.name = “david”;
person.age = 33;
//ContentValues以鍵值對(duì)的形式存放數(shù)據(jù)
ContentValues cv = new ContentValues();
cv.put(“name”, person.name);
cv.put(“age”, person.age);
//插入ContentValues中的數(shù)據(jù)
db.insert(“person”, null, cv);
cv = new ContentValues();
cv.put(“age”, 35);
純攜凳//更新數(shù)據(jù)
db.update(“person”, cv, “name = ?”, new String{“john”});
Cursor c = db.rawQuery(“SELECT * FROM person WHERE age >= ?”, new String{“33”});
while (c.moveToNext()) {
int _id = c.getInt(c.getColumnIndex(“_id”));
隱余String name = c.getString(c.getColumnIndex(“name”));
int age = c.getInt(c.getColumnIndex(“age”));
Log.i(“db”, “_id=>” + _id + “, name=>” + name + “, age=>” + age);
}
c.close();
//刪除數(shù)據(jù)
db.delete(“person”, “age = ?”, new String{“33”});
while (c.moveToNext()) {
int _id = c.getInt(c.getColumnIndex(“_id”));
String name = c.getString(c.getColumnIndex(“name”));
int age = c.getInt(c.getColumnIndex(“age”));
Log.i(“db”, “_id=>” + _id + “, name=>” + name + “, age=>” + age);
}
c.close();
//刪除數(shù)據(jù)
db.delete(“person”, “age ? and age
下面來(lái)說(shuō)說(shuō)查詢操作。查詢操作相對(duì)于上面的幾種操作要復(fù)雜些,因?yàn)槲覀兘?jīng)常要面對(duì)著各種各樣的查詢條件,所以系統(tǒng)也考慮到這種復(fù)雜性,為我們提供了較為豐富的查詢形式:
view plain copy print?
db.rawQuery(String sql, String selectionArgs);
db.query(String table, String columns, String selection, String selectionArgs, String groupBy, String having, String orderBy);
db.query(String table, String columns, String selection, String selectionArgs, String groupBy, String having, String orderBy, String limit);
db.query(String distinct, String table, String columns, String selection, String selectionArgs, String groupBy, String having, String orderBy, String limit);
db.rawQuery(String sql, String selectionArgs);
db.query(String table, String columns, String selection, String selectionArgs, String groupBy, String having, String orderBy);
db.query(String table, String columns, String selection, String selectionArgs, String groupBy, String having, String orderBy, String limit);
db.query(String distinct, String table, String columns, String selection, String selectionArgs, String groupBy, String having, String orderBy, String limit);
上面幾種都是常用的查詢方法,之一種最為簡(jiǎn)單,將所有的SQL語(yǔ)句都組織到一個(gè)字符串中,使用占位符代替實(shí)際參數(shù),selectionArgs就是占位符實(shí)際參數(shù)集;下面的幾種參數(shù)都很類似,columns表示要查詢的列所有名稱集,selection表示W(wǎng)HERE之后的條件語(yǔ)句,可以使用占位符,groupBy指定分組的列名,having指定分組條件,配合groupBy使用,orderBy指定排序的列名,limit指定分頁(yè)參數(shù),distinct可以指定“true”或“false”表示要不要過(guò)濾重復(fù)值。需要注意的是,selection、groupBy、having、orderBy、limit這幾個(gè)參數(shù)中不包括“WHERE”、“GROUP BY”、“HAVING”、“ORDER BY”、“LIMIT”等SQL關(guān)鍵字。
最后,他們同時(shí)返回一個(gè)Cursor對(duì)象,代表數(shù)據(jù)集的游標(biāo),有點(diǎn)類似于JavaSE中的ResultSet。
下面是Cursor對(duì)象的常用方法:
view plain copy print?
c.move(int offset); //以當(dāng)前位置為參考,移動(dòng)到指定行
c.moveToFirst(); //移動(dòng)到之一行
c.moveToLast(); //移動(dòng)到最后一行
c.moveToPosition(int position); //移動(dòng)到指定行
c.moveToPrevious(); //移動(dòng)到前一行
c.moveToNext(); //移動(dòng)到下一行
c.isFirst();//是否指向之一條
c.isLast(); //是否指向最后一條
c.isBeforeFirst(); //是否指向之一條之前
c.isAfterLast(); //是否指向最后一條之后
c.isNull(int columnIndex); //指定列是否為空(列基數(shù)為0)
c.isClosed();//游標(biāo)是否已關(guān)閉
c.getCount();//總數(shù)據(jù)項(xiàng)數(shù)
c.getPosition(); //返回當(dāng)前游標(biāo)所指向的行數(shù)
c.getColumnIndex(String columnName);//返回某列名對(duì)應(yīng)的列索引值
c.getString(int columnIndex); //返回當(dāng)前行指定列的值
c.move(int offset);//以當(dāng)前位置為參考,移動(dòng)到指定行
c.moveToFirst();//移動(dòng)到之一行
c.moveToLast();//移動(dòng)到最后一行
c.moveToPosition(int position);//移動(dòng)到指定行
c.moveToPrevious();//移動(dòng)到前一行
c.moveToNext();//移動(dòng)到下一行
c.isFirst();//是否指向之一條
c.isLast();//是否指向最后一條
c.isBeforeFirst();//是否指向之一條之前
c.isAfterLast();//是否指向最后一條之后
c.isNull(int columnIndex);//指定列是否為空(列基數(shù)為0)
c.isClosed();//游標(biāo)是否已關(guān)閉
c.getCount();//總數(shù)據(jù)項(xiàng)數(shù)
c.getPosition();//返回當(dāng)前游標(biāo)所指向的行數(shù)
c.getColumnIndex(String columnName);//返回某列名對(duì)應(yīng)的列索引值
c.getString(int columnIndex);//返回當(dāng)前行指定列的值
在上面的代碼示例中,已經(jīng)用到了這幾個(gè)常用方法中的一些,關(guān)于更多的信息,大家可以參考官方文檔中的說(shuō)明。
最后當(dāng)我們完成了對(duì)數(shù)據(jù)庫(kù)的操作后,記得調(diào)用SQLiteDatabase的close()方法釋放數(shù)據(jù)庫(kù)連接,否則容易出現(xiàn)SQLiteException。
上面就是SQLite的基本應(yīng)用,但在實(shí)際開發(fā)中,為了能夠更好的管理和維護(hù)數(shù)據(jù)庫(kù),我們會(huì)封裝一個(gè)繼承自SQLiteOpenHelper類的數(shù)據(jù)庫(kù)操作類,然后以這個(gè)類為基礎(chǔ),再封裝我們的業(yè)務(wù)邏輯方法。
下面,我們就以一個(gè)實(shí)例來(lái)講解具體的用法,我們新建一個(gè)名為db的項(xiàng)目,結(jié)構(gòu)如下:
其中DBHelper繼承了SQLiteOpenHelper,作為維護(hù)和管理數(shù)據(jù)庫(kù)的基類,DBManager是建立在DBHelper之上,封裝了常用的業(yè)務(wù)方法,Person是我們的person表對(duì)應(yīng)的JavaBean,MainActivity就是我們顯示的界面。
下面我們先來(lái)看一下DBHelper:
view plain copy print?
package com.scott.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DBHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = “test.db”;
private static final int DATABASE_VERSION = 1;
public DBHelper(Context context) {
//CursorFactory設(shè)置為null,使用默認(rèn)值
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
//數(shù)據(jù)庫(kù)之一次被創(chuàng)建時(shí)onCreate會(huì)被調(diào)用
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(“CREATE TABLE IF NOT EXISTS person” +
“(_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age INTEGER, info TEXT)”);
}
//如果DATABASE_VERSION值被改為2,系統(tǒng)發(fā)現(xiàn)現(xiàn)有數(shù)據(jù)庫(kù)版本不同,即會(huì)調(diào)用onUpgrade
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(“ALTER TABLE person ADD COLUMN other STRING”);
}
}
package com.scott.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DBHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = “test.db”;
private static final int DATABASE_VERSION = 1;
public DBHelper(Context context) {
//CursorFactory設(shè)置為null,使用默認(rèn)值
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
//數(shù)據(jù)庫(kù)之一次被創(chuàng)建時(shí)onCreate會(huì)被調(diào)用
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(“CREATE TABLE IF NOT EXISTS person” +
“(_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age INTEGER, info TEXT)”);
}
//如果DATABASE_VERSION值被改為2,系統(tǒng)發(fā)現(xiàn)現(xiàn)有數(shù)據(jù)庫(kù)版本不同,即會(huì)調(diào)用onUpgrade
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(“ALTER TABLE person ADD COLUMN other STRING”);
}
}
正如上面所述,數(shù)據(jù)庫(kù)之一次創(chuàng)建時(shí)onCreate方法會(huì)被調(diào)用,我們可以執(zhí)行創(chuàng)建表的語(yǔ)句,當(dāng)系統(tǒng)發(fā)現(xiàn)版本變化之后,會(huì)調(diào)用onUpgrade方法,我們可以執(zhí)行修改表結(jié)構(gòu)等語(yǔ)句。
關(guān)于andorid數(shù)據(jù)庫(kù)基類的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
成都創(chuàng)新互聯(lián)科技有限公司,是一家專注于互聯(lián)網(wǎng)、IDC服務(wù)、應(yīng)用軟件開發(fā)、網(wǎng)站建設(shè)推廣的公司,為客戶提供互聯(lián)網(wǎng)基礎(chǔ)服務(wù)!
創(chuàng)新互聯(lián)(www.cdcxhl.com)提供簡(jiǎn)單好用,價(jià)格厚道的香港/美國(guó)云服務(wù)器和獨(dú)立服務(wù)器。創(chuàng)新互聯(lián)——四川成都IDC機(jī)房服務(wù)器托管/機(jī)柜租用。為您精選優(yōu)質(zhì)idc數(shù)據(jù)中心機(jī)房租用、服務(wù)器托管、機(jī)柜租賃、大帶寬租用,高電服務(wù)器托管,算力服務(wù)器租用,可選線路電信、移動(dòng)、聯(lián)通機(jī)房等。
網(wǎng)站名稱:Android數(shù)據(jù)庫(kù)基類:實(shí)現(xiàn)數(shù)據(jù)的快速存儲(chǔ)與調(diào)用(andorid數(shù)據(jù)庫(kù)基類)
網(wǎng)頁(yè)網(wǎng)址:http://m.fisionsoft.com.cn/article/coohdps.html


咨詢
建站咨詢
