SpringBoot全局異常處理方式
SpringBoot全局異常處理
為了讓客戶端能有一個更好的體驗,當(dāng)客戶端發(fā)送請求到服務(wù)端發(fā)生錯誤時服務(wù)端應(yīng)該明確告訴客戶端錯誤信息。

SpringBoot內(nèi)置的異常處理返回的界面太雜亂,不夠友好。我們需要將異常信息做封裝處理響應(yīng)給前端。本文介紹的為將錯誤信息統(tǒng)一封裝成如下格式j(luò)son響應(yīng)給前端。
{
code:10001,
message:xxxxx,
request:GET url
}
自定義異常類
package com.lin.missyou.exception;
public class HttpException extends RuntimeException{
protected Integer code;
protected Integer httpStatusCode;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public Integer getHttpStatusCode() {
return httpStatusCode;
}
public void setHttpStatusCode(Integer httpStatusCode) {
this.httpStatusCode = httpStatusCode;
}
}
package com.lin.missyou.exception;
public class NotFoundException extends HttpException{
public NotFoundException(int code){
this.httpStatusCode = 404;
this.code = code;
}
}
package com.lin.missyou.exception;
public class ForbiddenException extends HttpException{
public ForbiddenException(int code){
this.httpStatusCode = 403;
this.code = code;
}
}
創(chuàng)建一個用于封裝異常信息的類UnifyResponse
package com.lin.missyou.core;
public class UnifyResponse {
private int code;
private String message;
private String request;
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
public String getRequest() {
return request;
}
public UnifyResponse(int code, String message, String request) {
this.code = code;
this.message = message;
this.request = request;
}
}
將異常信息寫在配置文件exception-code.properties里
lin.codes[10000] = 通用異常 lin.codes[10001] = 通用參數(shù)錯誤
自定義配置類管理配置文件
package com.lin.missyou.core.configuration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@PropertySource(value="classpath:config/exception-code.properties")
@ConfigurationProperties(prefix = "lin")
@Component
public class ExceptionCodeConfiguration {
private Map<Integer,String> codes = new HashMap<>();
public Map<Integer, String> getCodes() {
return codes;
}
public void setCodes(Map<Integer, String> codes) {
this.codes = codes;
}
public String getMessage(int code) {
String message = codes.get(code);
return message;
}
}
創(chuàng)建一個全局異常處理類GlobalExceptionAdvice,用@ControllerAdvice標(biāo)明異常處理類。@ResponseStatus用于指定http狀態(tài)碼。
@ExceptionHandler標(biāo)明異常處理器,傳入?yún)?shù)指定當(dāng)前函數(shù)要處理哪種類型的異常。Springboot會幫我們把這些異常信息傳入到函數(shù)。第一個函數(shù)用于處理未知異常,不需要向前端提供詳細(xì)的錯誤原因,只需提示統(tǒng)一的文本信息即可。
第二個函數(shù)用于處理已知異常,需要指明具體的錯誤原因,需要根據(jù)Exception傳遞過來的信息靈活的定制httpStatusCode。ResponseEntity可以自定義很多屬性,包括可以設(shè)置httpheaders,httpbodys,httpStatus。
package com.lin.missyou.core;
import com.lin.missyou.core.config.ExceptionCodeConfiguration;
import com.lin.missyou.exception.HttpException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
@ControllerAdvice
public class GlobalExceptionAdvice {
@Autowired
ExceptionCodeConfiguration exceptionCodeConfiguration ;
@ExceptionHandler(Exception.class)
@ResponseBody
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public UnifyResponse handleException(HttpServletRequest req,Exception e){
String method = req.getMethod();
String requestUrl = req.getRequestURI();
System.out.println(e);
UnifyResponse unifyResponse = new UnifyResponse(9999,"服務(wù)器錯誤",method+" "+requestUrl);
return unifyResponse;
}
@ExceptionHandler(HttpException.class)
public ResponseEntity<UnifyResponse> handleHttpException(HttpServletRequest req, HttpException e){
String method = req.getMethod();
String requestUrl = req.getRequestURI();
System.out.println(e);
UnifyResponse unifyResponse = new UnifyResponse(e.getCode(),exceptionCodeConfiguration.getMessage(e.getCode()),method+" "+requestUrl);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpStatus httpStatus = HttpStatus.resolve(e.getHttpStatusCode());
ResponseEntity<UnifyResponse> responseEntity = new ResponseEntity(unifyResponse,httpHeaders,httpStatus);
return responseEntity;
}
//參數(shù)校驗
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public UnifyResponse handleBeanValidation(HttpServletRequest req, MethodArgumentNotValidException e){
String method = req.getMethod();
String requestUrl = req.getRequestURI();
List<ObjectError> errors = e.getBindingResult().getAllErrors();
String message = formatAllErrorMessages(errors);
return new UnifyResponse(10001,message,method+" "+requestUrl);
}
private String formatAllErrorMessages(List<ObjectError> errors){
StringBuffer errorMsg = new StringBuffer();
errors.forEach(error ->
errorMsg.append(error.getDefaultMessage()).append(";")
);
return errorMsg.toString();
}
@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public UnifyResponse handleConstrainException(HttpServletRequest req, ConstraintViolationException e){
String method = req.getMethod();
String requestUrl = req.getRequestURI();
String message = e.getMessage();
return new UnifyResponse(10001,message,method+" "+requestUrl);
}
}

