XML & DOM4j & 自定义连接池
一、XML
XML简介
- xml 与 properties 的区别 - 平铺的关系二者都行,但是如果有层级关系用xml 才行。
XML组成
文档声明
注释
元素(标签)
标签属性
转义字符
字符区
代码示例
<?xml version="1.0" encoding="UTF-8" ?><!--这是一个文档声明--> <!--我是一个注释--> <!--我是 一个 多行注释--> <!--根标签 不能是 自闭和 标签--> <aa> <!--闭合标签--> <bb></bb> <!--自闭和标签--> <cc/> <!--标签不能交叉嵌套--> <!--<ee><dd></ee></dd>--> <!--属性:属性 = 属性值--> <bb id="b01"></bb> <bb id="b02" name="bb01" ></bb> <bb id="b03"/> <bb id="b04" name="bb02"/> <!--转义字符--> <bb> <!-- 1 < 10--> <!--这里的小于号,与xml语法冲突,造成报错--> 1 < 10 1 > 10 <!--省略号、单双引号和大于号等是合法的,但将其替换为转义字符是个好习惯--> <!--jdbc:mysql///day16?useSSL=false&encoding=utf-8;--> jdbc:mysql///day16?useSSL=false&encoding=utf-8; </bb> <!--字符区--> <!--格式:<![CDATA[文本数据]]>--> <![CDATA[ 1<10 jdbc:mysql///day16?useSSL=false&encoding=utf-8; ]]> </aa>
XML约束
概述
· 这些约束会优先从本地去找,如果发现本地就有,那就不会去你写的那个网站去找。
DTD约束
<1> 定义格式
<2> 引用方式
- 网络上公共的DTD,其实在第一次引用的时候,会从网上下载到本地
内部DTD
<?xml version="1.0" encoding="UTF-8" ?> <!--内部DTD:<!DOCTYPE 根元素名称 [元素约束] >--> <!DOCTYPE books [ <!ELEMENT books (book,book2)> <!ELEMENT book ANY > <!ELEMENT book2 ANY > ]> <books> <book></book> <book2></book2> </books>
本地DTD
//book.dtd <!ELEMENT books (book,book2)> <!ELEMENT book ANY > <!ELEMENT book2 ANY > <?xml version="1.0" encoding="UTF-8" ?> <!--本地DTD:<!DOCTYPE 根元素名称 SYSTEM "文件名">--> <!DOCTYPE books SYSTEM "book.dtd"> <books> <book></book> <book2></book2> </books>
公共DTD
<?xml version="1.0" encoding="UTF-8" ?> <!--公共DTD:<!DOCTYPE 根元素名称 PUBLIC “DTD名称” “DTD文档URL”>--> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> </struts>
<3> 例子
~ 代码示例
· book.dtd
<?xml version="1.0" encoding="UTF-8" ?> <!ELEMENT 书架 (书+)> <!ELEMENT 书 (书名,作者,售价)> <!ELEMENT 书名 (#PCDATA)> <!ELEMENT 作者 (#PCDATA)> <!ELEMENT 售价 (#PCDATA)> <!ATTLIST 书 id ID #REQUIRED 编号 CDATA #IMPLIED 出版社 (清华|北大) "北大" type CDATA #FIXED "IT" >
· book.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE 书架 SYSTEM "book.dtd"> <书架> <书 id="b01" 编号="book001" 出版社="北大" type="IT"> <书名></书名> <作者></作者> <售价></售价> </书> <书 id="b02" > <书名></书名> <作者></作者> <售价></售价> </书> </书架>
Schema约束
<1> 概述 与 定义
<2> 引用方式
· booka.xsd
<?xml version="1.0" encoding="UTF-8" ?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.xmltest.cn" elementFormDefault="qualified" > <xs:element name='书'> <xs:complexType> <xs:sequence> <xs:element name='书名' type='xs:string'/> <xs:element name='作者' type='xs:string'/> <xs:element name='售价' type='xs:double'/> </xs:sequence> <xs:attribute name="bid" type="xs:int" use="optional"/> </xs:complexType> </xs:element> </xs:schema>
· bookb.xsd
<?xml version="1.0" encoding="UTF-8" ?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.xmltest.cn" elementFormDefault="qualified" > <xs:element name='书'> <xs:complexType> <xs:sequence> <xs:element name='书名' type='xs:string'/> <xs:element name='作者' type='xs:string'/> </xs:sequence> <xs:attribute name="bid" type="xs:int" use="optional"/> </xs:complexType> </xs:element> </xs:schema>
· book.xml
<?xml version="1.0" encoding="UTF-8"?> <书架 xmlns:aa="http://www.xmltest1.cn" xmlns:bb="http://www.xmltest.cn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xmltest1.cn booka.xsd http://www.itheima.cn bookb.xsd" > <aa:书> <aa:书名>三国演义</aa:书名> <aa:作者>罗贯中</aa:作者> <aa:售价>199</aa:售价> </aa:书> <bb:书> <bb:书名>水浒传</bb:书名> <bb:作者>施耐庵</bb:作者> <!--<aa:售价>199</aa:售价>--> </bb:书> </书架>
<3> 对应关系
XML解析概述
二、DOM4j
DOM4j 解析
books.xml
<?xml version="1.0" encoding="UTF-8"?> <books> <book id="0001"> <name>JavaWeb开发教程</name> <author>张孝祥</author> <sale>100.00元</sale> </book> <book id="0002"> <name>三国演义</name> <author>罗贯中</author> <sale>100.00元</sale> </book> <book2 id="0003"> <name>三国演义</name> <author>罗贯中</author> <sale>100.00元</sale> </book2> </books>
DOM4j 解析 - 代码示例
public class Test { public static void main(String[] args) throws Exception { //1. 导入jar包: dom4j-1.6.1j.jar //2. 创建解析器:public SAXReader() SAXReader saxReader = new SAXReader(); //3. 通过解析器对象读取xml,获得Document对象:Document read(InputStream in) in是xml文件对应的输入流 FileInputStream in = new FileInputStream("day18\\src\\books.xml"); Document document = saxReader.read(in); //4. 通过树结构对象获取根元素:Element getRootElement(); Element rootElement = document.getRootElement(); //5. 操作元素节点(使用Element中的方法) //需求1:获取根标签的标签名 System.out.println("rootElement.getName()=" + rootElement.getName()); //需求2:获取books标签下面所有的book子标签 //List<Element> elements = rootElement.elements();//获取所有子标签 List<Element> elements = rootElement.elements("book");//获取所有book子标签 for (Element element : elements) { System.out.println("element.getName()=" + element.getName()); } //需求3:获取books标签下面第一个book标签 Element book = rootElement.element("book"); System.out.println("book.getName()="+book.getName()); //需求4:获取第1个book标签指定的属性值 String id = book.attributeValue("id"); System.out.println("id="+id); //需求5:获取第一个book标签的子标签name的内容 Element name = book.element("name"); System.out.println("name.getText()="+name.getText()); } }
Xpath解析
tianqi.xml
<?xml version="1.0" encoding="UTF-8"?> <天气预报> <北京 provide='京' id='1'> <温度> <最高温度 level="A">18</最高温度> <最低温度>6</最低温度> </温度> <湿度>20%</湿度> </北京> <深圳> <温度> <最高温度 level="C">36</最高温度> <最低温度>24</最低温度> </温度> <湿度>50%</湿度> </深圳> <广州> <温度> <最高温度 level="C">32</最高温度> <最低温度>21</最低温度> </温度> <湿度>50%</湿度> <黄浦区> <温度> <最高温度 level="C">31</最高温度> <最低温度>22</最低温度> </温度> <湿度>50%</湿度> </黄浦区> <天河区> <温度> <最高温度 level="C">30</最高温度> <最低温度>26</最低温度> </温度> <湿度>50%</湿度> </天河区> </广州> </天气预报>
Xpath 解析 - 代码示例
public class Test { public static void main(String[] args) throws Exception { //导入dom4j-1.6.1j.jar和jaxen-1.1-beta-6.jar //创建解析器对象获取Document对象获取根节点 SAXReader saxReader = new SAXReader(); Document document = saxReader.read(new FileInputStream("day18\\src\\tianqi.xml")); Element rootElement = document.getRootElement(); //Element对象支持以下方法 //Node selectSingleNode("xpath语法"):获得一个节点(标签/元素) //List selectNodes("xpath语法"):获得多个节点(标签/元素) //操作元素节点 //①基本使用 //需求1:获取深圳的最低温度(绝对路径) Node node1 = rootElement.selectSingleNode("/天气预报/深圳/温度/最低温度"); System.out.println(node1.getName()+"=="+node1.getText()); //需求2:获取深圳的最低温度(相对路径) Node node2 = rootElement.selectSingleNode("深圳/温度/最低温度"); System.out.println(node2.getName()+"=="+node2.getText()); //需求3:获取深圳的最低温度(全文搜索) Node node3 = rootElement.selectSingleNode("//深圳//温度//最低温度"); System.out.println(node3.getName()+"=="+node3.getText()); //需求4:获取北京的最高温度(谓语) Node node4 = rootElement.selectSingleNode("//最高温度[@level='A']"); System.out.println(node4.getName()+"=="+node4.getText()); //②特殊情况 //需求5:通过深圳最低温度节点,获取广州黄浦区的最低温度(相对路径) Node node5 = node1.selectSingleNode("../../../广州/黄浦区/温度/最低温度"); System.out.println(node5.getName()+"=="+node5.getText()); //需求6:获取所有最高温度(全文搜索) List list = rootElement.selectNodes("//最高温度"); for (Object o : list) { //System.out.println(o.getName()+"=="+o.getText());//error Node node = (Node) o; System.out.println("--->"+node.getName()+"=="+node.getText()); } //需求7:获取属性level='C'的所有最高温度(谓语) List list2 = rootElement.selectNodes("//最高温度[@level='C']"); for (Object o : list2) { Node node = (Node) o; System.out.println("===>"+node.getName()+"=="+node.getText()); } } }
三、自定义连接池
概述
优化版
- 自己写的获取连接的方法与别人定义的可能不一样,所以不够通用,但因为sun公司定义了一个接口DataSource,让所有自定义连接池有了统一的规范,我们只需要重写获取连接的方法。
- 归还连接的方法也不够通用,而且DataSource接口没有定义归还连接的统一方法,那我们只能通过代理模式,对连接对象的close功能进行增强实现。
代码示例
public class MyDataSource implements DataSource { private static LinkedList<Connection> pool = new LinkedList<>(); private static int initCount = 5; //定义静态代码块,添加连接对象 static { try { //注册驱动 Class.forName("com.mysql.jdbc.Driver"); //准备连接数据 String url = "jdbc:mysql:///day16?useSSL=false"; String username = "*********"; String password = "************"; for (int i = 0; i < initCount; i++) { //获取连接对象 Connection conn = DriverManager.getConnection(url, username, password); //将连接对象添加到连接池 pool.addLast(conn); } } catch (Exception e) { e.printStackTrace(); } } @Override public Connection getConnection() throws SQLException { //被代理的连接对象 Connection conn = pool.removeFirst(); //准备获取代理对象的数据 ClassLoader classLoader = conn.getClass().getClassLoader(); Class<?>[] interfaces = conn.getClass().getInterfaces(); InvocationHandler handler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //System.out.println("method===>"+ method.getName()); //对连接对象原有的close方法进行处理 if ("close".equals(method.getName())) { pool.addLast(conn); return null; } else { //千万注意,要对其他的方法,进行处理,不处理,意味着调用其他方法,啥也不做。 Object result = method.invoke(conn, args); return result; } } }; //获取代理对象 Connection connProxy = (Connection) Proxy.newProxyInstance(classLoader, interfaces, handler); //返回连接对象的代理对象 return connProxy; } //获取连接池中的连接对象个数 public int size() { return pool.size(); } @Override public Connection getConnection(String username, String password) throws SQLException { return null; } @Override public <T> T unwrap(Class<T> iface) throws SQLException { return null; } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; } @Override public PrintWriter getLogWriter() throws SQLException { return null; } @Override public void setLogWriter(PrintWriter out) throws SQLException { } @Override public void setLoginTimeout(int seconds) throws SQLException { } @Override public int getLoginTimeout() throws SQLException { return 0; } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { return null; } }
测试类
public class Test { public static void main(String[] args) throws SQLException { //获取连接池对象 MyDataSource pool = new MyDataSource(); //获取连接对象(实际获取的是代理对象) Connection conn = pool.getConnection(); //打印连接对象 System.out.println(conn); //执行sql操作 ... //打印归还前的连接池中的连接数量 System.out.println("终极版-->连接池中的连接数:" + pool.size()); //归还连接对象 conn.close(); //打印归还后的连接池中的连接数量 System.out.println("终极版-->连接池中的连接数:" + pool.size()); } }
本文含有隐藏内容,请 开通VIP 后查看