详解Springboot自定义异常处理

作者:whatlookingfor 时间:2021-11-04 17:15:12 

背景

Springboot 默认把异常的处理集中到一个ModelAndView中了,但项目的实际过程中,这样做,并不能满足我们的要求。具体的自定义异常的处理,参看以下

具体实现

如果仔细看完spring boot的异常处理详解,并且研究过源码后,我觉得具体的实现可以不用看了。。。

重写定义错误页面的url,默认只有一个/error


@Bean
 public EmbeddedServletContainerCustomizer containerCustomizer(){
   return new EmbeddedServletContainerCustomizer(){
     @Override
     public void customize(ConfigurableEmbeddedServletContainer container) {
       container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"));
       container.addErrorPages(new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500"));
       container.addErrorPages(new ErrorPage(java.lang.Throwable.class,"/error/500"));
     }
   };
 }

重写通过实现ErrorController,重写BasicErrorController的功能实现


/**
* 重写BasicErrorController,主要负责系统的异常页面的处理以及错误信息的显示
* @see org.springframework.boot.autoconfigure.web.BasicErrorController
* @see org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration
*
* @author Jonathan
* @version 2016/5/31 11:22
* @since JDK 7.0+
*/
@Controller
@RequestMapping(value = "error")
@EnableConfigurationProperties({ServerProperties.class})
public class ExceptionController implements ErrorController {

private ErrorAttributes errorAttributes;

@Autowired
 private ServerProperties serverProperties;

/**
  * 初始化ExceptionController
  * @param errorAttributes
  */
 @Autowired
 public ExceptionController(ErrorAttributes errorAttributes) {
   Assert.notNull(errorAttributes, "ErrorAttributes must not be null");
   this.errorAttributes = errorAttributes;
 }

/**
  * 定义404的ModelAndView
  * @param request
  * @param response
  * @return
  */
 @RequestMapping(produces = "text/html",value = "404")
 public ModelAndView errorHtml404(HttpServletRequest request,
                HttpServletResponse response) {
   response.setStatus(getStatus(request).value());
   Map<String, Object> model = getErrorAttributes(request,
       isIncludeStackTrace(request, MediaType.TEXT_HTML));
   return new ModelAndView("error/404", model);
 }

/**
  * 定义404的JSON数据
  * @param request
  * @return
  */
 @RequestMapping(value = "404")
 @ResponseBody
 public ResponseEntity<Map<String, Object>> error404(HttpServletRequest request) {
   Map<String, Object> body = getErrorAttributes(request,
       isIncludeStackTrace(request, MediaType.TEXT_HTML));
   HttpStatus status = getStatus(request);
   return new ResponseEntity<Map<String, Object>>(body, status);
 }

/**
  * 定义500的ModelAndView
  * @param request
  * @param response
  * @return
  */
 @RequestMapping(produces = "text/html",value = "500")
 public ModelAndView errorHtml500(HttpServletRequest request,
                HttpServletResponse response) {
   response.setStatus(getStatus(request).value());
   Map<String, Object> model = getErrorAttributes(request,
       isIncludeStackTrace(request, MediaType.TEXT_HTML));
   return new ModelAndView("error/500", model);
 }

/**
  * 定义500的错误JSON信息
  * @param request
  * @return
  */
 @RequestMapping(value = "500")
 @ResponseBody
 public ResponseEntity<Map<String, Object>> error500(HttpServletRequest request) {
   Map<String, Object> body = getErrorAttributes(request,
       isIncludeStackTrace(request, MediaType.TEXT_HTML));
   HttpStatus status = getStatus(request);
   return new ResponseEntity<Map<String, Object>>(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 = this.serverProperties.getError().getIncludeStacktrace();
   if (include == ErrorProperties.IncludeStacktrace.ALWAYS) {
     return true;
   }
   if (include == ErrorProperties.IncludeStacktrace.ON_TRACE_PARAM) {
     return getTraceParameter(request);
   }
   return false;
 }

/**
  * 获取错误的信息
  * @param request
  * @param includeStackTrace
  * @return
  */
 private Map<String, Object> getErrorAttributes(HttpServletRequest request,
                         boolean includeStackTrace) {
   RequestAttributes requestAttributes = new ServletRequestAttributes(request);
   return this.errorAttributes.getErrorAttributes(requestAttributes,
       includeStackTrace);
 }

/**
  * 是否包含trace
  * @param request
  * @return
  */
 private boolean getTraceParameter(HttpServletRequest request) {
   String parameter = request.getParameter("trace");
   if (parameter == null) {
     return false;
   }
   return !"false".equals(parameter.toLowerCase());
 }

/**
  * 获取错误编码
  * @param request
  * @return
  */
 private HttpStatus getStatus(HttpServletRequest request) {
   Integer statusCode = (Integer) request
       .getAttribute("javax.servlet.error.status_code");
   if (statusCode == null) {
     return HttpStatus.INTERNAL_SERVER_ERROR;
   }
   try {
     return HttpStatus.valueOf(statusCode);
   }
   catch (Exception ex) {
     return HttpStatus.INTERNAL_SERVER_ERROR;
   }
 }

/**
  * 实现错误路径,暂时无用
  * @see ExceptionMvcAutoConfiguration#containerCustomizer()
  * @return
  */
 @Override
 public String getErrorPath() {
   return "";
 }

}

总结

第一步,通过定义containerCustomizer,重写定义了异常处理对应的视图。目前定义了404和500,可以继续扩展。

第二步,重写BasicErrorController,当然可以直接定义一个普通的controller类,直接实现第一步定义的视图的方法。重写的目的是重用ErrorAttributes。这样在页面,直接可以获取到status,message,exception,trace等内容。

如果仅仅是把异常处理的视图作为静态页面,不需要看到异常信息内容的话,直接第一步后,再定义error/404,error/500等静态视图即可。

ErrorController根据Accept头的内容,输出不同格式的错误响应。比如针对浏览器的请求生成html页面,针对其它请求生成json格式的返回

以上两步的操作,比网上流传的更能实现自定义化。希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

来源:http://blog.csdn.net/whatlookingfor/article/details/51548923

标签:spring,boot,异常
0
投稿

猜你喜欢

  • 一文搞懂JMeter engine中HashTree的配置问题

    2022-05-11 01:21:08
  • C#实现五子棋游戏

    2022-07-26 12:55:34
  • springMvc注解之@ResponseBody和@RequestBody详解

    2022-10-09 17:57:19
  • Java远程连接Linux服务器并执行命令及上传文件功能

    2023-01-28 14:03:31
  • Android Studio 透明状态栏的实现示例

    2022-12-06 21:44:23
  • Android广播实现App开机自启动

    2023-01-06 14:54:44
  • Android Retrofit原理深入探索

    2023-09-06 02:47:15
  • Netty分布式高性能工具类同线程下回收对象解析

    2023-05-24 22:00:55
  • 分享几个Java工作中实用的代码优化技巧

    2023-11-28 12:04:50
  • Java实现过滤掉map集合中key或value为空的值示例

    2021-05-25 10:26:17
  • 基于Spring整合mybatis的mapper生成过程

    2022-01-11 03:49:26
  • Java编写实现坦克大战小游戏

    2023-11-24 09:15:34
  • java使用集合实现通讯录功能

    2023-01-30 21:27:15
  • 详解SpringBoot程序启动时执行初始化代码

    2022-05-07 13:36:05
  • Android编程实现图片平铺的方法分析

    2022-05-27 06:37:40
  • Springboot打包为Docker镜像并部署的实现

    2023-06-05 23:11:52
  • springboot中使用FastJson解决long类型在js中失去精度的问题

    2022-04-05 05:15:27
  • java中抽象类和接口的相同和不同点介绍

    2021-05-30 04:53:31
  • 老生常谈Scanner的基本用法

    2021-08-27 00:34:18
  • SpringMVC底层执行流程及原理解析

    2022-11-19 03:34:56
  • asp之家 软件编程 m.aspxhome.com