日志框架之Logback
1 日志框架选择
日志门面:SLF4J
日志实现:Logback
2 实现控制台的日志打印输出01
2.1 在需要实现日志信息打印的类中实例化Logger对象
坑01:springBoot项目默认使用slf4j的logback来实现日志处理,所以我们在导入日志相关的包是必须是 org.slf4j.Logger
private final Logger logger = LoggerFactory.getLogger(getClass());
注意01:getClass() 可以换成 类名.class
注意02: 与日志相关的包导入的是 org.slf4j 下面的
技巧01:LoggerFactory.getLogger() 中的参数是会包含在日志信息中的,所以参数必须是本类名,这样就可以根据日志信息准确的定位到日志产生处,如果写成其他的类名名就很容器造成歧义。
2.2 通过日志对象调用相应的方法实现日志的打印
log.debug("===debug===");
log.info("===info===");
log.warn("===warn===");
2.3 运行,在控制台观察打印信息【我使用的是一个测试类】
注意01:这里没有打印出debug相关的log信息,那是因为spring默认配置的日志级别是info,只有在info及以上级别的日志信息才会被打印出来
技巧02:如何查看 日志级别 信息
通过 navigate -> class 打开类名搜索窗口,IDEA的快捷键是 ctrl + N
输入 Level
选择 org.slf4j.event
从源代码中可以看出 debug 的日志级别要低于info的日志级别(数字越大级别越高)

2.4 控制台的日志输出信息
从控制台的输出信息可以看出,即使我们没有对log进行任何配置还是按照某种日志输出格式进行了输出;这是因为SpringBoot的logback日志框架有一些默认的日志配置,这就是SpringBoot默认大于配置的强大之处,如果开发者不进行任何配置时就会使用默认的配置。

2.5 查看SpringBoot默认的日志配置
在依赖文件中找到logback先关的包,正式由于这些默认的日志配置文件才出现了2.4的输出结果

3 实现控制台的日志打印输出02
3.1 在相应的类上添加 @Slf4j 注解
注意01:需要额外导入相关jar包,这个lomboc依赖包不仅包含一些日志相关的还包含一些Get/Set相关的
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
3.2 在需要进行日志输出的地方直接使用log对象的相关方法进行啦
问题01: 在使用了 @Slf4j 注解,并且导入相关jar包后,log对象出现找不到的错误信息
解决01:安装lombok相关插件,具体步骤请参见:点击前往

3.3 运行项目,观察控制台信息【我使用的是一个测试类】

3.4 如何在日志中输出变量
@Test
public void Test03() {
String name = "warrior";
Integer age = 24;
log.info("===姓名:{} = 年龄:{}", name, age);
}

4 日志配置之利用yml文件进行配置
如果只是对日志信息进行一些简单的配置就可以通过yml配置文件后者properties配置文件进行
技巧01:通常在yml或者properties配置文件中只配置日志输出级别和日志文件存储路径,其他的都使用SpringBoot原生的配置
logging:
level:
cn.xiangxu.demo.log: debug
# file: "C:/Users/a/Desktop/fury/log/logInfo.log"
path: "C:/Users/a/Desktop/fury/log" # 坑01:level 设置必须制定一个包名
# 坑02:path 和 file 只能设置一个
坑01:path 和 file 只能设置一个,而且 path 仅仅是路径而已,具体日志文件名会使用 spring.log ;而 file 不经需要设置路径还要指定日志文件名,最末尾就代表日志文件名
坑02:如果直接将 level 设置成 level: debug 这种形式就会报错,错误信息如下;因为之前版本的SpringBoot如果像这样设置就会对整个项目设置日志输出级别,我使用SpringBoot2.0版本时就会出现这种错误;解决办法时在设置 level 时指定一个包;参考博文:点击前往

4.1 控制台输出的日志信息
技巧01:日志文件中的日志信息和控制台输出的日志信息是一致的
技巧02:从日志输出信息可以看出调试的日志信息也被打印出来了,这是因为我们在设置日志的输出级别时设置的是 debug 级别

5 日志配置之利用xml文件进行配置
5.1 在 resources 目录下创建一个名为 logback-spring.xml 的日志文件

