项目调试技巧
- 响应状态码的含义
- 服务端断点调试技巧
- 客户端断点调试技巧
- 设置日志级别,并将日志输出到不同的终端
响应状态码
还是之前提到过的文档,HTTP 响应状态代码指示特定 HTTP 请求是否已成功完成。响应分为五类:信息响应(100
–199
),成功响应(200
–299
),重定向(300
–399
),客户端错误(400
–499
)和服务器错误 (500
–599
)。
常见的一些:
- 200 OK
- 请求成功。成功的含义取决于HTTP方法:
- GET:资源已被提取并在消息正文中传输。
- HEAD:实体标头位于消息正文中。
- POST:描述动作结果的资源在消息体中传输。
- TRACE:消息正文包含服务器收到的请求消息
- 302 Found
- 请求的资源现在临时从不同的 URI 响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的。
- 404 Not Found
- 请求失败,请求所希望得到的资源未被在服务器上发现。没有信息能够告诉用户这个状况到底是暂时的还是永久的。假如服务器知道情况的话,应当使用410状态码来告知旧资源因为某些内部的配置机制问题,已经永久的不可用,而且没有任何可以跳转的地址。404这个状态码被广泛应用于当服务器不想揭示到底为何请求被拒绝或者没有其他适合的响应可用的情况下。
- 500 Internal Server Error
- 服务器遇到了不知道如何处理的情况。(代码报错)
服务端断点
在开发的时候,有时候出现了问题需要排查,我们就可以使用断点。断点调试就是在某一行代码打下断点,程序执行到设置的断点时会暂停,并显示相关数据。以IDEA为例,打断点的放在就是在行号旁点击一下,就可以设置一个断点。
以上一节写的HomeController为例,我在如图位置设置一个断点,然后将程序以debug模式运行,快捷键shift+F9或者点击右上角像小虫子的按钮。
然后打开浏览器,访问首页让程序运行到我们设置的断点,可以看到程序卡在了断点这一行,并且下方显示了当前的一些对象,比如page对象,我们可以点开查看page对象的值。查看发现这一行没问题,可以使用快捷键或者点击按钮向下运行一行或者进入这行代码内部。这些按钮怎么用就自行去实践了。包括左下角的功能,可以管理断点等。
客户端断点
客户端断点和服务端差不多,打开浏览器进入首页检查,找到source下的js文件,点击行号设置断点,刷新后会卡在断点,同样可以向下运行和进入代码内。
日志
断点调试之前,最好查看日志,日志内不懂的也可以百度。springboot支持多种日志工具,默认是logback
可以看到有五种日志级别,我们可以在开发和上线的时候使用不同级别,就可以便于开发,
- trace跟踪
- debug调试
- info正常
- warn警告
- error错误
我们先在测试类里体验一下,然后再application.properties里配置一下日志级别和日志存储路径
package com.neu.langsam.community;
import org.junit.Test;
import org.slf4j.Logger;
import org.junit.runner.RunWith;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class LoggerTests {
//新建一个logger类
private static final Logger logger= LoggerFactory.getLogger(LoggerTests.class);
@Test
public void testLogger(){
System.out.println(logger.getName());
logger.debug("debug log");
logger.info("info log");
logger.warn("warn log");
logger.error("error log");
}
}
# logger
logging.level.com.neu.langsam.community=debug
logging.file.name=d:/workspace/community.log
在实际开发中,需要把各种级别的日志分开,那使用这种方式就不够了,就需要写配置文件,比较复杂,就直接复制现成的,修改一下。logback-spring.xml放在resource下,主要修改的地方在开头的路径和项目名,和结尾的包名。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<contextName>community</contextName>
<property name="LOG_PATH" value="D:/workspace"/>
<property name="APPDIR" value="community"/>
<!-- error file -->
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${APPDIR}/log_error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${APPDIR}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>5MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory>
</rollingPolicy>
<append>true</append>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>error</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- warn file -->
<appender name="FILE_WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${APPDIR}/log_warn.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${APPDIR}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>5MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory>
</rollingPolicy>
<append>true</append>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- info file -->
<appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${APPDIR}/log_info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${APPDIR}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>5MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory>
</rollingPolicy>
<append>true</append>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- console -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
</appender>
<logger name="com.neu.langsam.community" level="debug"/>
<root level="info">
<appender-ref ref="FILE_ERROR"/>
<appender-ref ref="FILE_WARN"/>
<appender-ref ref="FILE_INFO"/>
<appender-ref ref="STDOUT"/>
</root>
</configuration>
那么我输出到了项目目录下。