1. package cn.itcast.config;
    2. import com.alibaba.druid.pool.DruidDataSourceFactory;
    3. import org.dom4j.Document;
    4. import org.dom4j.Element;
    5. import org.dom4j.Node;
    6. import org.dom4j.io.SAXReader;
    7. import javax.sql.DataSource;
    8. import java.io.InputStream;
    9. import java.util.List;
    10. import java.util.Properties;
    11. /*
    12. 配置类
    13. 1. 解析XML文件
    14. 2. 创建德鲁伊连接池
    15. */
    16. public class Configuration {
    17. /* 定义数据库连接对象相关属性 */
    18. private String driver;//驱动 com.mysql.jdbc.Driver
    19. private String url;//连接地址 jdbc:mysql://127.0.0.1:3306/heima02
    20. private String username;//登录名 root
    21. private String password;//密码 1234
    22. /* Mapper接口的全名称 */
    23. private String interName;//"cn.itcast.mapper.UserMapper"
    24. /* 数据库连接池对象 */
    25. private DataSource dataSource;//连接池初始化成功
    26. /* 映射类对象 */
    27. //当前类Configuration加载创建Mapper对象
    28. //Mapper映射类,该类中具有成员变量: private String sql;//存储sql语句 private String resultType;//结果类型
    29. //private String sql="select * from user"
    30. //private String resultType="cn.itcast.pojo.User"
    31. private Mapper mapper = new Mapper();
    32. //无参构造方法
    33. public Configuration() {
    34. try {
    35. //解析"config.xml"文件
    36. SAXReader reader = new SAXReader();
    37. InputStream is = Configuration.class.getClassLoader().getResourceAsStream("config.xml");
    38. Document doc = reader.read(is);
    39. //调用自定义方法: 将核心配置文件中的数据封装到Configuration类的属性中
    40. loadConfigXml(doc);
    41. //调用自定义方法: 初始化数据库连接池对象
    42. createDataSource();
    43. } catch (Exception e) {
    44. e.printStackTrace();
    45. }
    46. }
    47. //初始化数据库连接池对象
    48. private void createDataSource() throws Exception {
    49. //创建属性集对象
    50. Properties p = new Properties();
    51. //向属性集对象p中添加数据:
    52. p.setProperty("url",url);//url=jdbc:mysql://127.0.0.1:3306/heima02
    53. p.setProperty("username",username);//username=root
    54. p.setProperty("password",password);//password=1234
    55. p.setProperty("driverClassName",driver);//driverClassName=com.mysql.jdbc.Driver
    56. //获取数据库连接池对象
    57. DataSource ds = DruidDataSourceFactory.createDataSource(p);
    58. //将ds赋值给成员变量dataSource
    59. this.dataSource = ds;//数据库连接池对象
    60. }
    61. //将核心配置文件中的数据封装到Configuration类属性中
    62. private void loadConfigXml(Document doc) {
    63. /*
    64. //使用document对象调用方法获取property标签:
    65. <property name="driver" value="com.mysql.jdbc.Driver"/>
    66. <property name="url" value="jdbc:mysql://127.0.01:3306/itheima"/>
    67. <property name="username" value="root"/>
    68. <property name="password" value="itheima"/>
    69. */
    70. List<Node> list = doc.selectNodes("//property");
    71. //遍历List集合
    72. for (Node node : list) {
    73. //强制转换
    74. //Node使用Element的父接口
    75. Element e = (Element) node;// <property name="driver" value="com.mysql.jdbc.Driver"/>
    76. //获取property标签的name属性值
    77. String name = e.attributeValue("name");//双引号中的name是property标签的name属性 driver
    78. //获取property标签的value属性值
    79. String value = e.attributeValue("value");//双引号中的value是property标签的value属性 com.mysql.jdbc.Driver
    80. //将value的值赋值给成员变量
    81. switch (name) {
    82. case "driver":
    83. //将从config.xml文件中获取的值com.mysql.jdbc.Driver赋值给成员变量driver
    84. this.driver = value;//数据库驱动
    85. break;
    86. case "url":
    87. this.url = value;//连接url
    88. break;
    89. case "username":
    90. this.username = value;//登录名
    91. break;
    92. case "password":
    93. this.password = value;//密码
    94. break;
    95. }
    96. }
    97. //<package name="xxx.xxx.UserMapper"></package>
    98. Node node = doc.selectSingleNode("//package");
    99. Element e = (Element) node;
    100. //Mapper接口的全名称
    101. this.interName = e.attributeValue("name");//"xxx.xxx.UserMapper" cn.itcast.mapper.UserMapper
    102. }
    103. public String getDriver() {
    104. return driver;
    105. }
    106. public void setDriver(String driver) {
    107. this.driver = driver;
    108. }
    109. public String getUrl() {
    110. return url;
    111. }
    112. public void setUrl(String url) {
    113. this.url = url;
    114. }
    115. public String getUsername() {
    116. return username;
    117. }
    118. public void setUsername(String username) {
    119. this.username = username;
    120. }
    121. public String getPassword() {
    122. return password;
    123. }
    124. public void setPassword(String password) {
    125. this.password = password;
    126. }
    127. public String getInterName() {
    128. return interName;
    129. }
    130. public void setInterName(String interName) {
    131. this.interName = interName;
    132. }
    133. public DataSource getDataSource() {
    134. return dataSource;
    135. }
    136. public void setDataSource(DataSource dataSource) {
    137. this.dataSource = dataSource;
    138. }
    139. public Mapper getMapper() {
    140. return mapper;
    141. }
    142. public void setMapper(Mapper mapper) {
    143. this.mapper = mapper;
    144. }
    145. }
    146. package cn.itcast.config;
    147. /*
    148. 映射类
    149. */
    150. public class Mapper {
    151. private String sql;//存储sql语句
    152. private String resultType;//结果类型
    153. public Mapper() {
    154. }
    155. public Mapper(String sql) {
    156. this.sql = sql;
    157. }
    158. public String getSql() {
    159. return sql;
    160. }
    161. public void setSql(String sql) {
    162. this.sql = sql;
    163. }
    164. public String getResultType() {
    165. return resultType;
    166. }
    167. public void setResultType(String resultType) {
    168. this.resultType = resultType;
    169. }
    170. }
    171. package cn.itcast.config类;
    172. import cn.itcast.anno.ResultType;
    173. import cn.itcast.anno.Select;
    174. import cn.itcast.mapper.UserMapper;
    175. import cn.itcast.pojo.User;
    176. import javax.management.relation.Role;
    177. import javax.sql.DataSource;
    178. import java.lang.reflect.*;
    179. import java.sql.Connection;
    180. import java.sql.PreparedStatement;
    181. import java.sql.ResultSet;
    182. import java.sql.SQLException;
    183. import java.util.ArrayList;
    184. import java.util.List;
    185. @SuppressWarnings("all")
    186. public class SqlSession {
    187. /**
    188. * 动态代理:
    189. * 生成接口UserMapper的代理对象,将代理对象返回给调用者
    190. * UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    191. * 说明:
    192. * 1.这里使用自定义泛型方法,调用传递是什么类型,那么泛型就是什么类型,那么这里返回的类型使用自定义泛型,所有返回的类型也是
    193. * 传递的类型
    194. */
    195. public <T> T getMapper(Class<T> clazz) {//Class<T> clazz = UserMapper.class
    196. //1.使用Proxy类调用静态方法生成接口xxxMapper(例如UserMapper)的代理对象proxyMapper
    197. //1.1类加载器:加载代理类和接口
    198. ClassLoader loader = clazz.getClassLoader();
    199. //1.2接口,这里代理的是接口
    200. // Class<?>[] interfaces = {UserMapper.class}; 不推荐使用,因为书写固定了
    201. Class<?>[] interfaces = {clazz};
    202. //1.3调用处理程序即InvocationHandler的对象
    203. InvocationHandler h = new InvocationHandler(){
    204. /*
    205. 说明:
    206. 1)在测试类中使用返回的代理对象mapper调用UserMapper接口中的方法queryAllUser(),那么
    207. 就会执行当前接口InvocationHandler的invoke方法List<User> users = mapper.queryAllUser();
    208. 2)
    209. Object proxy 代理对象 不用
    210. Method method 接口增强的方法 public abstract List queryAllUser();
    211. Object[] args:增强方法的实参
    212. 3)
    213. 测试类代码: List<User> users = mapper.queryAllUser();
    214. 要求在invoke方法体中使用jdbc技术查询数据表所有数据封装到List集合中,最后返回的是List集合
    215. */
    216. @Override
    217. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    218. //1.创建配置类对象,对象创建好之后Configuration类的成员变量都已经别赋值了
    219. Configuration config = new Configuration();
    220. //2.解析UserMapper接口中queryAllUser方法上的注解 @Select("select * from user") 和
    221. // @ResultType("cn.itcast.pojo.User")
    222. //2.1获取UserMapper接口中的方法 Class<T> clazz = UserMapper.class
    223. Method[] methods = clazz.getMethods();
    224. //2.2遍历数组取出每个方法
    225. for (Method m : methods) {//m 就是接口UserMapper中的方法 public abstract List queryAllUser();
    226. //2.3判断方法上是否有注解
    227. boolean boo1 = m.isAnnotationPresent(Select.class);
    228. boolean boo2 = m.isAnnotationPresent(ResultType.class);
    229. if(boo1 && boo2){
    230. //2.4说明获取的方法上有两个注解@Select @ResultType,开始解析注解
    231. Select select = m.getAnnotation(Select.class);
    232. ResultType resultType = m.getAnnotation(ResultType.class);
    233. //2.5获取注解的属性值
    234. String[] sqlArr = select.value();//{"select * from user"}
    235. String resultTypeValue = resultType.value();//"cn.itcast.pojo.User"
    236. //2.6获取映射类Mapper的对象
    237. Mapper mapper = config.getMapper();
    238. //2.7将解析出的注解数据存放到mapper对象中
    239. mapper.setSql(sqlArr[0]);
    240. mapper.setResultType(resultTypeValue);
    241. }
    242. }
    243. //3.获取数据库连接池对象
    244. DataSource ds = config.getDataSource();
    245. //4.从数据库连接池中获取连接
    246. Connection conn = ds.getConnection();
    247. //5.获取发送给数据库的sql语句
    248. Mapper mapper = config.getMapper();
    249. String sql = mapper.getSql();//"select * from user"
    250. //6.获取封装数据表数据的结果类型
    251. String resultType = mapper.getResultType();//"cn.itcast.pojo.User"
    252. //7.获取结果类型的Class对象 Class.forName("cn.itcast.pojo.User");
    253. Class<?> resultTypeClazz = Class.forName(resultType);
    254. //8.调用方法使用jdbc技术查询数据表数据封装到List集合中
    255. List list = queryForListUsers(conn,sql,resultTypeClazz);
    256. //9.将存储数据的list集合对象返回给调用者 List<User> users = mapper.queryAllUser();
    257. return list;
    258. }
    259. /*
    260. String sql = "select * from user"
    261. Class<?> resultTypeClazz = User.class
    262. 以下方法功能:使用jdbc技术查询数据表数据封装到List集合中
    263. */
    264. private List queryForListUsers(Connection conn, String sql, Class<?> resultTypeClazz) throws Exception {
    265. //1.创建List集合对象
    266. ArrayList list = new ArrayList();
    267. //2.根据连接对象获取预编译对象
    268. PreparedStatement pst = conn.prepareStatement(sql);
    269. //3.执行sql
    270. ResultSet rs = pst.executeQuery();
    271. //4.处理结果集
    272. while(rs.next()){
    273. //5.创建实体类对象
    274. //User user = new User();
    275. Object obj = resultTypeClazz.newInstance();//调用的是实体类中无参构造方法
    276. //6.获取rs结果集对象中的数据
    277. //getObject(列名/别名/第几列的编号) 可以获取数据表的任意类型的数据varchar int double date
    278. //getObject(列名/别名/第几列的编号) 参数现在不知道书写啥了,必须保证通用性,适合所有的数据表
    279. /*
    280. 规定:
    281. 数据表的字段名和类型要和实体类的成员变量名以及类型一致(ORM映射关系)。
    282. 举例:
    283. 数据表字段名:id 实体类成员变量名 : id
    284. 数据表字段名:name 实体类成员变量名 : name
    285. */
    286. //6.1获取实体类所有的成员变量
    287. Field[] fields = resultTypeClazz.getDeclaredFields();
    288. //6.2遍历数组取出每个成员变量所属类型是Field类型
    289. for (Field f : fields) {//f就是实体类的成员变量id name passwd age gender adddate
    290. //6.3获取每个成员变量名
    291. String fieldName = f.getName();//fieldName表示是成员变量名:"id" "name" "passwd" "age" "gender" "adddate"
    292. //6.4根据下述方法结合成员变量名获取数据表的字段值
    293. Object tableValue = rs.getObject(fieldName);//1 itcast 123123....
    294. //6.5暴力反射
    295. f.setAccessible(true);
    296. //6.6调用Field类中的set方法给成员变量赋值
    297. f.set(obj,tableValue);
    298. }
    299. //7.将实体类对象放到list集合中
    300. list.add(obj);
    301. }
    302. //返回集合
    303. return list;
    304. }
    305. };
    306. T proxyMapper = (T)Proxy.newProxyInstance(loader, interfaces, h);
    307. //2.将生成的代理对象proxyMapper返回给当前方法getMapper的调用者即在测试类中:
    308. //UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    309. return proxyMapper;
    310. }
    311. }