Refactor common error render again

pull/210/head
johnniang 2019-06-18 21:48:15 +08:00
parent f3a42147b9
commit fffc1c9c7f
1 changed files with 73 additions and 21 deletions

View File

@ -1,18 +1,22 @@
package run.halo.app.controller.core;
import cn.hutool.core.text.StrBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.http.HttpStatus;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.util.NestedServletException;
import run.halo.app.exception.HaloException;
import run.halo.app.service.ThemeService;
import run.halo.app.utils.FilenameUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -34,17 +38,22 @@ public class CommonController extends AbstractErrorController {
private static final String INTERNAL_ERROR_TEMPLATE = "500.ftl";
private static final String ERROR_TEMPLATE = "common/error/error";
private static final String ERROR_TEMPLATE = "error.ftl";
private static final String DEFAULT_ERROR_PATH = "common/error/error";
private final ThemeService themeService;
private final ErrorProperties errorProperties;
private final ErrorAttributes errorAttributes;
public CommonController(ThemeService themeService,
ErrorAttributes errorAttributes,
ServerProperties serverProperties) {
super(errorAttributes);
this.themeService = themeService;
this.errorAttributes = errorAttributes;
this.errorProperties = serverProperties.getError();
}
@ -60,17 +69,19 @@ public class CommonController extends AbstractErrorController {
log.error("Error path: [{}], status: [{}]", getErrorPath(), status);
// Get the exception
Throwable throwable = (Throwable) request.getAttribute("javax.servlet.error.exception");
Object throwableObject = request.getAttribute("javax.servlet.error.exception");
if (throwable != null) {
if (throwableObject != null) {
Throwable throwable = (Throwable) throwableObject;
log.error("Captured an exception", throwable);
if (StringUtils.startsWithIgnoreCase(throwable.getMessage(), "Could not resolve view with name '")) {
// TODO May cause unknown-reason problem
// if Ftl was not found then redirect to /404
return contentNotFround();
return contentNotFound();
}
handleCustomException(request);
}
Map<String, Object> errorDetail = Collections.unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request)));
@ -81,7 +92,7 @@ public class CommonController extends AbstractErrorController {
if (status.equals(HttpStatus.INTERNAL_SERVER_ERROR)) {
return contentInternalError();
} else if (status.equals(HttpStatus.NOT_FOUND)) {
return contentNotFround();
return contentNotFound();
} else {
return defaultErrorHandler();
}
@ -93,14 +104,16 @@ public class CommonController extends AbstractErrorController {
* @return String
*/
@GetMapping(value = "/404")
public String contentNotFround() {
if (!themeService.templateExists(NOT_FOUND_TEMPLATE)) {
return defaultErrorHandler();
public String contentNotFound() {
if (themeService.templateExists(ERROR_TEMPLATE)) {
return getActualTemplatePath(ERROR_TEMPLATE);
}
StrBuilder path = new StrBuilder("themes/");
path.append(themeService.getActivatedTheme().getFolderName());
path.append("/404");
return path.toString();
if (themeService.templateExists(NOT_FOUND_TEMPLATE)) {
return getActualTemplatePath(NOT_FOUND_TEMPLATE);
}
return defaultErrorHandler();
}
/**
@ -110,18 +123,57 @@ public class CommonController extends AbstractErrorController {
*/
@GetMapping(value = "/500")
public String contentInternalError() {
if (!themeService.templateExists(INTERNAL_ERROR_TEMPLATE)) {
return defaultErrorHandler();
if (themeService.templateExists(ERROR_TEMPLATE)) {
return getActualTemplatePath(ERROR_TEMPLATE);
}
StrBuilder path = new StrBuilder("themes/");
path.append(themeService.getActivatedTheme().getFolderName());
path.append("/500");
if (themeService.templateExists(INTERNAL_ERROR_TEMPLATE)) {
return getActualTemplatePath(INTERNAL_ERROR_TEMPLATE);
}
return defaultErrorHandler();
}
private String defaultErrorHandler() {
return DEFAULT_ERROR_PATH;
}
private String getActualTemplatePath(@NonNull String template) {
Assert.hasText(template, "FTL template must not be blank");
StringBuilder path = new StringBuilder();
path.append("themes/")
.append(themeService.getActivatedTheme().getFolderName())
.append('/')
.append(FilenameUtils.getBasename(template));
return path.toString();
}
public String defaultErrorHandler() {
return ERROR_TEMPLATE;
/**
* Handles custom exception, like HaloException.
*
* @param request http servlet request must not be null
*/
private void handleCustomException(@NonNull HttpServletRequest request) {
Assert.notNull(request, "Http servlet request must not be null");
Object throwableObject = request.getAttribute("javax.servlet.error.exception");
if (throwableObject == null) {
return;
}
Throwable throwable = (Throwable) throwableObject;
if (throwable instanceof NestedServletException) {
Throwable rootCause = ((NestedServletException) throwable).getRootCause();
if (rootCause instanceof HaloException) {
HaloException haloException = (HaloException) rootCause;
request.setAttribute("javax.servlet.error.status_code", haloException.getStatus().value());
request.setAttribute("javax.servlet.error.exception", rootCause);
request.setAttribute("javax.servlet.error.message", haloException.getMessage());
}
}
}
/**