您的位置:首页 > 其它

[AS2.3.3]greenDao3.2.2基本使用

2017-09-07 17:41 399 查看
本篇大部分来自网上,算是个整合。

greenDao的优势就不说了 直接开始吧!

1.首先是搭建greenDao

greenDao3在原来的版本做了很大的修改,所以先谈谈搭建!

首先按github官方说明可以知道要在根build.gradle和app下的build.gradle进行设置

首先是根 build.gradle的设置

// In your root build.gradle file:
buildscript {
repositories {
jcenter()
mavenCentral() // add repository
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.1'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
}
}
在之后是app build.gradle的设置

// In your app projects build.gradle file:
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin

dependencies {
compile 'org.greenrobot:greendao:3.2.2' // add library
}


然后如果需要设置greenDao的生成地方需要在app build.gradle中加入设置。
我的设置如下

//schemaVersion: 数据库schema版本,也可以理解为数据库版本号
//daoPackage:设置DaoMaster、DaoSession、Dao包名
//targetGenDir:设置DaoMaster、DaoSession、Dao目录
//targetGenDirTest:设置生成单元测试目录
//generateTests:设置自动生成单元测试用例
greendao {
schemaVersion 1
daoPackage 'com.gjn.msdemo.green'
targetGenDir 'src/main/java'
}
之后再dependencies中加入greenDao3.2.2就好了  中间其他导入的就省略了

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
......
compile 'org.greenrobot:greendao:3.2.2'
}


这样就算搭建好了greenDao了

之后需要设置我们的数据库了

2.greenDao注解说明

greenDao3之后是以注解式来创建表的,下面先放一些注解说明 来自这边

2.1 常用注解

@Entity 用于标识这是一个需要Greendao帮我们生成代码的bean

@Id 标明主键,括号里可以指定是否自增 

@Property 用于设置属性在数据库中的列名(默认不写就是保持一致)

@NotNull 非空

@Transient 标识这个字段是自定义的不会创建到数据库表里

2.2实体类注解

@Entity(
schema = "myschema",

active = true,

nameInDb = "AWESOME_USERS",

indexes = {
@Index(value = "name DESC", unique = true)
},

createInDb = false
)
schema是一个项目中有多个schema时 标明要让这个dao属于哪个schema

active 是标明是否支持实体类之间update,refresh,delete等操作 

nameInDb 就是写个存在数据库里的表名(不写默认是一致)

indexes 定义索引,这里可跨越多个列

CreateInDb 如果是有多个实体都关联这个表,可以把多余的实体里面设置为false避免重复创建(默认是true)

2.3索引注解

@Entity
public class User {
@Id private Long id;
@Index(unique = true)
private String name;
}

@Entity
public class User {
@Id private Long id;
@Unique private String name;
}
@Index 通过这个字段建立索引

@Unique 添加唯一约束,上面的括号里unique=true作用相同

2.4关系注解

@ToOne 是将自己的一个属性与另一个表建立关联

@ToMany 是将自己的一个属性与多个表建立关联

这两个比较繁琐可以看原文,这边就不详细说明了!

3.使用greenDao

首先我们创建一个类GDUser.class

如下添加注解

@Entity
public class GDUser {
@Id
private Long id;
@NotNull
private String name;
private String sex;
private int age;
}


之后我们rebuild的项目

下面使greenDao自动帮我们添加的新的

GDUser.class

package com.gjn.msdemo.greendaoModel;

import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.NotNull;
import org.greenrobot.greendao.annotation.Generated;

/**
* GDUser
* Author: gjn.
* Time: 2017/9/7.
*/
@Entity
public class GDUser {
@Id
private Long id;
@NotNull
private String name;
private String sex;
private int age;
@Generated(hash = 1925400777)
public GDUser(Long id, @NotNull String name, String sex, int age) {
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
}
@Generated(hash = 1014226889)
public GDUser() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return this.sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
}
然后项目中在green设置的下面也多了一个GDUserDao的类

