Версия среды разработки персональных приложений SpringBoot 2.1 — настройка журнала и глобальная обработка исключений

Spring Boot
Версия среды разработки персональных приложений SpringBoot 2.1 — настройка журнала и глобальная обработка исключений

Эта статья является подразделом фреймворка персональной разработки SpringBoot 2.1, сначала прочтите ее.Фреймворк персональной разработки версии SpringBoot 2.1Прочтите эту статью еще раз

Адрес бэкенд-проекта:Версия SpringBoot 2.1 среды разработки персональных приложений

Адрес фронтенд проекта:ywh-vue-admin

настройка журнала

При тестировании в предыдущей главе мы обнаружили, что консоль выводит журнал по умолчанию, и многие журналы не распечатываются, и мы не можем настроить информацию, которую хотим выводить. существенная часть. Онлайн-отслеживание проблем, статистический анализ бизнес-логики на основе журналов и т. д. — все это неотделимо от журналов.

Справочные материалы журнала я много искал в Интернете, и более подробное введение можно легко получить Вот несколько справочных материалов:

В Java есть много распространенных фреймворков ведения журналов, таких как Log4j, Log4j 2, Commons Logging, Slf4j, Logback и т. д.

Commons Logging и Slf4j — это фасады журналов, которые предоставляют унифицированный высокоуровневый интерфейс, а также простой и унифицированный интерфейс для различных API ведения журналов. Log4j и Logback — это конкретные реализации журналов. Это можно просто понять как реализацию интерфейса и интерфейса.Вызывающему абоненту нужно только обратить внимание на интерфейс, не обращая внимания на конкретную реализацию, чтобы добиться развязки.

Наиболее часто используемой комбинацией является комбинация Slf4j и Logback, а также комбинация Commons Logging и Log4j.На основе следующих преимуществ выбрана структура ведения журнала Slf4j+Logback:

Более высокая скорость выполнения, Logback переписывает внутреннюю реализацию и повышает производительность более чем в 10 раз на некоторых критических путях выполнения. И logback не только имеет улучшенную производительность, но и инициализированную загрузку памяти меньше

Автоматически очищайте старые архивы журналов. Установив свойство maxHistory TimeBasedRollingPolicy или SizeAndTimeBasedFNATP, вы можете контролировать максимальное количество архивов журналов.

Logback имеет гораздо более богатые возможности фильтрации, чем log4j, и может записывать низкоуровневые журналы без снижения уровня журнала.

Logback должен использоваться с Slf4j. Поскольку Logback и Slf4j принадлежат одному и тому же автору, их совместимость очевидна.

По умолчанию Spring Boot будет использовать Logback для регистрации и вывода на консоль с уровнем INFO.

журнал конфигурации

Из вышеизложенного видно, что наш проект springboot использует Logback по умолчанию, мы можем установить формат журнала, установив файл yml, или установить управление журналом с помощью logback.xml.

YML-метод: Этот метод проще, чем метод xml, потому что, если вы не настроите его, springboot также будет иметь настройки по умолчанию. Добавьте следующую конфигурацию в среду разработки application-dev.yml, чтобы она вступила в силу. Путь пути может быть windows в среде разработки При развертывании на сервере liunx необходимо использовать файл конфигурации производственной среды application-prod.Путь, указанный в файле, является путем к liunx.

logging:
  file:
    #存放文件的最大天数
    max-history: 15
    #存放日志最大size
    max-size: 100MB
  #存放日志文件位置
  path: E:\logs
  pattern:
    #输出到控制台的格式
    console: "YWH - %d{yyyy-MM-dd HH:mm:ss} -%-4r  [%t]  %-5level %logger{36} - %msg%n"
  #日志级别映射,可以指定包下的日志级别 也可指定root为info级别
  level:
    root: info
    com.ywh.core: debug
*************************************************
<!--    %d{HH: mm:ss.SSS}——日志输出时间   -->
<!--    %thread  [%t] ——输出日志的进程名字,这在Web应用以及异步任务处理中很有用  -->
<!--    %-4r —— "-"代表了左对齐  将输出从程序启动到创建日志记录的时间 进行左对齐 且最小宽度为4 -->
<!--    %-5level——日志级别,并且使用5个字符靠左对齐 -->
<!--    %logger{36}——日志输出者的名字   -->
<!--    %msg——日志消息  -->
<!--    %n——平台的换行符  -->

