反射实例:ORM搭建

版权声明:本文为博主原创文章,转载请附上链接。 https://blog.csdn.net/qq_36182135/article/details/82667531

反射机制是Java给开发者留下的后门之一,让开发者可以通过API去动态获得被封装的属性和方法,很多框架的功能都是基于反射实现的,像Hibernate、Mybatis、Spring(这个是真的多)。今天就手写一个ORM最基础的实现,也就是Java对象和数据库表之间的映射。

项目使用SpringBoot搭建,其实用什么都一样,只不过SpringBoot本身配置都写好了,创建也快,习惯了= =

pom.xml里引入MySQL的依赖

创建实体类,其中@Table、@MyId、@Column三个注解是我自定义的,用来实现ORM映射

package pers.hong.entity;

import java.io.Serializable;
import pers.hong.annotation.Column;
import pers.hong.annotation.MyId;
import pers.hong.annotation.Table;

/**
 * @Description:
 * @Auther: hong
 * @Date: 2018/09/12
 */
@Table(name = "user")
public class User implements Serializable{
    @MyId(name="id",isAuto=false)
    private Long id;
    @Column(name="user_name")
    private String userName;
    @Column(name="user_password")
    private String userPassword;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getuserName() {
        return userName;
    }

    public void setuserName(String userName) {
        this.userName = userName;
    }

    public String getuserPassword() {
        return userPassword;
    }

    public void setuserPassword(String userPassword) {
        this.userPassword = userPassword;
    }
}

新建user表,对应实体类

然后是三个注解,其中@Table的作用范围在类上,其他两个在属性上,作用域都是运行时起作用,和Hibernate的注解差不多,@MyId是控制主键是否自增

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
    String name();
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyId {
    boolean isAuto() default true;
    String name();
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    String name();
}

定义dao层接口和实现类

package pers.hong.dao;

import pers.hong.entity.User;

/**
 * @Description:
 * @Auther: hong
 * @Date: 2018/09/12
 */
public interface UserDao {
    void saveUser();
}

@Component
public class UserDaoImpl implements UserDao {

    @Autowired
    private ORMUtil ormUtil;

    @Override
    public void saveUser() {
        User user = new User();
        user.setId(111L);
        user.setuserName("宏宏");
        user.setuserPassword("hong52ni");
        try {
            ormUtil.save(user);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

然后就是最重要的ORMUtil类,save()方法就是jdbc的写法,只不过手动输入sql语句变成自动转换,也就是由实体类到表字段的映射,具体实现方法代码都做了注释。数据库连接信息通过properties文件传入,这里有个有意思的地方,如果设置user为username,是会直接读到系统Administrator的,访问不了数据库,所以配置文件的字段也不能瞎写= =

package pers.hong.orm;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import pers.hong.annotation.Column;
import pers.hong.annotation.Table;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;

/**
 * @Description:
 * @Auther: hong
 * @Date: 2018/09/12
 */
@Component
public class ORMUtil {
    @Value("${user}")
    private String user;
    @Value("${password}")
    private String password;
    @Value("${jdbcDriver}")
    private String driver;
    @Value("${url}")
    private String url;

    public void save(Object object) throws Exception {
        //加载驱动
        Class.forName(driver);
        //建立连接
        Connection conn = DriverManager.getConnection(url, user,password);
        //预编译语句
        PreparedStatement pstmt = conn.prepareStatement(prepareSql(object));
        //执行
        pstmt.executeUpdate();
        pstmt.close();
        conn.close();
    }

    private String prepareSql(Object object) throws Exception {
        StringBuffer str = new StringBuffer("INSERT INTO ");
        //反射获得类对象
        Class<?> clazz = object.getClass();
        String tableName = clazz.getSimpleName().toUpperCase();
        //判断是否加了@Table注解
        Table table = clazz.getAnnotation(Table.class);
        if (table != null) {
            tableName = table.name().toUpperCase();
        }
        str.append(tableName + "(");
        //获取字段
        Field[] fields = clazz.getDeclaredFields();
        // 定义存储字段对应值的集合
        List<Object> valueList = new ArrayList<>();
        for (Field field : fields) {
            String fieldName = field.getName().toUpperCase();
            //判断是否使用@Column注解
            Column column = field.getAnnotation(Column.class);
            if (column != null) {
                fieldName = column.name().toUpperCase();
            }
            //开启权限
            field.setAccessible(true);
            Object value = field.get(object);
            if (value != null) {
                str.append(fieldName + ",");
                valueList.add(value);
            }
        }
        //删除最后一个逗号
        str.deleteCharAt(str.length() - 1);
        str.append(") VALUES (");
        for (Object value : valueList) {
            Object temp = value;

            // 判断value是否为String类型
            if (value instanceof String) {
                temp = "'"+value+"'";
            }

            str.append(temp+",");
        }
        //删除最后一个逗号
        str.deleteCharAt(str.length() - 1);
        str.append(")");
        return str.toString();
    }
}

测试类,直接调用方法即可


@RunWith(SpringRunner.class)
@SpringBootTest
public class OrmApplicationTests {
    @Autowired
    private UserDaoImpl userDao;

    @Test
    public void contextLoads() {
    }

    @Test
    public void ormValidateTest() {
		userDao.saveUser();
    }
}

以上,通过注解实现的简单ORM映射就写好了,GitHub地址:https://github.com/hong52ni/ORM-demo

猜你喜欢

转载自blog.csdn.net/qq_36182135/article/details/82667531
今日推荐