之后我们需要对这个GDUser表进行操作就需要建一个帮助类

GreenDaoHelper.class

package com.gjn.msdemo.util;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;

import com.gjn.msdemo.green.DaoMaster;
import com.gjn.msdemo.green.DaoSession;

/**
* GreenDaoHelper
* Author: gjn.
* Time: 2017/9/6.
*/

public class GreenDaoHelper {
private static DaoMaster.DevOpenHelper devOpenHelper;
private static SQLiteDatabase database;
private static DaoMaster daoMaster;
private static DaoSession daoSession;

/**
* 初始化 建议放在Application中
* @param context
*/
public static void initDatabase(Context context){
// 注意:默认的 DaoMaster.DevOpenHelper 会在数据库升级时,删除所有的表,意味着这将导致数据的丢失。
// 所以,在正式的项目中,你还应该做一层封装,来实现数据库的安全升级。
devOpenHelper = new DaoMaster.DevOpenHelper(context,"msdemo_db",null);
database = devOpenHelper.getWritableDatabase();
// 注意:该数据库连接属于 DaoMaster,所以多个 Session 指的是相同的数据库连接。
daoMaster = new DaoMaster(database);
daoSession = daoMaster.newSession();
}

public static SQLiteDatabase getDatabase() {
return database;
}

public static DaoSession getDaoSession() {
return daoSession;
}
}
帮助类写好了之后 我们就可以对数据库进行操作了

首先我做了个简单的界面操作



操作如下

添加数据->查询全部->删除1号数据->查询全部->全部删除->添加数据->修改张三数据->查询全部



代码如下

GreenDaoActivity.class

package com.gjn.msdemo.greendaoModel;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import com.gjn.msdemo.R;
import com.gjn.msdemo.green.GDUserDao;
import com.gjn.msdemo.util.GreenDaoHelper;

import butterknife.ButterKnife;
import butterknife.OnClick;

public class GreenDaoActivity extends AppCompatActivity {
private static final String TAG = "GreenDaoActivity";
private GDUserDao userDao;

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

ButterKnife.bind(this);

userDao = GreenDaoHelper.getDaoSession().getGDUserDao();
}

@OnClick(R.id.btn_add_gd)
public void add(){
userDao.insert(new GDUser(null,"张三","男",18));
userDao.insert(new GDUser(null,"李四","女",28));
userDao.insert(new GDUser(null,"王五","男",38));
Log.e(TAG, "添加成功");
}

@OnClick(R.id.btn_delete_gd)
public void delete(){
try{
userDao.deleteByKey((long) 1);
Log.e(TAG, "删除成功");
}catch (Exception e){
Log.e(TAG, "删除失败");
}
}

@OnClick(R.id.btn_change_gd)
public void change(){
GDUser user = userDao.queryBuilder()
.where(GDUserDao.Properties.Name.eq("张三"))
.build()
.unique();
if (user != null){
user.setName("马六");
userDao.update(user);
Log.e(TAG, "修改成功");
}else{
Log.e(TAG, "修改失败");
}

}

@OnClick(R.id.btn_query_gd)
public void query(){
for (GDUser gdUser : userDao.loadAll()) {
Log.e(TAG, "==>\n"+gdUser.getId()+","+gdUser.getName()
+","+gdUser.getSex() +","+gdUser.getAge());
}
}

@OnClick(R.id.btn_deleteall_gd)
public void deleteAll(){
userDao.deleteAll();
Log.e(TAG, "全部删除");
}
}
可以看到这些都是基本的操作

下面我将把这块分开来讲解下

首先我们先通过帮助类获取写操作

userDao = GreenDaoHelper.getDaoSession().getGDUserDao();


3.1增

增加是最简单的直接加入对象即可

userDao.insert(new GDUser(null,"张三","男",18));
userDao.insert(new GDUser(null,"李四","女",28));
userDao.insert(new GDUser(null,"王五","男",38));
首先我上面设置的实体类是Long,当@Id设置的是Long的时候 传入null id就会自增

