瞎j8封装第二版之用xml文件来代理dao接口

时间:2023-03-09 17:38:35
瞎j8封装第二版之用xml文件来代理dao接口

也是重新整理了之前的那篇

    模仿Mybatis用map

per.xml实现Dao层接口的功能

话不多说直接上代码

首先是结构

瞎j8封装第二版之用xml文件来代理dao接口

依赖pom.xml

瞎j8封装第二版之用xml文件来代理dao接口
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>yebatis</groupId>
    <artifactId>com.yck.yebatis</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.42</version>
        </dependency>
    </dependencies>

</project>
瞎j8封装第二版之用xml文件来代理dao接口

一些基本类

用来封装一个dao信息的Mapper类

瞎j8封装第二版之用xml文件来代理dao接口
package com.yck.yebaitis;

import java.util.List;

public class Mapper {

    private String mapperClass;
    private List<Function> functions;

    public String getMapperClass() {
        return mapperClass;
    }

    public void setMapperClass(String mapperClass) {
        this.mapperClass = mapperClass;
    }

    public List<Function> getFunctions() {
        return functions;
    }

    public void setFunctions(List<Function> functions) {
        this.functions = functions;
    }
}
瞎j8封装第二版之用xml文件来代理dao接口

封装一条方法信息的Function类

瞎j8封装第二版之用xml文件来代理dao接口
package com.yck.yebaitis;

public class Function {
    private String name;
    private String type;
    private Class<?> resultClass;
    private String sql;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Class<?> getResultClass() {
        return resultClass;
    }

    public void setResultClass(Class<?> resultClass) {
        this.resultClass = resultClass;
    }

    public String getSql() {
        return sql;
    }

    public void setSql(String sql) {
        this.sql = sql;
    }
}
瞎j8封装第二版之用xml文件来代理dao接口

常量

瞎j8封装第二版之用xml文件来代理dao接口
package com.yck.yebaitis;

public class FunctionConstants {
    public static final String ADD = "add";
    public static final String DELETE = "delete";
    public static final String UPDATE = "update";
    public static final String SELECT = "select";

}
瞎j8封装第二版之用xml文件来代理dao接口

实现功能的DaoFactory

瞎j8封装第二版之用xml文件来代理dao接口
package com.yck.yebaitis;

import com.yck.jdbc.DataUtil;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.yck.util.StringUtil;
import com.yck.exception.NoConfigFileException;

import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;

public class DaoFactory {

    private static final String configPath = "src/dao/mapper";
    private static DaoFactory instance;

    private DaoFactory() {
    }

    public static DaoFactory getInstance() {
        if (instance == null) {
            synchronized (DaoFactory.class) {
                if (instance == null)
                    instance = new DaoFactory();
            }
        }
        return instance;
    }

    public Map<String, Object> getDaoMap() {
        Map<String, Object> map = null;
        try {
            File[] files = getAllFiles();
            map = new HashMap<>(files.length);
            for (File file : files) {
                Mapper mapper = readerMapper(file);
                Object obj = implDao(mapper);
                map.put(mapper.getMapperClass(), obj);

            }
        } catch (NoConfigFileException | ClassNotFoundException | DocumentException e) {
            e.printStackTrace();
        }
        return map;
    }

