First Commit
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
package quant.rich.emoney.component;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import quant.rich.emoney.exception.PageNotFoundException;
|
||||
import quant.rich.emoney.exception.RException;
|
||||
import quant.rich.emoney.pojo.dto.LayPageResp;
|
||||
import quant.rich.emoney.pojo.dto.R;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.security.auth.login.LoginException;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.resource.NoResourceFoundException;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
/**
|
||||
* 异常处理
|
||||
*/
|
||||
@ControllerAdvice
|
||||
@Slf4j
|
||||
public class EmoneyAutoPlatformExceptionHandler {
|
||||
|
||||
@Autowired
|
||||
HttpServletResponse response;
|
||||
|
||||
@Autowired
|
||||
HttpServletRequest request;
|
||||
|
||||
@ExceptionHandler({
|
||||
BindException.class,
|
||||
ConstraintViolationException.class,
|
||||
MethodArgumentNotValidException.class })
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public <Ex extends BindException> R<?> handleBindException(Ex ex) {
|
||||
StringBuilder messageSb = new StringBuilder();
|
||||
ex.getBindingResult().getAllErrors().forEach(error -> messageSb.append(error.getDefaultMessage()).append("\n"));
|
||||
log.warn("Resolved Exception {}", messageSb.substring(0, messageSb.length() - 1));
|
||||
log.warn(httpServletRequestToString(request));
|
||||
return bodyOrPage(HttpStatus.BAD_REQUEST, messageSb.substring(0, messageSb.length() - 1));
|
||||
}
|
||||
|
||||
@ExceptionHandler(LoginException.class)
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.NOT_ACCEPTABLE)
|
||||
public R<?> handleLoginException(LoginException ex) {
|
||||
return bodyOrPage(HttpStatus.NOT_ACCEPTABLE, ex);
|
||||
}
|
||||
|
||||
@ExceptionHandler(RException.class)
|
||||
@ResponseBody
|
||||
public R<?> handleRException(RException ex) {
|
||||
response.setStatus(ex.getHttpStatus().value());
|
||||
if (ex.getLogRequest()) {
|
||||
log.warn(httpServletRequestToString(request));
|
||||
}
|
||||
return bodyOrPage(ex.getHttpStatus(), ex);
|
||||
}
|
||||
|
||||
@ExceptionHandler(ServletException.class)
|
||||
@ResponseBody
|
||||
public R<?> handleServletException(ServletException ex) {
|
||||
HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
if (ex instanceof HttpRequestMethodNotSupportedException)
|
||||
httpStatus = HttpStatus.METHOD_NOT_ALLOWED;
|
||||
response.setStatus(httpStatus.value());
|
||||
return bodyOrPage(httpStatus, ex);
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = Exception.class)
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public R<?> handleException(Exception ex) {
|
||||
if (ex instanceof PageNotFoundException) {
|
||||
throw (PageNotFoundException) ex;
|
||||
}
|
||||
String message = null;
|
||||
if (ex.getMessage() != null) {
|
||||
message = ex.getMessage();
|
||||
}
|
||||
else if (ex.getCause() != null) {
|
||||
message = ex.getCause().getMessage();
|
||||
}
|
||||
ex.printStackTrace();
|
||||
log.warn("Resolved exception {}", message);
|
||||
log.warn(httpServletRequestToString(request));
|
||||
return bodyOrPage(HttpStatus.INTERNAL_SERVER_ERROR, ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 @Autowired request 等自动判断当前请求是 text/html 还是 application/json
|
||||
* @return
|
||||
*/
|
||||
private boolean isPage() {
|
||||
boolean isPage = true;
|
||||
String accept;
|
||||
// 匹配当前 request 在控制层的方法,根据是否是
|
||||
// @ResponseBody 注解、@RestController 注解、
|
||||
// 已知的返回类型来判断返回的是否是页面
|
||||
Object handler = request.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE);
|
||||
|
||||
if (handler instanceof HandlerMethod handlerMethod) {
|
||||
Method method = handlerMethod.getMethod();
|
||||
Class<?> controllerClass = handlerMethod.getBeanType();
|
||||
|
||||
boolean hasResponseBody =
|
||||
method.isAnnotationPresent(ResponseBody.class) ||
|
||||
controllerClass.isAnnotationPresent(ResponseBody.class) ||
|
||||
controllerClass.isAnnotationPresent(RestController.class);
|
||||
|
||||
Class<?> returnType = method.getReturnType();
|
||||
boolean isDtoReturnType =
|
||||
returnType.equals(R.class) ||
|
||||
returnType.equals(LayPageResp.class) ||
|
||||
JsonNode.class.isAssignableFrom(returnType);
|
||||
|
||||
if (hasResponseBody || isDtoReturnType) {
|
||||
isPage = false;
|
||||
}
|
||||
}
|
||||
if (isPage && (accept = request.getHeader("Accept")) != null) {
|
||||
int indexOfHtml = accept.indexOf("text/html"), indexOfJson = accept.indexOf("application/json");
|
||||
if (indexOfHtml == -1 && indexOfJson != -1) {
|
||||
isPage = false;
|
||||
} else if (indexOfHtml != -1 && indexOfJson != -1) {
|
||||
isPage = indexOfHtml < indexOfJson;
|
||||
}
|
||||
}
|
||||
return isPage;
|
||||
}
|
||||
|
||||
private R<?> bodyOrPage(HttpStatus httpStatus, String message) {
|
||||
boolean isPage = isPage();
|
||||
if (isPage) {
|
||||
throw message == null ? new RuntimeException("Page exception raised") : new RuntimeException(message);
|
||||
}
|
||||
R<?> r = message != null ?
|
||||
R.status(httpStatus).setMessage(message).setData(message)
|
||||
: R.status(httpStatus);
|
||||
return r;
|
||||
}
|
||||
|
||||
private R<?> bodyOrPage(HttpStatus httpStatus, Exception ex) {
|
||||
boolean isPage = true;
|
||||
String message = null;
|
||||
if (ex instanceof RException ||
|
||||
ex instanceof LoginException) {
|
||||
isPage = false;
|
||||
message = ex.getMessage();
|
||||
}
|
||||
else {
|
||||
isPage = isPage();
|
||||
}
|
||||
if (isPage) {
|
||||
if (ex instanceof NoResourceFoundException nrfe) {
|
||||
if (StringUtils.isNotEmpty(nrfe.getMessage())
|
||||
&& nrfe.getMessage().endsWith(" .well-known/appspecific/com.chrome.devtools.json.")) {
|
||||
// 傻逼 Chrome 开发工具默认调用该地址
|
||||
return null;
|
||||
}
|
||||
}
|
||||
throw ex == null ? new RuntimeException("Page exception raised") : new RuntimeException(ex);
|
||||
}
|
||||
R<?> r = message != null ?
|
||||
R.status(httpStatus).setMessage(message).setData(message)
|
||||
: R.status(httpStatus);
|
||||
return r;
|
||||
}
|
||||
|
||||
private static String httpServletRequestToString(HttpServletRequest request) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("Request Method = \"" + request.getMethod() + "\", ");
|
||||
sb.append("Request URL Path = \"" + request.getRequestURL() + "\", ");
|
||||
|
||||
String headers = Collections.list(request.getHeaderNames()).stream()
|
||||
.map(headerName -> headerName + " : " + Collections.list(request.getHeaders(headerName)))
|
||||
.collect(Collectors.joining(", "));
|
||||
|
||||
if (headers.isEmpty()) {
|
||||
sb.append("Request headers: NONE,");
|
||||
} else {
|
||||
sb.append("Request headers: [" + headers + "],");
|
||||
}
|
||||
|
||||
String parameters = Collections.list(request.getParameterNames()).stream().map(p -> {
|
||||
String[] values = request.getParameterValues(p);
|
||||
return p + ": [" + StringUtils.join(values, ", ") + "]";
|
||||
}).collect(Collectors.joining(", "));
|
||||
|
||||
if (parameters.isEmpty()) {
|
||||
sb.append("Request parameters: NONE.");
|
||||
} else {
|
||||
sb.append("Request parameters: [" + parameters + "].");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user