首页 > 其他分享 >自定义ORM框架

自定义ORM框架

时间:2024-07-02 21:20:08浏览次数:20  
标签:自定义 框架 value class 获取 ORM sql public String

手撕ORM框架

1.创建Maven工程

image-20240702211254563

2.导入依赖

    <dependencies>
        <!-- 引入 jdbc 的依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>
        <!-- 引入数据源的依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
        </dependency>
    </dependencies>

3.设计操作数据库的工具类

public class DbUtil {
    // 德鲁伊连接池
    private static DataSource dataSource;

    // 使用静态代码块加载配置文件
    static{
        try{
            // 创建一个属性对象
            Properties properties = new Properties();
            // 加载属性文件
            InputStream inputStream = DbUtil.class.getClassLoader().getResourceAsStream("db.properties");
            properties.load(inputStream);
            // 获取连接池对象
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    public static Connection getConnection(){
        try {
         Connection connection = dataSource.getConnection();
         return connection;
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
        }
        return null;
    }

    public static void closeAll(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet){
        if(resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(preparedStatement != null){
            try {
                preparedStatement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (connection != null){
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

4.创建配置文件 db.properties

#数据源信息
url=jdbc:mysql://localhost:3306/demo?serverTimezone=Asia/Shanghai
username=root
password=123456
driverClass=com.mysql.cj.jdbc.Driver

5.设计自定义注解

// 修饰表名
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableName {
    String value();
}
// 修饰主键Id
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableId {
    String value() default "id";
}
// 修饰表字段
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableField {
    String value();
}

6.实体类中使用自定义注解

@TableName("表名")
@Data
public class Student {
    @TableId("主键名")
    private Integer id;
    @TableField("列名")
    private String name;
    @TableField("列名")
    private Integer age;
}

7.设计BaseDao

public class BaseDao <T> {

    private Class<T> clazz;

    public BaseDao(){
        // this表示子类 Dao对象
        Class<? extends BaseDao> aClass = this.getClass();
        // 获取当前子类的父类反射类
        ParameterizedType genericSuperclass = (ParameterizedType) aClass.getGenericSuperclass();
        // 获取该反射类中的泛型类型
        Type actualTypeArgument = genericSuperclass.getActualTypeArguments()[0];
        // 将获取得到的泛型类型经过强转后重新给 clazz
        clazz = (Class) actualTypeArgument;
    }

    public int insert(T t) {
        try{
            // 设计通用的添加
            // 1.首先写出添加的 sql insert into 表名(字段名) values(属性名)
            // 这里注意 into 后面的空格
            StringBuffer sql = new StringBuffer("insert into ");
            // 2.获取实体类所对应的表名
            // 2.1自定义注解 @TableName 标识实体类所对应的表
            // 2.2拿到实体类的反射类,利用反射获取注解,进而获得表的名称
            Class clazz = t.getClass();
            // 实体类的名称
            String simpleName = clazz.getSimpleName();
            // 表的名称
            String tableName = "";
            // 获取类上的注解
            TableName annotation = (TableName) clazz.getAnnotation(TableName.class);
            if(annotation != null){
                tableName = annotation.value();
            }
            // 追加拿到的表名
            sql.append(tableName);
            // 3.获取所有的列名和对应的属性名
            // 3.1用来存储数据库中对应的列
            List<String> columnNames = new ArrayList<String>();
            // 3.2用来存储需要插入的值
            List<Object> values = new ArrayList<Object>();
            // 4.获取所有的属性对象
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                // 4.1获取类中的属性名
                String name = field.getName();
                // 4.2获取属性上的注解
                // 获取主键的注解
                TableId tableId = field.getAnnotation(TableId.class);
                // 获取成员的注解
                TableField tableField = field.getAnnotation(TableField.class);
                // 4.3根据拿到的值进行过滤
                if(tableId != null){
                    // 4.3.1 此时拿到的是主键的注解 退出本轮循环
                    continue;
                }
                if(tableField != null){
                    // 4.3.2 此时拿到的是成员的注解
                    // 覆盖掉类中的属性名 使用表中的字段名
                    name = tableField.value();
                }
                // 对私有属开启暴力反射
                field.setAccessible(true);
                // 获取对象属性对应的值
                Object value = field.get(t);
                // 将值经过添加引号后加入到值list中
                values.add("'"+value+"'");
                // 将属性列加入到列list中
                columnNames.add(name);
            }
            // 5.将列list转换成字符串,然后使用字符串替换方法将其转换成需要的格式
            String columnList = columnNames.toString().replace("[","(").replace("]", ")");
            // 6.将值list转换成字符串,然后使用字符串替换方法将其转换成需要的格式
            String valueList = values.toString().replace("[","(").replace("]",")");
            // 7.合并字符串
            sql.append(columnList + " values " + valueList);
            System.out.println(sql);
            // 8.执行插入语句
            Connection connection = DbUtil.getConnection();
            PreparedStatement preparedStatement = connection.prepareStatement(sql.toString());
            int i = preparedStatement.executeUpdate();
            return i;
        } catch (Exception e){
            e.printStackTrace();
        }
        return 0;
    }

    public int update(T t){
        try{
            //设计通用的修改
            // 1.设计 sql update 表名 set 属性名=值,...
            StringBuffer sql = new StringBuffer("update ");
            // 2.获取表名
            // 2.1获取对象的反射类实例
            Class clazz = t.getClass();
            // 2.2拿到对象对应的表名 类的简名
            String tableName = clazz.getSimpleName();
            TableName tableNameAnnotation = (TableName) clazz.getAnnotation(TableName.class);
            if (tableNameAnnotation != null){
                // 2.3拿到表的名称 使用注解的名称进行覆盖
                tableName = tableNameAnnotation.value();
            }
            // 3.将拿到的表名追加到sql后面
            sql.append(tableName + " set ");
            // 4.设置条件部分
            String where = "where ";
            // 5.获取所有的列对象
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                // 5.1获取所有的属性名
                String name = field.getName();
                // 5.2获取属性上的注解
                // 5.2.1获取主键的注解
                TableId tableId =(TableId) field.getAnnotation(TableId.class);
                // 5.2.2获取属性的注解
                TableField tableField =(TableField) field.getAnnotation(TableField.class);
                // 6.设置私有属性允许访问
                field.setAccessible(true);
                // 7.获取属性的值
                Object value = field.get(t);
                // 根据注解的种类进行选择性拼接
                if(tableId != null){
                    String id = tableId.value();
                    where += id + "='" + value + "'";
                    // 拼接完成退出本轮循环
                    continue;
                }
                if(tableField != null){
                    name = tableField.value();
                }
                sql.append(name + "='" + value + "',");
            }
            // 去除 sql 中最后一个 ,
            sql.deleteCharAt(sql.length() - 1).append(where);
            System.out.println(sql);
            // 执行 sql 语句
            Connection connection = DbUtil.getConnection();
            PreparedStatement preparedStatement = connection.prepareStatement(sql.toString());
            int i = preparedStatement.executeUpdate();
            return i;
        } catch (Exception e){
            e.printStackTrace();
        }
        return 0;
    }

    public int deleteById(Object id){
        try {
            // 设计删除的 sql 语句
            StringBuffer sql = new StringBuffer("delete from ");
            // 获取实体类的名称
            String tableName = clazz.getSimpleName();
            // 获取表名的注解
            TableName tableNameAnnotation = clazz.getAnnotation(TableName.class);
            // 判断是否添加了@TableName注解
            if(tableNameAnnotation != null){
                tableName = tableNameAnnotation.value();
            }
            // 追加 where条件
            sql.append(tableName + " where ");
            // 获取所有的属性对象
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                TableId tableId =(TableId) field.getAnnotation(TableId.class);
                if(tableId != null){
                    sql.append(tableId.value() + "=" + id);
                    // 跳出循环
                    break;
                }
            }
            // 执行 sql
            Connection connection = DbUtil.getConnection();
            PreparedStatement preparedStatement = connection.prepareStatement(sql.toString());
            int i = preparedStatement.executeUpdate();
            return i;
        } catch (Exception e){
            e.printStackTrace();
        }
        return 0;
    }

}

8.用户定义Dao使用BaseDao

public class StudentDao extends BaseDao <Student>{}
public class TeacherDao extends BaseDao <Teacher>{}

9.测试

public class Test {
    @org.junit.Test
    public void test01(){
        // 测试添加
        StudentDao studentDao = new StudentDao();
        Student student = new Student();
        student.setId(1);
        student.setName("李白");
        student.setAge(18);
        studentDao.insert(student);
    }
    @org.junit.Test
    public void test02(){
        // 测试更新
        StudentDao studentDao = new StudentDao();
        Student student = new Student();
        student.setId(1);
        student.setName("李白");
        student.setAge(25);
        studentDao.update(student);
    }
    @org.junit.Test
    public void test03(){
        // 测试删除
        StudentDao studentDao = new StudentDao();
        Student student = new Student();
        student.setId(1);
        studentDao.deleteById(student.getId());
    }
}

标签:自定义,框架,value,class,获取,ORM,sql,public,String
From: https://www.cnblogs.com/lsran/p/18280561

相关文章

  • Transformer模型学习
    Transformer模型是深度学习领域的一种创新架构,尤其在自然语言处理(NLP)任务中表现出色。它是由Vaswani等人在2017年的论文《AttentionisAllYouNeed》中首次提出的。以下是对Transformer模型的详细介绍:Transformer的起源和重要性Transformer模型的提出是为了解决传统循环......
  • Transformer模型
    Transformer模型是深度学习领域的一种创新架构,尤其在自然语言处理(NLP)任务中表现出色。它是由Vaswani等人在2017年的论文《AttentionisAllYouNeed》中首次提出的。以下是对Transformer模型的详细介绍:Transformer的起源和重要性Transformer模型的提出是为了解决传统循环......
  • WebAPI项目框架JWT权限验证
    JWT是什么?校验逻辑?授权过程?这里就不过多的阐述了,直接上代码在appsettings.json中配置jwt参数的值SecretKey必须大于16个字符1{2"Logging":{3"LogLevel":{4"Default":"Information",5"Microsoft.AspNetCore":"Warni......
  • Dockerfile语法,自定义镜像
    我们一直在使用别人准备好的镜像,那如果我要部署一个Java项目,把它打包为一个镜像该怎么做呢?镜像结构要想自己构建镜像,必须先了解镜像的结构。镜像之所以能让我们快速跨操作系统部署应用而忽略其运行环境、配置,就是因为镜像中包含了程序运行需要的系统函数库、环境、配置、依......
  • WebAPI项目框架新建读取配置文件帮助类
    在.netcorewebapi项目中,我们会把配置信息同意放置在appsettings.json中,通过新建读取帮助类,更加简单的读取配置信息。新建公共类库文件夹Common,新建公共类库Web.Core.Common在Web.Core.Common类库下新建Helper文件夹,新建AppSettings帮助类 .NetCore6.0WebAPI项目框架搭......
  • 57.Django框架之序列化输出
    Django框架【一】序列化组件1)使用案例在前端获取到后端用户表里面的所有数据,并且格式是列表套字典#创建模型表classUser(models.Model): username=models.CharField(max_length=32,verbose_name="姓名")age=models.IntegerField(verbose_name="年龄")2)基于J......
  • Shiro框架
    入门概述1shiro是什么?ApacheShiro是一个功能强大且易于使用的Java安全(权限)框架。Shiro可以完成:认证、授权、加密、会话管理、与Web集成、缓存等。借助Shiro您可以快速轻松地保护任何应用程序——从最小的移动应用程序到最大的Web和企业应用程序。简单来说,sh......
  • 低资源语言的Transformer挑战:探索与机遇
    低资源语言的Transformer挑战:探索与机遇在自然语言处理(NLP)的广阔领域中,低资源语言(也称为小种语言或少数民族语言)面临着独特的挑战。尽管Transformer模型在高资源语言上取得了巨大成功,但其在低资源语言上的应用仍然充满挑战。本文将深入探讨这些挑战,并探索可能的解决方案。......
  • MyBatis是什么以及为什么需要ORM框架、快速搭建
    MyBatis是什么MyBatis的前身是Ibatis,本质是一款半自动化的ORM框架,除了能对POJO进行ORM映射之外,还可以编写SQL脚本语句。主要是为了解决我们平时开发中经常写的JDBC代码,将繁琐的JDBC代码封装起来,化繁为简。MyBatis映射文件四要素:1.SQL语句2.映射规则3.POJO4.Mapper接口为......
  • String.format 日期占位 去除左侧的填充0
    原文链接: https://baijiahao.baidu.com/s?id=1764834107971798887&wfr=spider&for=pc假设我们要输出当前的日期时间,我们可以使用如下代码:Datedate=newDate();System.out.println("输出结果:"+String.format("%tF%tT",date,date));输出结果为:输出结果:2023-......