Обработка исключений в контроллере SpringMvc

Spring

Обработка исключений по умолчанию в Spring

В Spring некоторые исключения по умолчанию сопоставляются с кодами состояния HTTP и не требуют программной обработки. В следующей таблице перечислены способы обработки исключений в Spring по умолчанию:

Весеннее исключение Коды состояния HTTP
BindException 400 - Bad Request
ConversionNotSupportedException 500 - Internal Server Error
HttpMediaTypeNotAcceptableException 406 - Not Acceptable
HttpMediaTypeNotSupportedException 415 - Unsupported Media Type
HttpMessageNotReadableException 400 - Bad Request
HttpMessageNotWritableException 500 - Internal Server Error
HttpRequestMethodNotSupportedException 405 - Method Not Allowed
MethodArgumentNotValidException 400 - Bad Request
MissingServletRequestParameterException 400 - Bad Request
MissingServletRequestPartException 400 - Bad Request
NoSuchRequestHandlingMethodException 404 - Not Found
TypeMismatchException 400 - Bad Request

Исключения в приведенной выше таблице генерируются самой Spring, еслиDispatcherServletВозвращает напрямую, когда возникает проблема во время обработки или при выполнении проверки. Например, еслиDispatcherServletНевозможно найти подходящий метод контроллера для обработки запроса, выдастNoSuchRequestHandlingMethodExceptionИсключение, конечным результатом является ответ с кодом состояния 404 (не найдено).

использовать@ResponseStatusОбработка пользовательских исключений

Но он не может обрабатывать пользовательские исключения, создаваемые внутри приложения. Например, в службе выдается пользовательское исключение (NullOrgException),МыNullOrgExceptionДобавлено исключение@ResponseStatusАннотация, вы можете присвоить ей код состояния.

Например, следующий код:

package com.rebecca.springmvc.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

/**
 * 自定义异常
 * @Author: Rebecca
 * @Description:
 * @Date: Created in 2019/6/14 17:04
 * @Modified By:
 */

@ResponseStatus(value = HttpStatus.NO_CONTENT, reason = "No Content")
public class NullOrgException extends RuntimeException {
}

использоватьtry {…} catchПерехватывать исключения вручную

После определения вышеупомянутого исключения, пока в приложении есть бросокNullOrgExceptionИсключения перехватываются и сопоставляются с соответствующими кодами состояния. Что делать, если программе нужен не только код состояния, но и сгенерированная ошибка? На данный момент мы больше не можем обрабатывать исключения как ошибки HTTP, а обрабатывать исключения так же, как мы обрабатываем запросы.

package com.rebecca.springmvc.controller.exception;

import com.rebecca.springmvc.org.bean.Org;
import com.rebecca.springmvc.org.service.OrgService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

@Controller
@RequestMapping("test/exception")
public class ExceptionTestController {
    private Logger logger = LoggerFactory.getLogger(ExceptionTestController.class);

    @Autowired
    private OrgService service;

    @RequestMapping(value = "orgs", method = RequestMethod.GET)
    @ResponseBody
    public List<Org> getOrgs ()  {
        List<Org> orgs = null;
        try {
            orgs = service.getOrgs();
        } catch (NullOrgException e) {
            logger.error("无组织机构相关数据!",e);
        }
        return orgs;
    }
}

Например, в коде вышеNullOrgExceptionИсключение, в Spring нет сопоставления по умолчанию, самый простой способ -try {…} catch (NullOrgException e) {…}.

использовать@ExceptionHandlerОбработка пользовательских исключений

вышесказанноеtry {…} catchЭтот метод не способствует сопровождению кода, к счастью, Spring предоставляет механизм, который можно использовать.@ExceptionHandlerАннотации сопоставляют исключения с кодами состояния HTTP. Ниже приведено использование@ExceptionHandlerАннотированный способ:

package com.rebecca.springmvc.controller.exception;

import com.rebecca.springmvc.org.bean.Org;
import com.rebecca.springmvc.org.service.OrgService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

@Controller
@RequestMapping("test/exception")
public class ExceptionTestController {
    private Logger logger = LoggerFactory.getLogger(ExceptionTestController.class);

    @Autowired
    private OrgService service;

    @RequestMapping(value = "orgs", method = RequestMethod.GET)
    @ResponseBody
    public List<Org> getOrgs ()  {
        List<Org> orgs = service.getOrgs();
        return orgs;
    }