響應(yīng)信息可能會出現(xiàn)亂碼現(xiàn)象,修改配置文件編碼。在設(shè)置面板搜索File Encodings,Default encoding for properties files選擇UTF-8,勾選Transparent native-to-ascii conversion

springboot全局異常處理——@ControllerAdvice+ExceptionHandler
一、全局捕獲異常后,返回json給瀏覽器
項目結(jié)構(gòu):

1、自定義異常類 MyException.java
package com.gui.restful;
/**
* 自定義異常類
*/
public class MyException extends RuntimeException{
private String code;
private String msg;
public MyException(String code,String msg){
this.code=code;
this.msg=msg;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
2、控制器 MyController.java
package com.gui.restful;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* controller拋出異常
*/
@RestController
public class MyController {
@RequestMapping("hello")
public String hello() throws Exception{
throw new MyException("101","系統(tǒng)異常");
}
}
3、全局異常處理類 MyControllerAdvice
package com.gui.restful;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
/**
* 全局異常捕獲處理
*/
@ControllerAdvice //controller增強器
public class MyControllerAdvice {
@ResponseBody
@ExceptionHandler(value=MyException.class) //處理的異常類型
public Map myExceptionHandler(MyException e){
Map<String,String> map=new HashMap<>();
map.put("code",e.getCode());
map.put("msg",e.getMsg());
return map;
}
}
4、運行結(jié)果
啟動應(yīng)用,訪問 http://localhost:8080/hello,出現(xiàn)以下結(jié)果,說明自定義異常被成功攔截

二、全局捕獲異常后,返回頁面給瀏覽器
1、自定義異常類 MyException.java(同上)
2、控制器 MyController.java(同上)
3、全局異常處理類 MyControllerAdvice
package com.gui.restful;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import java.util.HashMap;
import java.util.Map;
/**
* 全局異常捕獲處理
*/
@ControllerAdvice //controller增強器
public class MyControllerAdvice {
@ExceptionHandler(value=MyException.class) //處理的異常類型
public ModelAndView myExceptionHandler(MyException e){
ModelAndView modelAndView=new ModelAndView();
modelAndView.setViewName("error");
modelAndView.addObject("code",e.getCode());
modelAndView.addObject("msg",e.getMsg());
return modelAndView;
}
}
4、頁面渲染 error.ftl(用freemarker渲染)
pom.xml中引入freemarker依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency>
error.ftl
<!DOCTYPE>
<html>
<head>
<title>錯誤頁面</title>
</head>
<body>
<h1>code:$[code]</h1>
<h1>msg:${msg}</h1>
</body>
</html>
5、運行結(jié)果
啟動應(yīng)用,訪問 http://localhost:8080/hello,出現(xiàn)以下結(jié)果,說明自定義異常被成功攔截

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
java通過HttpServletRequest獲取post請求中的body內(nèi)容的方法
本篇文章主要介紹了java通過HttpServletRequest獲取post請求中的body內(nèi)容的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-02-02
詳解Spring關(guān)于@Resource注入為null解決辦法
這篇文章主要介紹了詳解Spring關(guān)于@Resource注入為null解決辦法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05

