您的位置:首页 > 编程语言 > Java开发

SpringBoot初始教程之统一异常处理(三)

2016-11-08 11:54 991 查看

SpringBoot初始教程之统一异常处理(三)

1.介绍

在日常开发中发生了异常,往往是需要通过一个统一的异常处理处理所有异常,来保证客户端能够收到友好的提示。SpringBoot在页面

发生异常的时候会自动把请求转到/error,SpringBoot内置了一个
BasicErrorController
对异常进行统一的处理,当然也可以自定义这个路径

application.yaml

server:
port: 8080
error:
path: /custom/error


BasicErrorController
提供两种返回错误一种是页面返回、当你是页面请求的时候就会返回页面,另外一种是json请求的时候就会返回json错误

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

@RequestMapping
@ResponseBody
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.ALL));
HttpStatus status = getStatus(request);
return new ResponseEntity<Map<String, Object>>(body, status);
}


分别会有如下两种返回



{
"timestamp": 1478571808052,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/rpc"
}


2.通用Exception处理

通过使用@ControllerAdvice来进行统一异常处理,
@ExceptionHandler(value = Exception.class)
来指定捕获的异常

下面针对两种异常进行了特殊处理分别返回页面和json数据,使用这种方式有个局限,无法根据不同的头部返回不同的数据格式,而且无法针对404、403等多种状态进行处理

@ControllerAdvice
public class GlobalExceptionHandler {
public static final String DEFAULT_ERROR_VIEW = "error";
@ExceptionHandler(value = CustomException.class)
@ResponseBody
public ResponseEntity defaultErrorHandler(HttpServletRequest req, CustomException e) throws Exception {
return ResponseEntity.ok("ok");
}
@ExceptionHandler(value = Exception.class)
public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
ModelAndView mav = new ModelAndView();
mav.addObject("exception", e);
mav.addObject("url", req.getRequestURL());
mav.setViewName(DEFAULT_ERROR_VIEW);
return mav;
}
}


3.自定义
BasicErrorController
错误处理

在初始介绍哪里提到了
BasicErrorController
,这个是SpringBoot的默认错误处理,也是一种全局处理方式。咱们可以模仿这种处理方式自定义自己的全局错误处理

下面定义了一个自己的BasicErrorController,可以根据自己的需求自定义
errorHtml()
error()
的返回值。

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
private final ErrorProperties errorProperties;
private static final Logger LOGGER = LoggerFactory.getLogger(BasicErrorController.class);
@Autowired
private ApplicationContext applicationContext;

/**
* Create a new {@link org.springframework.boot.autoconfigure.web.BasicErrorController} instance.
*
* @param errorAttributes the error attributes
* @param errorProperties configuration properties
*/
public BasicErrorController(ErrorAttributes errorAttributes,
ErrorProperties errorProperties) {
this(errorAttributes, errorProperties,
Collections.<ErrorViewResolver>emptyList());
}

/**
* Create a new {@link org.springframework.boot.autoconfigure.web.BasicErrorController} instance.
*
* @param errorAttributes    the error attributes
* @param errorProperties    configuration properties
* @param errorViewResolvers error view resolvers
*/
public BasicErrorController(ErrorAttributes errorAttributes,
ErrorProperties errorProperties, List<ErrorViewResolver> errorViewResolvers) {
super(errorAttributes, errorViewResolvers);
Assert.notNull(errorProperties, "ErrorProperties must not be null");
this.errorProperties = errorProperties;
}

@Override
public String getErrorPath() {
return this.errorProperties.getPath();
}

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

@RequestMapping
@ResponseBody
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.ALL));
HttpStatus status = getStatus(request);
insertError(request);
return new ResponseEntity(body, status);
}

/**
* Determine if the stacktrace attribute should be included.
*
* @param request  the source request
* @param produces the media type produced (or {@code MediaType.ALL})
* @return if the stacktrace attribute should be included
*/
protected boolean isIncludeStackTrace(HttpServletRequest request,
MediaType produces) {
ErrorProperties.IncludeStacktrace include = getErrorProperties().getIncludeStacktrace();
if (include == ErrorProperties.IncludeStacktrace.ALWAYS) {
return true;
}
if (include == ErrorProperties.IncludeStacktrace.ON_TRACE_PARAM) {
return getTraceParameter(request);
}
return false;
}

/**
* Provide access to the error properties.
*
* @return the error properties
*/
protected ErrorProperties getErrorProperties() {
return this.errorProperties;
}
}


SpringBoot提供了一种特殊的Bean定义方式,可以让我们容易的覆盖已经定义好的Controller,原生的
BasicErrorController
是定义在
ErrorMvcAutoConfiguration
中的

具体代码如下:

@Bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
this.errorViewResolvers);
}


可以看到这个注解
@ConditionalOnMissingBean
意思就是定义这个bean 当
ErrorController.class
这个没有定义的时候,

意思就是说只要我们在代码里面定义了自己的
ErrorController.class
时,这段代码就不生效了,具体自定义如下:

@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({Servlet.class, DispatcherServlet.class})
@AutoConfigureBefore(WebMvcAutoConfiguration.class)
@EnableConfigurationProperties(ResourceProperties.class)
public class ConfigSpringboot {
@Autowired(required = false)
private List<ErrorViewResolver> errorViewResolvers;
private final ServerProperties serverProperties;

public ConfigSpringboot(
ServerProperties serverProperties) {
this.serverProperties = serverProperties;
}

@Bean
public MyBasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
return new MyBasicErrorController(errorAttributes, this.serverProperties.getError(),
this.errorViewResolvers);
}

}


在使用的时候需要注意
MyBasicErrorController
不能被自定义扫描Controller扫描到,否则无法启动。

3.总结

一般来说自定义BasicErrorController这种方式比较实用,因为可以通过不同的头部返回不同的数据格式,在配置上稍微复杂一些,但是从实用的角度来说比较方便而且可以定义通用组件

本文代码

https://git.oschina.net/wangkang_daydayup/SpringBoot-Learn/tree/master

springboot-3
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息