springboot全局异常与日志

日志

在resources文件夹中创建logback-spring.xml文件这个会在你项目的平级目录创建一个Logs文件夹,根据时间进行区分,并包含错误日志和控制台打印日志

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="false">

    <conversionRule conversionWord="ip" converterClass="com.util.LogIpConfig" />
    <!-- Log file path -->
    <property name="log.path" value="../Logs/" />

    <!-- Console log output -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!--            <pattern> [%ip]%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>-->
            <pattern> [host:%ip]%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    <!-- Log file debug output -->
    <appender name="fileRolling_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/info.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!--每个文件的大小限制-->
            <MaxFileSize>1GB</MaxFileSize>
            <!--最多保留10天的文件,10天之前的将被清除-->
            <MaxHistory>10</MaxHistory>
            <!--该滚动策略日志的总大小,超过的日志会被清除-->
            <!--            <totalSizeCap>10GB</totalSizeCap>-->
            <!--启动时清理日志文件  此项置灰清理超过保留天数的  也会清理超过总大小的-->
            <cleanHistoryOnStart>true</cleanHistoryOnStart>
        </rollingPolicy>
        <encoder>
            <pattern> [host:%ip]%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n
            </pattern>
        </encoder>
        <!--<filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level>
            <onMatch>DENY</onMatch> <onMismatch>NEUTRAL</onMismatch> </filter> -->
    </appender>
    <!-- Log file error output -->
    <appender name="fileRolling_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!--每个文件的大小限制-->
            <MaxFileSize>1GB</MaxFileSize>
            <!--最多保留10天的文件,10天之前的将被清除-->
            <MaxHistory>10</MaxHistory>
            <!--该滚动策略日志的总大小,超过的日志会被清除-->
            <!--            <totalSizeCap>10GB</totalSizeCap>-->
            <!--启动时清理日志文件  此项置灰清理超过保留天数的  也会清理超过总大小的-->
            <cleanHistoryOnStart>true</cleanHistoryOnStart>
        </rollingPolicy>
        <encoder>
            <pattern> [host:%ip]%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n </pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
    </appender>

    <!-- Level: FATAL 0 ERROR 3 WARN 4 INFO 6 DEBUG 7 -->
    <root level="debug">
        <appender-ref ref="console"/>
    </root>
    <root level="info">
        <!--        <appender-ref ref="console"/>-->
        <appender-ref ref="fileRolling_info" />
        <appender-ref ref="fileRolling_error" />
    </root>
    <logger name="org.springframework" level="INFO"/>
    <logger name="org.mybatis" level="INFO"/>
    <logger name="com.test" level="debug"/>

    <!-- Enable MDC -->
    <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
        <resetJUL>true</resetJUL>
    </contextListener>
</configuration>

日志中ip

import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

public class LogIpConfig extends ClassicConverter {
    @Override
    public String convert(ILoggingEvent event) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null) {
            return "127.0.0.1";
        }
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        String remoteAddr = "";
        if (request != null) {
            remoteAddr = request.getHeader("X-Forwarded-For");
            if (remoteAddr == null || remoteAddr.trim().isEmpty()) {
                remoteAddr = request.getHeader("X-Real-IP");
            }
            if (remoteAddr == null || remoteAddr.trim().isEmpty()) {
                remoteAddr = request.getRemoteAddr();
            }
        }
        return remoteAddr;
    }
}

在application.yml文件中引入

logging:
  config: classpath:logback-spring.xml

全局捕获异常

springboot中通过GlobalExceptionHandler类来实现。通过全局捕获异常可以减少trycatch的使用并且可以通过枚举创建状态码和信息。

通过下方几个文件实现

BaseErrorInfoInterface.java文件

public interface BaseErrorInfoInterface {
    /**
     * 错误码
     */
    int getResultCode();

    /**
     * 错误描述
     */
    String getResultMsg();
}

 BusinessException.java文件

public class BusinessException extends RuntimeException  {
    private static final long serialVersionUID = -4879677283847539655L;

    private int errorCode;

    private String errorMessage;

    private String exceptionMessage;

    private Exception exception;

    public BusinessException(String errorMessage) {
        super();
        this.errorMessage = errorMessage;
    }

    public BusinessException(int errorCode, String errorMessage) {
        super();
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
    }

