<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何在SpringBoot中優(yōu)雅的處理異常

          共 16297字,需瀏覽 33分鐘

           ·

          2021-07-27 19:39

          點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)

          真香!24W字的Java面試手冊(cè)(點(diǎn)擊查看)

          SpringBoot 統(tǒng)一異常處理 像這種統(tǒng)一異常的文章博客有許多,但是每個(gè)人使用都有自己的心得,我來(lái)總結(jié)一下自己使用的心得統(tǒng)一異常,顧名思義,就是統(tǒng)一管理項(xiàng)目中會(huì)方法的異常,然后進(jìn)行一個(gè)處理,Spring發(fā)生錯(cuò)誤后,底層會(huì)去請(qǐng)求一個(gè)/error的地址,拋出對(duì)應(yīng)的異常到頁(yè)面上,對(duì)客戶或者開發(fā)來(lái)說(shuō)都不是特別的友好使用統(tǒng)一異常處理的話,可以返回自定義的異常數(shù)據(jù),閱讀性提高,優(yōu)雅的處理異常

          使用異常

          使用異常的方式很簡(jiǎn)單,Spring提供了兩個(gè)注解:@ControllerAdvice@ExceptionHandler

          創(chuàng)建統(tǒng)一異常類

          import org.slf4j.Logger;
          import org.slf4j.LoggerFactory;
          import org.springframework.beans.TypeMismatchException;
          import org.springframework.beans.factory.annotation.Value;
          import org.springframework.boot.autoconfigure.web.AbstractErrorController;
          import org.springframework.boot.autoconfigure.web.ErrorAttributes;
          import org.springframework.http.HttpHeaders;
          import org.springframework.http.HttpStatus;
          import org.springframework.stereotype.Controller;
          import org.springframework.web.HttpRequestMethodNotSupportedException;
          import org.springframework.web.bind.MissingServletRequestParameterException;
          import org.springframework.web.bind.annotation.*;
          import org.springframework.web.multipart.MultipartException;
          import org.springframework.web.servlet.NoHandlerFoundException;

          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          import java.sql.SQLException;
          import java.util.Map;

          /**
           * 全局異常處理
           * 一般情況下,方法都有異常處理機(jī)制,但不能排除有個(gè)別異常沒(méi)有處理,導(dǎo)致返回到前臺(tái),因此在這里做一個(gè)異常攔截,統(tǒng)一處理那些未被處理過(guò)的異常
           *
           * @author ${author} on ${date}
           */

          @ControllerAdvice
          @Controller
          @RequestMapping
          public class GlobalExceptionHandler extends AbstractErrorController {

              private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);

              public GlobalExceptionHandler(ErrorAttributes errorAttributes) {
                  super(errorAttributes);
              }

              @Value("${server.error.path:${error.path:/error}}")
              private static String errorPath = "/error";


              /**
               * sql異常
               *
               * @param req
               * @param rsp
               * @param ex
               * @return
               * @throws Exception
               */

              @ResponseBody
              @ExceptionHandler(SQLException.class)
              public Result<StringsqlException(HttpServletRequest reqHttpServletResponse rspException ex
          {
                  LOGGER.error("!!! request uri:{} from {} server exception:{}", req.getRequestURI(), RequestUtil.getIpAddress(req), ex == null ? null : ex);
                  return ResponseMsgUtil.builderResponse(1002, ex == null ? null : ex.getMessage(), null);
              }


              /**
               * 500錯(cuò)誤.
               *
               * @param req
               * @param rsp
               * @param ex
               * @return
               * @throws Exception
               */

              @ResponseBody
              @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
              @ExceptionHandler(Exception.class)
              public Result<StringserverError(HttpServletRequest reqHttpServletResponse rspException exthrows Exception 
          {
                  LOGGER.error("!!! request uri:{} from {} server exception:{}", req.getRequestURI(), RequestUtil.getIpAddress(req), ex == null ? null : ex);
                  return ResponseMsgUtil.builderResponse(1002, ex == null ? null : ex.getMessage(), null);
              }


              /**
               * 404的攔截.
               *
               * @param request
               * @param response
               * @param ex
               * @return
               * @throws Exception
               */

              @ResponseBody
              @ResponseStatus(code = HttpStatus.NOT_FOUND)
              @ExceptionHandler(NoHandlerFoundException.class)
              public Result<StringnotFound(HttpServletRequest requestHttpServletResponse responseException exthrows Exception 
          {
                  LOGGER.error("!!! request uri:{} from {} not found exception:{}", request.getRequestURI(), RequestUtil.getIpAddress(request), ex);
                  return ResponseMsgUtil.builderResponse(404, ex == null ? null : ex.getMessage(), null);
              }

              @ExceptionHandler(MissingServletRequestParameterException.class)
              @ResponseBody
              public Result<StringparamException(MissingServletRequestParameterException ex
          {
                  LOGGER.error("缺少請(qǐng)求參數(shù):{}", ex.getMessage());
                  return ResponseMsgUtil.builderResponse(99999"缺少參數(shù):" + ex.getParameterName(), null);
              }

              //參數(shù)類型不匹配
              //getPropertyName()獲取數(shù)據(jù)類型不匹配參數(shù)名稱
              //getRequiredType()實(shí)際要求客戶端傳遞的數(shù)據(jù)類型
              @ExceptionHandler(TypeMismatchException.class)
              @ResponseBody
              public Result<StringrequestTypeMismatch(TypeMismatchException ex
          {
                  LOGGER.error("參數(shù)類型有誤:{}", ex.getMessage());
                  return ResponseMsgUtil.builderResponse(99999"參數(shù)類型不匹配,參數(shù)" + ex.getPropertyName() + "類型應(yīng)該為" + ex.getRequiredType(), null);
              }

              @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
              @ResponseBody
              public Result<StringrequestMethod(HttpRequestMethodNotSupportedException ex
          {
                  LOGGER.error("請(qǐng)求方式有誤:{}", ex.getMethod());
                  return ResponseMsgUtil.builderResponse(99999"請(qǐng)求方式有誤:" + ex.getMethod(), null);
              }

              @ExceptionHandler(MultipartException.class)
              @ResponseBody
              public Result<StringfileSizeLimit(MultipartException m
          {
                  LOGGER.error("超過(guò)文件上傳大小限制");
                  return ResponseMsgUtil.builderResponse(99999"超過(guò)文件大小限制,最大10MB"null);
              }


              /**
               * 重寫/error請(qǐng)求, ${server.error.path:${error.path:/error}} IDEA報(bào)紅無(wú)需處理,作用是獲取spring底層錯(cuò)誤攔截
               *
               * @param request
               * @param response
               * @return
               * @throws Exception
               */

              @ResponseBody
              @RequestMapping(value = "${server.error.path:${error.path:/error}}")
              public Result<String> handleErrors(HttpServletRequest request, HttpServletResponse response) throws Exception {
                  HttpStatus status = getStatus(request);
                  if (status == HttpStatus.NOT_FOUND) {
                      throw new NoHandlerFoundException(request.getMethod(), request.getRequestURL().toString(), new HttpHeaders());
                  }
                  Map<String, Object> body = getErrorAttributes(request, true);
                  return ResponseMsgUtil.builderResponse(Integer.parseInt(body.get("status").toString()), body.get("message").toString(), null);
              }


              @Override
              public String getErrorPath() {
                  return errorPath;
              }
          }

          從上面可以看出來(lái),我定義了sql異常,500異常,404異常該做的事情,通過(guò)@ExceptionHandler注解來(lái)攔截程序中的異常,比如執(zhí)行SQL時(shí),拋出了異常,就會(huì)被統(tǒng)一異常給攔截,然后返回我們想要返回的數(shù)據(jù)

          @ResponseStatus注解可加可不加,就是對(duì)響應(yīng)碼進(jìn)行攔截,如代碼上,對(duì)404響應(yīng)碼進(jìn)行了攔截

          最下面的handleErrors方法,是對(duì)Spring底層訪問(wèn)/error的時(shí)候進(jìn)行了一次攔截,獲取當(dāng)前請(qǐng)求碼,如果是404.拋出404的異常

          優(yōu)化處理異常怎么能沒(méi)有自定義返回?cái)?shù)據(jù)呢

          import com.alibaba.fastjson.JSON;
          import com.alibaba.fastjson.serializer.SerializerFeature;

          /**
           * 返回?cái)?shù)據(jù)結(jié)果集合
           */

          public class Result<T{
              private Integer code;
              private String resMsg;
              private T data;

              public Result() {
              }

              public Integer getCode() {
                  return this.code;
              }

              public void setCode(Integer resCode) {
                  this.code = resCode;
              }

              public String getResMsg() {
                  return this.resMsg;
              }

              public void setResMsg(String resMsg) {
                  this.resMsg = resMsg;
              }

              public T getData() {
                  return this.data;
              }

              public void setData(T data) {
                  this.data = data;
              }

              public String toJson() {
                  return this.data == null ? JSON.toJSONString(this) : this.toJson(SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.WriteMapNullValue);
              }

              public String toJson(SerializerFeature... features) {
                  return features == null ? this.toJson() : JSON.toJSONString(this, features);
              }

              public String toString() {
                  return "Result{code=" + this.code + ", resMsg='" + this.resMsg + '\'' + ", data=" + this.data + '}';
              }
          }
          /**
           * 返回?cái)?shù)據(jù)結(jié)果集合
           * @author RuXuanWo on 2019/02/21
           */

          public class ResponseMsgUtil {
              public ResponseMsgUtil() {
              }

              public static <T> Result<T> builderResponse(int code, String msg, T data) {
                  Result<T> res = new Result();
                  res.setCode(code);
                  res.setResMsg(msg);
                  res.setData(data);
                  return res;
              }

              public static <T> Result<T> success(String msg) {
                  return builderResponse(0, msg, null);
              }
              public static <T> Result<T> success(String msg, T data) {
                  return builderResponse(0, msg, data);
              }
              public static <T> Result<T> success(T data) {
                  return builderResponse(0"Success", data);
              }
              public static <T> Result<T> success() {
                  return builderResponse(0"Success"null);
              }

              public static <T> Result<T> failure() {
                  return builderResponse(1"Failure"null);
              }
              public static <T> Result<T> failure(String msg) {
                  return builderResponse(1, msg, null);
              }
              public static <T> Result<T> failure(T date) {
                  return builderResponse(-1"Failure", date);
              }

              public static <T> Result<T> illegalRequest() {
                  return builderResponse(1008"Illegal request", (T) null);
              }

              public static <T> Result<T> exception() {
                  return builderResponse(1002"request exception", (T) null);
              }

              public static <T> Result<T> paramsEmpty() {
                  return builderResponse(1009"the input parameter is null", (T) null);
              }
          }

          測(cè)試

          將這些準(zhǔn)備都做好以后,項(xiàng)目跑起來(lái),訪問(wèn)一個(gè)接口,故意不傳某個(gè)必填項(xiàng),就會(huì)被統(tǒng)一異常攔截,如下

          {
           code: 1002,
           data: null,
           msg: "Required String parameter 'id' is not present"
          }


          如有文章對(duì)你有幫助,

          歡迎關(guān)注??、點(diǎn)贊??、轉(zhuǎn)發(fā)??!



          推薦, Java面試手冊(cè) 
          內(nèi)容包括網(wǎng)絡(luò)協(xié)議、Java基礎(chǔ)、進(jìn)階、字符串、集合、并發(fā)、JVM、數(shù)據(jù)結(jié)構(gòu)、算法、MySQL、Redis、Mongo、Spring、SpringBoot、MyBatis、SpringCloud、Linux以及各種中間件(Dubbo、Nginx、Zookeeper、MQ、Kafka、ElasticSearch)等等...

          點(diǎn)擊文末“閱讀原文”可直達(dá)

          瀏覽 130
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  无码破解一区二区三区在线播报 | 国产呦精品 | 最近中文字幕免费mv第一季歌词強上 | 欧美成人Aⅴ | 999av |