    private Object implDao(Mapper mapper) throws ClassNotFoundException {
        ClassLoader classLoader = DaoFactory.class.getClassLoader();
        final Mapper temp = mapper;
        //加载一个接口类
        Class<?> interfaze;
        interfaze = classLoader.loadClass(mapper.getMapperClass());

        /*
        代理实现方法
        之前我是理解错了,我以为是在执行下面这个方法时,就已经实现了类似我们自己写一个DaoImpl,其实它就只是返回了一个代理类实例
         */
        return Proxy.newProxyInstance(classLoader, new Class[]{interfaze}, new InvocationHandler() {

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) {
                List<Function> functions = temp.getFunctions();
                for (Function func : functions) {
                    if (func.getName().equals(method.getName())) {
                        if (func.getType().equals(FunctionConstants.SELECT)) {
                            if (method.getReturnType().equals(List.class)) {
                                return DataUtil.queryForList(func.getSql(), func.getResultClass(), args);
                            } else {
                                return DataUtil.queryForObject(func.getSql(), func.getResultClass(), args);
                            }
                        } else {
                            return DataUtil.excuteUpdate(func.getSql(), args);
                        }
                    }
                }
                return null;
            }
        });
    }

    private File[] getAllFiles() throws NoConfigFileException {

        FileFilter fileFilter = new FileFilter() {
            public boolean accept(File pathname) {
                String fileName = pathname.getName().toLowerCase();
                return fileName.endsWith(".xml");
            }
        };
        File configPath = new File("src/mapper");
        File[] files = configPath.listFiles(fileFilter);
        if (files == null || files.length == 0) {
            throw new NoConfigFileException("file not find");
        }
        return files;
    }

    private Mapper readerMapper(File file) throws DocumentException, ClassNotFoundException {
        SAXReader reader = new SAXReader();
        Mapper mapper = new Mapper();

        Document doc = reader.read(file);
        Element root = doc.getRootElement(); //读取根节点 即dao节点
        mapper.setMapperClass(root.attributeValue("class").trim()); //把dao节点的class值存为接口名
        List<Function> list = new ArrayList<>(); //用来存储方法的List
        for (Iterator<?> rootIter = root.elementIterator(); rootIter.hasNext(); ) //遍历根节点下所有子节点
        {
            Function fun = new Function();    //用来存储一条方法的信息
            Element e = (Element) rootIter.next();
            String type = e.getName().trim();
            switch (type) {
                case FunctionConstants.ADD:
                    fun.setType(FunctionConstants.ADD);
                    break;
                case FunctionConstants.DELETE:
                    fun.setType(FunctionConstants.DELETE);
                    break;
                case FunctionConstants.UPDATE:
                    fun.setType(FunctionConstants.UPDATE);
                    break;
                case FunctionConstants.SELECT:
                    fun.setType(FunctionConstants.SELECT);
                    break;
                default:
                    continue;
            }
            fun.setName(e.attributeValue("id").trim());
            fun.setSql(e.getText().trim());
            String resultType = e.attributeValue("resultType");
            if (!StringUtil.isBlank(resultType)) {
                fun.setResultClass(Class.forName(resultType));
            }
            list.add(fun);
        }
        mapper.setFunctions(list);
        return mapper;
    }
}
瞎j8封装第二版之用xml文件来代理dao接口

测试用类

 瞎j8封装第二版之用xml文件来代理dao接口

实现IUserDao的xml文件就是最底下的userdao.xml

瞎j8封装第二版之用xml文件来代理dao接口
<?xml version="1.0" encoding="UTF-8"?>
<dao id="userdao" class="dao.IUserDao">

    <select id="selectById" resultType ="po.User">
        select * from t_user where id = ?
    </select>

    <update id="updateName">
        update t_user set name = ? where id = ?
    </update>

    <delete id="deleteById">
        delete from t_user where id=?
    </delete>

    <insert id="add">
        insert into t_user(name,age,score,create_time,update_time)
        values(?,?,?,now(),now());
    </insert>

    <select id="getAll" resultType = "po.User">
        select * from t_user;
    </select>

</dao>
瞎j8封装第二版之用xml文件来代理dao接口

测试代码

瞎j8封装第二版之用xml文件来代理dao接口
import com.yck.yebaitis.DaoFactory;
import dao.IUserDao;
import po.User;

import java.util.List;
import java.util.Map;

public class Test {

    public static void main(String[] args) {

        Map<String,Object> daoMap = DaoFactory.getInstance().getDaoMap();
        IUserDao dao = (IUserDao) daoMap.get("dao.IUserDao");
        List<User>  users = dao.getAll();
        System.out.println("查询多条记录:"+users);
        System.out.println("*******************************************");

        User user = dao.selectById(2);
        System.out.println("查询一条记录:"+user);
        System.out.println("*******************************************");

        int i = dao.updateName("二傻",2);
        System.out.println("更新一条记录:"+i);
        System.out.println("*******************************************");

        List<User> userList = dao.getAll();
        System.out.println("更新一条记录后查询所有记录:"+user);
        System.out.println("*******************************************");

    }
}
瞎j8封装第二版之用xml文件来代理dao接口

测试结果

瞎j8封装第二版之用xml文件来代理dao接口

大王让我写代码 23:15:19