    public BusinessException(int errorCode, String errorMessage, Exception exception) {
        super();
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
        this.exception = exception;
    }

    public BusinessException(String errorMessage, String exceptionMessage) {
        super();
        this.exceptionMessage = exceptionMessage;
        this.errorMessage = errorMessage;
    }

    public String getExceptionMessage() {
        return exceptionMessage;
    }

    public void setExceptionMessage(String exceptionMessage) {
        this.exceptionMessage = exceptionMessage;
    }

    public int getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(int errorCode) {
        this.errorCode = errorCode;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }

    public Exception getException() {
        return exception;
    }

    public void setException(Exception exception) {
        this.exception = exception;
    }

    public BusinessException(int errorCode, String errorMessage, String exceptionMessage) {
        super();
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
        this.exceptionMessage = exceptionMessage;
    }
}

 CommonEnum.java文件

public enum CommonEnum implements BaseErrorInfoInterface {
    // 数据操作错误定义
    SUCCESS(200, "成功!"),
    BODY_NOT_MATCH(400,"请求的数据格式不符!"),
    SIGNATURE_NOT_MATCH(401,"请求的数字签名不匹配!"),
    NOT_FOUND(404, "未找到该资源!"),
    INTERNAL_SERVER_ERROR(500, "服务器内部错误!"),
    SERVER_BUSY(503,"服务器正忙,请稍后再试!")
    ;

    /** 错误码 */
    private int resultCode;

    /** 错误描述 */
    private String resultMsg;

    CommonEnum(int resultCode, String resultMsg) {
        this.resultCode = resultCode;
        this.resultMsg = resultMsg;
    }

    @Override
    public int getResultCode() {
        return resultCode;
    }

    @Override
    public String getResultMsg() {
        return resultMsg;
    }

}

 ErrController.java文件

import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ErrController implements ErrorController {

    public String getErrorPath() {
        // TODO Auto-generated method stub
        return "/error";
    }

    @RequestMapping("/error")
    public boolean handlerError() {
        throw new BusinessException(-1,"页面不存在");
    }

}

 GlobalExceptionHandler.java文件

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;

@ControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 处理自定义的业务异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = BusinessException.class)
    @ResponseBody
    public Result bizExceptionHandler(HttpServletRequest req, BusinessException e){
        StackTraceElement[] stackTrace = e.getStackTrace();
        StringBuilder sb = new StringBuilder();
        for (StackTraceElement stackTraceElement : stackTrace) {
            sb.append(stackTraceElement.toString()).append("\n");
        }
        logger.error("未知异常:"+e.getErrorMessage()+"!原因是:"+e);
        logger.error("未知异常!錯誤信息是:"+sb.toString());
        return Result.error(e.getErrorCode(),e.getErrorMessage());
    }

    /**
     * 处理空指针的异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =NullPointerException.class)
    @ResponseBody
    public Result exceptionHandler(HttpServletRequest req, NullPointerException e){
        StackTraceElement[] stackTrace = e.getStackTrace();
        StringBuilder sb = new StringBuilder();
        for (StackTraceElement stackTraceElement : stackTrace) {
            sb.append(stackTraceElement.toString()).append("\n");
        }
        logger.error("未知异常!原因是:"+e);
        logger.error("未知异常!錯誤信息是:"+sb.toString());
        return Result.error(CommonEnum.BODY_NOT_MATCH);
    }

    /**
     * 处理其他异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =Exception.class)
    @ResponseBody
    public Result exceptionHandler(HttpServletRequest req, Exception e){
        StackTraceElement[] stackTrace = e.getStackTrace();
        StringBuilder sb = new StringBuilder();
        for (StackTraceElement stackTraceElement : stackTrace) {
            sb.append(stackTraceElement.toString()).append("\n");
        }
        logger.error("未知异常!原因是:"+e);
        logger.error("未知异常!錯誤信息是:"+sb.toString());
        return Result.error(CommonEnum.INTERNAL_SERVER_ERROR);
    }
}

 MyCustomErrorAttributes.java文件

import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.WebRequest;

import java.util.Map;

@Component
public class MyCustomErrorAttributes extends DefaultErrorAttributes  {
    @Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
        Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, options);
        return errorAttributes;
    }
}

Result.java文件

import com.alibaba.fastjson.JSONObject;

public class Result {
    /**
     * 响应代码
     */
    private int code;

    /**
     * 响应消息
     */
    private String message;

    /**
     * 响应结果
     */
    private Object result;

    public Result() {
    }

    public Result(BaseErrorInfoInterface errorInfo) {
        this.code = errorInfo.getResultCode();
        this.message = errorInfo.getResultMsg();
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getResult() {
        return result;
    }

    public void setResult(Object result) {
        this.result = result;
    }

    /**
     * 成功
     *
     * @return
     */
    public static Result success() {
        return success(null);
    }

    /**
     * 成功
     * @param data
     * @return
     */
    public static Result success(Object data) {
        Result rb = new Result();
        rb.setCode(CommonEnum.SUCCESS.getResultCode());
        rb.setMessage(CommonEnum.SUCCESS.getResultMsg());
        rb.setResult(data);
        return rb;
    }

    /**
     * 失败
     */
    public static Result error(BaseErrorInfoInterface errorInfo) {
        Result rb = new Result();
        rb.setCode(errorInfo.getResultCode());
        rb.setMessage(errorInfo.getResultMsg());
        rb.setResult(null);
        return rb;
    }

    /**
     * 失败
     */
    public static Result error(int code, String message) {
        Result rb = new Result();
        rb.setCode(code);
        rb.setMessage(message);
        rb.setResult(null);
        return rb;
    }

    /**
     * 失败
     */
    public static Result error(String message) {
        Result rb = new Result();
        rb.setCode(-1);
        rb.setMessage(message);
        rb.setResult(null);
        return rb;
    }

    @Override
    public String toString() {
        return JSONObject.toJSONString(this);
    }

}

