Springboot基础系列:统一处理(返回/异常)

  • Post author:
  • Post category:其他




1 统一异常

  • 统一异常配置,使用@RestControllerAdvice增强@RestController,同时直接返回JSON数据,若使用@ControllerAdvice,需要在异常方法上添加@ResponseBody.
  • 异常返回方法上添加@ExceptionHandler,捕获指定的异常类.
  • 方法参数异常使用org.springframework.web.bind.MethodArgumentNotValidException.
package com.company.web.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.MethodArgumentNotValidException;
// import org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import com.company.web.vo.common.*;

import java.util.List;
import java.util.stream.Collectors;
import javax.validation.ConstraintViolationException;

/**
 * Uniform exception handle. 
 * @author xindaqi
 * @since 2020-10-21
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 参数绑定异常
     * @param e
     * @return
     */
    @ExceptionHandler(BindException.class) 
    public ResponseVO validationExceptionHandler(BindException e) {
        BindingResult bindingResult = e.getBindingResult();
        List<FieldError> fieldErrors = bindingResult.getFieldErrors();
        String errorMsg = "bindException";
        logger.info("Bind Validataion: {}", errorMsg);

        return ResponseVO.invalid(errorMsg);
        
    }

    /**
     * 方法参数校验异常
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class) 
    public ResponseVO methodValidationExceptionHandler(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        List<FieldError> fieldErrors = bindingResult.getFieldErrors();
        fieldErrors.forEach(fieldError -> {
            logger.info("Invalid message: {}", fieldError.getDefaultMessage());
        });
        
        fieldErrors.stream().map(FieldError::getDefaultMessage).collect(Collectors.toList());
        logger.info("field error: {}", fieldErrors);
        String errorMsg = fieldErrors.toString();
        logger.info("Method Validataion: {}", errorMsg);
        return ResponseVO.invalid(errorMsg); 
    }

    /**
     * 空指针异常
     * @param e
     * @return
     */
    @ExceptionHandler(NullPointerException.class) 
    public ResponseVO exceptionHandler(NullPointerException e) {
            String errorMsg = e.getMessage();
            logger.info("Null pointer Exception Validataion: {}", errorMsg);
            return ResponseVO.exception(4004); 
        
    }


    /**
     * 数据计算异常
     * @param e
     * @return
     */
    @ExceptionHandler(ArithmeticException.class) 
    public ResponseVO exceptionHandler(ArithmeticException e) {
            String errorMsg = e.getMessage();
            logger.info("Arithmetic Exception Validataion: {}", errorMsg);
            return ResponseVO.exception(4003); 
        
    }

    /**
     * 未知异常
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class) 
    public ResponseVO exceptionHandler(Exception e) {
            String errorMsg = e.getMessage();
            logger.info("Exception Validataion: {}", errorMsg);
            return ResponseVO.invalid(errorMsg); 
        
    }
 
}



2 统一返回

统一异常码和异常信息返回,可依据情况自定义添加.

package com.company.web.vo.common;

import com.company.web.enums.common.*;

/**
 * Uniform response. 
 * @author xindaqi 
 * @since 2020-10-20
 * @param <T>
 */

public class ResponseVO<T> {

    private Integer code;

    private String msg;

    private T data;

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

    public void setMsg(String msg) {
        this.msg = msg;
    }
    public String getMsg() {
        return msg;
    }

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

    public ResponseVO(){}

    public ResponseVO(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public ResponseVO(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public static ResponseVO ok() {
        return new ResponseVO(EnumsCode.SUCCESS.getCode(), EnumsCode.SUCCESS.getMsg());
    }

    public static ResponseVO ok(Object data) {
        return new ResponseVO(EnumsCode.SUCCESS.getCode(), EnumsCode.SUCCESS.getMsg(), data);
    }

    public static ResponseVO fail() {
        return new ResponseVO(EnumsCode.FAIL.getCode(), EnumsCode.FAIL.getMsg());
    }

    public static ResponseVO invalid() {
        return new ResponseVO(EnumsCode.INVALID.getCode(), EnumsCode.FAIL.getMsg());
    }

    public static ResponseVO invalid(String msg) {
        return new ResponseVO(EnumsCode.INVALID.getCode(), msg);
    }

    public static ResponseVO exception(Integer code) {
        switch (code) {
            case 4003:
                return new ResponseVO(EnumsCode.ARITHMETICEXCEPTION.getCode(), EnumsCode.ARITHMETICEXCEPTION.getMsg());
                
            case 4004:
                return new ResponseVO(EnumsCode.NULLPOINTEREXCEPTION.getCode(), EnumsCode.NULLPOINTEREXCEPTION.getMsg());
                
        }
        return new ResponseVO(EnumsCode.INVALID.getCode(), EnumsCode.INVALID.getMsg());
    }
    
}



3 接口测试



3.1 异常捕捉:空指针

package com.company.web.controller;

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.validation.BindException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.company.web.dto.*;
import com.company.web.service.*;
import com.company.web.vo.common.*;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.util.List;

/**
 * Transactional test.
 * @author xindaqi
 * @since 2020-10-20
 */
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController 
@RequestMapping("/api/function/test")
@Validated
public class TransactionalTestController {

    static Logger logger = LoggerFactory.getLogger(TransactionalTestController.class);

    @Autowired 
    private IDataSaveService dataSaveService;

    @RequestMapping(value = "/transactional/rollback/raw", method = RequestMethod.POST)
    public ResponseVO saveDataWithRollback(@RequestBody QuestionAnswerInputDTO params) {
       
        String result = null;
        if(result.equals("SUCCESS")) {
            return ResponseVO.ok();
        }
        // Integer a = 1 / 0;
        

        return ResponseVO.ok();
        

    }
   
}
  • 结果
{
    "code": 4005,
    "msg": "空指针异常",
    "data": null
}



3.2 异常捕捉:计算异常

package com.company.web.controller;

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.validation.BindException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.company.web.dto.*;
import com.company.web.service.*;
import com.company.web.vo.common.*;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.util.List;

/**
 * Transactional test.
 * @author xindaqi
 * @since 2020-10-20
 */
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController 
@RequestMapping("/api/function/test")
@Validated
public class TransactionalTestController {

    static Logger logger = LoggerFactory.getLogger(TransactionalTestController.class);

    @Autowired 
    private IDataSaveService dataSaveService;

    @RequestMapping(value = "/transactional/rollback/raw", method = RequestMethod.POST)
    public ResponseVO saveDataWithRollback(@RequestBody QuestionAnswerInputDTO params) {
      
        Integer a = 1 / 0;
        
        return ResponseVO.ok(); 

    }
   
}
  • 结果
{
    "code": 4004,
    "msg": "计算异常",
    "data": null
}



4 小结

  • 统一异常处理通过注解@RestControllerAdvice实现
  • 在方法上添加注解@ExceptionHandler(Exception.class),参数为特定的异常类
  • 所有的异常可以通过统一异常类进行捕获
  • 接口中省略了try…catch,使代码更简洁

[参考文献]

[1]

https://blog.csdn.net/Three_Two/article/details/87699211


[2]

https://blog.csdn.net/starexplode/article/details/81198703


[3]

https://blog.csdn.net/songguopeng/article/details/98961787


[4]

https://www.cnblogs.com/gaomanito/p/10863765.html


[5]

https://blog.csdn.net/RudeCrab/article/details/105834218


[6]

https://zhuanlan.zhihu.com/p/109227851



版权声明:本文为Xin_101原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。