前言:
@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就不整合了,现在封装的就已经很复杂了。