[Java] Java core 77: Dom4j parsing XML comprehensive case



insert image description here

1. Demand

need: Custom dao layer jdbc framework

  • In order to facilitate programmers to operate the database, let programmers pay more attention to sql code level and business level

2. The effect of the case

insert image description here

insert image description here

insert image description here

technology used:
- reflection
- annotation
- dynamic proxy
- xml parsing: xpath


3. Case analysis

Custom jdbc framework development steps:

1. Connect to the database through soft configuration

  • Parse the xml configuration file to get: driver, url, username, password
  • druid connection pool
    • Create a connection pool object according to the parameters in the configuration file

2. Create @Select annotation

  • Parse the value in the @Select annotation:select查询语句

3. Create a mapping class Mapper

  • Assign the value parsed from the @Select annotation select查询语句to the sql member variable in the Mapper

4. Create the SqlSession class

  • Provide getMapper() method to get proxy object
    • Description: After obtaining the proxy object, when the programmer uses the proxy object to call a method, it will be intercepted by the proxy object

4. Customize the JDBC framework-code implementation

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. Notes

@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. Mapping class: 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 class

@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. Use of custom JDBC framework


5.1, data table

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. Create entity class

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 interface

public interface UserMapper {
    
    

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

}

5.4. Configuration file: 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, test class

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, test class

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);
        }
    }
}


insert image description here

Guess you like

Origin blog.csdn.net/m0_60915009/article/details/131401048