背景
Springboot 默認把異常的處理集中到一個ModelAndView中了,但項目的實際過程中,這樣做,并不能滿足我們的要求。具體的自定義異常的處理,參看以下
具體實現
如果仔細看完spring boot的異常處理詳解,并且研究過源碼后,我覺得具體的實現可以不用看了。。。
重寫定義錯誤頁面的url,默認只有一個/error
1
2
3
4
5
6
7
8
9
10
11
|
@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的功能實現
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
|
/** * 重寫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