為了專案的正常運行中,例外捕獲,記錄也是非常重要的,方便我們排查問題,定位問題
定義例外
為了方便定位例外,自定義了幾種例外類,方便我們快速定位例外,
基類
public class HttpException extends RuntimeException {
protected String code;
protected Integer httpStatusCode = 500;
}
ParameterException
public class ParameterException extends HttpException {
public ParameterException(String code){
this.code = code;
this.httpStatusCode = 400;
}
}
ServerErrorException
public class ServerErrorException extends HttpException {
public ServerErrorException(String code) {
this.code = code;
this.httpStatusCode = 500;
}
}
UnAuthenticatedException
public class UnAuthenticatedException extends HttpException{
public UnAuthenticatedException(String code){
this.code = code;
this.httpStatusCode = 401;
}
}
ForbiddenException
public class ForbiddenException extends HttpException {
public ForbiddenException(String code) {
this.code = code;
this.httpStatusCode = 403;
}
}
NotFoundException
public class NotFoundException extends HttpException {
public NotFoundException(String code){
this.httpStatusCode = 404;
this.code = code;
}
}
這里定義了我在專案中常用的幾種例外,也可根據實際情況定義自己所需的例外,
捕獲例外
捕獲例外需要用到一個注解@ControllerAdvice,關于它的詳細解釋可查看檔案,
使用方法如下,定義一個例外捕獲類
@ControllerAdvice
public class GlobalExceptionAdvice {
}
這個類就已經實作了捕獲全域例外的功能,下面在加上上面定義的幾種例外
@ControllerAdvice
public class GlobalExceptionAdvice {
@ExceptionHandler(UnAuthenticatedException.class)
public ResponseEntity unAuthenticatedException(UnAuthenticatedException e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.getCode());
}
@ExceptionHandler(ParameterException.class)
public ResponseEntity handleParameterException(ParameterException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getCode());
}
@ExceptionHandler(ForbiddenException.class)
public ResponseEntity handleForbiddenException(ForbiddenException e) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getCode());
}
@ExceptionHandler(NotFoundException.class)
public ResponseEntity handleNotFoundException(NotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.getCode());
}
@ExceptionHandler(RuntimeException.class)
public ResponseEntity handleRunTimeException(RuntimeException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(500);
}
}
@ExceptionHandler注解表示該方法捕獲的例外型別,就可以在不同的例外中進行不同的處理方式,
記錄例外
捕獲到例外之后我們要記錄下來,方便我們對bug的追蹤解決,
記錄方法有多種多樣的,比如記錄到資料庫或者log檔案中,我使用了第二種方式,
加入依賴
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.2</version>
</dependency>
增加日志組態檔
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 控制臺 appender, 幾乎是默認的配置 -->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder charset="UTF-8">
<!-- 輸出的日志文本格式, 其他的 appender 與之相同 -->
<pattern> %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %L - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- info 級別的 appender -->
<appender name="info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日志寫入的檔案名, 可以是相對目錄, 也可以是絕對目錄, 如果上級目錄不存在會自動創建 -->
<file>./logs/info/log-stack.log</file>
<!-- 如果是 true, 日志被追加到檔案結尾; 如果是 false, 清空現存檔案. 默認是true -->
<append>true</append>
<!-- 日志級別過濾器, 只打 INFO 級別的日志-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<!-- 下面2個屬性表示: 匹配 level 的接受列印, 不匹配的拒絕列印 -->
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 最常用的滾動策略, 它根據時間來制定滾動策略, 既負責滾動也負責觸發滾動 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 設定滾動檔案規則, 如果直接使用 %d, 默認格式是 yyyy-MM-dd -->
<fileNamePattern>./logs/info/log-stack.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 保留14天的日志 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<!-- 定義日志輸出格式 -->
<encoder charset="UTF-8">
<pattern> %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %L - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- error 級別的 appender -->
<appender name="error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>./logs/error/log-stack.log</file>
<append>true</append>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>./logs/error/log-stack.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 保留7天的日志 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<!-- 定義日志輸出格式 -->
<encoder charset="UTF-8">
<pattern> %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %L - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- error 級別的 appender -->
<appender name="debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>./logs/debug/log-stack.log</file>
<append>true</append>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>./logs/debug/log-stack.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 保留7天的日志 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<!-- 定義日志輸出格式 -->
<encoder charset="UTF-8">
<pattern> %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %L - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 指定 com.github 下的日志列印級別, appender -->
<logger name="com.github" level="debug" additivity="false">
<appender-ref ref="stdout"/>
<appender-ref ref="info"/>
<appender-ref ref="error"/>
<appender-ref ref="debug"/>
</logger>
<root level="info">
<appender-ref ref="stdout"/>
<appender-ref ref="info"/>
<appender-ref ref="error"/>
</root>
</configuration>
寫入日志
@ControllerAdvice
@Slf4j
public class GlobalExceptionAdvice {
@ExceptionHandler(ParameterException.class)
public ResponseEntity handleParameterException(ParameterException e) {
log.error(e.getLocalizedMessage());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getCode());
}
}
完善例外資訊
文章中的例外只定義了code,具體的例外資訊可以寫在組態檔中或者保存在資料庫中,在捕獲到例外之后,找到對應的描述資訊回傳呼叫者,增加友好度,
完善記錄日志
以上如果發生了例外,在日志檔案中是這樣記錄的
10:19:32.024 [http-nio-8080-exec-2] ERROR c.g.e.d.advice.GlobalExceptionAdvice 41 - / by zero
發現記錄的行號是在GlobalExceptionAdvice類中,并非是代碼真實的位置,
如果要記錄到代碼的真實位置可以這樣實作
public String getExceptionDetail(Exception e) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(e.getClass() + System.getProperty("line.separator"));
stringBuilder.append(e.getLocalizedMessage() + System.getProperty("line.separator"));
StackTraceElement[] arr = e.getStackTrace();
for (int i = 0; i < arr.length; i++) {
stringBuilder.append(arr[i].toString() + System.getProperty("line.separator"));
}
return stringBuilder.toString();
}
log.error(getExceptionDetail(e));
根據實際情況選擇適合自己的方式
完整代碼
Github
Gitee
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/289676.html
標籤:其他
上一篇:MacBook安裝Redis
