Java进阶知识10 Hibernate一对多_多对一双向关联(Annotation+XML实现)

时间:2021-09-18 19:34:45

本文知识点(目录):

1、Annotation 注解版(只是测试建表)
    2、XML版 的实现(只是测试建表)
    3、附录(Annotation 注解版CRUD操作)【注解版有个问题:插入值时,外键为null,用xml 版可以解决此问题】



1、Annotation 注解版

1.1、在“一”的一方(Customer类)加@OneToMany;在“多”的一方(Order类)加@ManyToOne

1.2、创建Customer类和Order类

注意:必须在“一”的一方配mappedBy=”XXXX”;否则会多一个中间表,或者出现两个外键(加@JoinColumn的时候)。
          XXXX表示在“多”的一方中,定义的“一”的一方类的一个实例/对象

 package com.shore.model;

 import java.util.HashSet;
import java.util.Set; import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table; /**
* @author DSHORE/2019-9-20
* 一对多,双向关联(注解版)
* 一对多双向关联:在“一”的一方加(@OneToMany),在“多”的一方加(@ManyToOne)
*/
@Entity
@Table(name="anno_customer")
public class Customer {//顾客 (“一”的一方);一对多,在“一”的一方加Set;并且在该对象的get方法上加@OneToMany
private Integer id;
private String name;
private Integer age;
private Set<Order> orders = new HashSet<Order>();
/**
* List 有序,可重复,可以用index取值(get(index))
* Set 无序,不可重复
*/ @Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
} @OneToMany(mappedBy="customer") //告诉JVM在Order对象的customer中已经做了ManyToOne的映射
//@JoinColumn(name="customerId")
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
}

Order类

 package com.shore.model;

 import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table; /**
* @author DSHORE/2019-9-20
* 一对多,单向关联(注解版)
*/
@Entity
@Table(name="anno_order") //Order是MySQL数据库关键字。需重新定义表名
public class Order {//订单 (“多”的一方); 一对多,在“多”的一方加@ManyToOne
private Integer id;
private String number;
private Float sum;
private Customer customer; @Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Float getSum() {
return sum;
}
public void setSum(Float sum) {
this.sum = sum;
} @ManyToOne
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}

1.3、创建hibernate.cfg.xml核心配置文件

 <?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hibernate</property>
<property name="connection.username">root</property>
<property name="connection.password">123456</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">create</property> <mapping class="com.shore.model.Customer" />
<mapping class="com.shore.model.Order" />
</session-factory>
</hibernate-configuration>

1.4、开始测试

 package com.shore.test;

 import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.Test; /**
* @author DSHORE/2019-9-20
*
*/
public class AnnotationTest {
@Test
public void test() {//简单测试,只创建表,不插入数据
//注解版,用AnnotationConfiguration()方法
new SchemaExport(new AnnotationConfiguration().configure()).create(
false, true);
}
}

测试结果图:

Java进阶知识10 Hibernate一对多_多对一双向关联(Annotation+XML实现)

Java进阶知识10 Hibernate一对多_多对一双向关联(Annotation+XML实现)    Java进阶知识10 Hibernate一对多_多对一双向关联(Annotation+XML实现)

Java进阶知识10 Hibernate一对多_多对一双向关联(Annotation+XML实现)

2、XML版 的实现

2.1、创建Customer类和Order类

 package com.shore.model;

 import java.util.HashSet;
import java.util.Set; /**
* @author DSHORE/2019-9-20
* 一对多,双向关联(xml版)
*/
public class Customer {//顾客 (“一”的一方);一对多,在“一”的一方加Set
private Integer id;
private String name;
private Integer age;
private Set<Order> orders = new HashSet<Order>();
/**
* List 有序,可重复,可以用index取值(get(index))
* Set 无序,不可重复
*/ public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
}

Order类

 package com.shore.model;

 /**
* @author DSHORE/2019-9-20
* 一对多,单向关联(xml版)
*/
public class Order {//订单 (“多”的一方)
private Integer id;
private String number;
private Float sum;
private Customer customer; public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Float getSum() {
return sum;
}
public void setSum(Float sum) {
this.sum = sum;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}

2.2、创建 Customer.hbm.xml 配置文件和 Order.hbm.xml 配置文件

 <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.shore.model">
<class name="Customer" table="customer_xml">
<id name="id">
<generator class="native"/>
</id>
<property name="name" type="java.lang.String"/>
<property name="age" type="java.lang.Integer"/>
<set name="orders">
<key column="customerId"></key>
<one-to-many class="com.shore.model.Order"/>
</set>
</class>
</hibernate-mapping>

Order.hbm.xml 配置文件