5.2 配置结果说明
技巧01:一个配置文件中可以配置多个 appender 来处理日志输出
技巧02:在 appender 由 layout 或者 encoder 负责日志格式化相关配置
技巧03:在 appender 中通过 rollingPolicy 来设置日志滚动配置(例如:每天产生一个日志文件)
技巧04:在 appender 可以通过 filter 来过滤日志级别
》LevelFilter
主要过滤日志级别,只用满足条件的日志级别会被处理;必须通过 onMatch 和 onMismatch 设置匹配到的和没匹配到的状态;状态种类如下

例子:
<onMatch>DENY</onMatch> -->> 表示对匹配到的日志级别不做处理
<onMismatch>DENY</onMismatch> -->> 表示对未匹配到的日志级别不做任何处理
》ThresholdFilter
主要过滤某个日志级别及其之上的日志级别
坑01:不可以通过 onMatch 和 onMismatch 设置匹配到的和没匹配到的状态
<?xml version="1.0" encoding="UTF-8"?> <configuration>
<!--控制台日志配置-->
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg %n</pattern>
</layout>
</appender> <!--文件日志配置【info以及warn】-->
<appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg %n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>
C:/Users/a/Desktop/fury/log/fileInfoLog.%d.log
</fileNamePattern>
</rollingPolicy>
</appender> <!--指定日志配置应用位置-->
<root lever="info">
<appender-ref ref="consoleLog" />
<appender-ref ref="fileInfoLog" />
<appender-ref ref="fileErLog" />
</root>
</configuration>
5.3 完整的日志配置文件
参考博文:点击前往
<?xml version="1.0" encoding="UTF-8"?> <configuration>
<!--控制台日志配置-->
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg %n</pattern>
</layout>
<!--<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">-->
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<!--<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg %n</pattern>-->
<!--</encoder>-->
</appender> <!--文件日志配置【info以及warn】-->
<appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--过滤日志级别:此处是将匹配到的排除,未匹配到的保留-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<!--格式配置-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg %n</pattern>
</encoder>
<!--滚动配置(按照日期生成日志文件)-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件名配置-->
<fileNamePattern>
C:/Users/a/Desktop/fury/log/fileInfoLog.%d.log
</fileNamePattern>
</rollingPolicy>
</appender> <!--日志文件配置【error及其以上的都会被处理】-->
<appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--过滤日志级别:此处是指保留匹配到的级别-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<!--日志格式配置-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg %n</pattern>
</encoder>
<!--滚动配置-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件名配置-->
<fileNamePattern>
C:/Users/a/Desktop/fury/log/fileErrorLog.%d.log
</fileNamePattern>
</rollingPolicy>
</appender> <!--日志文件配置【fileDebugLog】(仅仅处理DEBUG级别)-->
<appender name="fileDebugLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--过滤日志级别:此处是指处理匹配到的级别-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!--日志格式配置-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg %n</pattern>
</encoder>
<!--滚动配置-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件名配置-->
<fileNamePattern>
C:/Users/a/Desktop/fury/log/fileDebugLog.%d.log
</fileNamePattern>
</rollingPolicy>
</appender> <!--指定日志配置应用位置-->
<root lever="info">
<appender-ref ref="consoleLog" />
<appender-ref ref="fileInfoLog" />
<appender-ref ref="fileErrorLog" />
<appender-ref ref="fileDebugLog" />
</root>
</configuration>
5.4 在配置文件中对日志进行相关配置(参考)
<?xml version="1.0" encoding="UTF-8"?> <configuration>
<!--控制台日志配置-->
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>
%d - %msg - %n
</pattern>
</layout>
</appender> <!--文件日志配置【info以及warn】-->
<appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--过滤日志级别:此处是将匹配到的排除,未匹配到的保留-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<!--格式配置-->
<encoder>
<pattern>
%d - %msg - %n
</pattern>
</encoder>
<!--滚动配置-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件名配置-->
<fileNamePattern>
C:/Users/a/Desktop/fury/fileInfoLog.%d.log
</fileNamePattern>
</rollingPolicy>
</appender> <!--日志文件配置【error】-->
<appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--过滤日志级别:此处是指保留匹配到的级别-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<!--日志格式配置-->
<encoder>
<pattern>
%d - %msg - %n
</pattern>
</encoder>
<!--滚动配置-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件名配置-->
<fileNamePattern>
C:/Users/a/Desktop/fury/fileErrorLog.%d.log
</fileNamePattern>
</rollingPolicy>
</appender> <!--指定日志配置应用位置-->
<root lever="info">
<appender-ref ref="consoleLog" />
<appender-ref ref="fileInfoLog" />
<appender-ref ref="fileErrorLog" />
</root>
</configuration> <!--<beans xmlns="http://www.springframework.org/schema/beans"-->
<!--xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"-->
<!--xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">-->
<!--</beans>-->
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<!--<property name="LOG_HOME" value="./logs" />-->
<property name="LOG_HOME" value="C:/Users/a/Desktop/fury/log" />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg %n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/runtime.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg %n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender> <!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
</configuration>
详细配置02
<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="false" scanPeriod="60000" debug="false"> <!--定义控制台的日志输出格式-->
<property name="CONSOLE_LOG_PATTERN" value="%highlight(console) %highlight(%d{yyyy-MM-dd HH:mm:ss.SSS}) %highlight([%-10thread]) %highlight(%-5level) %highlight(%logger) -> %highlight(%msg%n)"></property>
<property name="FILE_LOG_POSITION" value="F:/AltEnter/SpringBoot/01LvYiMing/01TwoQi/03AltEnterCode/00logdir/study0util.log"></property>
<property name="FILE_LOG_PATTERN" value="console %d{yyyy-MM-dd HH:mm:ss.SSS} [%-10thread] %-5level %logger -> %msg%n"></property>
<property name="ROLLING_FILE_LOG_POSITION" value="F:/AltEnter/SpringBoot/01LvYiMing/01TwoQi/03AltEnterCode/00logdir/study0util.%d{yyyy-MM-dd}.log"></property>
<property name="ROLLING_FILE_LOG_PATTERN" value="console %d{yyyy-MM-dd HH:mm:ss.SSS} [%-10thread] %-5level %logger -> %msg%n"></property> <!--控制台输出的日志格式-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!--<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>-->
<!--<pattern>%black(控制台-) %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{10}) - %cyan(%msg%n)</pattern>-->
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender> <!--固定文件输出的日志格式-->
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<!--文件位置及其文件名-->
<file>${FILE_LOG_POSITION}</file>
<!--日志追加方式-->
<append>true</append>
<!--日志格式-->
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
</appender> <!--滚动文件输出的日志格式-->
<appender name="ROLLING-FILE-1" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--滚动配置(按照日期生成日志文件)-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件名配置-->
<fileNamePattern>${ROLLING_FILE_LOG_POSITION}</fileNamePattern>
<!--旧文件存储数量-->
<maxHistory>30</maxHistory>
</rollingPolicy>
<!--日志格式-->
<encoder>
<pattern>${ROLLING_FILE_LOG_PATTERN}</pattern>
</encoder>
</appender> <!-- 异步输出 -->
<appender name ="ASYNC" class= "ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>256</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref ="ROLLING-FILE-1"/>
</appender> <!--指定某个包或者类的日志输出方式(如果某个包在这里设定了,并且additivity="false",那么对应root中设定的日志输出方式就会失效)-->
<!--<logger name="com.xunyji.point01logback" additivity="true"></logger>-->
<!--<logger name="com.xunyji.point01logback" additivity="false" level="trace">-->
<!--<appender-ref ref="CONSOLE"></appender-ref>-->
<!--<appender-ref ref="ASYNC"></appender-ref>-->
<!--</logger>--> <!--指定所有的日志输出方式-->
<root level="info">
<appender-ref ref="CONSOLE"></appender-ref>
<appender-ref ref="FILE"></appender-ref>
<appender-ref ref="ROLLING-FILE-1"></appender-ref>
</root> </configuration>
推荐配置文件
对应参考博文:http://www.cnblogs.com/xrq730/p/8628945.html
控制台日志输出颜色设置:https://www.cnblogs.com/sxdcgaq8080/p/7885340.html
6 源代码

日志框架之Logback的更多相关文章
- Java日志框架:logback详解
为什么使用logback 记得前几年工作的时候,公司使用的日志框架还是log4j,大约从16年中到现在,不管是我参与的别人已经搭建好的项目还是我自己主导的项目,日志框架基本都换成了logback,总结 ...
- 【转】Java日志框架:logback详解
为什么使用logback 记得前几年工作的时候,公司使用的日志框架还是log4j,大约从16年中到现在,不管是我参与的别人已经搭建好的项目还是我自己主导的项目,日志框架基本都换成了logback,总结 ...
- java日志框架之logback(一)——logback工程简介
Logback工程 致力于成为log4j工程的继承者 Logback的架构足够泛型化,故能够应用于许多不同的环境.当前,logback划分为三个组件: logback-core logback-cla ...
- SpringBoot04 日志框架之Logback
1 日志框架选择 日志门面:SLF4J 日志实现:Logback 2 实现控制台的日志打印输出01 2.1 在需要实现日志信息打印的类中实例化Logger对象 坑01:springBoot项目默认使用 ...
- 拨云见日,彻底弄清楚Java日志框架 log4j, logback, slf4j的区别与联系
log4j 以及 logback, slf4j 官网 日志框架的困惑 作为一个正常的项目,是必须有日志框架的存在的,没有日志,很难追踪一些奇奇怪怪的系统问题. 但是,我们经常在项目的依赖中,见到奇奇怪 ...
- 日志框架一logback配置和使用
把logback或者log4j放在src/main/resources下,Spring容器就可以自动加载日志文件. 前言 Logback是由log4j创始人设计的又一个开源日志组件, 比log4j的性 ...
- lombok+slf4j+logback SLF4J和Logback日志框架详解
maven 包依赖 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lomb ...
- SLF4J和Logback日志框架详解
SLF4J和Logback日志框架详解 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs 本文讲述SLF4J和Logback日志框架. SLF4J是一套 ...
- SpringBoot 日志框架
默认的日志框架 logback SpringBoot使用Logback作为默认的日志框架.logback 是log4j框架的作者开发的新一代日志框架,它效率更高.能够适应诸多的运行环境,同时天然支持S ...
随机推荐
- 关于SpringBoot bean无法注入的问题(与文件包位置有关)改变自动扫描的包
原因:同事在写demo时出现bean加了@component后却无法被spring扫描到(在编译的时候IDEA就提示拿不到对应的bean)的问题. 后来经过研究是跟文件包的位置有关的. springb ...
- eclipse环境下基于已构建struts2项目整合spring+hibernate
本文是基于已构建的struts2项目基础上整合 spring+hibernate,若读者还不熟悉struts2项目,请先阅读 eclipse环境下基于tomcat-7.0.82构建struts2项目 ...
- 二、Hadoop学习笔记————架构学习
1.成百上千台服务器组成集群,需要时刻检测服务器是否故障 2.用流读取数据更加高效快速 3.存储节点具有运算功能,省略了服务器之间来回传数据的网络带宽限制 4.一次写入,多次访问,不修改数据 5.多平 ...
- JAVA基础3——常见关键字解读(1)
常见的JAVA中的关键字 static static静态变量 静态变量:使用static关键字定义的变量.static可以修饰变量和方法,也有static静态代码块.被static修饰的成员变量和成员 ...
- 简单说下 Winform 的分页快速开发框架必须要实现的几个功能之一
简单说下 Winform 的分页快速开发框架必须要实现的几个功能之一 分页非为前端分页 和 后端分页,前端分页只有适用于B/S,B/S的呈现速度远远不如C/S,而C/S则没有这个问题,所以分页必然是 ...
- Less循环
Less循环 在Less中,mixin可以调用它自身.通过这种递归调用,再结合Guard表达式和模式匹配,就可以写出各种循环结构.如,使用循环来创建一个网格类: .generate-columns(4 ...
- GDI+ 应用,Release没有错误,Debug很多。
问题描述: 在VC6环境中,一个界面工程利用了GDI+的一些库,Release模式下编译.运行无误,但在Debug模式下就会报告错误. xxx.cpp D:\Program Files\Microso ...
- Web Api 2.0中使用Swagger生成Api文档的2个小Tips
当Web Api 2.0使用OAuth2授权时,如何在Swagger中添加Authorization请求头? Swagger说明文档支持手动调用Api, 但是当Api使用OAuth2授权时,由于没有地 ...
- 使用python将多个excel合并
最近看视频学习,老师布置了个作业,关于如何使用python将多个excel进行合并,老师写的代码我感觉比较复杂,下面是我自己改良之后较简单的方式. 实现这个功能主要有两种方法,一种是用xlwd,xls ...
- CCF-201409-2-画图
问题描述 试题编号: 201409-2 试题名称: 画图 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 在一个定义了直角坐标系的纸上,画一个(x1,y1)到(x2,y2)的矩 ...