我们经常写代码的时候会在controller中写大量的try{}catch(exception e){}来响应一些信息给用户以保证接口的完整性。这样在写接口的时候会存在大量重复的代码,即浪费时间,代码看起来又不美观,那么我们是不是可以定义一个异常信息,当出现这种情况的时候直接抛出异常,在异常中响应给用户一些信息。比如,我们写接口的时候,会接收参数,我们要判断参数是否为空,如果不为空的时候那就可以接下来的操作,如果为空的时候我们是不是可以抛出我们自定义的一个异常,在异常中给用户响应一些信息呢?接下来我们就一起看看代码如何实现。
一、使用@RestControllerAdvice和@ExceptionHandler统一处理异常。
/**
* 这是用来测试的接口
*/
@RequestMapping("/handle/{id}")
public String demo(@PathVariable(name="id") String id)throws Exception{
if(StringUtils.isBlank(id)){
throw new MyException(false,"10001");
}
return "1";
}
/**
* 这是我们自定义的一个异常,实现RuntimeException
*/
public class MyException extends RuntimeException {
private boolean success;
private String errorCode;
public MyException(boolean success, String errorCode) {
this.success = success;
this.errorCode = errorCode;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
/**
* 这是封住的一个返回数据的格式
*/
public class ResultMessage {
// 消息标记
private boolean success;
// 消息主体
private Object data;
// 消息代码
private String errorCode;
//错误信息
private String msg;
public ResultMessage() {
super();
}
/**
* 正确数据返回
* @param
*/
public ResultMessage(Object data) {
super();
this.success = true;
this.data = data;
this.errorCode = "00000";
}
/**
* 错误数据
* @param
* @param
*/
public ResultMessage(boolean success, String errorCode) {
super();
this.success = false;
this.errorCode = errorCode
;
this.msg = ErrorCodeEnum.getName(errorCode);
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
/**
* @ClassName: MyControllerAdvice
* @Description: 异常捕获处理
* @Author: zhbin
* @CreateDate: 2019/5/14 14:55
* @Version: 1.0
*/
@RestControllerAdvice
@Slf4j
public class MyControllerAdvice {
@ExceptionHandler(MyException.class)
public String myExceptionHandle(MyException e, HttpServletRequest request){
System.out.println(e);
return JSON.toJSONString(new ResultMessage(e.isSuccess(),e.getErrorCode()));
}
}
这样是不是特别方便呢,当参数为空的时候我们直接抛出我们自定义的异常,在异常中响应用户请求,使的我们程序能够走下去。但是有时侯可能即会有我们自定义的异常,也会有系统出错时抛出的异常。接下来我们看一下,该如何处理呢?首先我们改造一下代码。
/**
* @ClassName: MyControllerAdvice
* @Description: 异常捕获处理
* @Author: zhbin
* @CreateDate: 2019/5/14 14:55
* @Version: 1.0
*/
@RestControllerAdvice
@Slf4j
public class MyControllerAdvice {
@ExceptionHandler(Exception.class)
public String exceptionHand(Exception e, HttpServletRequest request){
ResultMessage resultMessage = null;
System.out.println(request.getMethod()+"----"+request.getServletPath()+"==="+request.getQueryString());
System.out.println();
if(e instanceof MyException){
resultMessage = new ResultMessage(((MyException) e).isSuccess(),((MyException) e).getErrorCode());
}else{
resultMessage = new ResultMessage(false,"10002");
}
return JSON.toJSONString(resultMessage);
}
}
我们只需要判断一下异常是不是属于我们自定义的异常(instanceof),如果是响应自定义内容,如果不是响应其他内容就可以。当然我们也可以自定义多种异常来处理我们的义务。这里就不进行演示了。
二、aop进行统一异常处理
我们平时会使用aop来记录日志,那么是否记得aop有一种通知是异常通知,当程序发生异常的时候会进入到异常通知,我们是不是可以在这里面进行全局异常处理呢,接下来我们来看看能否通过aop实现异常处理?
经过测试发现,在异常通知中得不到异常信息,那么是不是aop就处理不了异常呢,其实不然,在环绕通知@Around中可以捕获到异常信息,下面我们看看代码。
/**
* @ClassName: MyControllerAspect
* @Description: aop统一处理异常
* @Author: zhbin
* @CreateDate: 2019/5/16 20:09
* @Version: 1.0
*/
@Aspect
@Component
@Slf4j
public class MyControllerAspect {
// 切点,定义横切的方法
@Pointcut("execution(public * com.zhb.exception_handle.controller..*.*(..))")
public void pcut(){}
@Around("pcut()")
public String exciption(ProceedingJoinPoint joinPoint){
ResultMessage resultMessage = null;
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
log.info("url={}",request.getRequestURL());
log.info("前置通知------------"+joinPoint);
Object proceed="";
try {
proceed = joinPoint.proceed();
log.info("后置通知-----------"+joinPoint);
}catch (Throwable e){
resultMessage = exceptionHandle(e);
log.info(e+"===异常通知");
// 异常的时候直接返回异常信息
return JSON.toJSONString(resultMessage);
}
// 正常的时候返回程序中的响应内容即可。
return JSON.toJSONString(proceed);
}
/**
* 判断异常类型
* @param e
* @return
*/
public ResultMessage exceptionHandle(Throwable e){
ResultMessage resultMessage = null;
if(e instanceof MyException){
resultMessage = new ResultMessage(((MyException) e).isSuccess(),((MyException) e).getErrorCode());
}else{
resultMessage = new ResultMessage(false,"10002");
}
return resultMessage;
}
}
是不是特别方便呢,在环绕通知中捕获到异常后,就可以进行全局异常处理了。和第一种方式一样,只需要判断异常类型后进行相应的操作就可以了。是不是没有想到aop还有这么强大的功能呢。