[Java学习日记]日志、类加载器、XML、DTD与schema、XML解析、XPath、单元测试、Assert、BeforeAfter、注解、自定义注解、注解案例

下面的案例中只是做一个简单的了解,不做深入理解啦

目录

一.使用Logback写日志

二.类加载器

三.XML

四.XML编写规定:DTD与schema

五.XML解析

六.XPath

七.单元测试

七.Assert(断言):检验方法结果

八.使用before与after注解备份与还原数据

九.注解

十.自定义注解

十一.注解案例:用注解模拟JUnit


使用到的部分jar包版本如下:

 

 

一.使用Logback写日志

使用Logback写日志
把输出语句保存到文件当中
接口规范:Commons Logging(JCL)与Simple Logging Facade for java(slf4j)
日志实现框架:JUL(Java自带)、log4j、Logback(现在学习的,基于slf4j)
在使用Logger前应该做的准备工作有哪些?
1.需要导入的jar包:slf4j(规范)logback-core(核心)logback-classic(实现了完整的slf4j)logback-access(与汤猫服务器继承,提供了日志访问功能)
2.将配置文件logback.xml拷贝到src目录下

在测试类中如何使用logback产生日志文件?
1.通过LoggerFactory类的静态方法getLogger,传入本类对象创建Logger对象
2.通过Logger的info(或者其他方法记录信息)写入日志信息

配置文件:

<?xml version="1.0" encoding="UTF-8"?> 
<configuration>
    <!-- appender标签用于设置输出位置与输出格式 -->
    <!-- 控制台输出,CONSOLE表示可以输出到控制台 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--可以改为error-->
        <target>System.out</target>
        <encoder charset="UTF-8">
            <!-- 输出日志记录格式 %d是日期  level表示日志级别  c表示当前操作的类  thread是线程名  %msg%n是显示消息加换行 -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%c] [%thread] : %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 输出文件日志 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder charset="UTF-8">
            <pattern>%d{yyyy-MM-dd HH:mm:ss} : %msg%n</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志输出路径,每天产生一个文件-->
            <fileNamePattern>D:/IDEACode/demo1/JAVA基础/src/Day36/MyLog/data%d{yyyy-MMdd}.log</fileNamePattern>
        </rollingPolicy>
    </appender>

    <!--
    level设置日志输出级别   ref标识输出位置,表示可以输出到控制台与File文件
    All表示全打印,OFF表示全部不打印(也可以用来关闭日志)
    一般写INFO与DEBUG,高于这个级别的,比如ERROR也会输出
    -->
    <root level="All">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
</configuration>
public class Demo361Logback {
    final static Logger LOGGER = LoggerFactory.getLogger("Demo361Logback.class");
    public static void main(String[] args) {
        LOGGER.info("SunCoya学习日志");
    }
}

 

 

 


 

二.类加载器

类加载器:把字节码class文件搬运到虚拟机里面

类加载时机-用到才加载
1.创建对象 2.调用静态方法 3.访问静态变量 4.使用反射创建class对象 5.初始化子类 6.java.exe

类加载过程
加载:
    通过全限定名获取定义此类的二进制流
    把静态存储结构转化为运行时数据结构
    加载完毕则创建一个class对象
连接:
    验证:检查信息有没有安全隐患
    准备:为静态变量初始化值—默认
    解析:加载把引用型变量需要用到的类,把符号引用变为直接引用
初始化:
    初始化静态变量:变为被复制的值

加载器分类
所有加载请求都会被送到最顶层的启动类加载器,然后往下送,看那个加载器能加载
启动类加载器:虚拟机内置类加载器
平台类加载器:加载JDK特殊模块
系统类加载器:加载用户类路径上所指定的类库
自定义加载器
public class Demo362ClassLoader {
    final static String FILE_STR = "Day35_Reflect_DynamicAgent\\message.properties";
    public static void main(String[] args) throws IOException {
        //获得系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        ClassLoader platformClassLoader = systemClassLoader.getParent();
        ClassLoader bootStrapClassLoader = platformClassLoader.getParent();
        System.out.println(systemClassLoader);
        System.out.println(platformClassLoader);
        System.out.println(bootStrapClassLoader);

        //加载某一个资源文件:只能设置本模块中的路径
        InputStream stream = systemClassLoader.getResourceAsStream(FILE_STR);
        Properties properties = new Properties();
        properties.load(stream);
        System.out.println(properties);
        stream.close();
    }
}

 

 


 

三.XML

XML(EXtensible markup language,可扩展(标签名字随便写)的标记性语言)
一般用来保存配置文件,缺点就是解析起来比较复杂
使用properties配置文件时遇到同键多值的情况会出现问题