 <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.shore.model">
<class name="Order" table="order_xml">
<id name="id">
<generator class="native"/>
</id>
<property name="number" type="java.lang.String"/>
<property name="sum" type="java.lang.Float"/>
<many-to-one name="customer" column="customerId"/>
</class>
</hibernate-mapping>

2.3、创建hibernate.cfg.xml 核心配置文件

 <?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hibernate</property>
<property name="connection.username">root</property>
<property name="connection.password">123456</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">create</property> <!-- <mapping class="com.shore.model.Customer" />
<mapping class="com.shore.model.Order" /> -->
<mapping resource="com/shore/model/Customer.hbm.xml" />
<mapping resource="com/shore/model/Order.hbm.xml" />
</session-factory>
</hibernate-configuration>

2.4、开始测试

 package com.shore.test;

 import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.Test; /**
* @author DSHORE/2019-9-20
*
*/
public class AnnotationTest {
@Test
public void test() {//简单测试,只创建表,不插入数据
//注解版,用Configuration()方法
new SchemaExport(new Configuration().configure()).create(
false, true);
}
}

测试结果图:

Java进阶知识10 Hibernate一对多_多对一双向关联(Annotation+XML实现)

Java进阶知识10 Hibernate一对多_多对一双向关联(Annotation+XML实现)    Java进阶知识10 Hibernate一对多_多对一双向关联(Annotation+XML实现)

Java进阶知识10 Hibernate一对多_多对一双向关联(Annotation+XML实现)

附录

1、一对多_多对一,双向关联注解版CRUD操作

1.1、创建Customer类和Order类

 package com.shore.model;

 import java.util.HashSet;
import java.util.Set; import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table; /**
* @author DSHORE/2019-9-20
* 一对多_多对一(注解版) CRUD操作
* 一对多双向关联:在“一”的一方加(@OneToMany),在“多”的一方加(@ManyToOne)【即:一对多_多对一】
*/
@Entity
@Table(name="anno_customer")
public class Customer {//顾客 (“一”的一方);一对多,在“一”的一方加Set;并且在该对象的get方法上加@OneToMany
private Integer id;
private String name;
private Integer age;
private Set<Order> orders = new HashSet<Order>();
/**
* List 有序,可重复,可以用index取值(get(index))
* Set 无序,不可重复
*/ @Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
} /**
* cascade:级联(进行CRUD操作时,需要加上cascade=CascadeType.ALL。all表示:包括增删改查这几个操作)。
* mappedBy:映射(告诉JVM在Order对象的customer中已经做了ManyToOne的映射)。
*/
@OneToMany(mappedBy="customer",cascade=CascadeType.ALL)
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
}

Order类

 package com.shore.model;

 import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table; /**
* @author DSHORE/2019-9-20
* 一对多_多对一(注解版) CRUD操作
*/
@Entity
@Table(name="anno_order") //Order是MySQL数据库关键字。需重新定义表名
public class Order {//订单 (“多”的一方); 一对多,在“多”的一方加@ManyToOne
private Integer id;
private String number;
private Float sum;
private Customer customer; @Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Float getSum() {
return sum;
}
public void setSum(Float sum) {
this.sum = sum;
} @ManyToOne(cascade=CascadeType.ALL) //cascade:级联
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}

1.2、创建hibernate.cfg.xml 核心配置文件

 <?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hibernate2</property>
<property name="connection.username">root</property>
<property name="connection.password">123456</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">update</property> <mapping class="com.shore.model.Customer" />
<mapping class="com.shore.model.Order" />
</session-factory>
</hibernate-configuration>

1.3、开始测试

 package com.shore.test;

 import java.util.HashSet;
