Hibernate4学习总结(4)--注解形式的集合映射,关联关系映射
来源:互联网 发布:spss怎么导入excel数据 编辑:程序博客网 时间:2024/05/18 01:44
本文将接着上文,讲解hibernate4的集合映射的注解和关联关系映射的注解。本文包括两个部分:
- 集合映射的注解。
- 关联关系映射的注解。
一、集合映射的注解
当持久化中有一个属性是集合(Set、List、Map),就要用到集合映射。集合属性会单独生成一张表。定义集合属性时面向接口,并且集合属性需要程序员自己初始化(例如:private List<String> list = new ArrayList<String>();)。
集合属性都要用到的注解:
- @ElementCollection(fetch="该属性的加载策略",targetClass="集合中元素的类型")。
fetch=FetchType.EAGER: 立即加载
fetch=FetchType.LAZY: 延迟加载- @CollectionTable(name="表名") : 指定集合生成表的相关信息。
1.1 List集合映射(有序集合): @OrderColumn() 指定排序列
注意:List集合生成表的主键列:(外键列 + 排序列)
1.1.1 List<String> : 集合中元素是标量类型 8个基本类型、包装类、String。
例如:Employee类
package edu.scut.e_CollectionMapping_List;import java.io.Serializable;import java.util.ArrayList;import java.util.List;import javax.persistence.*;@Entity@Table(name="EMP_INFO")public class Employee implements Serializable {@Id @GeneratedValue(strategy=GenerationType.AUTO)private int id; private String name; private int age; @ElementCollection(fetch=FetchType.LAZY, //加载策略,延迟加载targetClass=String.class) //指定集合中元素的类型 @CollectionTable(name="ADD_INFO") //指定集合生成的表@OrderColumn(name="O_ID") //指定排序列的名称 private List<String> address = new ArrayList<String>(); public int getId() {return id; } public List<String> getAddress() { return address;}public void setAddress(List<String> address) {this.address = address;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}
生成两张表:emp_info表
add_info表
1.1.2 List<Address> : 集合中元素是复合类型。复合属性类上需要加注解:@Embeddable。
例如:Person类
package edu.scut.e_CollectionMapping_List;import java.util.ArrayList;import java.util.List;import javax.persistence.*;@Entity@Table(name="PER_INFO")public class Person {@Id @GeneratedValue(strategy=GenerationType.AUTO)private int id; private String name;@ElementCollection(fetch=FetchType.LAZY, //加载策略 targetClass=Address.class) //指定元素中集合的类型@CollectionTable(name="PER_ADD_INFO") //指定集合生成的表 @OrderColumn(name="O_A_ID") //指定排序列的名称 private List<Address> address = new ArrayList<Address>(); public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; }public List<Address> getAddress() { return address; } public void setAddress(List<Address> address) { this.address = address; }}Address类
package edu.scut.e_CollectionMapping_List;import javax.persistence.Embeddable;@Embeddablepublic class Address {private String zip;private String info;public String getZip() {return zip;}public void setZip(String zip) {this.zip = zip;}public String getInfo() {return info;}public void setInfo(String info) {this.info = info;}}
生成的两张表:per_info表
per_add_info表
1.2 Set集合映射(无序集合)
注意: Set集合生成表的主键列:(外键列 + Set集合的元素列 .. )
1.2.1· Set<String> : 集合中元素是标量类型 8个基本类型、包装类、String。Set集合生成表默认是没有主键列的。如果想要生成主键列,需要为Set集合添加非空约束!
例如:Employee类
package edu.scut.e_CollectionMapping_Set;import java.io.Serializable;import java.util.ArrayList;import java.util.HashSet;import java.util.List;import java.util.Set;import javax.persistence.*;@Entity@Table(name="EMP_INFO")public class Employee implements Serializable { @Id @GeneratedValue(strategy=GenerationType.AUTO)private int id; private String name; private int age;@ElementCollection(fetch=FetchType.LAZY, //加载策略,延迟加载 targetClass=String.class) //指定集合中元素的类型@CollectionTable(name="ADD_INFO") //指定集合生成的表@Column(nullable=false) //添加非空约束 private Set<String> address = new HashSet<String>();public int getId() { return id;} public Set<String> getAddress() { return address; }public void setAddress(Set<String> address) { this.address = address; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; }}1.2.2 Set<Address> : 集合中元素是复合类型。
复合属性类上需要加注解:@Embeddable
Set集合生成表默认是没有主键列的。如果想要生成主键列,需要为Set集合的元素类的属性上添加非空约束!
例如:Person类
package edu.scut.e_CollectionMapping_Set;import java.util.ArrayList;import java.util.HashSet;import java.util.List;import java.util.Set;import javax.persistence.*;@Entity@Table(name="PER_INFO")public class Person {@Id @GeneratedValue(strategy=GenerationType.AUTO)private int id; private String name; @ElementCollection(fetch=FetchType.LAZY, //加载策略 targetClass=Address.class) //指定元素中集合的类型 @CollectionTable(name="PER_ADD_INFO") //指定集合生成的表 private Set<Address> address = new HashSet<Address>(); public int getId() { return id;} public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Address> getAddress() { return address; }public void setAddress(Set<Address> address) { this.address = address; }}Address类
package edu.scut.e_CollectionMapping_Set;import javax.persistence.Column;import javax.persistence.Embeddable;@Embeddablepublic class Address {//@Column(nullable=false)private String zip;@Column(nullable=false)private String info;public String getZip() {return zip;}public void setZip(String zip) {this.zip = zip;}public String getInfo() {return info;}public void setInfo(String info) {this.info = info;}}
1.3 Map集合映射(有Map的key): @MapKeyColumn() 指定Map的key生成的列
注意: Map集合生成表的主键列:(外键列 + Map的Key)
1.3.1 Map<String, String> : 集合中元素是标量类型 8个基本类型、包装类、String。
例如:Employee类
package edu.scut.e_CollectionMapping_Map;import java.io.Serializable;import java.util.ArrayList;import java.util.HashMap;import java.util.HashSet;import java.util.List;import java.util.Map;import java.util.Set;import javax.persistence.*;@Entity@Table(name="EMP_INFO")public class Employee implements Serializable {@Id@GeneratedValue(strategy=GenerationType.AUTO)private int id; private String name;private int age; @ElementCollection(fetch=FetchType.LAZY, //加载策略,延迟加载targetClass=String.class) //指定集合中元素的类型 @CollectionTable(name="ADD_INFO") //指定集合生成的表@MapKeyColumn(name="M_KEY") //指定map的key生成的列 private Map<String, String> address = new HashMap<String, String>(); public int getId() { return id;}public Map<String, String> getAddress() { return address; }public void setAddress(Map<String, String> address) { this.address = address; } public void setId(int id) {this.id = id;} public String getName() { return name; } public void setName(String name) {this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age;}}1.3.2 Map<String, Address> : 集合中元素是复合类型。
复合属性类上需要加注解:@Embeddable
例如:Person类package edu.scut.e_CollectionMapping_Map;import java.util.HashMap;import java.util.HashSet;import java.util.Map;import java.util.Set;import javax.persistence.*;@Entity@Table(name="PER_INFO")public class Person { @Id@GeneratedValue(strategy=GenerationType.AUTO) private int id; private String name; @ElementCollection(fetch=FetchType.LAZY, //加载策略 targetClass=Address.class) //指定元素中集合的类型 @CollectionTable(name="PER_ADD_INFO") //指定集合生成的表 @MapKeyColumn(name="ADD_KEY") //指定key生成的列private Map<String,Address> address = new HashMap<String,Address>(); public int getId() { return id; }public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name;} public Map<String,Address> getAddress() { return address; } public void Address(Map<String,Address> address) { this.address = address; }}Address类
package edu.scut.e_CollectionMapping_Map;import javax.persistence.Column;import javax.persistence.Embeddable;@Embeddablepublic class Address {//@Column(nullable=false)private String zip;@Column(nullable=false)private String info;public String getZip() {return zip;}public void setZip(String zip) {this.zip = zip;}public String getInfo() {return info;}public void setInfo(String info) {this.info = info;}}
二、关联关系映射的注解(重点)
单向关联映射和双向关联映射的最大区别就是在查询数据时,单向关联只能通过一边进行查询,而双向关联两边都可以互相查询。
2.1 单向关联映射(一边配置)
2.1.1 一对一
/** 一方*/@OneToOne(fetch=FetchType.LAZY,cascade=CascadeType.ALL,targetEntity=Persons.class) //维护关联关系(从表)/** 生成外键列*/@JoinColumn(name="P_ID",unique=true,referencedColumnName="id")通过公民(Person)和身份证(IdCards)的例子来说明:
Person.java
package edu.scut.f_AssoMap_single_one2one;import javax.persistence.*;//公民(一方)@Entity@Table(name="PER_INFO")public class Persons { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() {return name; }public void setName(String name) { this.name = name; }}IdCards.java
package edu.scut.f_AssoMap_single_one2one;import javax.persistence.*;//身份证(一方)@Entity@Table(name="IDCD_INFO")public class IdCards {@Id@GeneratedValue(strategy=GenerationType.AUTO)@Column(name="IDCD_ID")private int id;private String cardno;/** 一方*/@OneToOne(fetch=FetchType.LAZY,cascade=CascadeType.ALL,targetEntity=Persons.class) //维护关联关系(从表)/** 生成外键列*/@JoinColumn(name="P_ID",unique=true,referencedColumnName="id")private Persons persons;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getCardno() {return cardno;}public void setCardno(String cardno) {this.cardno = cardno;}public Persons getPersons() {return persons;}public void setPersons(Persons persons) {this.persons = persons;}}2.1.2 一对多
/** 一方*/ @OneToMany(fetch=FetchType.LAZY, //延迟加载targetEntity=Orders.class, //目标对象 cascade=CascadeType.ALL,//级联操作 orphanRemoval=true) //孤儿删除 @JoinColumn(name="C_ID",referencedColumnName="CUS_ID")通过客户(Customers)和订单(Orders)的例子说明:
Customers.java
package edu.scut.f_AssoMap_single_one2n;import java.util.HashSet;import java.util.Set;import javax.persistence.*;//客户(一方)@Entity@Table(name="CUS_INFO")public class Customers {@Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="CUS_ID")private int id; private String name;/** 一方*/ @OneToMany(fetch=FetchType.LAZY, //延迟加载targetEntity=Orders.class, //目标对象 cascade=CascadeType.ALL,//级联操作 orphanRemoval=true) //孤儿删除 @JoinColumn(name="C_ID",referencedColumnName="CUS_ID")private Set<Orders> orders = new HashSet<Orders>(); public int getId() {return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Orders> getOrders() { return orders; } public void setOrders(Set<Orders> orders) { this.orders = orders; }}Orders.java
package edu.scut.f_AssoMap_single_one2n;import javax.persistence.*;;import javax.persistence.Table;//订单(多方)@Entity@Table(name="ORD_INFO")public class Orders { @Id@GeneratedValue(strategy=GenerationType.AUTO) private int id; private String orderno; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getOrderno() {return orderno; } public void setOrderno(String orderno) { this.orderno = orderno; }}2.1.3 多对一
/** 多方*/ @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL, targetEntity=Customers.class)/** 生成外键列*/@JoinColumn(name="C_ID",referencedColumnName="CUS_ID")通过客户(Customers)和订单(Orders)的例子说明:
Customers.java
package edu.scut.f_AssoMap_single_n2one;import java.util.HashSet;import java.util.Set;import javax.persistence.*;//客户(一方)@Entity@Table(name="CUS_INFO")public class Customers {@Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="CUS_ID")private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name;} public void setName(String name) { this.name = name; }}Orders.java
package edu.scut.f_AssoMap_single_n2one;import javax.persistence.*;//订单(多方)@Entity@Table(name="ORD_INFO")public class Orders {@Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String orderno; /** 多方*/ @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL, targetEntity=Customers.class) /** 生成外键列*/ @JoinColumn(name="C_ID",referencedColumnName="CUS_ID") private Customers customers; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getOrderno() { return orderno; } public void setOrderno(String orderno) {this.orderno = orderno; }public Customers getCustomers() { return customers; } public void setCustomers(Customers customers) {this.customers = customers; }}2.1.4 多对多
/** 多方*/@ManyToMany(fetch=FetchType.LAZY, //延迟加载cascade=CascadeType.ALL,targetEntity=Teacher.class) //目标对象/** 中间表*/@JoinTable(name="TEA_STU", //指定中间表名称joinColumns=@JoinColumn(name="S_ID",referencedColumnName="STU_ID"), //@ManyToMany中没有加mappedby的主键列inverseJoinColumns=@JoinColumn(name="T_ID",referencedColumnName="TEA_ID")) //@ManyToMany中加mappedby的主键列通过老师(Teachers)和学生(Students)的例子说明:
Teachers.java
package edu.scut.f_AssoMap_single_n2n;import java.util.HashSet;import java.util.Set;import javax.persistence.*;//多方@Entity@Table(name="TEA_INFO")public class Teacher {@Id@GeneratedValue(strategy=GenerationType.AUTO)@Column(name="TEA_ID") private int id; private String name;private String dept; public int getId() {return id; } public void setId(int id) {this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name;} public String getDept() { return dept; } public void setDept(String dept) { this.dept = dept; }}Students.java
package edu.scut.f_AssoMap_single_n2n;import java.util.HashSet;import java.util.Set;import javax.persistence.*;//多方@Entity@Table(name="STU_INFO")public class Student {@Id@GeneratedValue(strategy=GenerationType.AUTO)@Column(name="STU_ID")private int id;private String name;private float score;/** 多方*/@ManyToMany(fetch=FetchType.LAZY, //延迟加载cascade=CascadeType.ALL,targetEntity=Teacher.class) //目标对象/** 中间表*/@JoinTable(name="TEA_STU", //指定中间表名称joinColumns=@JoinColumn(name="S_ID",referencedColumnName="STU_ID"), //@ManyToMany中没有加mappedby的主键列inverseJoinColumns=@JoinColumn(name="T_ID",referencedColumnName="TEA_ID")) //@ManyToMany中加mappedby的主键列private Set<Teacher> teachers = new HashSet<Teacher>();public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public float getScore() {return score;}public void setScore(float score) {this.score = score;}public Set<Teacher> getTeachers() {return teachers;}public void setTeachers(Set<Teacher> teachers) {this.teachers = teachers;}}
2.2 双向关联映射(两边同时配置)
2.2.1 一对一
一方:
/** 一方 */@OneToOne(fetch=FetchType.LAZY,targetEntity=IdCards.class,mappedBy="persons", //不维护关联关系(主表)cascade=CascadeType.ALL)另一方:/** 一方*/@OneToOne(fetch=FetchType.LAZY,targetEntity=Persons.class) //维护关联关系(从表)/** 生成外键列*/@JoinColumn(name="P_ID",unique=true,referencedColumnName="id")还是通过公民(Persons)和身份证(IdCards)的例子来说明:
Persons.java
package edu.scut.f_AssoMap_double_one2one;import javax.persistence.*;//公民(一方)@Entity@Table(name="PER_INFO")public class Persons {@Id@GeneratedValue(strategy=GenerationType.AUTO)private int id;private String name;/** 一方 */@OneToOne(fetch=FetchType.LAZY,targetEntity=IdCards.class,mappedBy="persons", //不维护关联关系(主表)cascade=CascadeType.ALL) private IdCards idcards;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public IdCards getIdcards() {return idcards;}public void setIdcards(IdCards idcards) {this.idcards = idcards;}}IdCards.javapackage edu.scut.f_AssoMap_double_one2one;import javax.persistence.*;//身份证(一方)@Entity@Table(name="IDCD_INFO")public class IdCards {@Id@GeneratedValue(strategy=GenerationType.AUTO)@Column(name="IDCD_ID")private int id;private String cardno;/** 一方*/@OneToOne(fetch=FetchType.LAZY,targetEntity=Persons.class) //维护关联关系(从表)/** 生成外键列*/@JoinColumn(name="P_ID",unique=true,referencedColumnName="id")private Persons persons;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getCardno() {return cardno;}public void setCardno(String cardno) {this.cardno = cardno;}public Persons getPersons() {return persons;}public void setPersons(Persons persons) {this.persons = persons;}}2.2.2 一对多
一方:
/** 一方*/@OneToMany(fetch=FetchType.LAZY, //延迟加载targetEntity=Orders.class, //目标对象cascade=CascadeType.ALL, //级联操作orphanRemoval=true, //孤儿删除mappedBy="customers") //指定由哪边维护关系(从表维护)多方:
/** 多方*/@ManyToOne(fetch=FetchType.LAZY,//cascade=CascadeType.ALL,targetEntity=Customers.class)/** 生成外键列*/@JoinColumn(name="C_ID",referencedColumnName="CUS_ID")还是通过客户(Customers)和订单(Orders)的例子说明:
Customers.java
package edu.scut.f_AssoMap_double_one2n;import java.util.HashSet;import java.util.Set;import javax.persistence.*;//客户(一方)@Entity@Table(name="CUS_INFO")public class Customers {@Id @GeneratedValue(strategy=GenerationType.AUTO)@Column(name="CUS_ID")private int id; private String name; /** 一方*/@OneToMany(fetch=FetchType.LAZY, //延迟加载 targetEntity=Orders.class, //目标对象cascade=CascadeType.ALL, //级联操作 orphanRemoval=true, //孤儿删除mappedBy="customers") //指定由哪边维护关系(从表维护)private Set<Orders> orders = new HashSet<Orders>();public int getId() { return id;}public void setId(int id) { this.id = id; } public String getName() {return name; } public void setName(String name) { this.name = name; }public Set<Orders> getOrders() { return orders; }public void setOrders(Set<Orders> orders) { this.orders = orders; }}Orders.java
package edu.scut.f_AssoMap_double_one2n;import javax.persistence.*;//订单(多方)@Entity@Table(name="ORD_INFO")public class Orders { @Id@GeneratedValue(strategy=GenerationType.AUTO) private int id; private String orderno; /** 多方*/ @ManyToOne(fetch=FetchType.LAZY,//cascade=CascadeType.ALL, targetEntity=Customers.class)/** 生成外键列*/ @JoinColumn(name="C_ID",referencedColumnName="CUS_ID") private Customers customers;public int getId() { return id; } public void setId(int id) {this.id = id; } public String getOrderno() {return orderno; }public void setOrderno(String orderno) { this.orderno = orderno; } public Customers getCustomers() { return customers; } public void setCustomers(Customers customers) {this.customers = customers; }}2.2.3 多对多
多方:
/** 多方*/@ManyToMany(fetch=FetchType.LAZY, //延迟加载targetEntity=Student.class, //指定目标对象cascade=CascadeType.ALL,mappedBy="teachers") //老师不维护关联关系另一个多方:
/** 多方*/@ManyToMany(fetch=FetchType.LAZY, //延迟加载targetEntity=Teacher.class) //目标对象/** 中间表*/@JoinTable(name="TEA_STU", //指定中间表名称joinColumns=@JoinColumn(name="S_ID",referencedColumnName="STU_ID"), //@ManyToMany中没有加mappedby的主键列inverseJoinColumns=@JoinColumn(name="T_ID",referencedColumnName="TEA_ID")) //@ManyToMany中加mappedby的主键列还是通过老师(Teachers)和学生(Students)的例子说明:
Teachers.java
package edu.scut.f_AssoMap_double_n2n;import java.util.HashSet;import java.util.Set;import javax.persistence.*;//多方@Entity@Table(name="TEA_INFO")public class Teacher {@Id@GeneratedValue(strategy=GenerationType.AUTO)@Column(name="TEA_ID")private int id;private String name;private String dept;/** 多方*/@ManyToMany(fetch=FetchType.LAZY, //延迟加载targetEntity=Student.class, //目标对象cascade=CascadeType.ALL,mappedBy="teachers") //老师不维护关联关系private Set<Student> students = new HashSet<Student>();public int getId() {return id;}public void setId(int id) {this.id = id; }public String getName() { return name; }public void setName(String name) { this.name = name;} public String getDept() {return dept;} public void setDept(String dept) {this.dept = dept; }public Set<Student> getStudents() { return students;} public void setStudents(Set<Student> students) {this.students = students; }}Students.java
package edu.scut.f_AssoMap_double_n2n;import java.util.HashSet;import java.util.Set;import javax.persistence.*;//多方@Entity@Table(name="STU_INFO")public class Student {@Id@GeneratedValue(strategy=GenerationType.AUTO)@Column(name="STU_ID")private int id;private String name;private float score;/** 多方*/@ManyToMany(fetch=FetchType.LAZY, //延迟加载targetEntity=Teacher.class) //目标对象 /** 中间表*/@JoinTable(name="TEA_STU", //指定中间表名称 joinColumns=@JoinColumn(name="S_ID",referencedColumnName="STU_ID"), //@ManyToMany中没有加mappedby的主键列inverseJoinColumns=@JoinColumn(name="T_ID",referencedColumnName="TEA_ID")) //@ManyToMany中加mappedby的主键列private Set<Teacher> teachers = new HashSet<Teacher>(); public int getId() {return id;} public void setId(int id) {this.id = id; }public String getName() { return name;} public void setName(String name) {this.name = name; }public float getScore() { return score;} public void setScore(float score) {this.score = score;} public Set<Teacher> getTeachers() {return teachers; }public void setTeachers(Set<Teacher> teachers) { this.teachers = teachers; }}
- Hibernate4学习总结(4)--注解形式的集合映射,关联关系映射
- Hibernate4学习总结(2)--配置形式的集合映射,关联关系映射
- Hibernate4学习总结(3)--注解形式的基础映射,主键映射,基本属性映射,复合属性映射,继承映射。
- Hibernate4 关联关系的映射案例
- Hibernate4关系映射总结
- Hibernate4使用注解关系映射
- Hibernate4-5 映射一对多关联关系
- Hibernate4-6 映射一对一关联关系
- 第九章 关系映射 集合关联映射
- Hibernate4使用注解关系映射说明
- Hibernate_集合映射、关联关系、Session方法总结
- Hibernate学习---关联关系映射
- hibernate4- 双向一对多的关联映射
- Hibernate4-集合映射
- hibernate5(15)注解映射[7]集合关联
- hibernate关联关系中的集合映射的比较
- 学习总结-映射集合
- J2EE系列之Hibernate4学习笔记(四)--关联关系一对多映射
- s3c2440中断程序(烧录到NORFlash,运行在SDRAM中)
- Android RSA 加密出现Decryption error
- hrbust 2080 哈理工oj 2080 链条【简单贪心】
- c# abstract抽象类与继承类子类的构造函数_base
- 初识OpenStack(1)
- Hibernate4学习总结(4)--注解形式的集合映射,关联关系映射
- 如何开启tomcat7的gzip压缩
- JTree 方法设置树节点的展开图标
- hdu 4334 Trouble(两个数组寻找目标和)
- 实现MATLAB2016a和M文件关联
- 可重入函数与线程安全函数
- 打印回形矩阵
- Android - ★知识点
- JavaScript表单之基础篇