【Java】Java核心 77:Dom4j 解析 XML综合案例



在这里插入图片描述

1、需求

需求:自定义dao层jdbc框架

  • 为了方便程序员操作数据库,让程序员更关注于sql代码层面和业务层面

2、案例效果

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

使用到的技术
- 反射
- 注解
- 动态代理
- xml解析:xpath


3、案例分析

自定义jdbc框架开发步骤:

1、通过软配置方式,和数据库连接

  • 解析xml配置文件,获得:driver、url、username、password
  • 德鲁伊连接池
    • 根据配置文件中的参数,创建连接池对象

2、创建@Select注解

  • 解析@Select注解中value值:select查询语句

3、创建映射类Mapper

  • 把从@Select注解中解析出来的select查询语句,赋值给Mapper中的sql成员变量

4、创建SqlSession类

  • 提供getMapper()方法,用来获取代理对象
    • 说明:程序员在获取到代理对象后,利用代理对象调用某个方法时,会被代理对象拦截处理

4、自定义JDBC框架-代码实现

4.1、Configuration

/*配置类
  1. 解析XML文件
  2. 创建德鲁伊连接池
*/
public class Configuration {
    
    
    /* 定义数据库连接对象相关属性 */
    private String driver;//驱动
    private String url;//连接地址
    private String username;//登录名
    private String password;//密码

    /* Mapper接口的全名称 */
    private String interName;

    /* 数据库连接池对象 */
    private DataSource dataSource;

    /* 映射类对象 */
    private Mapper mapper = new Mapper();


    //无参构造方法
    public Configuration() {
    
    
        try {
    
    
            //解析"config.xml"文件
            SAXReader reader = new SAXReader();
            InputStream is = Configuration.class.getClassLoader().getResourceAsStream("config.xml");
            Document doc = reader.read(is);
            //调用自定义方法: 将核心配置文件中的数据封装到Configuration类的属性中
            loadConfigXml(doc);

            //调用自定义方法: 初始化数据库连接池对象
            createDataSource();

        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }


    //初始化数据库连接池对象
    private void createDataSource() throws Exception {
    
    
        //创建c3p0核心类对象
        ComboPooledDataSource cpds = new ComboPooledDataSource();
        //使用对象调用方法将四大连接参数给数据库连接池
        cpds.setDriverClass(driver);
        cpds.setJdbcUrl(url);
        cpds.setUser(username);
        cpds.setPassword(password);

        //将cpds赋值给成员变量ds
        this.dataSource = cpds;//数据库连接池对象
    }


    //将核心配置文件中的数据封装到Configuration类属性中
    private void loadConfigXml(Document doc) {
    
    
        /*
        //使用document对象调用方法获取property标签:
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/itheima"/>
        <property name="username" value="root"/>
        <property name="password" value="itheima"/>
        */
        List<Node> list = doc.selectNodes("//property");

        //遍历List集合
        for (Node node : list) {
    
    
            //强制转换
            Element e = (Element) node;
            //获取property标签的name属性值
            String name = e.attributeValue("name");//双引号中的name是property标签的name属性 driver
            //获取property标签的value属性值
            String value = e.attributeValue("value");//双引号中的value是property标签的value属性 com.mysql.jdbc.Driver
           
            //将value的值赋值给成员变量
            switch (name) {
    
    
                case "driver":
                    this.driver = value;//数据库驱动
                    break;
                case "url":
                    this.url = value;//连接url
                    break;
                case "username":
                    this.username = value;//登录名
                    break;
                case "password":
                    this.password = value;//密码
                    break;
            }
        }

        //<package name="xxx.xxx.UserMapper"></package>
        Node node = doc.selectSingleNode("//package");
        Element e = (Element) node;
        //Mapper接口的全名称
        this.interName = e.attributeValue("name");//"xxx.xxx.UserMapper"
    }


    public String getDriver() {
    
    
        return driver;
    }

    public void setDriver(String driver) {
    
    
        this.driver = driver;
    }

    public String getUrl() {
    
    
        return url;
    }

    public void setUrl(String url) {
    
    
        this.url = url;
    }

    public String getUsername() {
    
    
        return username;
    }

    public void setUsername(String username) {
    
    
        this.username = username;
    }

    public String getPassword() {
    
    
        return password;
    }

    public void setPassword(String password) {
    
    
        this.password = password;
    }

    public String getInterName() {
    
    
        return interName;
    }

    public void setInterName(String interName) {
    
    
        this.interName = interName;
    }

    public DataSource getDataSource() {
    
    
        return dataSource;
    }

    public void setDataSource(DataSource dataSource) {
    
    
        this.dataSource = dataSource;
    }

    public Mapper getMapper() {
    
    
        return mapper;
    }

    public void setMapper(Mapper mapper) {
    
    
        this.mapper = mapper;
    }
}

4.2、注解

@Select

//查询时使用的注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Select {
    
    
    String[] value();
}

