package com.siniswift.efb.acars.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 错误页控制器
*
* @author: simon
* @date: 2019/7/12 15:03
*/
@Controller
public class ErrorPageController {
/**
* 404错误页
*
* @return 404错误页
*/
@RequestMapping("/error_404")
public String page404View(){
return "error/error404";
}
/**
* 400错误页
*
* @return 400错误页
*/
@RequestMapping("/error_400")
public String page400View(){
return "error/error400";
}
/**
* 500错误页
*
* @return 500错误页
*/
@RequestMapping("/error_500")
public String page500View(){
return "error/error500";
}
}
在/resources/templates/error目录下新增error400,error404,error500页面。以error400页面为例:
400
400
Spring Boot默认使用嵌入式Tomcat,默认没有页面来处理404等常见错误。因此,为了给用户最佳的使用体验,404等常见错误需要我们自定义页面来处理。
在springboot2.0之前用org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer类来实现该功能。
package com.siniswift.efb.acars.config;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.servlet.ErrorPage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
/**
* 错误页配置
*
* @author: simon
* @date: 2019/7/12 15:11
*/
@Configuration
public class ErrorPageConfig {
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
ErrorPage error400Page = new ErrorPage(HttpStatus.UNAUTHORIZED, "/error_400");
ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/error_404");
ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error_500");
container.addErrorPages(error400Page, error404Page, error500Page);
}
};
}
}
在Spring Boot2.0以上配置嵌入式Servlet容器时EmbeddedServletContainerCustomizer类不存在,使用WebServerFactoryCustomizer接口替换EmbeddedServletContainerCustomizer组件完成对嵌入式Servlet容器的配置
@Bean
public WebServerFactoryCustomizer webServerFactoryCustomizer() {
return new WebServerFactoryCustomizer() {
@Override
public void customize(ConfigurableWebServerFactory factory) {
// 对嵌入式servlet容器的配置
// factory.setPort(8081);
/* 注意:new ErrorPage(stat, path);中path必须是页面名称,并且必须“/”开始。
底层调用了String.java中如下方法:
public boolean startsWith(String prefix) {
return startsWith(prefix, 0);
}*/
ErrorPage errorPage400 = new ErrorPage(HttpStatus.BAD_REQUEST,
"/error-400");
ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND,
"/error-404");
ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR,
"/error-500");
factory.addErrorPages(errorPage400, errorPage404,
errorPage500);
}
};
}
使用@ControllerAdvice
处理全局异常
package com.siniswift.efb.acars.utils;
import com.siniswift.efb.acars.enums.ResultEnum;
/**
* 响应封装
*
* @author: simon
* @date: 2019/3/26 16:16
*/
public class JsonResult {
/**
* 错误码
*/
private int code;
/**
* 提示信息
*/
private String msg;
/**
* 返回结果
*/
private T data;
/**
* 成功时候的调用
*
* @param data 返回内容
* @return 结果
*/
public static JsonResult success(T data) {
return new JsonResult<>(data);
}
/**
* 成功时候的调用
*
* @param msg 提示信息
* @return 结果
*/
public static JsonResult success(String msg) {
return new JsonResult<>(ResultEnum.SUCCESS.getCode(), msg);
}
/**
* 成功时候的调用
*
* @param msg 提示信息
* @param data 返回内容
* @return 结果
*/
public static JsonResult success(String msg, T data) {
return new JsonResult<>(ResultEnum.SUCCESS.getCode(), msg, data);
}
/**
* 根据返回的状态对象构建返回结果
*
* @param resultEnum 返回结果枚举
* @return 结果
*/
public static JsonResult build(ResultEnum resultEnum) {
return new JsonResult<>(resultEnum);
}
/**
* 根据code和msg构建返回结果
*
* @param code 结果代码
* @param msg 提示信息
* @return 结果
*/
public static JsonResult build(int code, String msg) {
return new JsonResult<>(code, msg);
}
/**
* 根据code,和msg,和data构建返回结果
*
* @param code 结果代码
* @param msg 提示信息
* @return 结果
*/
public static JsonResult build(int code, String msg, T data) {
return new JsonResult<>(code, msg, data);
}
/**
* 失败的调用
*
* @param msg 错误描述
* @return 结果
*/
public static JsonResult error(String msg) {
return new JsonResult<>(msg);
}
/**
* 失败的调用,将返回结果传入
*
* @param data 返回内容
* @return
*/
public static JsonResult error(T data) {
return new JsonResult<>(ResultEnum.ERROR.getCode(), ResultEnum.ERROR.getMsg(), data);
}
private JsonResult(T data) {
this.code = ResultEnum.SUCCESS.getCode();
this.msg = ResultEnum.SUCCESS.getMsg();
this.data = data;
}
private JsonResult(String msg) {
this.code = ResultEnum.ERROR.getCode();
this.data = null;
this.msg = msg;
}
private JsonResult(ResultEnum resultEnum) {
this.code = resultEnum.getCode();
this.msg = resultEnum.getMsg();
}
private JsonResult(int code, String msg) {
this.code = code;
this.msg = msg;
}
private JsonResult(int code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
package com.siniswift.efb.acars.enums;
/**
* @author: simon
* @date: 2019/3/26 16:35
* @description: 返回结果枚举
*/
public enum ResultEnum {
SUCCESS(0, "成功"),
ERROR(-1, "失败");
/**
* 结果代码
*/
private int code;
/**
* 结果描述
*/
private String msg;
ResultEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
package com.siniswift.efb.acars.config;
import com.siniswift.efb.acars.utils.JsonResult;
import com.siniswift.efb.acars.utils.WebServiceUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* 全局异常捕获
*
* @author: simon
* @date: 2019/3/26 16:15
*/
@CrossOrigin
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
/**
* 提示消息模板
*/
private static final String logExceptionFormat = "Capture Exception By GlobalExceptionHandler: Code: %s Detail: %s";
/**
* 日志
*/
private static Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 运行时异常
*/
@ExceptionHandler(RuntimeException.class)
public Object runtimeExceptionHandler(RuntimeException ex) {
return exceptionFormat(1, ex);
}
/**
* 空指针异常
*/
@ExceptionHandler(NullPointerException.class)
public Object nullPointerExceptionHandler(NullPointerException ex) {
return exceptionFormat(2, ex);
}
/**
* 类型转换异常
*/
@ExceptionHandler(ClassCastException.class)
public Object classCastExceptionHandler(ClassCastException ex) {
return exceptionFormat(3, ex);
}
/**
* IO异常
*/
@ExceptionHandler(IOException.class)
public Object iOExceptionHandler(IOException ex) {
return exceptionFormat(4, ex);
}
/**
* 未知方法异常
*/
@ExceptionHandler(NoSuchMethodException.class)
public Object noSuchMethodExceptionHandler(NoSuchMethodException ex) {
return exceptionFormat(5, ex);
}
/**
* 数组越界异常
*/
@ExceptionHandler(IndexOutOfBoundsException.class)
public Object indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) {
return exceptionFormat(6, ex);
}
/**
* 400错误
*/
@ExceptionHandler({HttpMessageNotReadableException.class})
public Object requestNotReadable(HttpMessageNotReadableException ex) {
return exceptionFormat(7, ex);
}
/**
* 400错误
*/
@ExceptionHandler({TypeMismatchException.class})
public Object requestTypeMismatch(TypeMismatchException ex) {
return exceptionFormat(8, ex);
}
/**
* 400错误
*/
@ExceptionHandler({MissingServletRequestParameterException.class})
public Object requestMissingServletRequest(MissingServletRequestParameterException ex) {
return exceptionFormat(9, ex);
}
/**
* 405错误
*/
@ExceptionHandler({HttpRequestMethodNotSupportedException.class})
public Object request405(HttpRequestMethodNotSupportedException ex) {
return exceptionFormat(10, ex);
}
/**
* 406错误
*/
@ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
public Object request406(HttpMediaTypeNotAcceptableException ex) {
return exceptionFormat(11, ex);
}
/**
* 500错误
*/
@ExceptionHandler({ConversionNotSupportedException.class, HttpMessageNotWritableException.class})
public Object server500(RuntimeException ex) {
return exceptionFormat(12, ex);
}
/**
* 栈溢出
*/
@ExceptionHandler({StackOverflowError.class})
public Object requestStackOverflow(StackOverflowError ex) {
return exceptionFormat(13, ex);
}
/**
* 其他错误
*/
@ExceptionHandler({Exception.class})
public Object exception(Exception ex) {
return exceptionFormat(14, ex);
}
private Object exceptionFormat(Integer code, T ex) {
log.error(String.format(logExceptionFormat, code, ex.getMessage()));
//获取request对象
HttpServletRequest request = WebServiceUtils.getRequest();
if(isAjax(request)){
return JsonResult.build(code, ex.getMessage());
}else{
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error/error404");
return modelAndView;
}
}
/**
* 判断是否是Ajax请求
*
* @param request 请求对象
* @return 0:否;1:是
*/
private boolean isAjax(HttpServletRequest request) {
return (request.getHeader("X-Requested-With") != null &&
"XMLHttpRequest".equals(request.getHeader("X-Requested-With")));
}
}
}