一、全局異常處理
代碼示例如下:
/**
* @author qinxun
* @date 2023-06-14
* @Descripion: 業(yè)務(wù)層異常枚舉
*/
public enum ServiceExceptionEnum {
SUCCESS(0, "成功"),
ERROR(1, "失敗"),
SYS_ERROR(1000, "服務(wù)端發(fā)生異常"),
MISSING_REQUEST_PARAM_ERROR(1001, "參數(shù)缺失"),
INVALID_REQUEST_PARAM_ERROR(1002, "請求參數(shù)不合法");
private final String message;
private final int code;
ServiceExceptionEnum(int code, String message) {
this.code = code;
this.message = message;
}
public String getMessage() {
return message;
}
public int getCode() {
return code;
}
}
import com.example.quartzdemo.enums.ServiceExceptionEnum;
import java.io.Serializable;
/**
* @author qinxun
* @date 2023-06-14
* @Descripion: 統(tǒng)一返回結(jié)果實體類
*/
public class CommonResult<T> implements Serializable {
/**
* 錯誤碼
*/
private Integer code;
/**
* 錯誤提示
*/
private String message;
/**
* 返回數(shù)據(jù)
*/
private T data;
/**
* 成功
*
* @param data
* @param <T>
* @return
*/
public static <T> CommonResult<T> success(T data) {
CommonResult<T> commonResult = new CommonResult<>();
commonResult.setCode(ServiceExceptionEnum.SUCCESS.getCode());
commonResult.setMessage(ServiceExceptionEnum.SUCCESS.getMessage());
commonResult.setData(data);
return commonResult;
}
/**
* 失敗
*
* @param message
* @param <T>
* @return
*/
public static <T> CommonResult<T> error(String message) {
CommonResult<T> commonResult = new CommonResult<>();
commonResult.setCode(ServiceExceptionEnum.ERROR.getCode());
commonResult.setMessage(message);
return commonResult;
}
/**
* 失敗
*
* @param message
* @param <T>
* @return
*/
public static <T> CommonResult<T> error(int code, String message) {
CommonResult<T> commonResult = new CommonResult<>();
commonResult.setCode(code);
commonResult.setMessage(message);
return commonResult;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
@Override
public String toString() {
return "CommonResult{" +
"code=" + code +
", message='" + message + '\'' +
", data=" + data +
'}';
}
}
全局異常處理類:
import com.example.quartzdemo.common.CommonResult;
import com.example.quartzdemo.enums.ServiceExceptionEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
/**
* @author qinxun
* @date 2023-06-14
* @Descripion: 全局異常處理
*/
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* 處理 MissingServletRequestParameterException 異常
* <p>
* SpringMVC 參數(shù)不正確
*/
@ResponseBody
@ExceptionHandler(value = MissingServletRequestParameterException.class)
public CommonResult<String> missingServletRequestParameterExceptionHandler(HttpServletRequest req, MissingServletRequestParameterException ex) {
log.error("[missingServletRequestParameterExceptionHandler]", ex);
// 包裝 CommonResult 結(jié)果
return CommonResult.error(ServiceExceptionEnum.MISSING_REQUEST_PARAM_ERROR.getCode(),
ServiceExceptionEnum.MISSING_REQUEST_PARAM_ERROR.getMessage());
}
@ResponseBody
@ExceptionHandler(value = ConstraintViolationException.class)
public CommonResult<String> constraintViolationExceptionHandler(HttpServletRequest req, ConstraintViolationException ex) {
log.error("[constraintViolationExceptionHandler]", ex);
// 拼接錯誤
StringBuilder detailMessage = new StringBuilder();
for (ConstraintViolation<?> constraintViolation : ex.getConstraintViolations()) {
// 使用 ; 分隔多個錯誤
if (detailMessage.length() > 0) {
detailMessage.append(";");
}
// 拼接內(nèi)容到其中
detailMessage.append(constraintViolation.getMessage());
}
// 包裝 CommonResult 結(jié)果
return CommonResult.error(
ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getMessage() + ":" + detailMessage.toString());
}
/**
* 處理參數(shù)校驗異常
*
* @param req
* @param ex
* @return
*/
@ResponseBody
@ExceptionHandler(value = BindException.class)
public CommonResult<String> bindExceptionHandler(HttpServletRequest req, BindException ex) {
log.info("========進(jìn)入了 bindException======");
log.error("[bindExceptionHandler]", ex);
// 拼接錯誤
StringBuilder detailMessage = new StringBuilder();
for (ObjectError objectError : ex.getAllErrors()) {
// 使用 ; 分隔多個錯誤
if (detailMessage.length() > 0) {
detailMessage.append(";");
}
// 拼接內(nèi)容到其中
detailMessage.append(objectError.getDefaultMessage());
}
// 包裝 CommonResult 結(jié)果
return CommonResult.error(ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getCode(),
ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getMessage() + ":" + detailMessage.toString());
}
/**
* 處理參數(shù)校驗異常
*
* @param req
* @param ex
* @return
*/
@ResponseBody
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public CommonResult<String> MethodArgumentNotValidExceptionHandler(HttpServletRequest req, MethodArgumentNotValidException ex) {
log.info("-----------------進(jìn)入了 MethodArgumentNotValidException-----------------");
log.error("[MethodArgumentNotValidException]", ex);
// 拼接錯誤
StringBuilder detailMessage = new StringBuilder();
for (ObjectError objectError : ex.getBindingResult().getAllErrors()) {
// 使用 ; 分隔多個錯誤
if (detailMessage.length() > 0) {
detailMessage.append(";");
}
// 拼接內(nèi)容到其中
detailMessage.append(objectError.getDefaultMessage());
}
// 包裝 CommonResult 結(jié)果
return CommonResult.error(ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getCode(),
ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getMessage() + ":" + detailMessage.toString());
}
/**
* 處理其它 Exception 異常
*
* @param req
* @param e
* @return
*/
@ExceptionHandler(value = Exception.class)
public CommonResult<String> exceptionHandler(HttpServletRequest req, Exception e) {
// 記錄異常日志
log.error("[exceptionHandler]", e);
// 返回 ERROR CommonResult
return CommonResult.error(ServiceExceptionEnum.SYS_ERROR.getCode(),
ServiceExceptionEnum.SYS_ERROR.getMessage());
}
}
二、全局?jǐn)?shù)據(jù)綁定
全局?jǐn)?shù)據(jù)綁定可以用來做一些初始化數(shù)據(jù)的操作,我們可以將一些公共的數(shù)據(jù)定義到添加了@ControllerAdvice注解的類中,這樣我們就可以在每一個Controller中可以訪問這些數(shù)據(jù)。
1.定義全局?jǐn)?shù)據(jù)綁定類
import java.util.HashMap;
import java.util.Map;
/**
* @author qinxun
* @date 2023-06-15
* @Descripion: 全局?jǐn)?shù)據(jù)綁定
*/
@ControllerAdvice
public class GlobalDataBindHandler {
@ModelAttribute(name = "gd")
public Map<String, Object> globalData() {
Map<String, Object> map = new HashMap<>();
map.put("website", "https://www.xx.com/");
map.put("email", "xxxx@qq.com");
return map;
}
}
使用@ModelAttribute注解標(biāo)記該方法返回的是一個全局?jǐn)?shù)據(jù)。
2.我們在Controller類中使用這個全局?jǐn)?shù)據(jù)
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* @author qinxun
* @date 2023-06-15
* @Descripion: 全局?jǐn)?shù)據(jù)綁定測試
*/
@RestController
public class HelloController {
@GetMapping("/hello")
public String toHello(Model model) {
Map<String, Object> map = model.asMap();
// 輸出 {map={website=https://www.xx.com/, email=xxxx@qq.com}}
System.out.println(map);
return "hello";
}
}
三、全局?jǐn)?shù)據(jù)預(yù)處理
1.我們準(zhǔn)備兩個實體類
/**
* @author qinxun
* @date 2023-06-15
* @Descripion: Author實體
*/
public class Author {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Author{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
/**
* @author qinxun
* @date 2023-06-15
* @Descripion: Book實體
*/
public class Book {
private String name;
private Integer price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
我們定義一個訪問接口
import com.example.quartzdemo.bean.Author;
import com.example.quartzdemo.bean.Book;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author qinxun
* @date 2023-06-15
* @Descripion: 測試
*/
@RestController
public class TestController {
/**
* 測試
*
* @param book Book對象
* @param author Author對象
*/
@PostMapping("/book")
public void addBook(Book book, Author author) {
System.out.println(book);
System.out.println(author);
}
}
這個時候,我們的添加操作就會有問題,因為這兩個實體類中都有一個name的屬性,前端傳遞數(shù)據(jù)的時候,無法區(qū)分是哪個實體的name屬性,這種情況我們可以通過@ControllerAdvice的全局?jǐn)?shù)據(jù)預(yù)處理來解決這個問題。
我們在postman上進(jìn)行測試
?控制臺打印返回文章來源地址http://www.zghlxwxcb.cn/news/detail-485166.html
Book{name='書名,作者', price=20}
Author{name='書名,作者', age=20}
發(fā)現(xiàn)數(shù)據(jù)混亂了,這不是我們需要的結(jié)果。
如何解決?
1.給接口中的變量取別名
import com.example.quartzdemo.bean.Author;
import com.example.quartzdemo.bean.Book;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author qinxun
* @date 2023-06-02
* @Descripion: 測試
*/
@RestController
public class TestController {
/**
* 測試
*
* @param book Book對象
* @param author Author對象
*/
@PostMapping("/book")
public void addBook(@ModelAttribute("b") Book book, @ModelAttribute("a") Author author) {
System.out.println(book);
System.out.println(author);
}
}
2.全局?jǐn)?shù)據(jù)處理類
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import java.util.HashMap;
import java.util.Map;
/**
* @author qinxun
* @date 2023-06-15
* @Descripion: 全局?jǐn)?shù)據(jù)處理
*/
@ControllerAdvice
public class GlobalDataBindHandler {
// 全局?jǐn)?shù)據(jù)綁定
@ModelAttribute
public Map<String, Object> globalData() {
Map<String, Object> map = new HashMap<>();
map.put("website", "https://www.xx.com/");
map.put("email", "xxxx@qq.com");
return map;
}
// 對命名為b的全局?jǐn)?shù)據(jù)預(yù)處理
@InitBinder("b")
public void b(WebDataBinder binder) {
binder.setFieldDefaultPrefix("b.");
}
// 對命名為a的全局?jǐn)?shù)據(jù)預(yù)處理
@InitBinder("a")
public void a(WebDataBinder binder) {
binder.setFieldDefaultPrefix("a.");
}
}
@InitBinder("b")表示該方法用來處理和Book相關(guān)的參數(shù),給參數(shù)添加一個b前綴,要求參數(shù)必須有b前綴。
3.postman測試
文章來源:http://www.zghlxwxcb.cn/news/detail-485166.html
?控制臺打印返回
Book{name='書名', price=20}
Author{name='作者', age=20}
到了這里,關(guān)于SpringBoot中@ControllerAdvice的三種使用場景的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!