自己实现简单版的注解Mybatis

Mybatis属于ORM(Object Relational Mapping)框架,将java对象和关系型数据库建立映射关系,方便对数据库进行操作,其底层还是对jdbc的封装。

实现的思路是:

1 定义注解,对Dao中的方法进行标注

2 为Dao创建代理类

3 在invocationHandler中对进行具体的逻辑操作

@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ExtInsert {

    String value();
}
public interface UserDao {

    @ExtSelect("select * from User where userName=#{userName} and userAge=#{userAge} ")
    User selectUser(@ExtParam("userName") String name, @ExtParam("userAge") Integer userAge);

    @ExtInsert("insert into user(userName,userAge) values(#{userName},#{userAge})")
    int insertUser(@ExtParam("userAge") Integer userAge, @ExtParam("userName") String name);
    
    @ExtDelete("delete from user where userName=#{userName} ")
    void deleteUserByUserName(@ExtParam("userName") String name);
    
    @ExtUpdate("update user set userAge = #{userAge}  where userName = #{userName} ")
    void updateUser(@ExtParam("userAge") Integer userAge, @ExtParam("userName") String name);
}
public class SqlSession {

    // 获取getMapper
    @SuppressWarnings("unchecked")
    public static <T> T getMapper(Class<T> clz)
            throws IllegalArgumentException, InstantiationException, IllegalAccessException {
        return (T) Proxy.newProxyInstance(clz.getClassLoader(), new Class[] { clz },
                new MyInvocationHandlerMbatis(clz));
    }

}
public class MyInvocationHandlerMbatis implements InvocationHandler {

    /**
     * 这个就是我们要代理的真实对象
     */
    private Object subject;

    /**
     * 构造方法,给我们要代理的真实对象赋初值
     * 
     * @param subject
     */
    public MyInvocationHandlerMbatis(Object subject) {
        this.subject = subject;
    }

