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