Java反射实现无Sql语句的DAO抽象类

明天全栈大作业ddl就要截止了, 晚上我本想再认真检查一遍业务的,但是我看这些相似度80%的XxxDao是在看不顺眼, 于是突发奇想,写了一套完全脱离Sql语句使用的增删查改操作(主要使用了反射, 感觉就是在玩高难度的字符串拼接游戏)

因为只是大作业, 所以用了比较古老的JavaEE,没有上手框架

package dao;

import lombok.SneakyThrows;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import utils.JdbcUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.List;
import java.util.Locale;

/**
 * author Xiao
 * @param <T> 要查询的实体类
 */
public abstract class BaseDao<T>{

    QueryRunner runner = new QueryRunner();
    Connection connection = JdbcUtils.getConnection();
    protected Class<T> cls;

    /**
     * @return class的类名(不是全类名)
     */
    private String getClassName(){
        String[] split = cls.getName().split("\\.");
        return split[split.length - 1];
    }

    @SneakyThrows
    public T getById(int id){
        String sql = "select * from " + getClassName() +" where id=?";
        return runner.query(connection, sql, new BeanHandler<>(cls), id);
    }

    /**
     * 根据 name 查询结果
     * @param pattern 可以匹配的字符串
     * @return 查询结果List集合
     */
    @SneakyThrows
    public List<T> getByName(String pattern){
        String sql;
        String name;
        switch(cls.getName()){
            case "User":{
                name = "username";
                break;
            }
            case "RepoInfo":{
                name = "goodsName";
                break;
            }
            default:{
                name = "name";
            }
        }
        sql = "select * from retail." + getClassName() +  " where " + name + " like ? ";
        return runner.query(connection, sql, new BeanListHandler<>(cls), "%" + pattern + "%");
    }

    /**
     * @return 所有对象的List集合
     */
    @SneakyThrows
    public List<T> getAll(){
        String sql = "select * from retail." + getClassName();
        return runner.query(connection, sql, new BeanListHandler<>(cls));
    }

    /**
     * 根据 id 删除表项
     * @param id id
     * @return 是否删除成功
     */
    @SneakyThrows
    public boolean deleteById(int id){
        String sql = "delete from retail." + getClassName()  + " where id=?";
        return runner.update(connection, sql, id) > 0;
    }

    /**
     * 插入一条记录
     * @param t 实体类对象
     * @return 是否插入成功
     * @throws NoSuchMethodException 找不到方法
     * @throws InvocationTargetException 方法作用的对象不正确
     * @throws IllegalAccessException 参数异常
     */
    @SneakyThrows
    public boolean insert(T t) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException{
        Field[] declaredFields = this.cls.getDeclaredFields(); // 所有的属性
        int fieldNum = declaredFields.length; // 属性的数量
        StringBuilder placeHolder = new StringBuilder();
        placeHolder.append("(");
        for(int i = 0; i < fieldNum; i++){
            if(i < fieldNum - 1)
                placeHolder.append("?").append(",");
            else
                placeHolder.append("?");
        }
        placeHolder.append(")");
        String sql = "insert into retail.Goods values" + placeHolder;
        int maxId = getMaxId();
        Object[] paramArray = new Object[fieldNum];
        // 方法对象
        paramArray[0] = maxId + 1;
        for(int i = 1; i < fieldNum; i++){ // 从1开始因为id不需要设置
            String filedName = declaredFields[i].getName(); // 属性名
            String methodName = "get" + filedName.substring(0, 1).toUpperCase(Locale.ROOT) + filedName.substring(1);
            // 合成get属性的方法名
            Method method = this.cls.getDeclaredMethod(methodName);
            // 方法对象
            paramArray[i] = method.invoke(t);
        }
        return runner.update(connection, sql, paramArray) > 0;
    }

    /**
     * 根据 id 修改一条记录
     * @param t 实体类对象
     * @return 是否修改成功
     * @throws NoSuchMethodException 找不到方法
     * @throws InvocationTargetException 方法作用的对象不正确
     * @throws IllegalAccessException 参数异常
     */
    @SneakyThrows
    public boolean updateById(T t) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException{
        Field[] declaredFields = this.cls.getDeclaredFields(); // 所有的属性
        int fieldNum = declaredFields.length; // 属性的数量
        StringBuilder placeHolder = new StringBuilder();
        placeHolder.append(" set ");
        for(int i = 1; i < fieldNum; i++){ // 从1开始, 因为不用set id
            if(i < fieldNum - 1)
                placeHolder.append(declaredFields[i].getName()).append("=?,");
            else
                placeHolder.append(declaredFields[i].getName()).append("=?"); // 最后一句set不要逗号
        }
        String sql = "update retail." + getClassName() + placeHolder + " where id=?";
        Object[] paramArray = new Object[fieldNum];
        // 方法对象
        for(int i = 1; i < fieldNum; i++){ // 从1开始, 因为id是最后一个参数
            String filedName = declaredFields[i].getName(); // 属性名
            String methodName = "get" + filedName.substring(0, 1).toUpperCase(Locale.ROOT) + filedName.substring(1);
            // 合成get属性的方法名
            Method method = this.cls.getDeclaredMethod(methodName);
            // 方法对象
            paramArray[i - 1] = method.invoke(t);
        }
        Method method = this.cls.getDeclaredMethod("getId");
        paramArray[fieldNum - 1] = method.invoke(t); // 这个属性是id
        return runner.update(connection, sql, paramArray) > 0;
    }

    /**
     * @return 最大的 id 值
     */
    @SneakyThrows
    private int getMaxId(){
        String sql = "select max(id) from retail." + getClassName();
        return runner.query(connection, sql, new ScalarHandler<>());
    }
}

欢迎大家的批评建议

Guess you like

Origin blog.csdn.net/m0_50906780/article/details/121504903