注意:如果使用了全局捕获异常但是你的代码中还是有异常警告

解决办法1:在全局捕获异常中在使用try-catch在包一次这个代码,但是当try-catch捕获异常之后如果不做处理的话全局异常并不会识别到有异常就不会打印错误日志。所以可以将异常上抛或在catch中进行日志打印操作。

public class ExceptionExample {

    private static final Logger logger = Logger.getLogger(ExceptionExample.class.getName());

    public String test() throws Exception {
        try{
        //代码块
        }
        catch(catch (Exception e){
            throw new Exception(e);//上抛错误
            logger.error("错误信息");//直接打印日志
        }
    }
}

解决办法2:使用@SneakyThrows注解。这个注解是 Lombok 库中的一个注解,它可以帮助简化在 Java 中处理受检查异常(checked exception)的代码。在使用 @SneakyThrows 注解后,编译器会自动为标记的方法中的受检查异常生成 try-catch 代码,将异常转换为未经检查的异常(unchecked exception)抛出,但是可能会出现一些隐藏的异常处理问题,所以谨慎使用。

public class ExceptionExample {
    @SneakyThrows
    public String test(){
        
        //代码块
       
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot中,可以通过配置全局异常处理器来捕获和处理应用程序中的异常。以下是配置全局异常处理的步骤: 1. 创建一个全局异常处理器类,例如 `GlobalExceptionHandler`。 ```java @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleException(Exception ex) { // 处理异常逻辑,可以根据需要进行自定义处理 ErrorResponse errorResponse = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), ex.getMessage()); return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR); } // 可以在此定义其他异常处理方法,处理不同类型的异常 } ``` 2. 在全局异常处理器类上使用 `@ControllerAdvice` 注解,让它成为一个全局异常处理器。 3. 在全局异常处理器类中定义异常处理方法,使用 `@ExceptionHandler` 注解指定需要处理的异常类型。 4. 在异常处理方法中编写具体的异常处理逻辑,例如创建一个自定义的错误响应对象,并返回希望的 HTTP 状态码。 5. 可以在全局异常处理器类中定义多个异常处理方法,用于处理不同类型的异常。 6. 最后,将全局异常处理器类注册到Spring Boot应用程序中。 ```java @SpringBootApplication public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } @Bean public GlobalExceptionHandler globalExceptionHandler() { return new GlobalExceptionHandler(); } } ``` 通过以上步骤,您就可以在应用程序中配置一个全局异常处理器,捕获并处理应用程序中的异常。在处理方法中,您可以根据需要进行自定义异常处理,例如返回自定义的错误响应、记录日志等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值