背景
Springboot 默认把异常的处理集中到一个ModelAndView中了,但项目的实际过程中,这样做,并不能满足我们的要求。具体的自定义异常的处理,参看以下
前提
- Springboot 默认的application properties
- Spring Boot异常处理详解
具体实现
如果仔细看完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 ""; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
总结
第一步,通过定义containerCustomizer,重写定义了异常处理对应的视图。目前定义了404和500,可以继续扩展。
第二步,重写BasicErrorController,当然可以直接定义一个普通的controller类,直接实现第一步定义的视图的方法。重写的目的是重用ErrorAttributes。这样在页面,直接可以获取到status,message,exception,trace等内容。
如果仅仅是把异常处理的视图作为静态页面,不需要看到异常信息内容的话,直接第一步后,再定义error/404,error/500等静态视图即可。
ErrorController根据Accept头的内容,输出不同格式的错误响应。比如针对浏览器的请求生成html页面,针对其它请求生成json格式的返回
以上两步的操作,比网上流传的更能实现自定义化。
0 0