springBoot2.X配置全局捕獲異常的操作
springBoot2.X配置全局捕獲異常
先來看一段代碼:當傳入的id是0的時候,就會報異常。
@RestController public class HelloController { @GetMapping("/getUser") public String getUser(int id) { int j = 1 / id; return "SUCCESS" + j; } }
訪問時:
我們知道這個頁面要是給用戶看到,用戶可能不知道這是什么。
方法一:將異常捕獲
@GetMapping("/getUser") public String getUser(int id) { int j; try { j = 1 / id; } catch (Exception e) { return "系統(tǒng)異常"; } return "SUCCESS" + j; }
這種方法當然可以,但是當我們有很多方法時,需要在每個方法上都加上。
哎,太雞肋了吧。
那么都沒有全局的攔截處理呢?
當然了
方法二:通過@ControllerAdvice注解配置
/** * @Author 劉翊揚 * @Date 2020/9/30 11:39 下午 * @Version 1.0 */ @ControllerAdvice(basePackages = "com.yiyang.myfirstspringdemo.controller") public class GlobalExceptionHandler { @ExceptionHandler(RuntimeException.class) @ResponseBody public Map<String,Object> errorResult() { Map<String, Object> map = new HashMap<>(); map.put("errorCode", "500"); map.put("errorMsg", "全局捕獲異常"); return map; } }
@ExceptionHandler
表示攔截異常@ControllerAdvice
是 controller 的一個輔助類,最常用的就是作為全局異常處理的切面類@ControllerAdvice
可以指定掃描范圍
注意:下面還需要在啟動類上加上,否則誒呦效果
package com.yiyang.myfirstspringdemo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication(scanBasePackages = {"com.yiyang.myfirstspringdemo.error", "com.yiyang.myfirstspringdemo.controller"}) public class MyFirstSpringDemoApplication { public static void main(String[] args) { SpringApplication.run(MyFirstSpringDemoApplication.class, args); } }
在啟動類上,將掃描包范圍controller和全局異常處理類,加上去。
這樣當我們在訪問的時候,出現(xiàn)的異常提示信息就是我們在全局異常處理中設(shè)置的返回值。
springboot2.x 全局異常處理的正確方式
在web項目中,異常堆棧信息是非常敏感的。因此,需要一個全局的異常處理,捕獲異常,給客戶端以友好的錯誤信息提示?;?Spring boot 很容易實現(xiàn)全局異常處理。
相關(guān)jar依賴引入
<!-- Spring Boot 啟動父依賴 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <!-- Spring Boot Web 依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
全局異常控制器
package com.yb.demo.common.handler; import com.yb.demo.common.enums.CodeEnum; import com.yb.demo.common.exception.BizException; import com.yb.demo.pojo.response.Result; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.validation.BindException; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import javax.validation.ValidationException; import java.util.StringJoiner; /** * 全局異常處理 * <p> * 規(guī)范:流程跳轉(zhuǎn)盡量避免使用拋 BizException 來做控制。 * * @author daoshenzzg@163.com * @date 2019-09-06 18:02 */ @Slf4j @RestControllerAdvice public class GlobalExceptionHandler { /** * 處理自定義異常 * * @param ex * @return */ @ExceptionHandler(BizException.class) public Result handleBizException(BizException ex) { Result result = Result.renderErr(ex.getCode()); if (StringUtils.isNotBlank(ex.getRemark())) { result.withRemark(ex.getRemark()); } return result; } /** * 參數(shù)綁定錯誤 * * @param ex * @return */ @ExceptionHandler(BindException.class) public Result handleBindException(BindException ex) { StringJoiner sj = new StringJoiner(";"); ex.getBindingResult().getFieldErrors().forEach(x -> sj.add(x.getDefaultMessage())); return Result.renderErr(CodeEnum.REQUEST_ERR).withRemark(sj.toString()); } /** * 參數(shù)校驗錯誤 * * @param ex * @return */ @ExceptionHandler(ValidationException.class) public Result handleValidationException(ValidationException ex) { return Result.renderErr(CodeEnum.REQUEST_ERR).withRemark(ex.getCause().getMessage()); } /** * 字段校驗不通過異常 * * @param ex * @return */ @ExceptionHandler(MethodArgumentNotValidException.class) public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) { StringJoiner sj = new StringJoiner(";"); ex.getBindingResult().getFieldErrors().forEach(x -> sj.add(x.getDefaultMessage())); return Result.renderErr(CodeEnum.REQUEST_ERR).withRemark(sj.toString()); } /** * Controller參數(shù)綁定錯誤 * * @param ex * @return */ @ExceptionHandler(MissingServletRequestParameterException.class) public Result handleMissingServletRequestParameterException(MissingServletRequestParameterException ex) { return Result.renderErr(CodeEnum.REQUEST_ERR).withRemark(ex.getMessage()); } /** * 處理方法不支持異常 * * @param ex * @return */ @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class) public Result handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException ex) { return Result.renderErr(CodeEnum.METHOD_NOT_ALLOWED); } /** * 其他未知異常 * * @param ex * @return */ @ExceptionHandler(value = Exception.class) public Result handleException(Exception ex) { log.error(ex.getMessage(), ex); return Result.renderErr(CodeEnum.SERVER_ERR); } }
個性化異常處理
自定義異常
在實際web開發(fā)過程中,往往會遇到在某些場景下需要終止當前流程,直接返回。那么,通過拋出自定義異常,并在全局異常中捕獲,用以友好的提示客戶端。
/** * 業(yè)務(wù)異常跳轉(zhuǎn)。 * * @author daoshenzzg@163.com * @date 2019-09-09 14:57 */ @Data public class BizException extends RuntimeException { private static final long serialVersionUID = 1L; private CodeEnum code; private String remark; public BizException(CodeEnum code) { super(code.getMessage()); this.code = code; } public BizException withRemark(String remark) { this.remark = remark; return this; } }
使用方式如下:
/** * 添加學生 * * @param student * @return */ public Student1DO addStudent(Student1DO student) { if (StringUtils.isNotBlank(student.getStudName())) { // 舉例扔個業(yè)務(wù)異常,實際使用過程中,應(yīng)該避免扔異常 throw new BizException(CodeEnum.REQUEST_ERR).withRemark("studName不能為空"); } student1Mapper.insert(student); return student; }
返回效果如下:
{
"code": -400,
"msg": "請求錯誤(studName不能為空)",
"data": {},
"ttl": 0
}
根據(jù)阿里巴巴規(guī)范,流程控制還是不要通過拋異常的方式。在正常開發(fā)過程中,應(yīng)避免使用這種方式。
【強制】異常不要用來做流程控制,條件控制,因為異常的處理效率比條件分支低。
使用 Spring validation 完成數(shù)據(jù)后端校驗
定義實體類,加上validation相關(guān)注解
package com.yb.demo.pojo.model.db1; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import javax.validation.constraints.Min; import javax.validation.constraints.Size; /** * @author daoshenzzg@163.com * @date 2019-08-05 17:58 */ @Data @TableName("student") public class Student1DO { private Long id; @Size(max = 8, message = "studName長度不能超過8") private String studName; @Min(value = 12, message = "年齡不能低于12歲") private Integer studAge; private String studSex; @TableField(fill = FieldFill.INSERT) private Integer createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Integer updateTime; }
在Controller 方法上加上 @Validated 注解
@PostMapping("/student/add") public Result addStudent(@Validated @RequestBody Student1DO student) { student = studentService.addStudent(student); return Result.renderOk(student); }
實際效果如下:
{
"code": -400,
"msg": "請求錯誤(年齡不能低于12歲)",
"data": {},
"ttl": 0
}
結(jié)束語
具體代碼見:https://github.com/daoshenzzg/springboot2.x-example
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring data jpa的使用與詳解(復雜動態(tài)查詢及分頁,排序)
這篇文章主要介紹了Spring data jpa的使用與詳解(復雜動態(tài)查詢及分頁,排序),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-11-11一文搞懂如何實現(xiàn)Java,Spring動態(tài)啟停定時任務(wù)
定時任務(wù)的應(yīng)用場景十分廣泛,如定時清理文件、定時生成報表、定時數(shù)據(jù)同步備份等。本文將教你實現(xiàn)Java、Spring動態(tài)啟停定時任務(wù),感興趣的可以學習一下2022-06-06Java實現(xiàn)RedisUtils操作五大集合(增刪改查)
本文主要介紹了Java實現(xiàn)RedisUtils操作五大集合,文中通過示例代碼介紹的非常詳細,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-07-07在ssm中使用ModelAndView跳轉(zhuǎn)頁面失效的解決
這篇文章主要介紹了在ssm中使用ModelAndView跳轉(zhuǎn)頁面失效的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05SpringBoot參數(shù)校驗之@Valid的使用詳解
這篇文章主要通過示例為大家詳細介紹一下介紹了SpringBoot參數(shù)校驗中@Valid的使用方法,文中的示例代碼講解詳細,需要的可以參考一下2022-06-06Java實現(xiàn)跳轉(zhuǎn)到指定頁面的方法小結(jié)
在Java中,實現(xiàn)頁面跳轉(zhuǎn)主要涉及到Web開發(fā),而這通常通過使用Java的Web框架(如Servlet、Spring MVC)來完成,下面講解一下如何在不同的Java Web框架中實現(xiàn)頁面跳轉(zhuǎn),文中有詳細的代碼示例供大家參考,需要的朋友可以參考下2024-05-05