3.2删

删除的方法有几个

包括删除全部

userDao.deleteAll();
删除key为多少的对象

userDao.deleteByKey((long) 1);	//这边是删除id=1的对象


还可以通过查询找到对象在删除

比如我想删掉张三

GDUser user = userDao.queryBuilder()
.where(GDUserDao.Properties.Name.eq("张三"))
.build()
.unique();
userDao.delete(user);


这边就涉及到了查询,查询下面会说明

3.3改

改的话方法是update

userDao.update(user);
就只能依靠查询的对象来进行修改 

3.4查

查询是数据库中最重要的一环 所以会比较多

查询的方法主要依靠下面2个

userDao.queryRaw();
userDao.queryBuilder();


3.4.1 queryRaw

首先上面的queryRaw内部放的是 String where, String... selectionArg

这就很像我们直接对Sqlite数据库操作的的查询了并且返回的值是一个List 代表多个

现在我们要从上面的默认三个数据中查找男性user

for (GDUser gdUser : userDao.queryRaw("where T.SEX=?", "男")) {
Log.e(TAG, "==>\n"+gdUser.getId()+","+gdUser.getName()
+","+gdUser.getSex() +","+gdUser.getAge());
}
这边开始写的是直接

userDao.queryRaw("SEX=?", "男")
发现报错,然后看了下源码发现

/** A raw-style query where you can pass any WHERE clause and arguments. */
public List<T> queryRaw(String where, String... selectionArg) {
Cursor cursor = db.rawQuery(statements.getSelectAll() + where, selectionArg);
return loadAllAndCloseCursor(cursor);
}
然后依据报错 加入了 where和 T.  然后就可以成功查询了

结果如下



3.4.2 queryBuilder

下面在说个查询是通过构建查询对象进行查询

这边我想查询年龄小于等于30岁的user 代码如下

for (GDUser gdUser : userDao.queryBuilder()
.where(GDUserDao.Properties.Age.le(30))
.build()
.list()) {
Log.e(TAG, "==>\n"+gdUser.getId()+","+gdUser.getName()
+","+gdUser.getSex() +","+gdUser.getAge());
}


这边我们可以看到
上面我们在修改中也查询过,但是那个是查询单个人 最后build的是unique 而这边是集合 所以使用了list

其中后面的eq  le 可以直接点入源码查看

下面罗列下吧

eq ('=')
notEq ('<>')
likeLIKE
between BETWEEN ... AND ...
in IN (..., ..., ...)
notIn NOT IN (..., ..., ...)
gt ('>')
lt('<')
ge ('>=')
le ('<=')
isNull IS NULL
isNotNull IS NOT NULL
其他还有更多的应用我下面添加下  

作者:离羊

链接:http://www.jianshu.com/p/4e6d72e7f57a

來源:简书

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Dao 增加

long     insert(T entity)  // 插入指定实体
void     insertInTx(T... entities)
void     insertInTx(java.lang.Iterable<T> entities)
void     insertInTx(java.lang.Iterable<T> entities, boolean setPrimaryKey)
long     insertWithoutSettingPk(T entity)  // 插入指定实体,无主键
long     insertOrReplace(T entity)  // 插入或替换指定实体
void     insertOrReplaceInTx(T... entities)
void     insertOrReplaceInTx(java.lang.Iterable<T> entities)
void     insertOrReplaceInTx(java.lang.Iterable<T> entities, boolean setPrimaryKey)
void     save(T entity)  // 依赖指定的主键插入或修改实体
void     saveInTx(T... entities)
void     saveInTx(java.lang.Iterable<T> entities)


Dao 删除

void     deleteAll()  // 删除所有
void     delete(T entity)  // 删除指定的实体
void     deleteInTx(T... entities)
void     deleteInTx(java.lang.Iterable<T> entities)
void     deleteByKey(K key)  // 删除指定主键对应的实体
void     deleteByKeyInTx(K... keys)
void     deleteByKeyInTx(java.lang.Iterable<K> keys)


