文章目录
一、ORM 框架
1、ORM 框架概念
(1)O(对象):表示程序中的对象
(2)R(关系):表示关系型数据库
(3)M(模型):将java中的对象和关系型数据中的数据进行一一映射(类与表进行映射,属性与字段进行映射),在此模型的基础上可以用面向对象的方式操作数据库
2、自定义框架案例
(1)配置 jdbc.xml 文件,里面包括 driver、url、user、password。
<?xml version="1.0" encoding="UTF-8"?>
<jdbc>
<property name="driver">com.mysql.jdbc.Driver</property>
<property name="url">jdbc:mysql://localhost:3306/woniushop?useUnicode=true&characterEncoding=utf-8</property>
<property name="user">root</property>
<property name="password">admin</property>
</jdbc>
(2)JDBCInfo 实体类对象,用于
public class JDBCInfo {
private String driver;
private String url;
private String user;
private String password;
//定义字符串类型的集合 保存所有需要扫描的实体类名称
private List<String> classNames;
public List<String> getClassNames() {
return classNames;
}
public void setClassNames(List<String> classNames) {
this.classNames = classNames;
}
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
(3)解析 jdbc.xml 配置文件
public class JDBCXMLReader {
//定义读取jdbc.xml的方法 将读取出的信息封装到JDBCInfo对象中
public static JDBCInfo readJDBC() {
JDBCInfo jdbc = new JDBCInfo();
//使用dom4j解析方式解析jdbc.xml文件
//创建dom4j读取xml的对象
SAXReader reader = new SAXReader();
try {
//读取文件形成文档对象
Document document = reader.read("src/jdbc.xml");
//从文档对象中取出根标签
Element rootElement = document.getRootElement();
//取出根标签的property子标签,得到一个子标签集合
List<Element> propertyElements = rootElement.elements("property");
//循环遍历集合得到标签中driver、url、user、password的值
for(Element e: propertyElements) {
//attributeValue获取标签属性值
if(e.attributeValue("name").equals("driver")) {
//getText获取标签文本
jdbc.setDriver(e.getText());
}
if(e.attributeValue("name").equals("url")) {
//getText获取标签文本
jdbc.setUrl(e.getText());
}
if(e.attributeValue("name").equals("user")) {
//getText获取标签文本
jdbc.setUser(e.getText());
}
if(e.attributeValue("name").equals("password")) {
//getText获取标签文本
jdbc.setPassword(e.getText());
}
}
//读取根标签中的mapping标签中的class标签
List<Element> classElements = rootElement.element("mapping").elements("class");
List<String> list = new ArrayList<String>();
//遍历classElements并将所有的值存入到集合中
for(Element e: classElements) {
list.add(e.attributeValue("name"));
}
jdbc.setClassNames(list);
} catch (Exception e) {
e.printStackTrace();
}
return jdbc;
}
}
(4)建立自定义注解
① 表注解:用于保存表名
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TableAnnotation {
//设置属性用来保存所有的表名
String value();
}
@interface表示该注解可以被继承
② 列注解:用于保存列名
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ColumnAnnotion {
//设置属性值用来保存所有的列名
String value();
}
(5)创建 ClassInfo 类对象和 PropertyInfo类
① ClassInfo:用于保存每个类所有的表名
public class ClassInfo {
private String name;
private String table;
private List<PropertyInfo> properties=new ArrayList<PropertyInfo>();
public List<PropertyInfo> getProperties() {
return properties;
}
public void setProperties(List<PropertyInfo> properties) {
this.properties = properties;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTable() {
return table;
}
public void setTable(String table) {
this.table = table;
}
}
② PropertyInfo :用于每个表的所有列的属性和值
public class PropertyInfo {
private String name;
private String column;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColumn() {
return column;
}
public void setColumn(String column) {
this.column = column;
}
}
(6)QueryOperate 类:用于定义方法,如常用的增删改查,这里定义一个查询示例
public class QueryOperate {
public static final Map<String, ClassInfo> map = new HashMap<String, ClassInfo>();
private static JDBCInfo info;
//加载该类时 需要读取jdbc.xml信息
static {
//调用读取xml文件的方法 获取JDBCInfo对象
info = JDBCXMLReader.readJDBC();
try {
//创建连接
Class.forName(info.getDriver());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//非空判断
if(info.getClassNames() != null) {
//扫描实体类 获取实体类映射信息
for(String className: info.getClassNames()) {
//每一个实体类扫描的结果都应该对应一个ClassInfo对象
ClassInfo classInfo = new ClassInfo();
//获取类的字节码信息
try {
Class c = Class.forName(className);
//扫描实体类上的table注解
TableAnnotation table = (TableAnnotation) c.getAnnotation(TableAnnotation.class);
//获取table注解的值
String tableName = table.value();
//将table注解的值 也就是表名存到classinfo对象中
classInfo.setTable(tableName);
//获取该类上自己定义的所有属性
Field[] fields = c.getDeclaredFields();
//循环所有的属性 获取属性名和列名
if(fields != null) {
for(Field field: fields) {
//每一个属性对应一个PropertyInfo对象
PropertyInfo propertyInfo = new PropertyInfo();
propertyInfo.setName(field.getName());
propertyInfo.setColumn(field.getName());
if(field.isAnnotationPresent(ColumnAnnotation.class)) {
//如果有该注解说明这个属性的列名是跟属性名称不一致
//取出注解中的值
ColumnAnnotation column = field.getAnnotation(ColumnAnnotation.class);
propertyInfo.setColumn(column.value());
}
//将该对象保存到classinfo的集合中
classInfo.getProperties().add(propertyInfo);
}
}
//将classinfo保存到一个全局的键值对中
//用类的全限定名作为键 该类的映射信息作为值保存到键值对中
map.put(className, classInfo);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public List select(Class c) throws Exception{
//通过class信息得到类名
String className = c.getName();
//通过类名得到该类的映射信息ClassInfo对象
ClassInfo classInfo = map.get(className);
//获取连接
Connection conn = DriverManager.getConnection(info.getUrl(), info.getUser(), info.getPassword());
PreparedStatement ps = conn.prepareStatement("select * from " + classInfo.getTable());
ResultSet result = ps.executeQuery();
List list = new ArrayList();
while(result.next()) {
Object entity = c.newInstance();
// System.out.println(entity);
//循环classinfo中的属性映射集合
for(PropertyInfo pi: classInfo.getProperties()) {
//从查询到的结果集中取出每一列的值
Object propertyValue = result.getObject(pi.getColumn());
System.out.println(propertyValue);
//取出该属性对象
Field field = c.getDeclaredField(pi.getName());
//获取该属性的set方法
//通过属性名取出第一个字母转大写+第二到最后的所有字母 就是属性名首字母大写
String methodName = "set" + pi.getName().substring(0, 1).toUpperCase() + pi.getName().substring(1);
System.out.println(methodName);
//获取set方法
//属性对象.getType获取的是 该属性的类型
Method method = c.getMethod(methodName, field.getType());
System.out.println(field.getType());
//通过调用set方法给该属性赋值
method.invoke(entity, propertyValue);
}
list.add(entity);
}
result.close();
ps.close();
conn.close();
return list;
}
}
(7)定义要查询的表对应的类,如
@TableAnnotation("products")
public class Products {
private int p_id;
private String p_name;
private double p_price;
private int p_count;
private String p_class;
private String p_attribute;
private int p_typeid;
public int getP_id() {
return p_id;
}
public void setP_id(int p_id) {
this.p_id = p_id;
}
public String getP_name() {
return p_name;
}
public void setP_name(String p_name) {
this.p_name = p_name;
}
public double getP_price() {
return p_price;
}
public void setP_price(double p_price) {
this.p_price = p_price;
}
public int getP_count() {
return p_count;
}
public void setP_count(int p_count) {
this.p_count = p_count;
}
public String getP_class() {
return p_class;
}
public void setP_class(String p_class) {
this.p_class = p_class;
}
public String getP_attribute() {
return p_attribute;
}
public void setP_attribute(String p_attribute) {
this.p_attribute = p_attribute;
}
public int getP_typeid() {
return p_typeid;
}
public void setP_typeid(int p_typeid) {
this.p_typeid = p_typeid;
}
@Override
public String toString() {
return "Products [p_id=" + p_id + ", p_name=" + p_name + ", p_price="
+ p_price + ", p_count=" + p_count + ", p_class=" + p_class
+ ", p_attribute=" + p_attribute + ", p_typeid=" + p_typeid
+ "]";
}
}
(8)框架搭建完成,在实际运用中,首先需要在 jdbc.xml 文件中添加要查询的表对应的类,如,这里查询商品表:
<!--在jdbc.xml中配置项目中需要使用到的实体类 扫描这些实体类的注解 生成映射信息-->
<mapping>
<class name="definedorm.orm0604.own.model.Products"></class>
</mapping>
(9)main 函数类:
public class Test1 {
public static void main(String[] args) {
QueryOperate query=new QueryOperate();
try {
List<Products> list =query.select(Products.class);
//便利集合
for(Products p:list) {
System.out.println(p);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}