import java.util.Set; import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test; import com.shore.model.Customer;
import com.shore.model.Order; /**
* @author DSHORE/2019-9-20
* 一对多_多对一(注解版) CRUD操作
*/
public class MyTest {
public static SessionFactory sessionFactory = null;
public static Session session = null; @BeforeClass
public static void buildSessionFactory() {
sessionFactory = new AnnotationConfiguration().configure()
.buildSessionFactory();
} @AfterClass
public static void close() {
session.close();
sessionFactory.close();
} /**
* Create
*/
//多对一
@Test
public void testSaveOrder() {//以“多”的一方为主,进行测试
session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setName("张三");
customer.setAge(18); Order order = new Order();
order.setNumber("1008");
order.setSum(8.90f);
order.setCustomer(customer);
// session.save(customer); //已经使用了级联,这句话不需要了
session.save(order);
transaction.commit();
} //一对多 //【要么使用上面的testSaveOrder()方法,以“多”的一方为主,添加数据;要就用xml配置文件的方式来做】
@Test //一对多双向关联,以“一”的一方为主,进行测试,多的一方Order表中的外键(customer_id)是空的(null);解决方法在最下面“补充”处
public void testSaveCustomer() {//以“一”的一方为主,进行测试
session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Order order1 = new Order();
order1.setNumber("2008");
order1.setSum(9.90f);
Order order2 = new Order();
order2.setNumber("2010");
order2.setSum(99.90f); Customer customer = new Customer();
customer.setName("李四");
customer.setAge(20); Set<Order> orders = new HashSet<Order>();
orders.add(order1);
orders.add(order2);
customer.setOrders(orders);
session.save(customer);
transaction.commit();
} /**
* Read
* get:即时查询
* load:懒加载
*/
//多对一
@Test
public void testGetOrder() {
session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Order order = (Order) session.get(Order.class, 1); //即时查询
transaction.commit(); System.out.println("id:"+order.getId());
System.out.println("number:"+order.getNumber());
System.out.println("customer:"+order.getCustomer());
} //一对多
@Test
public void testGetCustomer() {
session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = (Customer) session.get(Customer.class, 1);
transaction.commit(); System.out.println("id:"+customer.getId());
System.out.println("name:"+customer.getName());
System.out.println("orders:"+customer.getOrders());
System.out.println("orders-size:"+customer.getOrders().size());
} /**
* Update
*/
//多对一
@Test
public void testUpdateOrderProperties(){
session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Order order = (Order) session.load(Order.class, 2); //懒加载
Customer customer = order.getCustomer();
customer.setAge(20);
customer.setName("赵六");
order.setCustomer(customer);
session.save(order);
transaction.commit();
} //多对一
@Test
public void testUpdateOrderPK(){
session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Order order = (Order) session.load(Order.class, 1);
Customer customer = (Customer) session.load(Customer.class, 2);
order.setCustomer(customer);
session.save(order);
transaction.commit();
} //一对多
@Test
public void testUpdateCustomer(){
session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = (Customer) session.load(Customer.class, 1);
Object[] objects = customer.getOrders().toArray();
Order order = (Order) objects[0];
order.setSum(20.00f);
session.save(order);
transaction.commit();
} /**
* Delete
*/
//多对一:多个order对应一个customer
@Test
public void testDeleteOrder(){//因为已经级联,所以删除id=3的订单时,对应的顾客也同时被删除
session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction(); Order order = (Order) session.load(Order.class, 3);
session.delete(order); transaction.commit();
} //一对多
@Test
public void testDeleteCustomer(){
session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction(); Customer customer = (Customer) session.get(Customer.class, 2);
session.delete(customer); transaction.commit();
}
}

补充:解决上面附录中第1.3小点测试类中的第二个测试方法testSaveCustomer()的问题。

该方法向数据库中插入数据时,Order表中的外键customer_id为null,一直插不进来有效的值。解决方法如下:首先我们得将注解的方式改为XML的方式,并在“一”的一方的xml配置文件加上inverse="false",且还需要在两方的xml配置文件中加上cascade="all"。即可解决外键一直插不进值得问题。

cascade关系有以下几种:
  all: 所有情况下均进行关联操作,即save-update和delete。
  none: 所有情况下均不进行关联操作。这是默认值。
  save-update: 在执行save/update/saveOrUpdate时进行关联操作。
  delete: 在执行delete 时进行关联操作。
  all-delete-orphan: 当一个节点在对象图中成为孤儿节点时,删除该节点

inverse 维护关系:
    inverse的值是boolean类型的,也就是只能设置为true或false。 如果一方的映射文件中设置为true,说明在映射关系(一对多,多对多等)中让对方来维护关系。如果为false,就自己来维护关系。默认值是false。 并且这属性只能在一端设置。比如一对多,这个一端。也就是在有set集合的这方设置。
  1、维护外键的关系:通俗点讲,就是由哪一方去设置这个被外键约束的字段的值。
  2、维护级联的关系:就是说如果让对方维护关系,则自己方的级联将会失效,对方设置的级联有用,如果自己维护关系,则自己方的级联会有用,但是对方设置的级联就会失效。