Dao 修改

void     update(T entity)
void     updateInTx(T... entities)
void     updateInTx(java.lang.Iterable<T> entities)


Dao 其它

void     refresh(T entity)  // 从数据库获取值刷新本地实体
long     count()  // 数量

boolean     detach(T entity)  // 从域中分离实体
void     detachAll()  // 从域中分离所有实体

AbstractDaoSession     getSession()
Database     getDatabase()
java.lang.String     getTablename()
java.lang.String[]     getAllColumns()
java.lang.String[]     getPkColumns()
java.lang.String[]     getNonPkColumns()
Property     getPkProperty()
Property[]     getProperties()


Dao 查询

java.util.List<T>     loadAll()
T     load(K key)
T     loadByRowId(long rowId)


QueryBuilder 查询

List joes = userDao.queryBuilder()  // 查询 User
.where(Properties.FirstName.eq("Joe"))  // 首名为 Joe
.orderAsc(Properties.LastName)  // 末名升序排列
.list();  // 返回集合

// Joe,>= 1970.10
QueryBuilder qb = userDao.queryBuilder();
qb.where(Properties.FirstName.eq("Joe"),
qb.or(Properties.YearOfBirth.gt(1970),
qb.and(Properties.YearOfBirth.eq(1970), Properties.MonthOfBirth.ge(10))));
List youngJoes = qb.list();
QueryBuilder<T>     queryBuilder()  // Dao

// QueryBuilder
QueryBuilder<T>     where(WhereCondition cond, WhereCondition... condMore)  // 条件,AND 连接
QueryBuilder<T>     whereOr(WhereCondition cond1, WhereCondition cond2, WhereCondition... condMore)  // 条件,OR 连接
QueryBuilder<T>     distinct()  // 去重,例如使用联合查询时
QueryBuilder<T>     limit(int limit)  // 限制返回数
QueryBuilder<T>     offset(int offset)  // 偏移结果起始位,配合limit(int)使用
QueryBuilder<T>     orderAsc(Property... properties)  // 排序,升序
QueryBuilder<T>     orderDesc(Property... properties)  // 排序,降序
QueryBuilder<T>     orderCustom(Property property, java.lang.String customOrderForProperty)  // 排序,自定义
QueryBuilder<T>     orderRaw(java.lang.String rawOrder)  // 排序,SQL 语句
QueryBuilder<T>     preferLocalizedStringOrder()  // 本地化字符串排序,用于加密数据库无效
QueryBuilder<T>     stringOrderCollation(java.lang.String stringOrderCollation)  // 自定义字符串排序,默认不区分大小写

WhereCondition     and(WhereCondition cond1, WhereCondition cond2, WhereCondition... condMore)  // 条件,AND 连接
WhereCondition     or(WhereCondition cond1, WhereCondition cond2, WhereCondition... condMore)  // 条件,OR 连接


Query 重复查询

// Joe,1970
Query query = userDao.queryBuilder().where(
Properties.FirstName.eq("Joe"), Properties.YearOfBirth.eq(1970)
).build();
List joesOf1970 = query.list();

// Maria,1977
query.setParameter(0, "Maria");
query.setParameter(1, 1977);
List mariasOf1977 = query.list();
// QueryBuilder
Query<T>     build()
CursorQuery     buildCursor()
CountQuery<T>     buildCount()
DeleteQuery<T>     buildDelete()

// Query
// 设置查询参数,从 0 开始
Query<T>     setParameter(int index, java.lang.Object parameter)
Query<T>     setParameter(int index, java.lang.Boolean parameter)
Query<T>     setParameter(int index, java.util.Date parameter)
void     setLimit(int limit)  // 限制返回数
void     setOffset(int offset)  // 偏移结果起始位,配合limit(int)使用

// Query 绑定线程,执行非本线程的 Query 抛异常,调用获取本线程 Query
Query<T>     forCurrentThread()  // 获取本线程 Query


获取查询结果

