XML
Element提供的方法

代码演示:
java
public class Dom4JTest1 {
public static void main(String[] args) throws DocumentException {
//目标:解析XML文件,使用Dom4j框架
//1、创建一个SaxReader解析对象
SAXReader saxReader = new SAXReader();
//2、把xml文件读成一个Document文档对象
Document document = saxReader.read("day11-special-file-log-code\\src\\Contact.xml");
//3、文档对象中包含了XML的全部数据,提供了方法获取数据
Element rootElement = document.getRootElement();
System.out.println(rootElement.getName());
//4、提取子元素对象
List<Element> sonEles = rootElement.elements();
for (Element sonElement : sonEles) {
System.out.println(sonElement.getName());
}
System.out.println("---");
//指定获取单个子元素对象
Element userEle = rootElement.element("user");
System.out.println(userEle.elementText("name"));
Element contactEle = rootElement.element("contact");
System.out.println(contactEle.elementText("name"));
//5、提取了元素的属性对象
Attribute idAttr = contactEle.attribute("id");
// 属性名称 "id"
System.out.println(idAttr.getName());
System.out.println(idAttr.getValue());
//直接拿属性值
System.out.println(contactEle.attributeValue("id"));
//6、文本值
//通过父元素拿到子元素的文本值
System.out.println(contactEle.elementText("name"));
System.out.println(contactEle.elementTextTrim("name"));
//先拿到元素对象,再提取文本值
Element emailEle = contactEle.element("email");
System.out.println(emailEle.getText());
System.out.println(emailEle.getTextTrim());
}
}
6、XML解析案例
需求:利用Dom4j框架,将contacts.xml文件中的联系人数据,解析出来,封装成List集合,并遍历输出;
代码演示:
java
public class Dom4JTest2 {
public static void main(String[] args) throws DocumentException {
//目标:解析XML文件,使用Dom4j框架
//1、创建一个SaxReader解析对象
SAXReader saxReader = new SAXReader();
//2、把xml文件读成一个Document文档对象
Document document = saxReader.read("day11-special-file-log-code\\src\\Contact.xml");
//3、文档对象中包含了XML的全部数据,提供了方法获取数据
Element rootElement = document.getRootElement();
//4、准备一个联系人集合存储联系人对象
List<Contact> contacts = new ArrayList<>();
//5、提取全部以及联系人元素对象
List<Element> sonEles = rootElement.elements("contact");
//6、遍历子元素对象
for (Element sonEle : sonEles) {
//7、每个子元素是一个联系人对象,创建联系人对象,封装数据
Contact contact = new Contact();
//注入数据
contact.setId(Integer.valueOf(sonEle.attributeValue("id")));
contact.setName(sonEle.elementTextTrim("name"));
contact.setGender(sonEle.elementTextTrim("gender").charAt(0));
contact.setEmail(sonEle.elementTextTrim("email"));
contacts.add(contact);
}
for (Contact contact : contacts) {
System.out.println(contact);
}
}
}
7、XML的创建
推荐直接把程序里的数据拼接成XML,然后用IO流写出去!
代码演示:
java
public class Dom4JTest3 {
public static void main(String[] args) throws Exception {
//目标:将数据写入到xml文件
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n");
sb.append("<user>\r\n");
sb.append("\t<name>").append("张三").append("</name>\r\n");
sb.append("\t<age>").append("12").append("</age>\r\n");
sb.append("\t<sex>").append("男").append("</sex>\r\n");
sb.append("</user>\r\n");
PrintStream ps = new PrintStream("day11-special-file-log-code/src/users.xml");
ps.println(sb);
ps.close();
}
}
8、约束
什么是约束XML文件的书写?
- 就是限制XML文件只能按照某种格式进行书写;
约束文档
- 专门用来限制XML书写格式的文档,比如:限制标签、属性应该怎么写。
约束文档的分类
- DTD文档
- Schema文档
XML文档约束-DTD的使用
需求:利用DTD约束文档,约束一个XML文件的编写。


