【学习】若依源码(前后端分离版)之 “ 异常处理”

大型纪录片:学习若依源码(前后端分离版)之 " 异常处理"

前言

通常一个web框架中,有大量需要处理的异常。比如业务异常,权限不足等等。前端通过弹出提示信息的方式告诉用户出了什么错误。

通常情况下我们用try...catch...对异常进行捕捉处理,但是在实际项目中对业务模块进行异常捕捉,会造成代码重复和繁杂, 我们希望代码中只有业务相关的操作,所有的异常我们单独设立一个类来处理它。

全局异常就是对框架所有异常进行统一管理。若依前后端分离版本的异常处理是通过使用Spring的@RestControllerAdvice注解来实现的。这个注解可以将一个类标记为全局异常处理器,用来捕获和处理所有的控制器层抛出的异常。

它中定义了一个 GlobalExceptionHandler 类,用来处理各种类型的异常,比如权限校验异常、请求方式不支持异常、业务异常、运行时异常、系统异常、自定义验证异常和演示模式异常。每种异常都有一个对应的@ExceptionHandler注解的方法,用来返回一个AjaxResult对象,包含了错误码和错误信息。这样,前端就可以根据返回的结果来显示相应的提示或者处理逻辑。

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

1、统一返回实体定义

cpp 复制代码
package com.ruoyi.common.core.domain;

import java.util.HashMap;

/**
 * 操作消息提醒
 * 
 * @author ruoyi
 */
public class AjaxResult extends HashMap<String, Object>
{
    private static final long serialVersionUID = 1L;

    /**
     * 返回错误消息
     * 
     * @param code 错误码
     * @param msg 内容
     * @return 错误消息
     */
    public static AjaxResult error(String msg)
    {
        AjaxResult json = new AjaxResult();
        json.put("msg", msg);
        json.put("code", 500);
        return json;
    }

    /**
     * 返回成功消息
     * 
     * @param msg 内容
     * @return 成功消息
     */
    public static AjaxResult success(String msg)
    {
        AjaxResult json = new AjaxResult();
        json.put("msg", msg);
        json.put("code", 0);
        return json;
    }
}

2、定义登录异常定义

cpp 复制代码
package com.ruoyi.common.exception;

/**
 * 登录异常
 * 
 * @author ruoyi
 */
public class LoginException extends RuntimeException
{
    private static final long serialVersionUID = 1L;

    protected final String message;

    public LoginException(String message)
    {
        this.message = message;
    }

    @Override
    public String getMessage()
    {
        return message;
    }
}

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

cpp 复制代码
package com.ruoyi.framework.web.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.LoginException;

/**
 * 全局异常处理器
 * 
 * @author ruoyi
 */
@RestControllerAdvice
public class GlobalExceptionHandler
{
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
	
	/**
     * 登录异常
     */
    @ExceptionHandler(LoginException.class)
    public AjaxResult loginException(LoginException e)
    {
        log.error(e.getMessage(), e);
        return AjaxResult.error(e.getMessage());
    }
}

@RestControllerAdvice 注解是一个组合注解,由@ControllerAdvice@ResponseBody组成,而@ControllerAdvice继承了@Component,因此@RestControllerAdvice本质上是个Component,适用于所有使用@RequestMapping方法。

@ExceptionHandler 注解是用来指定异常处理方法的,当控制器中抛出指定类型的异常时,Spring MVC会自动调用使用@ExceptionHandler标记的方法来处理异常。每种异常都有一个对应的@ExceptionHandler注解的方法,是通过在@ExceptionHandler注解中添加参数来实现的,参数是某个异常类的class,代表这个方法专门处理该类异常。

这样,当控制器中抛出不同类型的异常时,就会调用相应的@ExceptionHandler注解的方法来处理。如果有多个方法处理同一类型的异常,那么会抛出Ambiguous @ExceptionHandler异常。

如果有多个类使用@RestControllerAdvice注解,那么可以通过指定order属性来控制异常处理类的优先级,order值越小,优先级越高。

4、测试访问请求

cpp 复制代码
@Controller
public class SysIndexController 
{
    /**
     * 首页方法
     */
    @GetMapping("/index")
    public String index(ModelMap mmap)
    {
        /**
         * 模拟用户未登录,抛出业务逻辑异常
         */
        SysUser user = ShiroUtils.getSysUser();
        if (StringUtils.isNull(user))
		{
            throw new LoginException("用户未登录,无法访问请求。");
        }
		mmap.put("user", user);
        return "index";
    }
}

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

界面输出内容如下所示:

cpp 复制代码
{
    "msg": "用户未登录,无法访问请求。",
    "code": 500
}

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

cpp 复制代码
@ExceptionHandler(LoginException.class)
public Object loginException(HttpServletRequest request, LoginException e)
{
	log.error(e.getMessage(), e);

	if (ServletUtils.isAjaxRequest(request))
	{
		return AjaxResult.error(e.getMessage());
	}
	else
	{
		return new ModelAndView("/error/500");
	}
}

若依系统的全局异常处理器为GlobalExceptionHandler

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

结语

所以一定要养成看文档的好习惯啊。那么以上就是唐某的一些理解。这次的分享就到这里了。记得一键三连~( •̀ ω •́ )✧

相关推荐
莫非王土也非王臣1 天前
深度学习之对比学习
人工智能·深度学习·学习
Wzx1980121 天前
doker深学习
学习·docker
InterestOriented1 天前
破解银发学习痛点 兴趣岛 “普惠 + 品质” 模式打造积极老龄化范本
大数据·人工智能·学习
HyperAI超神经1 天前
IQuest-Coder-V1:基于代码流训练的编程逻辑增强模型;Human Face Emotions:基于多标注维度的人脸情绪识别数据集
人工智能·深度学习·学习·机器学习·ai编程
testpassportcn1 天前
UiPath-ADPV1 認證介紹|Automation Developer Professional v1
网络·学习·改行学it
生擒小朵拉1 天前
ROS1学习笔记(二)
笔记·学习
危险、1 天前
一套提升 Spring Boot 项目的高并发、高可用能力的 Cursor 专用提示词
java·spring boot·提示词
爬山算法1 天前
Hibernate(51)Hibernate的查询缓存如何使用?
spring·缓存·hibernate
sunnyday04261 天前
基于Netty构建WebSocket服务器实战指南
服务器·spring boot·websocket·网络协议
Gorgous—l1 天前
数据结构算法学习:LeetCode热题100-动态规划篇(下)(单词拆分、最长递增子序列、乘积最大子数组、分割等和子集、最长有效括号)
数据结构·学习·算法