package cn.itcast.config;import com.alibaba.druid.pool.DruidDataSourceFactory;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.Node;import org.dom4j.io.SAXReader;import javax.sql.DataSource;import java.io.InputStream;import java.util.List;import java.util.Properties;/* 配置类 1. 解析XML文件 2. 创建德鲁伊连接池*/public class Configuration { /* 定义数据库连接对象相关属性 */ private String driver;//驱动 com.mysql.jdbc.Driver private String url;//连接地址 jdbc:mysql://127.0.0.1:3306/heima02 private String username;//登录名 root private String password;//密码 1234 /* Mapper接口的全名称 */ private String interName;//"cn.itcast.mapper.UserMapper" /* 数据库连接池对象 */ private DataSource dataSource;//连接池初始化成功 /* 映射类对象 */ //当前类Configuration加载创建Mapper对象 //Mapper映射类,该类中具有成员变量: private String sql;//存储sql语句 private String resultType;//结果类型 //private String sql="select * from user" //private String resultType="cn.itcast.pojo.User" 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 { //创建属性集对象 Properties p = new Properties(); //向属性集对象p中添加数据: p.setProperty("url",url);//url=jdbc:mysql://127.0.0.1:3306/heima02 p.setProperty("username",username);//username=root p.setProperty("password",password);//password=1234 p.setProperty("driverClassName",driver);//driverClassName=com.mysql.jdbc.Driver //获取数据库连接池对象 DataSource ds = DruidDataSourceFactory.createDataSource(p); //将ds赋值给成员变量dataSource this.dataSource = ds;//数据库连接池对象 } //将核心配置文件中的数据封装到Configuration类属性中 private void loadConfigXml(Document doc) { /* //使用document对象调用方法获取property标签: <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.01:3306/itheima"/> <property name="username" value="root"/> <property name="password" value="itheima"/> */ List<Node> list = doc.selectNodes("//property"); //遍历List集合 for (Node node : list) { //强制转换 //Node使用Element的父接口 Element e = (Element) node;// <property name="driver" value="com.mysql.jdbc.Driver"/> //获取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": //将从config.xml文件中获取的值com.mysql.jdbc.Driver赋值给成员变量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" cn.itcast.mapper.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; }}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; }}package cn.itcast.config类;import cn.itcast.anno.ResultType;import cn.itcast.anno.Select;import cn.itcast.mapper.UserMapper;import cn.itcast.pojo.User;import javax.management.relation.Role;import javax.sql.DataSource;import java.lang.reflect.*;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.List;@SuppressWarnings("all")public class SqlSession { /** * 动态代理: * 生成接口UserMapper的代理对象,将代理对象返回给调用者 * UserMapper mapper = sqlSession.getMapper(UserMapper.class); * 说明: * 1.这里使用自定义泛型方法,调用传递是什么类型,那么泛型就是什么类型,那么这里返回的类型使用自定义泛型,所有返回的类型也是 * 传递的类型 */ public <T> T getMapper(Class<T> clazz) {//Class<T> clazz = UserMapper.class //1.使用Proxy类调用静态方法生成接口xxxMapper(例如UserMapper)的代理对象proxyMapper //1.1类加载器:加载代理类和接口 ClassLoader loader = clazz.getClassLoader(); //1.2接口,这里代理的是接口// Class<?>[] interfaces = {UserMapper.class}; 不推荐使用,因为书写固定了 Class<?>[] interfaces = {clazz}; //1.3调用处理程序即InvocationHandler的对象 InvocationHandler h = new InvocationHandler(){ /* 说明: 1)在测试类中使用返回的代理对象mapper调用UserMapper接口中的方法queryAllUser(),那么 就会执行当前接口InvocationHandler的invoke方法List<User> users = mapper.queryAllUser(); 2) Object proxy 代理对象 不用 Method method 接口增强的方法 public abstract List queryAllUser(); Object[] args:增强方法的实参 3) 测试类代码: List<User> users = mapper.queryAllUser(); 要求在invoke方法体中使用jdbc技术查询数据表所有数据封装到List集合中,最后返回的是List集合 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //1.创建配置类对象,对象创建好之后Configuration类的成员变量都已经别赋值了 Configuration config = new Configuration(); //2.解析UserMapper接口中queryAllUser方法上的注解 @Select("select * from user") 和 // @ResultType("cn.itcast.pojo.User") //2.1获取UserMapper接口中的方法 Class<T> clazz = UserMapper.class Method[] methods = clazz.getMethods(); //2.2遍历数组取出每个方法 for (Method m : methods) {//m 就是接口UserMapper中的方法 public abstract List queryAllUser(); //2.3判断方法上是否有注解 boolean boo1 = m.isAnnotationPresent(Select.class); boolean boo2 = m.isAnnotationPresent(ResultType.class); if(boo1 && boo2){ //2.4说明获取的方法上有两个注解@Select @ResultType,开始解析注解 Select select = m.getAnnotation(Select.class); ResultType resultType = m.getAnnotation(ResultType.class); //2.5获取注解的属性值 String[] sqlArr = select.value();//{"select * from user"} String resultTypeValue = resultType.value();//"cn.itcast.pojo.User" //2.6获取映射类Mapper的对象 Mapper mapper = config.getMapper(); //2.7将解析出的注解数据存放到mapper对象中 mapper.setSql(sqlArr[0]); mapper.setResultType(resultTypeValue); } } //3.获取数据库连接池对象 DataSource ds = config.getDataSource(); //4.从数据库连接池中获取连接 Connection conn = ds.getConnection(); //5.获取发送给数据库的sql语句 Mapper mapper = config.getMapper(); String sql = mapper.getSql();//"select * from user" //6.获取封装数据表数据的结果类型 String resultType = mapper.getResultType();//"cn.itcast.pojo.User" //7.获取结果类型的Class对象 Class.forName("cn.itcast.pojo.User"); Class<?> resultTypeClazz = Class.forName(resultType); //8.调用方法使用jdbc技术查询数据表数据封装到List集合中 List list = queryForListUsers(conn,sql,resultTypeClazz); //9.将存储数据的list集合对象返回给调用者 List<User> users = mapper.queryAllUser(); return list; } /* String sql = "select * from user" Class<?> resultTypeClazz = User.class 以下方法功能:使用jdbc技术查询数据表数据封装到List集合中 */ private List queryForListUsers(Connection conn, String sql, Class<?> resultTypeClazz) throws Exception { //1.创建List集合对象 ArrayList list = new ArrayList(); //2.根据连接对象获取预编译对象 PreparedStatement pst = conn.prepareStatement(sql); //3.执行sql ResultSet rs = pst.executeQuery(); //4.处理结果集 while(rs.next()){ //5.创建实体类对象 //User user = new User(); Object obj = resultTypeClazz.newInstance();//调用的是实体类中无参构造方法 //6.获取rs结果集对象中的数据 //getObject(列名/别名/第几列的编号) 可以获取数据表的任意类型的数据varchar int double date //getObject(列名/别名/第几列的编号) 参数现在不知道书写啥了,必须保证通用性,适合所有的数据表 /* 规定: 数据表的字段名和类型要和实体类的成员变量名以及类型一致(ORM映射关系)。 举例: 数据表字段名:id 实体类成员变量名 : id 数据表字段名:name 实体类成员变量名 : name */ //6.1获取实体类所有的成员变量 Field[] fields = resultTypeClazz.getDeclaredFields(); //6.2遍历数组取出每个成员变量所属类型是Field类型 for (Field f : fields) {//f就是实体类的成员变量id name passwd age gender adddate //6.3获取每个成员变量名 String fieldName = f.getName();//fieldName表示是成员变量名:"id" "name" "passwd" "age" "gender" "adddate" //6.4根据下述方法结合成员变量名获取数据表的字段值 Object tableValue = rs.getObject(fieldName);//1 itcast 123123.... //6.5暴力反射 f.setAccessible(true); //6.6调用Field类中的set方法给成员变量赋值 f.set(obj,tableValue); } //7.将实体类对象放到list集合中 list.add(obj); } //返回集合 return list; } }; T proxyMapper = (T)Proxy.newProxyInstance(loader, interfaces, h); //2.将生成的代理对象proxyMapper返回给当前方法getMapper的调用者即在测试类中: //UserMapper mapper = sqlSession.getMapper(UserMapper.class); return proxyMapper; }}