下面我们来看具体的代码实现:

Customer和Order实体类上面“附录”中有,就不在帖出来了。这个是xml版本的,把实体类中的所有注解去掉即可,其他的都不变。

1、创建 Customer.hbm.xml 配置文件和 Order.hbm.xml 配置文件

 <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.shore.model">
<class name="Customer" table="customer_xml">
<id name="id">
<generator class="native"/>
</id>
<property name="name" type="java.lang.String"/>
<property name="age" type="java.lang.Integer"/> <!-- 如果inverse="true",让对方维护关系,此时这里的cascade(级联)设置没什么用,因为自身不维护关系,它也就失效了。 -->
<set name="orders" inverse="false" cascade="all"> <!-- 解决外键为null的问题,主要在此 inverse="false" -->
<key column="customerId"></key>
<one-to-many class="com.shore.model.Order"/>
</set>
</class>
</hibernate-mapping>

Order.hbm.xml 配置文件

 <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.shore.model">
<class name="Order" table="order_xml">
<id name="id">
<generator class="native"/>
</id>
<property name="number" type="java.lang.String"/>
<property name="sum" type="java.lang.Float"/>
<many-to-one name="customer" column="customerId" cascade="all"/> <!-- cascade:级联 -->
</class>
</hibernate-mapping>

hibernate.cfg.xml 和上面的一样,此处也不贴出来了。

2、测试类,开始测试

 package com.shore.test;

 import java.util.HashSet;
import java.util.Set; import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test; import com.shore.model.Customer;
import com.shore.model.Order; /**
* @author DSHORE/2019-9-20
*
*/
public class CRUDTest {
public static SessionFactory sessionFactory = null;
public static Session session = null; @BeforeClass
public static void buildSessionFactory() {
sessionFactory = new AnnotationConfiguration().configure()
.buildSessionFactory();
} @AfterClass
public static void close() {
session.close();
sessionFactory.close();
}
/**
* Create
*/
//多对一
@Test
public void testSaveOrder() {//以“多”的一方为主,进行测试
session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setName("张三");
customer.setAge(18); Order order = new Order();
order.setNumber("1008");
order.setSum(8.90f);
order.setCustomer(customer);
// session.save(customer); //已经使用了级联,这句话不需要了
session.save(order);
transaction.commit();
} //一对多
@Test //一对多双向关联,以“一”的一方为主,进行测试,多的一方Order表中的外键(customer_id)是空的(null)
public void testSaveCustomer() {//以“一”的一方为主,进行测试
session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Order order1 = new Order();
order1.setNumber("2008");
order1.setSum(19.90f);
Order order2 = new Order();
order2.setNumber("2010");
order2.setSum(99.90f); Customer customer = new Customer();
customer.setName("李四");
customer.setAge(20); Set<Order> orders = new HashSet<Order>();
orders.add(order1);
orders.add(order2);
customer.setOrders(orders);
session.save(customer);
transaction.commit();
}
}

Java进阶知识10 Hibernate一对多_多对一双向关联(Annotation+XML实现)     Java进阶知识10 Hibernate一对多_多对一双向关联(Annotation+XML实现)

Hibernate一对一单向关联映射(Annotation+XML实现):https://www.cnblogs.com/dshore123/p/11545058.html
Hibernate一对一双向关联映射(Annotation+XML实现):https://www.cnblogs.com/dshore123/p/11545077.html

Hibernate多对一单向关联映射(Annotation+XML实现):https://www.cnblogs.com/dshore123/p/11553213.html
Hibernate一对多单向关联映射(Annotation+XML实现):https://www.cnblogs.com/dshore123/p/11553215.html
Hibernate一对多和多对一双向关联映射(Annotation+XML实现):https://www.cnblogs.com/dshore123/p/11560433.html

Hibernate多对多单向关联映射(Annotation+XML实现):https://www.cnblogs.com/dshore123/p/11568536.html
Hibernate多对多双向关联映射(Annotation+XML实现):https://www.cnblogs.com/dshore123/p/11568963.html

原创作者:DSHORE

作者主页:http://www.cnblogs.com/dshore123/

原文出自:https://www.cnblogs.com/dshore123/p/11560433.html

版权声明:欢迎转载,转载务必说明出处。(如果本文对您有帮助,可以点击一下右下角的 推荐,或评论,谢谢!