Post List Widget

header ads

全局异常处理




前言

在Java web 项目中,我们经常需要自己去实现一些异常处理的代码。随着Spring框架的不断升级,也给我们带来了更多的选择。下面说一下可行性比较好的两个方式吧:

  • 采用 Spring AOP 方式实现

  • 采用 Spring3.2之后提供的 @ControllerAdvice 注解 和 @ExceptionHandler 实现

关于 Controller 层异常的处理

如果你是想处理关于Controller层的异常(<strong>不仅限于是controller层自身主动抛出/catch的异常,只要是最终由controller层抛出的异常都可以使用 @ControllerAdvice 方式</stron>),那么以上两种方式均可由你选择。

@ControllerAdvice + @ExceptionHandler 方式

见名知意,@ControllerAdvice 是对于 使用@Controller的建议,那么凡是使用了@RequestMapping的地方的异常均可该种方式处理。 下面我以一个demo来说明一下,如何使用吧。 controller

@RestController
public class UserController {
 @RequestMapping(value = "/update", method = RequestMethod.POST)
   public R update(@RequestBody User user){
       userService.update(user);
       return R.success(null);
  }
}

注意:在调用的service中,我手动模拟抛出了一个异常,如下所示:

@Service
public class UserServiceImpl implements UserService {
 @Override
   public void update(User user) {
       userMapper.update(user);
       throw new RuntimeException("运行时易出错");
  }
}

关于类似这种controller层的异常我们就可以构造一个全局controller异常的处理工具,如下:

// 使用 @ControllerAdvice 方式来实现对 @RequestMapping 的异常拦截 // 缺点很明显,是对于 controller 的建议,只能对controller起作用
@ControllerAdvice
public class ControllerException {

   private static final Logger log = LoggerFactory.getLogger(ControllerException.class);

   @ExceptionHandler(value = Exception.class)
   @ResponseBody
   public Map<String, String> getMsg(HttpServletRequest request, HttpServletResponse response, Exception e){

       log.error("该服务可能出错了");
       return Collections.singletonMap("msg", "服务出错");
  }
}

这样当调用 /update 接口时,service层会报错,从而传递到controller层,从而被 ControllerException 异常处理类拦截,就可以在这里解决了,可以down下代码,自行测试一下,这里不做演示了。


这种方式的缺点很明显:只能处理 controller 层抛出的异常,对例如 Interceptor(拦截器)层的异常、定时任务中的异常、异步方法中的异常,不会进行处理。

Spring AOP 动态代理方式

上面的controller层和service代码不用作任何修改。只需要再新增一个异常处理类即可。

package com.example.study_source.transaction.exception;

// 使用 aop 来全局拦截异常,可以作用于你自定义的任何包路径下 // 相比 @ControllerAdvice 有优势

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
public class AOPGlobalException {

   @Pointcut("execution(* com.example.study_source.transaction..*.*(..))")
   public void point1(){

  }

   @AfterReturning(pointcut = "point1()")
   public void afterReturn(JoinPoint joinPoint){
       log.error("全局捕获到异常了..............");
       //纪录错误信息
       // todo 想要执行的操作
  }
}

如上方式不仅可以实现controller层的异常处理,只要符合切点包的定义的方法,都可以拦截。

本文参考于segmentfault,特此表示感谢!

Post a Comment

0 Comments