xml声明规则:
1.文档声明必须是第一行,声明版本号码,编码:<?xml version="1.0" encoding="UTF-8" ?>
2.标签必须要有一对<name></name>或者是不成对的标签:<name/>
3.必须要有根标签(最外面的标签),且只能有一个
4.在标签里面可以设置属性,要与标签名隔开,属性值要用引号引起来:<student id="1"><student/>
<?xml version="1.0" encoding="UTF-8" ?>
<students>
    <student id="1">
        <name>zhangsan</name>
        <age>23</age>
        <!--特殊符号-->
        <special>小于&lt; 大于&gt; 且&amp; 单引&apos; 双引&quot;</special>
        <!--使用CD快捷键加入CDATA模块-->
        <special><![CDATA[<&'">]]></special>
    </student>
</students>

 


 

四.XML编写规定:DTD与schema

DTD(Document Type Definition):约束文档,后缀必须是.dtd

<!ELEMENT 书架 (书+)>
元素根标签必须叫书架,书架里面的元素必须是书,书能写多个
<!ELEMENT 书 (书名,作者,售价)>
书里面有三个子标签
<!ELEMENT 书名 (#PCDATA)>
代表里面的元素只能是文本数据, 缺点就是不能限定数据类型

而schema可以约束具体数类型,约束能力更加强大,其本身也是一个xml文件,也受到其他xml文件的约束
编写schema约束文档,后缀名必须是xsd

dtd文件:

<!ELEMENT 书架 (书+)>
<!ELEMENT 书 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>

 chema文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!--xmlns:当前schema文件被谁约束 targetNamespace:地址名字-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
        targetNamespace="http://www.itcast.cn/"
        elementFormDefault="qualified">
    <xs:element name="书架">
        <xs:complexType>
            <xs:sequence maxOccurs="unbounded">
                <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:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>
引入DTD:
1.引入本地:<!DOCTYPE 根元素名 SYSTEM 'DTD文件的路径'>
2.内部引入:<!DOCTYPE 根元素名称[dtd文件内容]>
3.引入网络:<!DOCTYPE 根元素名称 PUBLIC "DTD文件名称" "DTD文档的URL"

 XML导入DTD:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE 书架 SYSTEM 'book.dtd'>
<!--引入之后直接左尖括号就能生成-->
<书架>
    <书>
        <书名>Java从入门到起飞</书名>
        <作者>阿玮</作者>
        <售价>100w</售价>
    </书>
    <书>
        <书名>Java算法真经</书名>
        <作者>????</作者>
        <售价>100w</售价>
    </书>
</书架>

 


 

五.XML解析

使用dom4j.jar去解析xml文档
SAX解析(Simple API for XML):逐行读取,只能查不能改,但是查询效率高
DOM解析:整体加载到内存,形成树型结构,可查可改,我们学习的也是DOM解析工具
在dom思想中:attribute是属性
public class Demo363XMLoad {
    final static String FILE_STR = "JAVA基础\\src\\Day36\\MyXML\\students2.xml";
    public static void main(String[] args) throws DocumentException {
        System.out.println("1.创建SAXReader对象");
        SAXReader saxReader = new SAXReader();
        System.out.println("2.调用saxReader的read方法,传入需要读取的文件,获取dom对象");
        Document document = saxReader.read(new File(FILE_STR));
        System.out.println(document);
        System.out.println("3.通过dom获取根标签对象");
        Element rootElement = document.getRootElement();
        System.out.println(rootElement.getName());
        System.out.println("4.通过根标签获取子标签,传入参数代表限制标签名");
        List<Element> elements = rootElement.elements();
        for (Element element : elements)System.out.println(element.getName());
        System.out.println("5.通过标签获取属性,内容,把数据放到集合中");
        ArrayList<Student> arrayList = new ArrayList<>();
        for (Element element : elements) {
            //获取标签属性
            Attribute attribute = element.attribute("id");
            String id = attribute.getText();
            //获取标签
            String name = element.element("name").getText();
            String age = element.element("age").getText();
            arrayList.add(new Student(Integer.parseInt(id),name,Integer.parseInt(age)));
        }
        System.out.println(arrayList);
    }
}
public class Student {
    private int id;
    private String name;
    private int age;
    public Student() {
    }
    public Student(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    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 int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String toString() {
        return "Student{id = " + id + ", name = " + name + ", age = " + age + "}";
    }
}

 

<?xml version="1.0" encoding="UTF-8" ?>
<students>
    <student id="1">
        <name>zhangsan</name>
        <age>23</age>
    </student>
    <student id="2">
        <name>lisi</name>
        <age>24</age>
    </student>
    <student id="3">
        <name>wangwu</name>
        <age>25</age>
    </student>
</students>

 


 

六.XPath

Xpath技术:获取xml文档中的单个元素,依赖于dom4j
其提供了比较独特的路径思想:使用路径来定位元素节点或者是属性节点
导入jaxen.jar包(暂时未用到)
public class Demo364XPath {
    public static void main(String[] args) throws DocumentException {
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(new File(Demo363XMLoad.FILE_STR));
        System.out.println("1.获取到DOM对象之后使用selectNodes方法获取节点元素");
        System.out.println("2.绝对路径:从头开始一级一级往下,可以检索多个符合这一条路径的元素,用多个/表示");
        List<Node> nodes = document.selectNodes("/students/student/name");
        for (Node node : nodes) {System.out.println(node.getText());}

        System.out.println("如果是获取单个标签,则得到第一个");
        Node node = document.selectSingleNode("students/student/name");
        System.out.println(node.getText());

        System.out.println("3.相对路径:需要找到一个当前节点,用.表示");
        Element rootElement = document.getRootElement();
        nodes = rootElement.selectNodes("./student/name");
        for (Node node1 : nodes) {System.out.println(node1.getText()); }

        System.out.println("""
                4.全文检索:直接搜索元素名,使用//,比如我的案例中可以直接使用//name
                下面的写法则是搜索所有students路径下的name,不必严格一级一级往下
                也可以写//student/name:表示搜索到的name一定要在student下一级
                也就是说有两条杠就可以随意玩,只有一条杠就需要遵守层级规则                   
                """);
        nodes = document.selectNodes("//students//name");
        for (Node node1 : nodes) {System.out.println(node1.getText()); }

        System.out.println("5.属性检索,使用//@属性名检索所有的属性");
        nodes = document.selectNodes("//@id");
        for (Node node1 : nodes) { System.out.println(node1.getText()); }

        System.out.println("6.通过特定属性检索标签:在标签后添加[@属性名]");
        nodes=document.selectNodes("//student[@id]");
        for (Node node1 : nodes) { System.out.println(node1.getName()); }

        System.out.println("7.通过固定属性检索标签,在上面的案例基础上给属性赋值即可,下面字符串中只能用单引");
        nodes = document.selectNodes("//student[@id='1']");
        for (Node node1 : nodes) { System.out.println(node1.getName()); }
    }
}

 

 


 

七.单元测试

单元测试:针对Java中的方法的测试
编写测试方法:public void method(),一定要是非静态方法,在测试方法上使用@Test注解
左边的External Libraries中出现JUnit4
点击类名左边的绿色箭头可测试多个方法
public class Demo365JUnitTest {
    @Test
    public void method1(){
        System.out.println("测试方法一");
    }
    @Test
    public void method2(){
        System.out.println("测试方法二");
    }
    @Test
    public void method3(){
        System.out.println("测试方法三");
    }
}

 


 

七.Assert(断言):检验方法结果

public class Demo366JUnitAssert {
    @Test
    public void method1(){
        Demo366JUnitAssert jt = new Demo366JUnitAssert();
        int res = jt.add(1, 1);
        //参数一:两个结果不一样的提示消息
        Assert.assertEquals("这个方法出错了",2,res);
    }
    public int add(int a,int b){
        return a*b;
    }
}

 

 


 

八.使用before与after注解备份与还原数据

public class Demo367BeforeAfter {
    //在测试单元中,相对路径是在当前模块中,和类加载器一样
    final static String FILE_STR = "src\\Day36\\MyLog\\a.txt";
    final static String FILE_COPY ="src\\Day36\\MyLog\\aCopy.txt";
    @Test
    public void test(){
        boolean b = new File(FILE_STR).delete();
        Assert.assertTrue(b);
        b=new File(FILE_STR).exists();
        Assert.assertFalse(b);
        System.out.println("Test,在这个方法里面做测试");
    }
    @Before
    public void before(){
        FileUtil.copy(new File(FILE_STR),new File(FILE_COPY),false);
        System.out.println("before,使用这个方法初始化数据,比如数据的删除");

    }
    @After
    public void after(){
        FileUtil.copy(new File(FILE_COPY),new File(FILE_STR),false);
        new File(FILE_COPY).delete();
        System.out.println("after,使用这个方法还原数据,删除备份数据");
    }
}

 

 


 

九.注解

注解主要是给编译器看的,用来检测
@Deprecated:表示方法已经过时:也会给你提示替代方案
@SuppressWarnings("all"):压制(去除)警告
@SuppressWarnings("all")
public class Demo368Annotation {
    public static void main(String[] args) {
        int a;
    }
    @Deprecated
    public static void method(){
        System.out.println("haihai");
    }
}

 


 

十.自定义注解

自定义注解:结合反射使用
能在变量上使用,也能在方法中使用
public @interface MyAnno {
    //可以不写默认值
    public String name()default "???";
    public int age();
}
public class Demo369MyAnno {
    //如果注解中只有一个属性,就可以只写值,如压制警告
    @MyAnno(name = "啊?",age=20)
    String aaa;
    String bbb;
    @MyAnno(name = "啊?",age=20)
    public void method(){
        System.out.println("方法一");
    }
    public void method2(){
        System.out.println("方法二");
    }
}

 


 

十一.注解案例:用注解模拟JUnit

元注解:注解的注解
@Target:约束注解使用的地方
@Retention:申明注解的生命周期
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {}
public class Main {
    public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException {
        Class<?> aClass = Class.forName("Day36.Demo3610.Main");
        //补个对象
        Main main = new Main();
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            method.setAccessible(true);
            if (method.isAnnotationPresent(MyTest.class)){
                method.invoke(main);
            }
        }
    }

    @MyTest
    public void method1(){
        System.out.println("方法一");
    }
    @MyTest
    public void method2(){
        System.out.println("方法二");
    }
    public void method3(){
        System.out.println("方法三");
    }
}
  • 16
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值