<!--    更多的详情可参考 : https://aub.iteye.com/blog/1103685  此博客最下方有解释 

Фотографии ниже взяты из:Версия для Австралии.ITeye.com/blog/110368…

XML-метод: Этот метод требует настройки нескольких тегов, что немного сложнее, чем метод yml.Создайте его в файле ресурсов.logback-spring.xmlфайл, если вы не хотите помещать файл xml непосредственно в ресурсы, вам нужно настроить logging.config= в файле yml, чтобы указать местоположение

<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。
                 当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration  scan="true" scanPeriod="60 seconds">
    <contextName>Y-W-H</contextName>
    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
    <property name="log.path" value="E:/logs/" />
 
    <!--0. 日志格式和颜色渲染 -->
    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName ) [%thread] %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
 
 
    <!--1. 输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
 
    。。。。。。省略代码,具体代码可前往github查看
 
</configuration>

После запуска проекта после настройки любого из двух вышеуказанных методов вы обнаружите, что мы использовали наш собственный формат вывода для вывода журнала, и файл журнала появляется по указанному нами пути.

Пользовательские исключения и глобальные классы исключений

Когда уровень журнала установлен на уровень INFO, выводятся только журналы выше INFO, такие как INFO, WARN и ERROR. Это нормально. Проблема в том, что стек исключений (исключение времени выполнения), созданный в программе, не печатается , что не способствует устранению неполадок.

Более того, в некоторых случаях мы хотим напрямую передать исключение Контроллеру в Сервисе, не обрабатывая его, но мы не можем напрямую выводить информацию об исключении клиенту, что очень недружественно, и мы хотим точного позиционирования. Ошибка в том, что мы необходимо определить вывод исключения самостоятельно и вернуть исключение ошибки во внешний интерфейс в унифицированном формате результата, который мы инкапсулировали ранее, поэтому нам нужно настроить исключение и определить глобальный класс исключения, мы сначала определяем пользовательское исключение Определите класс исключений, а затем определите глобальный класс исключений.

Согласно классификации аномальной информации в учебнике для новичков, аномалия делится на три случая.

проверенное исключение: Наиболее репрезентативными проверенными исключениями являются те, которые вызваны ошибкой пользователя или проблемами, которые программист не мог предвидеть. Например, при попытке открыть несуществующий файл возникает исключение, и эти исключения нельзя просто игнорировать во время компиляции.

исключение времени выполнения: Исключения во время выполнения — это исключения, которых программист может избежать. В отличие от проверенных исключений, исключения времени выполнения можно игнорировать во время компиляции.

Ошибка: Ошибки - это не исключения, а проблемы, не зависящие от программиста. Ошибки обычно игнорируются в коде. Например, при переполнении стека возникает ошибка, и их невозможно проверить во время компиляции.

И все, что нам нужно сделать, это наследовать исключения времени выполнения, настроить такие исключения и создать их в пакете исключений под общимMyExceptionКласс наследует RuntimeException.

package com.ywh.common.exception;
 
/**
 * CreateTime: 2018-11-21 19:07
 * ClassName: MyXiyiException
 * Package: com.ywh.common.exception
 * Describe:
 * 自定义异常,可以throws的时候用自己的异常类
 *
 * @author YWH
 */
public class MyException extends RuntimeException {
 
    public MyException(String msg) {
        super(msg);
    }
 
    public MyException(String message, Throwable throwable) {
        super(message, throwable);
    }
 
    public MyException(Throwable throwable) {
        super(throwable);
    }
}

Создан в пакете utils под общимMyExceptionUtilКласс инструментов для быстрого создания классов исключений

package com.ywh.common.utils;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.ywh.common.exception.MyException;

/**
 * CreateTime: 2018-12-18 22:32
 * ClassName: MyExceptionUtil
 * Package: com.ywh.common.utils
 * Describe:
 * 异常工具类
 *
 * @author YWH
 */
public class MyExceptionUtil {

    public MyExceptionUtil() {
    }

    public static MyException mxe(String msg, Throwable t, Object... params){
        return new MyException(StringUtils.format(msg, params),t);
    }

    public static MyException mxe(String msg, Object... params){
        return new MyException(StringUtils.format(msg, params));
    }

    public static MyException mxe(Throwable t){
        return new MyException(t);
    }

}

После создания настраиваемого исключения нам необходимо захватить и обработать настраиваемое исключение, что требует от нас определить глобальный класс исключений для его захвата и обработки, а также добавить его в исключение под общимGlobalExceptionHandlerДобрый.

package com.ywh.common.exception;
 
/**
 * @Author: YWH
 * @Description: 全局异常处理类,拦截controller  RestControllerAdvice此注解为ResponseBody和ControllerAdvice混合注解
 * @Date: Create in 17:16 2018/11/17
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
 
    /**
     *
     * 全局异常类中定义的异常都可以被拦截,只是触发条件不一样,如IO异常这种必须抛出异常到
     * controller中才可以被拦截,或者在类中用try..catch自己处理
     * 绝大部分不需要向上抛出异常即可被拦截,返回前端json数据,如数组下标越界,404 500 400等错误
     * 如果自己想要写,按着以下格式增加异常即可
     *HttpMessageNotReadableException
     */
 
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
 
    /**
     *   启动应用后,被 @ExceptionHandler、@InitBinder、@ModelAttribute 注解的方法,
     *   都会作用在 被 @RequestMapping 注解的方法上。
     * @param binder
     */
    @InitBinder
    public void initWebBinder(WebDataBinder binder){
 
    }
 
    /**
     * 系统错误,未知的错误   已测试
     * @param ex 异常信息
     * @return 返回前端异常信息
     */
    @ExceptionHandler({Exception.class})
    public Result exception(Exception ex){
        log.error("错误详情:" + ex.getMessage(),ex);
        return Result.errorJson(BaseEnum.SYSTEM_ERROR.getMsg(),BaseEnum.SYSTEM_ERROR.getIndex());
    }
 
  。。。。。。省略代码,具体代码请前往github查看
 
    /**
     * 自定义异常信息拦截
     * @param ex 异常信息
     * @return 返回前端异常信息
     */
    @ExceptionHandler(MyException.class)
    public Result myCustomizeException(MyException ex){
        log.warn("错误详情:" + ex);
        return Result.errorJson(BaseEnum.CUSTOMIZE_EXCEPTION.getMsg(),BaseEnum.CUSTOMIZE_EXCEPTION.getIndex());
    }
 
}

В GlobalExceptionHandler мы перехватили и настроили множество исключений, а также перехватили исключения во время выполнения, которые мы настроили выше. Я написал комментарии к методам в классе и должен быть хорошо понят в соответствии с информацией в Интернете. Я протестировал большую часть исключения, и они могут быть успешно перехвачены.

Пример теста

Мы используем почтальона для передачиpostспособ запроситьgetвы можете увидеть, что возвращается наш пользовательский формат json, и сообщить нам, что это ошибка, вызванная типом интерфейса, чтобы мы могли быстро найти ошибку и устранить ее.

异常信息拦截

Все вышеперечисленные ошибки фиксируются системой для нас и перехватываются глобальным классом исключений, а затем возвращаются в настраиваемый формат json, и как использовать наши настраиваемые исключения, настраиваемые исключения требуют от нас ручного захвата исключений и создания исключений, чтобы мы Глобальный класс исключений может быть перехвачен.

мы вExampleServiceImplОпределите метод на уровне контроллера, вызовите этот метод на уровне контроллера и вызовите этот интерфейс с помощью почтальона.

    /**
     * 测试自定义异常
     * @return 返回字符串
     */
    @Override
    public String myException() {
        int i = 0;
        int a = 10;
        if( i > a){
            System.out.println("测试!!!");
        }else{
            throw MyExceptionUtil.mxe("出错了,比他小啊!!");
        }
        return "没有进行拦截,失败了";
    }
    @Autowired
    private ExampleService exampleService;
    
    @GetMapping("myExceptionTest")
    public Result myExceptionTest(){
        return Result.successJson(exampleService.myException());
    }

自定义一场拦截

控制台信息

Вы можете видеть, что наше пользовательское исключение перехвачено, и нужная нам информация выводится в консоль.