注意:dtd,可以约束XML文件的编写;不能约束具体的数据类型。
XML文档约束-schema的使用
可以约束XML文件的编写、和数据类型
需求:利用schema文档约束,约束一个XML文件的编写。

注意:域名与数据类型的编写。
9、日志概述
什么是日志?
- 好比生活中的日记,可以记录你生活中的点点滴滴;
- 程序中的日志,通常就是一个文件,里面记录的是程序运行过程中的各种信息。
日志技术:
- 可以将系统执行的信息,方便的记录到指定的位置(控制台、文件中、数据库中)。
- 可以随时以开关的形式控制日志的启停,无需侵入到源代码中去进行修改。
日志框架:牛人或者第三方公司已经做好的实现代码,后来者直接可以拿去使用;
Logback是基于slf4j的日志规范实现的框架。
日志技术的体系结构

Logback日志框架官方网站:https://logback.qos.ch/
Logback日志框架有一下几个模块:

想使用Logback日志框架,至少需要在项目中整合如下三个模块:

10、日志技术框架搭建
需求:使用Logback日志框架,记录系统的运行信息;
实现步骤:

代码演示:
java
public class Test {
public static final Logger LOGGER = LoggerFactory.getLogger("Test.class");
public static void main(String[] args) {
//目标:1、创建一个Logback框架的Logger日志对象,来记日志;
try{
LOGGER.info("chu方法开始了~~");
chu(10,5);
LOGGER.info("chu方法成功了~~");
}catch(Exception e){
LOGGER.error("chu方法执行失败,出现异常: "+e.getMessage());
}
}
public static void chu(int a,int b){
LOGGER.debug("参数a: "+a);
LOGGER.debug("参数b: "+b);
int c = a/b;
LOGGER.info("c= " + c);
}
}
11、日志级别
什么是日志级别?
- 日志级别指的是日志信息的类型,日志都会分级别,常见的日志级别如下(优先级依次升高):

为什么要学习日志级别?
- 只有日志的级别是大于或等于核心配置文件配置的日志级别,才会被记录,否则不记录。

注意:all全部打印;error则只打印error及以上的级别日志;不想打印为off。
多线程
1、多线程创建方式一
什么是线程?
- 线程是一个程序内部的一条执行流程。

- 程序中如果只有一条执行流程,那这个程序就是单线程的程序;
多线程是什么?
- 多线程是指从软硬件上实现的多条执行流程的技术(多条线程由CPU负责调度执行)。
多线程用在哪里,有什么好处?
12306多用户同时购买票;百度网盘同时上传与下载;消息的发送与接收;
如何在程序中创建出多条线程?
- Java是通过java.lang.Thread类的对象来代表线程的。
多线程的创建方式一:继承Thread类

方法一优缺点:
优点:编码简单
缺点:线程类已经继承了Thread,无法继承其他类,不利于功能的扩展。
代码演示:
java
public class ThreadDemo1 {
//注意:main方法本身就是由一条主线程负责执行的
public static void main(String[] args) {
//目标:掌握线程的创建方式一:集成Thread类。
//3、创建线程对象代表具体的线程
Thread t = new MyThread();
//4、启动线程;会自动执行线程的run方法
t.start();
// t.run(); 此时就会一直子线程先跑。还是单线程,并没有去CPU注册线程
for (int i = 0; i < 4; i++) {
System.out.println("main线程输出: "+i);
}
}
}
//1、定义一个类继承Thread类,成为线程类
class MyThread extends Thread{
//2、重写run方法,声明线程要干的事情
@Override
public void run() {
for (int i = 0; i < 4; i++) {
System.out.println("子线程输出: "+i);
}
}
}
注意事项:
- 调用start方法,不调用run方法;
- 不要把主线程任务放在启动子线程之前。否则就相当于是一个单线程的效果了。
2、多线程创建方式二
实现Runnable接口

