Springboot(十一)@ControllerAdvice全局异常处理

前言:

       @ControllerAdvice,用于全局异常处理,减少代码入侵,必须在controller层抛出来,若异常在代码中被抓住了,没有抛出来,是不起作用的。


实现:

     写一个全局异常类GlobalDefaultException,类上加注解@RestControllerAdvice,在方法上加注解@ExceptionHandler(value = Exception.class) value表示要捕捉的异常,可以写多个,然后根据异常,就可以在这个方法里面进行处理。

代码:

    全局捕捉异常类:GlobalDefaultExceptionHandler.java

package com.xhx.springboot.config;

import com.xhx.springboot.exception.BusinessException;
import com.xhx.springboot.result.JsonResult;
import com.xhx.springboot.result.ReturnEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;

/**
 * xuhaixing
 * 2018/6/24 11:00
 * 返回string或者json需要@ResponseBody
 * 用RestControllerAdvice,就不用加@ResponseBody了
 **/
@RestControllerAdvice
public class GlobalDefaultExceptionHandler {

    private static Logger logger = LoggerFactory.getLogger(GlobalDefaultExceptionHandler.class);

    @ExceptionHandler(value = Exception.class)
    public JsonResult<ReturnEnum> exceptionHandler(HttpServletRequest request, Exception e) {
        Throwable throwable = getBusinessException(e);
        if (!Objects.isNull(throwable)) {
            ReturnEnum returnEnum = ((BusinessException) throwable).getReturnEnum();
            if(((BusinessException)throwable).getReturnEnum()!=null) {
                return JsonResult.error(returnEnum);
            }
        }
        return JsonResult.error();
    }

    /**
     * 若有异常进行嵌套,打印出每个异常的堆栈信息,若包含自定义异常,返回最内部的BusinessException异常。
     * @param e
     * @return
     */
    private Throwable getBusinessException(Throwable e) {
        if (e == null) {
            return null;
        } else if (e instanceof BusinessException) {
            if(((BusinessException)e).getReturnEnum()!=null) {
                logger.info(((BusinessException) e).getReturnEnum().toString());
            }
            e.printStackTrace();
            Throwable temp = getBusinessException(e.getCause());
            if (temp == null) {
                return e;
            } else {
                return temp;
            }
        } else {
            e.printStackTrace();
            return getBusinessException(e.getCause());
        }
    }

}


自己封装的枚举类:ReturnEnum.java

package com.xhx.springboot.result;

/**
 * xuhaixing
 * 2018/6/24 11:41
 **/
public enum ReturnEnum {
    success("200","",""),
    error("500","error","后台发生未知错误");

    //自定义异常码
    private String code;
    //国际化文件中的key
    private String type;
    //异常信息说明
    private String message;

    ReturnEnum(String code, String type, String message){
        this.code = code;
        this.type = type;
        this.message=message;
    }

    public String getCode() {
        return code;
    }

    public String getType() {
        return type;
    }

    public String getMessage() {
        return message;
    }

    @Override
    public String toString() {
        return "ReturnEnum{" +
                "code='" + code + '\'' +
                ", type='" + type + '\'' +
                ", message='" + message + '\'' +
                '}';
    }
}

自己封装的异常类,整合枚举类

package com.xhx.springboot.exception;

import com.xhx.springboot.result.ReturnEnum;

import javax.validation.constraints.NotNull;

/**
 * xuhaixing
 * 2018/6/24 11:38
 **/
public class BusinessException extends Exception {
    private ReturnEnum returnEnum;
    private Throwable cause;

    public BusinessException(ReturnEnum returnEnum) {
        super(returnEnum.getMessage());
        this.returnEnum = returnEnum;
    }

    public BusinessException(ReturnEnum returnEnum, Throwable cause) {
        super(returnEnum.getMessage(), cause);
        this.returnEnum = returnEnum;
        this.cause = cause;
    }
    public BusinessException(Throwable cause) {
        super(cause);
        this.cause = cause;
    }

    public ReturnEnum getReturnEnum() {
        return returnEnum;
    }
}

自己封装的统一返回前端的结果类 JsonResult.java:

package com.xhx.springboot.result;

import java.io.Serializable;

/**
 * xuhaixing
 * 2018/6/24 14:02
 **/
