异常处理

通常一个web框架中,有大量需要处理的异常。比如业务异常,权限不足等等。前端通过弹出提示信息的方式告诉用户出了什么错误。通常情况下我们用try…..catch…. 对异常进行捕捉处理,但是在实际项目中对业务模块进行异常捕捉,会造成代码重复和繁杂,我们希望代码中只有业务相关的操作,所有的异常我们单独设立一个类来处理它。全局异常就是对框架所有异常进行统一管理。我们在可能发生异常的方法里throw抛给控制器。然后由全局异常处理器对异常进行统一处理。如此,我们的Controller中的方法就可以很简洁了。

所谓全局异常处理器就是使用@ControllerAdvice注解。示例如下:

1、统一返回实体定义

  1. package com.ruoyi.common.core.domain;
  2. import java.util.HashMap;
  3. /**
  4. * 操作消息提醒
  5. *
  6. * @author ruoyi
  7. */
  8. public class AjaxResult extends HashMap<String, Object>
  9. {
  10. private static final long serialVersionUID = 1L;
  11. /**
  12. * 返回错误消息
  13. *
  14. * @param code 错误码
  15. * @param msg 内容
  16. * @return 错误消息
  17. */
  18. public static AjaxResult error(String msg)
  19. {
  20. AjaxResult json = new AjaxResult();
  21. json.put("msg", msg);
  22. json.put("code", 500);
  23. return json;
  24. }
  25. /**
  26. * 返回成功消息
  27. *
  28. * @param msg 内容
  29. * @return 成功消息
  30. */
  31. public static AjaxResult success(String msg)
  32. {
  33. AjaxResult json = new AjaxResult();
  34. json.put("msg", msg);
  35. json.put("code", 0);
  36. return json;
  37. }
  38. }

2、定义登录异常定义

  1. package com.ruoyi.common.exception;
  2. /**
  3. * 登录异常
  4. *
  5. * @author ruoyi
  6. */
  7. public class LoginException extends RuntimeException
  8. {
  9. private static final long serialVersionUID = 1L;
  10. protected final String message;
  11. public LoginException(String message)
  12. {
  13. this.message = message;
  14. }
  15. @Override
  16. public String getMessage()
  17. {
  18. return message;
  19. }
  20. }

3、基于@ControllerAdvice注解的Controller层的全局异常统一处理

  1. package com.ruoyi.framework.web.exception;
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. import org.springframework.web.bind.annotation.ExceptionHandler;
  5. import org.springframework.web.bind.annotation.RestControllerAdvice;
  6. import com.ruoyi.common.core.domain.AjaxResult;
  7. import com.ruoyi.common.exception.LoginException;
  8. /**
  9. * 全局异常处理器
  10. *
  11. * @author ruoyi
  12. */
  13. @RestControllerAdvice
  14. public class GlobalExceptionHandler
  15. {
  16. private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
  17. /**
  18. * 登录异常
  19. */
  20. @ExceptionHandler(LoginException.class)
  21. public AjaxResult loginException(LoginException e)
  22. {
  23. log.error(e.getMessage(), e);
  24. return AjaxResult.error(e.getMessage());
  25. }
  26. }

4、测试访问请求

  1. @Controller
  2. public class SysIndexController
  3. {
  4. /**
  5. * 首页方法
  6. */
  7. @GetMapping("/index")
  8. public String index(ModelMap mmap)
  9. {
  10. /**
  11. * 模拟用户未登录,抛出业务逻辑异常
  12. */
  13. SysUser user = ShiroUtils.getSysUser();
  14. if (StringUtils.isNull(user))
  15. {
  16. throw new LoginException("用户未登录,无法访问请求。");
  17. }
  18. mmap.put("user", user);
  19. return "index";
  20. }
  21. }

根据上面代码含义,当我们未登录访问/index时就会发生LoginException业务逻辑异常,按照我们之前的全局异常配置以及统一返回实体实例化,访问后会出现AjaxResult格式JSON数据,下面我们运行项目访问查看效果。界面输出内容如下所示:

  1. {
  2. "msg": "用户未登录,无法访问请求。",
  3. "code": 500
  4. }

对于一些特殊情况,如接口需要返回json,页面请求返回html可以使用如下方法

  1. @ExceptionHandler(LoginException.class)
  2. public Object loginException(HttpServletRequest request, LoginException e)
  3. {
  4. log.error(e.getMessage(), e);
  5. if (ServletUtils.isAjaxRequest(request))
  6. {
  7. return AjaxResult.error(e.getMessage());
  8. }
  9. else
  10. {
  11. return new ModelAndView("/error/500");
  12. }
  13. }

若依系统的全局异常处理器GlobalExceptionHandler注意:如果全部异常处理返回json,那么可以使用@RestControllerAdvice代替@ControllerAdvice,这样在方法上就可以不需要添加@ResponseBody