    @ExceptionHandler(NullOrgException.class)
    public String handleNullOrgException() {
        return "无组织机构相关数据!";
    }
}

В приведенном выше коде мыhandleNullOrgException()добавлен метод@ExceptionHandlerаннотацию, когда программа выбрасываетNullOrgExceptionКогда возникает исключение, этот метод будет делегирован для обработки. Его возвращаемое значение — String, вы также можете изменить его на другие типы возвращаемых значений в соответствии с потребностями приложения. для использования@ExceptionHandlerДля методов, аннотированных аннотациями, он может обрабатывать исключения, создаваемые всеми методами-обработчиками в одном и том же контроллере (контроллере).

Чтобы избежать записи дубликатов в нескольких контроллерах@ExceptionHandlerAnnotation, мы создадим базовый класс контроллера, все классы контроллера должны расширять этот класс, поэтомунаследоватьуниверсальный@ExceptionHandlerметод.

использовать@ControllerAdviceАннотация обрабатывает все исключения

Ранее мы говорили использовать@ExceptionHandlerАннотации могут обрабатывать только исключения, генерируемые всеми методами обработчика в контроллере (контроллере), поэтому есть ли способ обрабатывать исключения, генерируемые методами обработчика во всех контроллерах, без интеграции?

Ответ: да! Начиная с Spring 3.2 это определенно возможно, нам просто нужно определить это в классе уведомлений контроллера.

После Spring 3.2 для такого рода проблем было введено новое решение: совет контроллера.

Совет диспетчера относится к любому@ControllerAdviceАннотированный класс.

Этот класс будет содержать один или несколько из следующих типов методов:

  1. @ExceptionHandlerАннотационный метод аннотации;
  2. @InitBinderАннотационный метод аннотации;
  3. @ModelAttributeАннотационный метод аннотации.

в с@ControllerAdviceВ аннотированном классе вышеуказанные методы будут применяться ко всем контроллерам с@RequestMappingпо методу аннотации.@ControllerAdviceСама аннотация уже используется@Component,следовательно@ControllerAdviceКласс, отмеченный аннотацией, будет автоматически получен при сканировании компонента, и есть@ComponentАннотированные классы одинаковы.@ControllerAdviceОдин из наиболее практичных сценариев — объединить все@ExceptionHandlerМетоды собраны в класс, чтобы исключения от всех контроллеров можно было обрабатывать единообразно в одном месте. Например, мы хотимNullOrgExceptionМетод обработчика используется на всех контроллерах во всем приложении. Следующий листинг программы показываетAppWideExceptionHandlerможет выполнить эту задачу, это@ControllerAdviceАннотированный класс. Используйте следующий код@ControllerAdvice, для обработки исключений для всех контроллеров:

package com.rebecca.springmvc.controller.exception;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

/**
 * 控制器通知类
 * @Author: Rebecca
 * @Description:
 * @Date: Created in 2019/6/14 16:30
 * @Modified By:
 */
@ControllerAdvice  // 定义控制器类
public class AppWideException {

    // 定义异常处理方法
    @ExceptionHandler(NullOrgException.class)
    public String handleNullOrgException() {
        return "无组织机构相关数据!";
    }
}

Теперь, если какой-либо метод контроллера выдает исключение DuplicateSpittleException, для обработки исключения будет вызываться метод DuplicateSpittleHandler() независимо от того, в каком контроллере находится этот метод. Мы можем писать аннотированные методы @ExceptionHandler так же, как мы пишем аннотированные методы @RequestMapping. Как показано в листинге 7.10, он возвращает "error/duplicate" в качестве имени логического представления, поэтому пользователю будет представлена ​​удобная страница с ошибкой.

Суммировать

Обработка исключений в Spring:

  1. Определенные исключения Spring будут автоматически сопоставлены с указанными кодами состояния HTTP;
  2. аномальныйможно добавить на@ResponseStatusАннотация для сопоставления с кодом состояния HTTP;
  3. существуетметодможно добавить на@ExceptionHandlerАннотация, чтобы ее можно было использовать для обработки исключений.
  4. будет@ExceptionHandlerАннотированный метод исключения извлекается в@ControllerAdviceВ аннотированном классе действует все приложение (этот метод применим только к Spring 3.2+).

Самый простой способ обработки исключений — сопоставить их с кодами состояния HTTP и поместить в ответ.

Ссылаться на

«Весна в действии, 4-е издание»