// QueryBuilder、Query
T     unique()  // 返回唯一结果或者 null
T     uniqueOrThrow()  // 返回唯一非空结果,如果 null 则抛异常
java.util.List<T>     list()  // 返回结果集进内存
// 懒加载,须在 try/finally 代码中关闭。
LazyList<T>     listLazy()  // 第一次使用返回结果集,所有数据使用后会自动关闭
LazyList<T>     listLazyUncached()  // 返回虚拟结果集,数据库读取不缓存
CloseableListIterator<T>     listIterator()  // 懒加载数据迭代器,不缓存,所有数据使用后会自动关闭

// QueryBuilder、CountQuery
long     count()  // 获取结果数量


SQL 查询

// QueryBuilder.where() 配合 WhereCondition.StringCondition() 实现SQL查询
Query query = userDao.queryBuilder()
.where(new WhereCondition.StringCondition("_ID IN (SELECT USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 0)"))
.build();

// Dao.queryRawCreate() 实现SQL查询
Query query = userDao.queryRawCreate(  ", GROUP G WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin");
// Dao
java.util.List<T>     queryRaw(java.lang.String where, java.lang.String... selectionArg)
Query<T>     queryRawCreate(java.lang.String where, java.lang.Object... selectionArg)
Query<T>     queryRawCreateListArgs(java.lang.String where, java.util.Collection<java.lang.Object> selectionArg)

// WhereCondition.PropertyCondition
PropertyCondition(Property property, java.lang.String op)
PropertyCondition(Property property, java.lang.String op, java.lang.Object value)
PropertyCondition(Property property, java.lang.String op, java.lang.Object[] values)

// WhereCondition.StringCondition
StringCondition(java.lang.String string)
StringCondition(java.lang.String string, java.lang.Object value)
StringCondition(java.lang.String string, java.lang.Object... values)


DeleteQuery 删除查询

DeleteQuery<T>     buildDelete()  // QueryBuilder


查询日志

QueryBuilder.LOG_SQL = true;
QueryBuilder.LOG_VALUES = true;


DaoSession 增删改查

// DaoSession 的方法转换成 Dao 的对应方法执行
<T> long     insert(T entity)
<T> long     insertOrReplace(T entity)
<T> void     delete(T entity)
<T> void     deleteAll(java.lang.Class<T> entityClass)
<T> void     update(T entity)
<T,K> T     load(java.lang.Class<T> entityClass, K key)
<T,K> java.util.List<T>     loadAll(java.lang.Class<T> entityClass)
<T> QueryBuilder<T>     queryBuilder(java.lang.Class<T> entityClass)
<T,K> java.util.List<T>     queryRaw(java.lang.Class<T> entityClass, java.lang.String where, java.lang.String... selectionArgs)
<T> void     refresh(T entity)


进阶用法

联合查询

// 芝麻街住户
QueryBuilder<User> queryBuilder = userDao.queryBuilder();
queryBuilder.join(Address.class, AddressDao.Properties.userId)
.where(AddressDao.Properties.Street.eq("Sesame Street"));
List<User> users = queryBuilder.list();

// 欧洲超过百万人口的城市
QueryBuilder qb = cityDao.queryBuilder().where(Properties.Population.ge(1000000));
Join country = qb.join(Properties.CountryId, Country.class);
Join continent = qb.join(country, CountryDao.Properties.ContinentId,
Continent.class, ContinentDao.Properties.Id);
continent.where(ContinentDao.Properties.Name.eq("Europe"));
List<City> bigEuropeanCities = qb.list();