@ResultType

//查询结果的封装类型
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ResultType {
    
    
    String value();
}


4.3、映射类:Mapper

package cn.itcast.config;

public class Mapper {
    
    
    private String sql;//存储sql语句
    private String resultType;//结果类型

    public Mapper() {
    
    
    }

    public Mapper(String sql) {
    
    
        this.sql = sql;
    }

    public String getSql() {
    
    
        return sql;
    }

    public void setSql(String sql) {
    
    
        this.sql = sql;
    }

    public String getResultType() {
    
    
        return resultType;
    }

    public void setResultType(String resultType) {
    
    
        this.resultType = resultType;
    }
}


4.4、SqlSession类

@SuppressWarnings("all")
public class SqlSession {
    
    
    /**
     * 动态代理
     */
    public <T> T getMapper(Class<T> clazz) {
    
    
        //类加载器: 负责加载代理类到内存中
        ClassLoader classLoader = SqlSession.class.getClassLoader();

        //父接口
        Class[] interfaces = {
    
    clazz};


        T mapperProxy = (T) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
    
    

            //在调用方法时,代理对象执行invoke方法,返回List
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
                //创建核心配置类对象
                Configuration config = new Configuration();


                /******** 解析 @Select、@ResultType *******/
                Class clazz = Class.forName(config.getInterName());

                Method[] methods = clazz.getMethods();
                //遍历数组
                for (Method m : methods) {
    
    
                    //判断是否有注解
                    boolean boo = m.isAnnotationPresent(Select.class);

                    boolean boo2 = m.isAnnotationPresent(ResultType.class);

                    if (boo && boo2) {
    
    
                        //获取@Select注解对象
                        Select select = m.getAnnotation(Select.class);
                        //获取属性值
                        String[] value = select.value();//{"select * from user"}
                        String sql = value[0];
                        //给Mapper对象中的sql成员变量赋值
                        config.getMapper().setSql(sql);

                        //获取@ResultType注解对象
                        ResultType resultType = m.getAnnotation(ResultType.class);
                        String type = resultType.value();//获取属性值
                        config.getMapper().setResultType(type);
                    }
                }
                /*******************************/


                //获取映射对象
                Mapper mapper = config.getMapper();
                //利用映射对象,获取sql语句
                String sql = mapper.getSql();

                //利用映射对象,获取类型
                String resultType = mapper.getResultType();
                Class cl = Class.forName(resultType);


                //获取数据库连接池对象
                DataSource ds = config.getDataSource();
                //利用连接池对象,获取Connection对象
                Connection conn = ds.getConnection();

                //调用自定义方法: 执行sql查询语句
                List list = queryForList(conn, sql, cl);

                return list;
            }
        });

        //代理对象返回给getMapper的调用者     UserMapper mapper = sqlSession.getMapper(UserMapper.class);//mapperProxy
        return mapperProxy;
    }
   public List queryForList(Connection conn, String sql, Class clazz) throws SQLException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    
    
        List userList = new ArrayList();

        //通过连接对象得到预编译的语句对象
        PreparedStatement ps = conn.prepareStatement(sql);

        //执行SQL语句,得到结果集
        ResultSet rs = ps.executeQuery();

        while (rs.next()) {
    
    
            //获取构造方法对象,并实例化
            Object user = clazz.getConstructor().newInstance();

            //获取所有的成员变量(包含私有成员变量)
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
    
     //field可以是:id name passwd age gender adddate
                //得到成员变量的名字
                String name = field.getName();

                //暴力破解: 取消权限检查
                field.setAccessible(true);

                //rs.getObject(name) 表示根据数据表的列名取出数据表中的列值 因为User类中的成员变量名必须和数据表列名一致
                //例如: name 的值是birthday 那么这里 rs.getObject(name)---》rs.getObject("age")获取数据表的年龄20
                Object table_value = rs.getObject(name);

                //void set(Object obj, Object value)给成员变量赋值,参数1:对象名 参数2:要赋的值
                field.set(user, table_value);

            }
            //user对象添加到集合中
            userList.add(user);
        }

        //释放资源
        rs.close();
        ps.close();
        conn.close();

        //返回集合
        return userList;
    }
}   

5、自定义JDBC框架的使用


5.1、数据表

CREATE TABLE user (
  id int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
  name varchar(30) DEFAULT NULL,
  passwd varchar(20) DEFAULT NULL,
  age int(3) DEFAULT NULL,
  gender varchar(2) DEFAULT NULL,
  adddate date DEFAULT NULL
);

# 测试数据
INSERT INTO user VALUES (null, 'itcast', '123123', '10', '男', '2020-12-11');

5.2、创建实体类

public class User {
    
    
    private int id;
    private String name;
    private String passwd;
    private int age;
    private String gender;
    private Date adddate;

    public User() {
    
    
    }

    public User(int id, String name, String passwd, int age, String gender, Date adddate) {
    
    
        this.id = id;
        this.name = name;
        this.passwd = passwd;
        this.age = age;
        this.gender = gender;
        this.adddate = adddate;
    }

    public int getId() {
    
    
        return id;
    }

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

    public String getName() {
    
    
        return name;
    }

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

    public String getPasswd() {
    
    
        return passwd;
    }

    public void setPasswd(String passwd) {
    
    
        this.passwd = passwd;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public String getGender() {
    
    
        return gender;
    }

    public void setGender(String gender) {
    
    
        this.gender = gender;
    }

    public Date getAdddate() {
    
    
        return adddate;
    }

    public void setAdddate(Date adddate) {
    
    
        this.adddate = adddate;
    }


    @Override
    public String toString() {
    
    
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", passwd='" + passwd + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", adddate=" + adddate +
                '}';
    }
}


5.3、UserMapper接口

public interface UserMapper {
    
    

    //查询所有用户
    @Select("select * from user")
    @ResultType("com.itcast.pojo.User")
    public abstract List queryAllUser();

}

5.4、配置文件:config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>

    <!--数据源-->
    <dataSource>
        <!--驱动-->
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <!--地址-->
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/itheima"/>
        <!--用户名-->
        <property name="username" value="root"/>
        <!--密码-->
        <property name="password" value="itheima"/>
    </dataSource>

    <!--加载映射接口-->
    <mappers>
        <package name="com.itcast.mapper.UserMapper"></package>
    </mappers>

</configuration>

5.5、测试类

public class Test1 {
    
    
    @Test
    public void testSelect() {
    
    
        //实例化
        SqlSession sqlSession = new SqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        List<User> users = mapper.queryAllUser();

        for (User u : users) {
    
    
            System.out.println(u);
        }
    }
}

assword" value=“itheima”/>

<!--加载映射接口-->
<mappers>
    <package name="com.itcast.mapper.UserMapper"></package>
</mappers>
~~~

5.5、测试类

public class Test1 {
    
    
    @Test
    public void testSelect() {
    
    
        //实例化
        SqlSession sqlSession = new SqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        List<User> users = mapper.queryAllUser();

        for (User u : users) {
    
    
            System.out.println(u);
        }
    }
}


在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_60915009/article/details/131401048
今日推荐