    /**
     * 该方法负责集中处理动态代理类上的所有方法调用。 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行
     * 
     * @param proxy
     *            代理类实例
     * @param method
     *            被调用的方法对象
     * @param args
     *            调用参数
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 判断方法上是否有ExtInsert注解
        ExtInsert extInsert = method.getAnnotation(ExtInsert.class);
        if (extInsert != null) {
            return insertSQL(extInsert, method, args);
        }
        // 判断方法上是否有ExtSelect注解
        ExtSelect extSelect = method.getAnnotation(ExtSelect.class);
        if (extSelect != null) {
            return selectMybatis(extSelect, method, args);
        }
        // 判断方法上是否有ExtDelete注解
        ExtDelete extDelete = method.getAnnotation(ExtDelete.class);
        if(extDelete != null) {
            deleteSQL(extDelete,method,args);
            return null;
        }
        // 判断方法上是否有ExtUpdate注解
        ExtUpdate extUpdate =  method.getAnnotation(ExtUpdate.class);
        if(extUpdate != null) {
            updateSQL(extUpdate,method,args);
            return null;
        }
        return null;
    }

    
    private void updateSQL(ExtUpdate extUpdate, Method method, Object[] args) {
        // 获取注解上的sql
        String updateSql = extUpdate.value();
        System.out.println("sql:" + updateSql);
        // 获取方法上的参数
        Parameter[] parameters = method.getParameters();
        // 将方法上的参数存放在Map集合中
        ConcurrentHashMap<Object, Object> parameterMap = getExtParams(parameters, args);
        // 获取SQL语句上需要传递的参数 ,即获取的是#{userName} 里的userName
        String[] sqlParameter = SQLUtils.sqlUpdateParameter(updateSql);
        List<Object> parameValues = new ArrayList<>();
        for (int i = 0; i < sqlParameter.length; i++) {
            String str = sqlParameter[i];
            Object object = parameterMap.get(str);
            parameValues.add(object);
        }
        String newSql = SQLUtils.parameQuestion(updateSql, sqlParameter);
        System.out.println("newSql:" + newSql);
        // 调用jdbc代码执行 , 第二个参数false表示返回的是影响的行数
        JDBCUtils.execute(newSql, parameValues.get(0),parameValues.get(1));
    }

    private void deleteSQL(ExtDelete extDelete, Method method, Object[] args) {
        //获取注解上的sql
        String deleteSql = extDelete.value();
        System.out.println("sql:" + deleteSql);
        // 将SQL语句替换为?号
        String newSql = SQLUtils.parameQuestion(deleteSql, new String[] {"userName"});
        System.out.println("newSql:" + newSql);
        // 调用jdbc代码执行 , 第二个参数false表示返回的是影响的行数
        JDBCUtils.execute(newSql, args[0]);
    }

    public int insertSQL(ExtInsert extInsert, Method method, Object[] args) {
        // 获取注解上的sql
        String insertSql = extInsert.value();
        System.out.println("sql:" + insertSql);
        // 获取方法上的参数
        Parameter[] parameters = method.getParameters();
        // 将方法上的参数存放在Map集合中
        ConcurrentHashMap<Object, Object> parameterMap = getExtParams(parameters, args);
        // 获取SQL语句上需要传递的参数 ,即获取的是#{userName} 里的userName
        String[] sqlParameter = SQLUtils.sqlInsertParameter(insertSql);
        List<Object> parameValues = new ArrayList<>();
        for (int i = 0; i < sqlParameter.length; i++) {
            String str = sqlParameter[i];
            Object object = parameterMap.get(str);
            parameValues.add(object);
        }
        // 将SQL语句替换为?号
        String newSql = SQLUtils.parameQuestion(insertSql, sqlParameter);
        System.out.println("newSql:" + newSql);
        // 调用jdbc代码执行 , 第二个参数false表示返回的是影响的行数
        int insertResult = JDBCUtils.insert(newSql, false, parameValues);
        return insertResult;
    }

    public Object selectMybatis(ExtSelect extInsert, Method method, Object[] args) throws SQLException {
        try {
            // 获取查询SQL语句
            String selectSQL = extInsert.value();
            // 将方法上的参数存放在Map集合中
            Parameter[] parameters = method.getParameters();
            // 获取方法上参数集合
            ConcurrentHashMap<Object, Object> parameterMap = getExtParams(parameters, args);
            // 获取SQL传递参数
            List<String> sqlSelectParameter = SQLUtils.sqlSelectParameter(selectSQL);
            // 排序参数
            List<Object> parameValues = new ArrayList<>();
            for (int i = 0; i < sqlSelectParameter.size(); i++) {
                String parameterName = sqlSelectParameter.get(i);
                Object object = parameterMap.get(parameterName);
                parameValues.add(object.toString());
            }
            // 变为?号
            String newSql = SQLUtils.parameQuestion(selectSQL, sqlSelectParameter);
            System.out.println("执行SQL:" + newSql + "参数信息:" + parameValues.toString());
            // 调用JDBC代码查询
            ResultSet rs = JDBCUtils.query(newSql, parameValues);
            // 获取返回类型
            Class<?> returnType = method.getReturnType();
            if (!rs.next()) {
                // 没有查找数据
                return null;
            }
            // 向上移动
            rs.previous();
            // 实例化对象
            Object newInstance = returnType.newInstance();
            while (rs.next()) {
                for (String parameterName : sqlSelectParameter) {
                    // 获取集合中数据
                    Object value = rs.getObject(parameterName);
                    // 查找对应属性
                    Field field = returnType.getDeclaredField(parameterName);
                    // 设置允许私有访问
                    field.setAccessible(true);
                    // 赋值参数
                    field.set(newInstance, value);
                }

            }
            return newInstance;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private ConcurrentHashMap<Object, Object> getExtParams(Parameter[] parameters, Object[] args) {
        // 获取方法上参数集合
        ConcurrentHashMap<Object, Object> parameterMap = new ConcurrentHashMap<>();
        for (int i = 0; i < parameters.length; i++) {
            // 参数信息
            Parameter parameter = parameters[i];
            ExtParam extParam = parameter.getDeclaredAnnotation(ExtParam.class);
            // 参数名称
            String paramValue = extParam.value();
            // 参数值
            Object oj = args[i];
            parameterMap.put(paramValue, oj);
        }
        return parameterMap;
    }
}

项目结构:

jdbc工具类,

在一个字符串中找出含有特殊符号的多个子串的工具方法

利用jdk动态代理创建代理对象

github地址: https://github.com/jake1263/MYORM

原文地址:https://www.cnblogs.com/moris5013/p/11039569.html