// 爷爷叫林肯的人
QueryBuilder qb = personDao.queryBuilder();
Join father = qb.join(Person.class, Properties.FatherId);
Join grandfather = qb.join(father, Properties.FatherId, Person.class, Properties.Id);
grandfather.where(Properties.Name.eq("Lincoln"));
List<Person> lincolnDescendants = qb.list();
// QueryBuilder,联合查询
<J> Join<T,J>     join(java.lang.Class<J> destinationEntityClass, Property destinationProperty)
<J> Join<T,J>     join(Property sourceProperty, java.lang.Class<J> destinationEntityClass)
<J> Join<T,J>     join(Property sourceProperty, java.lang.Class<J> destinationEntityClass, Property destinationProperty)
<J> Join<T,J>     join(Join<?,T> sourceJoin, Property sourceProperty, java.lang.Class<J> destina


4.数据库升级

使用GreenDaoUpgradeHelper对开始的数据库帮助类进行修改即可

首先将app下的build.gradle进行修改即可
//schemaVersion: 数据库schema版本,也可以理解为数据库版本号
//daoPackage:设置DaoMaster、DaoSession、Dao包名
//targetGenDir:设置DaoMaster、DaoSession、Dao目录
//targetGenDirTest:设置生成单元测试目录
//generateTests:设置自动生成单元测试用例
greendao {
schemaVersion 2
daoPackage 'com.gjn.msdemo.green'
targetGenDir 'src/main/java'
}
这边升级为2了 

然后我在原来的GDUser中加入一个参数
private String remarks;


之后创建一个升级帮助类
UpgradeHelper.class
package com.gjn.msdemo.util;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;

import com.github.yuweiguocn.library.greendao.MigrationHelper;
import com.gjn.msdemo.green.DaoMaster;
import com.gjn.msdemo.green.GDUserDao;
import com.gjn.msdemo.green.TUserDao;

import org.greenrobot.greendao.database.Database;

/**
* UpgradeHelper
* Author: gjn.
* Time: 2017/9/7.
*/

public class UpgradeHelper extends DaoMaster.OpenHelper {
public UpgradeHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() {
@Override
public void onCreateAllTables(Database db, boolean ifNotExists) {
DaoMaster.createAllTables(db,ifNotExists);
}

@Override
public void onDropAllTables(Database db, boolean ifExists) {
DaoMaster.dropAllTables(db,ifExists);
}
}, GDUserDao.class, TUserDao.class);
}
}
继承DaoMaster.OpenHelper 重写 onUpgrade方法
其中后续需要加入 已有的Dao类

在修改数据库帮助类
GreenDaoHelper改.class
package com.gjn.msdemo.util;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;

import com.gjn.msdemo.green.DaoMaster;
import com.gjn.msdemo.green.DaoSession;

/**
* GreenDaoHelper
* Author: gjn.
* Time: 2017/9/6.
*/

public class GreenDaoHelper {
private static DaoMaster.DevOpenHelper devOpenHelper;
private static SQLiteDatabase database;
private static DaoMaster daoMaster;
private static DaoSession daoSession;

/**
* 初始化 建议放在Application中
* @param context
*/
public static void initDatabase(Context context){
// 注意:默认的 DaoMaster.DevOpenHelper 会在数据库升级时,删除所有的表,意味着这将导致数据的丢失。
// 所以,在正式的项目中,你还应该做一层封装,来实现数据库的安全升级。
//        devOpenHelper = new DaoMaster.DevOpenHelper(context,"msdemo_db",null);
//        database = devOpenHelper.getWritableDatabase();

//引用升级帮助类
UpgradeHelper helper = new UpgradeHelper(context,"msdemo_db",null);
database = helper.getWritableDatabase();

// 注意:该数据库连接属于 DaoMaster,所以多个 Session 指的是相同的数据库连接。
daoMaster = new DaoMaster(database);
daoSession = daoMaster.newSession();
}

public static SQLiteDatabase getDatabase() {
return database;
}

public static DaoSession getDaoSession() {
return daoSession;
}
}


其中重点
//引用升级帮助类
UpgradeHelper helper = new UpgradeHelper(context,"msdemo_db",null);
database = helper.getWritableDatabase();


之后再执行安装新的app就可以了

操作如下
查询数据->新增数据->查询数据



可以发现 原来的数据库中添加了新的数据但是确没有值 为null  后面新增的就有了

至此本篇greenDao3.2.2的基本用法就算说完!当做记录了!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: