Springboot 오류 처리 메커니즘 실현 원리 분석

1.기본 오류 메커니즘
기본 효과
① 브 라 우 저 에서 존재 하지 않 는 요청 에 접근 할 때 springboot 는 기본적으로 빈 페이지 로 돌아 갑 니 다.

브 라 우 저의 요청 헤더

② 클 라 이언 트 가 접근 할 때 json 데 이 터 를 되 돌려 줍 니 다.

{
  "timestamp": "2020-03-24T02:49:56.572+0000",
  "status": 404,
  "error": "Not Found",
  "message": "No message available",
  "path": "/"
}
클 라 이언 트 접근 요청 헤더

의 원리
ErrorMvcAutoConfiguration 오류 처리 자동 설정 참조
용기 에 다음 구성 요 소 를 추가 하 였 습 니 다.
    1.DefaultErrorAttributes

public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
  Map<String, Object> errorAttributes = new LinkedHashMap();
  errorAttributes.put("timestamp", new Date());
  this.addStatus(errorAttributes, webRequest);
  this.addErrorDetails(errorAttributes, webRequest, includeStackTrace);
  this.addPath(errorAttributes, webRequest);
  return errorAttributes;
}

@RequestMapping(
    produces = {"text/html"}
  )
  public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
    HttpStatus status = this.getStatus(request);
    //               model     ,  
    Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
    response.setStatus(status.value());
    ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
    return modelAndView != null ? modelAndView : new ModelAndView("error", model);
  }
 
 
 
//   AbstractErrorController#getErrorAttributes
  protected Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
    WebRequest webRequest = new ServletWebRequest(request);
    return this.errorAttributes.getErrorAttributes(webRequest, includeStackTrace);
  }
 
 
 
    DefaultErrorAttributes#getErrorAttributes
  public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
2.Basic ErrorController:기본/error 요청 처리

@Controller
@RequestMapping({"${server.error.path:${error.path:/error}}"}) 
public class BasicErrorController extends AbstractErrorController {
  private final ErrorProperties errorProperties;
public String getErrorPath() {
  return this.errorProperties.getPath();
}

@RequestMapping(
  produces = {"text/html"}  //  html     ,                
)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
  //     
  HttpStatus status = this.getStatus(request);
  //      
  Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
  response.setStatus(status.value());
  //           ,         
  ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
  return modelAndView != null ? modelAndView : new ModelAndView("error", model);
}

@RequestMapping //  json     ,                   
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
  HttpStatus status = this.getStatus(request);
  if (status == HttpStatus.NO_CONTENT) {
    return new ResponseEntity(status);
  } else {
    Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
    return new ResponseEntity(body, status);
  }
}
                 3.ErrorPageCustomizer

public class ErrorProperties {
  @Value("${error.path:/error}")
  private String path = "/error";  //             /error        ,(      web.xml           )
    4.DefaultErrorViewResolver

public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
    ModelAndView modelAndView = this.resolve(String.valueOf(status.value()), model);
    if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
      modelAndView = this.resolve((String)SERIES_VIEWS.get(status.series()), model);
    }
 
    return modelAndView;
  }
 
  private ModelAndView resolve(String viewName, Map<String, Object> model) {    //   springboot          error/404
    String errorViewName = "error/" + viewName;    //                      
    TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);    //               errorViewName        
    return provider != null ? new ModelAndView(errorViewName, model) : this.resolveResource(errorViewName, model);
  }
   //                    errorViewName        error/404.html
  private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
    String[] var3 = this.resourceProperties.getStaticLocations();
    int var4 = var3.length;
 
    for(int var5 = 0; var5 < var4; ++var5) {
      String location = var3[var5];
 
      try {
        Resource resource = this.applicationContext.getResource(location);
        resource = resource.createRelative(viewName + ".html");          //                    ,      
        if (resource.exists()) {
          return new ModelAndView(new DefaultErrorViewResolver.HtmlResourceView(resource), model);
        }
      } catch (Exception var8) {
      }
    }
     
    return null;
  }
단계:
시스템 에 4xx 또는 5xx 와 같은 오류 가 발생 하면 ErrorPageCustomizer 가 유효 합 니 다(잘못된 응답 규칙 을 맞 춤 형 으로 설정)./error 에 요청 하면 Basic ErrorController 에 의 해 발생 합 니 다.
처리
① 응답 페이지 에서 어느 페이지 로 갈 지 는 Default ErrorView Resolver 가 결정 합 니 다.

protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
  Iterator var5 = this.errorViewResolvers.iterator();     //      ErrorViewResolver    modelAndView
  ModelAndView modelAndView;
  do {
    if (!var5.hasNext()) {
      return null;
    }
    ErrorViewResolver resolver = (ErrorViewResolver)var5.next();
    modelAndView = resolver.resolveErrorView(request, status, model);
  } while(modelAndView == null);
  return modelAndView;
}
2.잘못된 정보의 맞 춤 형 제작
① 잘못된 페이지 를 만 드 는 방법
1>템 플 릿 엔진 이 있 는 경우:error/상태 코드;[오류 페이지 를 오류 코드 라 고 명명 합 니 다.html 를 템 플 릿 엔진 폴 더 아래 에 있 는 error 폴 더 아래 에 놓 습 니 다.]이 상태 코드 의 오류 가 발생 하면 옵 니 다.
대응 하 는 페이지;
우 리 는 4xx 와 5xx 를 오류 페이지 의 파일 이름 으로 사용 하여 이러한 유형의 원 하 는 오 류 를 일치 시 킬 수 있 습 니 다.정확 한 상태 코드 를 우선 찾 습 니 다.html).
페이지 에서 얻 을 수 있 는 정보
타임 스탬프:타임 스탬프
status:상태 코드
예외:예외 대상
메시지:이상 메시지
errors:JSR 303 데이터 검증 오류 가 여기 있 습 니 다.
2>.템 플 릿 엔진 이 없습니다(템 플 릿 엔진 에서 이 페이지 를 찾 을 수 없습니다).정적 자원 폴 더 에서 찾 습 니 다.
3>.이상 오류 페이지 가 없 으 면 기본적으로 springboot 기본 오류 페이지 로 갑 니 다.
②、사용자 정의 이상 처리&맞 춤 형 제 이 슨 데이터 되 돌려 주기;

@ControllerAdvice
public class MyExceptionHandler {
 
  @ResponseBody
  @ExceptionHandler(UserNotExistException.class)
  public Map<String,Object> handleException(Exception e){
    Map<String,Object> map = new HashMap<>();
    map.put("code","user.notexist");
    map.put("message",e.getMessage());
    return map;
  }
}
//       ,        (       ,       json  )
2),전송/error 적응 응답 효과 처리

@RequestMapping(
  produces = {"text/html"}
)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {     //        ,       ,         ?  =======》       ,  ……
  HttpStatus status = this.getStatus(request);
  Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
  response.setStatus(status.value());    //             ,      ,               (         200 ,       4xx 5xx    )
  ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
  return modelAndView != null ? modelAndView : new ModelAndView("error", model);
}

@ExceptionHandler(UserNotExistException.class)
  public String handleException(Exception e, HttpServletRequest request){
    Map<String,Object> map = new HashMap<>();
    <strong>//             4xx 5xx,                  </strong>
    /**
     * Integer statusCode = (Integer) request
     .getAttribute("javax.servlet.error.status_code");
     */
    request.setAttribute("javax.servlet.error.status_code",500);
    map.put("code","user.notexist");
    map.put("message",e.getMessage());
    //   /error
    return "forward:/error";
  }
3)、우리 의 맞 춤 형 데 이 터 를 가지 고 나 간다.model 의 값 을 수정 하면 됩 니 다.
오류 가 발생 하면/error 요청 이 올 것 입 니 다.Basic ErrorController 에 의 해 처 리 됩 니 다.응답 하면 얻 을 수 있 는 데 이 터 는 getErrorAttributes 에서 얻 을 수 있 습 니 다(AbstractErrorController(ErrorController)에 규정된 방법 입 니 다).
1.ErrorController 의 실현 클래스 를 완전히 작성 하거나 AbstractErrorController 의 하위 클래스 를 작성 하여 용기 에 넣 습 니 다.
2.페이지 에 사용 할 수 있 는 데이터 나 json 이 사용 할 수 있 는 데 이 터 를 되 돌려 주 는 것 은 모두 error Attributes.getError Attributes 를 통 해 얻 을 수 있 습 니 다.
용기 에 있 는 DefaultErrorAttributes.getErrorAttributes();기본적으로 데이터 처리 하기;
사용자 정의 오류 속성

//             ErrorAttributes
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
 
  @Override
  public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
    Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace);
    map.put("company","atguigu");
    return map;
  }
}
최종 효과:응답 은 자가 적응 입 니 다.ErroAttributes 를 통 해 되 돌아 갈 내용 을 바 꿀 수 있 습 니 다.

이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기