public class JsonResult<T> implements Serializable {
    private String code;
    private String message;
    private T data;

    public JsonResult(String code,String message,T data){
        this.code=code;
        this.message = message;
        this.data = data;
    }
    public JsonResult(ReturnEnum returnEnum, T data){
        this.code = returnEnum.getCode();
        this.message = returnEnum.getMessage();
        this.data = data;
    }
    public JsonResult(ReturnEnum returnEnum){
        this.code = returnEnum.getCode();
        this.message = returnEnum.getMessage();
    }

    public static JsonResult success(){
        return new JsonResult(ReturnEnum.success.getCode(),ReturnEnum.success.getMessage(),null);
    }
    public static <T> JsonResult success(T data){
        return new JsonResult(ReturnEnum.success.getCode(),ReturnEnum.success.getMessage(),data);
    }


    public static JsonResult error(){
        return new JsonResult(ReturnEnum.error.getCode(),ReturnEnum.error.getMessage(),null);
    }
    public static <T> JsonResult error(ReturnEnum returnEnum){
        return new JsonResult(returnEnum.getCode(),returnEnum.getMessage(),null);
    }

    public String getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

    public T getData() {
        return data;
    }
}


dao层:

package com.xhx.springboot.dao;

import com.xhx.springboot.entity.Account;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/**
 * @author xuhaixing
 * @date 2018/5/2 11:19
 */
@Repository
public interface AccountDao extends JpaRepository<Account, Integer> {

    Account findByName(String name);

}

service层:

package com.xhx.springboot.service;

import com.xhx.springboot.dao.AccountDao;
import com.xhx.springboot.entity.Account;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author xuhaixing
 * @date 2018/5/2 9:53
 */
@Service
public class AccountService {
    private static Logger logger = LoggerFactory.getLogger(AccountService.class);

    @Autowired
    private AccountDao accountDao;

    public Account findByName(String name) throws Exception{

        try {
            return accountDao.findByName(name);
        } catch (Exception e) {
            throw  new Exception("数据库异常",e);
        }
    }

}

controller层:

package com.xhx.springboot.controller;

import com.xhx.springboot.entity.Account;
import com.xhx.springboot.exception.BusinessException;
import com.xhx.springboot.result.JsonResult;
import com.xhx.springboot.result.ReturnEnum;
import com.xhx.springboot.service.AccountService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @author xuhaixing
 * @date 2018/5/2 9:55
 */
@RestController
@RequestMapping("account")
public class AccountController {
    private static  Logger logger = LoggerFactory.getLogger(AccountController.class);

    @Autowired
    private AccountService accountService;

    @RequestMapping(value = "findByName", method = RequestMethod.POST)
    public JsonResult<Account> findById(@RequestParam String name) throws Exception{

        logger.info("name="+name);
        if(name == null || name.equals("")){
            throw new BusinessException(ReturnEnum.error,new NullPointerException());
        }
        Account account = null;
        try {
            account = accountService.findByName(name);
        } catch (Exception e) {
            throw new BusinessException(e);
        }
        return JsonResult.success(account);
    }

}

实体类:

package com.xhx.springboot.entity;

import javax.persistence.Entity;
import javax.persistence.Id;

/**
 * @author xuhaixing
 * @date 2018/4/28 10:29
 */
@Entity
public class Account {
    @Id
    private int id;
    private String name;
    private Double money;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }
}

application.yml

spring:
  datasource:
    username: xuhaixing
    password: xuhaixing
    url: jdbc:mysql://192.168.94.151:3306/mytest?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
    driver-class-name: com.mysql.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true


启动类:

package com.xhx.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Springboot24Application {

    public static void main(String[] args) {
        SpringApplication.run(Springboot24Application.class, args);
    }
}


数据库中的值:


name是aaa的有两个,我有Account实体类接受的,一定会报错,bbb的有一个不会报错




先让jpa执行数据库赋值时报错,抛出Exception异常:





让入参name为空,抛出自定义BusinessException异常





报错时返回的内容code为自己定义的异常码,message为自己定义的异常信息。异常信息还可以整合国际化,这样就更好了。我主要是讲@ControllerAdvice就不整合了,现在封装的就已经很复杂了。



我的git代码地址


猜你喜欢

转载自blog.csdn.net/u012326462/article/details/80791455