BaseErrorController.java
package cn.home1.oss.lib.errorhandle.internal;
import cn.home1.oss.lib.errorhandle.api.HttpHeader;
import cn.home1.oss.lib.errorhandle.api.ResolvedError;
import cn.home1.oss.lib.errorhandle.api.StackTraceIndicator;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * override default BasicErrorController.
 *
 * {@link org.springframework.boot.autoconfigure.web.BasicErrorController}
 *
 * <p>
 * see: ErrorMvcAutoConfiguration, BasicErrorController
 * </p>
 */
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public abstract class BaseErrorController extends org.springframework.boot.autoconfigure.web.AbstractErrorController {
  private final ErrorProperties errorProperties;
  @Autowired
  @Setter
  private StackTraceIndicator traceIndicator;
  protected BaseErrorController( //
    final ExtendedErrorAttributes errorAttributes, //
    final ErrorProperties errorProperties //
  ) {
    super(errorAttributes);
    Assert.notNull(errorProperties, "AppErrorProperties must not be null");
    this.errorProperties = errorProperties;
  }
  protected ModelAndView errorHtml( //
    final HttpServletRequest request, //
    final HttpServletResponse response //
  ) {
    final Map<String, Object> errorAttributes = getErrorAttributes( //
      request, //
      isIncludeStackTrace(request, MediaType.TEXT_HTML) //
    );
    final ResolvedError resolvedError = ResolvedError.fromErrorAttributes(errorAttributes);
    final Integer status = resolvedError.getStatus();// this.getStatus(request)
    response.setStatus(status);
    // goto WhitelabelErrorViewConfiguration.defaultErrorView if not provided.
    final ModelAndView mav = new ModelAndView("error", resolvedError.toErrorAttributes());
    mav.addObject(ResolvedError.RESOLVED_ERROR_OBJECT, resolvedError);
    return mav;
  }
  protected ResponseEntity<ResolvedError> error(final HttpServletRequest request, final HttpServletResponse response) {
    final Map<String, Object> errorAttributes = getErrorAttributes( //
      request, //
      isIncludeStackTrace(request, MediaType.ALL) //
    );
    final ResolvedError body = ResolvedError.fromErrorAttributes(errorAttributes);
    final HttpStatus status = body.getHttpStatus();// this.getStatus(request);
    copyHeaders(body, response);
    return new ResponseEntity<>(body, status);
  }
  /**
   * copy ResolvedError的header到response.
   *
   * @param source   source
   * @param response response
   */
  private void copyHeaders(final ResolvedError source, final HttpServletResponse response) {
    if (source != null && source.getHeaders() != null) {
      for (final HttpHeader header : source.getHeaders()) {
        for (final String value : header.getValues()) {
          response.addHeader(header.getName(), value);
        }
      }
    }
  }
  protected boolean isIncludeStackTrace(final HttpServletRequest request, final MediaType produces) {
    return this.traceIndicator.stackTrace(request, null);
  }
  @Override
  public String getErrorPath() {
    return this.errorProperties.getPath();
  }
  public static class RestfulErrorController extends BaseErrorController {
    public RestfulErrorController( //
      final ExtendedErrorAttributes errorAttributes, //
      final ErrorProperties errorProperties //
    ) {
      super(errorAttributes, errorProperties);
    }
    @RequestMapping
    @ResponseBody
    public ResponseEntity<ResolvedError> error(final HttpServletRequest request, final HttpServletResponse response) {
      return super.error(request, response);
    }
  }
  public static class TemplateErrorController extends BaseErrorController {
    public TemplateErrorController( //
      final ExtendedErrorAttributes errorAttributes, //
      final ErrorProperties errorProperties //
    ) {
      super(errorAttributes, errorProperties);
    }
    @RequestMapping
    public ModelAndView errorHtml( //
      final HttpServletRequest request, //
      final HttpServletResponse response //
    ) {
      return super.errorHtml(request, response);
    }
  }
  public static class MixedErrorController extends BaseErrorController {
    public MixedErrorController( //
      final ExtendedErrorAttributes errorAttributes, //
      final ErrorProperties errorProperties //
    ) {
      super(errorAttributes, errorProperties);
    }
    @RequestMapping(produces = "text/html")
    public ModelAndView errorHtml( //
      final HttpServletRequest request, //
      final HttpServletResponse response //
    ) {
      return super.errorHtml(request, response);
    }
    @RequestMapping
    @ResponseBody
    public ResponseEntity<ResolvedError> error(final HttpServletRequest request, final HttpServletResponse response) {
      return super.error(request, response);
    }
  }
}