方法二的优缺点
优点:任务类只是实现接口,可以继续继承其他类,实现其他接口,扩展性强。
缺点:需要多一个Runnable对象。
代码演示:
java
public class ThreadDemo2 {
//注意:main方法本身就是由一条主线程负责执行的
public static void main(String[] args) {
//目标:掌握线程的创建方式一:集成Thread类。
//3、创建线程对象代表具体的线程
Runnable target = new MyRunnable();
//4、启动线程;会自动执行线程的run方法
new Thread(target).start();
// t.run(); 此时就会一直子线程先跑。还是单线程,并没有去CPU注册线程
for (int i = 0; i < 4; i++) {
System.out.println("main线程输出: "+i);
}
}
}
//1、定义一个类继承Runable类,成为线程类
class MyRunnable implements Runnable{
//2、重写run方法,声明线程要干的事情
@Override
public void run() {
for (int i = 0; i < 4; i++) {
System.out.println("子线程输出: "+i);
}
}
}
简化形式
匿名内部类
代码演示:
java
public class ThreadDemo2_2 {
//注意:main方法本身就是由一条主线程负责执行的
public static void main(String[] args) {
//目标:匿名内部类创建线程,Runnable
//3、创建线程对象代表具体的线程
//4、启动线程;会自动执行线程的run方法
new Thread(()-> {
for (int i = 0; i < 4; i++) {
System.out.println("子线程输出"+i);
}}).start();
// t.run(); 此时就会一直子线程先跑。还是单线程,并没有去CPU注册线程
for (int i = 0; i < 4; i++) {
System.out.println("main线程输出: "+i);
}
}
}
3、多线程创建方式三
前两种线程创建方式都存在的一个问题
- 假如线程执行完毕后有一些数据需要返回,他们重写的run方法均不能直接返回结果。
怎么解决这个问题?
- JDK 5.0提供了Callable接口和FutureTask类来实现(多线程的第三种创建方式)。
- 这种方式最大的优点:可以返回线程执行完毕后的结果。
多线程的第三种创建方式:利用Callable接口、FutureTask类来实现;

FutureTask的API

线程创建方式三的优缺点
优点:线程任务类只是实现接口,可以继续继承类和实现接口。扩展性强;可以在线程执行完毕后去获取线程执行的结果。
缺点:编码要复杂一点。
代码演示:
java
public class ThreadDemo3 {
public static void main(String[] args) {
//目标:掌握多线程的创建方式三:可以返回线程执行完成值
//3、创建Callable对象
Callable<String> call = new MyCallable(100);
//4、把Callable对象,封装成FutureTask对象
//未来任务对象有两个作用:
// 他是一个Runnable对象
// 可以获取线程执行后的结果
FutureTask<String> task = new FutureTask<>(call);
//5、把未来任务对象交给线程对象
Thread t = new Thread(task);
//6、启动线程
t.start();
Callable<String> call2 = new MyCallable(200);
FutureTask<String> task2 = new FutureTask<>(call2);
Thread t2 = new Thread(task2);
t2.start();
try {
//如果第一个线程没有执行完毕,会在这里等待第一个线程执行完毕后,再取结果
String rs1 = task.get();
System.out.println(rs1);
} catch (Exception e) {
e.printStackTrace();
}
try {
String rs2 = task2.get();
System.out.println(rs2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
//1、定义一个类实现Callable接口
class MyCallable implements Callable<String> {
private int n;
public MyCallable(int m) {
this.n = m;
}
//2、重写call方法,声明任务和返回的结果
@Override
public String call() throws Exception {
int sum = 0;
for (int i = 0; i < n; i++) {
sum += i;
}
return "子线程求和1-" + n + "的结果是" + sum;
}
}
4、线程的API
Thread提供了很多与线程操作相关的方法

