百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程文章 > 正文

《若依ruoyi》第十八章:Ruoyi Sping统一响应格式及统一异常处理

qiyuwang 2024-11-17 15:12 11 浏览 0 评论

在我们开发Ruoyi后端服务时,一般需要给前端统一响应格式,方便前端调试及配置错误提示等等。这篇文章讲讲实际工作中统一响应格式及统一异常处理是如何做的。

一、统一响应基础类

在项目中对应工具类或Vo层来创建我们的统一响应类

ruoyi统一响应类命名是AjaxResult,存放路径是ruoyi-common模块里面,具体路径如下图

AjaxResult

package com.ruoyi.common.core.domain;

import java.util.HashMap;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.utils.StringUtils;

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

    /** 状态码 */
    public static final String CODE_TAG = "code";

    /** 返回内容 */
    public static final String MSG_TAG = "msg";

    /** 数据对象 */
    public static final String DATA_TAG = "data";

    /**
     * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
     */
    public AjaxResult()
    {
    }

    /**
     * 初始化一个新创建的 AjaxResult 对象
     * 
     * @param code 状态码
     * @param msg 返回内容
     */
    public AjaxResult(int code, String msg)
    {
        super.put(CODE_TAG, code);
        super.put(MSG_TAG, msg);
    }

    /**
     * 初始化一个新创建的 AjaxResult 对象
     * 
     * @param code 状态码
     * @param msg 返回内容
     * @param data 数据对象
     */
    public AjaxResult(int code, String msg, Object data)
    {
        super.put(CODE_TAG, code);
        super.put(MSG_TAG, msg);
        if (StringUtils.isNotNull(data))
        {
            super.put(DATA_TAG, data);
        }
    }

    /**
     * 返回成功消息
     * 
     * @return 成功消息
     */
    public static AjaxResult success()
    {
        return AjaxResult.success("操作成功");
    }

    /**
     * 返回成功数据
     * 
     * @return 成功消息
     */
    public static AjaxResult success(Object data)
    {
        return AjaxResult.success("操作成功", data);
    }

    /**
     * 返回成功消息
     * 
     * @param msg 返回内容
     * @return 成功消息
     */
    public static AjaxResult success(String msg)
    {
        return AjaxResult.success(msg, null);
    }

    /**
     * 返回成功消息
     * 
     * @param msg 返回内容
     * @param data 数据对象
     * @return 成功消息
     */
    public static AjaxResult success(String msg, Object data)
    {
        return new AjaxResult(HttpStatus.SUCCESS, msg, data);
    }

    /**
     * 返回警告消息
     *
     * @param msg 返回内容
     * @return 警告消息
     */
    public static AjaxResult warn(String msg)
    {
        return AjaxResult.warn(msg, null);
    }

    /**
     * 返回警告消息
     *
     * @param msg 返回内容
     * @param data 数据对象
     * @return 警告消息
     */
    public static AjaxResult warn(String msg, Object data)
    {
        return new AjaxResult(HttpStatus.WARN, msg, data);
    }

    /**
     * 返回错误消息
     * 
     * @return 错误消息
     */
    public static AjaxResult error()
    {
        return AjaxResult.error("操作失败");
    }

    /**
     * 返回错误消息
     * 
     * @param msg 返回内容
     * @return 错误消息
     */
    public static AjaxResult error(String msg)
    {
        return AjaxResult.error(msg, null);
    }

    /**
     * 返回错误消息
     * 
     * @param msg 返回内容
     * @param data 数据对象
     * @return 错误消息
     */
    public static AjaxResult error(String msg, Object data)
    {
        return new AjaxResult(HttpStatus.ERROR, msg, data);
    }

    /**
     * 返回错误消息
     * 
     * @param code 状态码
     * @param msg 返回内容
     * @return 错误消息
     */
    public static AjaxResult error(int code, String msg)
    {
        return new AjaxResult(code, msg, null);
    }

    /**
     * 方便链式调用
     *
     * @param key 键
     * @param value 值
     * @return 数据对象
     */
    @Override
    public AjaxResult put(String key, Object value)
    {
        super.put(key, value);
        return this;
    }
}

统一封装返回json数据格式

格式如下:
{
  code:200,
  msg:"",
  data:[],
}

其中code定义了一些系统级的异常编码

HttpStatus类,路径是com.ruoyi.common.constant

package com.ruoyi.common.constant;

/**
 * 返回状态码
 * 
 * @author ruoyi
 */
public class HttpStatus
{
    /**
     * 操作成功
     */
    public static final int SUCCESS = 200;
    /**
     * 对象创建成功
     */
    public static final int CREATED = 201;
    /**
     * 请求已经被接受
     */
    public static final int ACCEPTED = 202;
    /**
     * 操作已经执行成功,但是没有返回数据
     */
    public static final int NO_CONTENT = 204;
    /**
     * 资源已被移除
     */
    public static final int MOVED_PERM = 301;
    /**
     * 重定向
     */
    public static final int SEE_OTHER = 303;
    /**
     * 资源没有被修改
     */
    public static final int NOT_MODIFIED = 304;

    /**
     * 参数列表错误(缺少,格式不匹配)
     */
    public static final int BAD_REQUEST = 400;

    /**
     * 未授权
     */
    public static final int UNAUTHORIZED = 401;
    /**
     * 访问受限,授权过期
     */
    public static final int FORBIDDEN = 403;
    /**
     * 资源,服务未找到
     */
    public static final int NOT_FOUND = 404;
    /**
     * 不允许的http方法
     */
    public static final int BAD_METHOD = 405;
    /**
     * 资源冲突,或者资源被锁
     */
    public static final int CONFLICT = 409;

    /**
     * 不支持的数据,媒体类型
     */
    public static final int UNSUPPORTED_TYPE = 415;
    /**
     * 系统内部错误
     */
    public static final int ERROR = 500;
    /**
     * 接口未实现
     */
    public static final int NOT_IMPLEMENTED = 501;
    /**
     * 系统警告消息
     */
    public static final int WARN = 601;
}

三、统一响应格式使用

在对应的controller或者service里面使用统一响应类

例如上一章节介绍的代码生成接口,所有的control控制类都继承了BaseController,BaseController类里面有一个success方法,这个方法返回AjaxResult对象

/**
 * 修改代码生成业务
 */
@PreAuthorize("@ss.hasPermi('tool:gen:query')")
@GetMapping(value = "/{tableId}")
public AjaxResult getInfo(@PathVariable Long tableId)
{
    GenTable table = genTableService.selectGenTableById(tableId);
    List<GenTable> tables = genTableService.selectGenTableAll();
    List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId);
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("info", table);
    map.put("rows", list);
    map.put("tables", tables);
    return success(map);
}

 /**
     * 返回成功消息
     */
    public AjaxResult success(Object data)
    {
        return AjaxResult.success(data);
    }

四、统一异常处理(ruoyi-vue没有封装,其他框架有封装,以后进行详细案例介绍)

1. 自定义异常

为什么我们需要自定义异常?因为在某些情况下,我们需要返回我们自定义的响应格式非常不方便,如在处理用户鉴权或token校验的时候,因为像这些部分我们一般都是在单独的工具类中去处理,这时候如果报错其实就可以抛出我们自定义的异常,交由我们全局的异常处理去统一返回响应。

  1. 在exception包下新建SystemException类
  2. SystemException继承RuntimeException

具体实现代码如下
exception.SystemException:


public class SystemException extends RuntimeException{
    private int code;
    private String msg;
    public int getCode() {
        return code;
    }
    public String getMsg() {
        return msg;
    }
    public SystemException(AppHttpCodeEnum appHttpCodeEnum) {
        super(appHttpCodeEnum.getMsg());
        this.code = appHttpCodeEnum.getCode();
        this.msg = appHttpCodeEnum.getMsg();
    }
}

目前只是自定义了异常,我们还需要对自定义的异常进行处理,返回统一的响应格式。

2.异常处理

  1. 在handler.exception包下新建GlobalExceptionHandler处理类
  2. @RestControllerAdvice是组合注解,由@ControllerAdvice、@ResponseBody组成,标明是一个统一异常处理的类,并把返回结果封装在ResponseBody中
  3. @Slf4j是Lombok实现日志输出的注解
  4. @ExceptionHandler标明该方法处理哪些异常

具体代码实现如下:

handler.exception.GlobalExceptionHandler:

import com.jk.exception.SystemException;
import com.jk.vo.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    @ExceptionHandler(SystemException.class)
    public ResponseResult systemExceptionHandler(SystemException e) {
        log.error("出现了异常! {}", e);
        return ResponseResult.errorResult(e.getCode(), e.getMsg());
    }
    @ExceptionHandler(Exception.class)
    public ResponseResult exceptionHandler(Exception e) {
        log.error("出现了异常! {}", e);
        return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(), e.getMessage());
    }
}

可以看到我们除了处理自定义异常SystemException外,还对Exception就是其他我们无法预料到的异常做了一个兜底。

3.自定义异常使用

在需要抛出异常的地方:

throw new SystemException(AppHttpCodeEnum.LOGIN_ERROR);

前端接收到的响应是:

{
    "code": 505,
    "msg": "用户名或密码错误"
}

这样就比接收到500错误也不知道错误原因好多了。

4、未来计划

1、ruoyi非分离版本拆解

2、ruoyi-vue-pro:讲解工作流

3、ruoyi-vue-pro:支付模块,电商模块

4、基于ruoyi-vue-pro项目开发

5、JEECG低代码开发平台

请关注我,本星球会持续推出更多的开源项目代码解析,如有更好的意见请留言回复或者私信。

相关推荐

在Word中分栏设置页码一页两个页码的技巧!

施老师:在正常情况下,Word文档中一页只会出现一个页码。但在某种情况下,比如说:用了分栏后,我们希望一页中出现两个页码,那应该如何实现呢?今天,就由宁双学好网施老师来为大家讲一下,利用域来实现一页两...

如何在关键时刻向上自荐(如何在关键时刻做出正确选择)

抓住机会,挺身而出有种时刻叫“关键时刻”,关键时刻,作为一个认为自己有能力的、训练有素的人,应该考虑挺身而出,甚至应该不考虑就挺身而出。...

WPS Word:跨页的文档表格,快速调整为一页。#Excel

如何快速将跨页的文档表格调整为一页?需要根据两种情况分别处理。如果表格所有行的行高相同,调整为一页的方法有两种。第一种方法是将光标移动到表格内,然后将鼠标移动到表格右下角的方框处,按住鼠标左键向上拖动...

word文档插入下一页分节符(word下一页分页符)

在word文档中,对文档页面进行分页是特别常见的操作,其中的下一页分节符也是用得比较多的,但是一些人不太清楚在哪里设置,也不知道它具体能实现的功能是什么。接下来看看如何在word文档中插入下一页分节符...

word文档如何设置某一页纸张的方向

word文档页面方向有横向和纵向,纵向是默认的纸张方向,有时我们需要将页面设置为横向,或只设置其中某一页方向,应该怎么操作呢?一起来看看下面的详细介绍第一步:...

word怎么单独设置一页为横向(word2019怎样设置单独一页为横向)

word里面其中一页可以改为横向的吗?经过实际操作发现是完全可以的。...

Word如何设置分栏,如何一页内容同时显示一栏和两栏

我们使用Word文档,有时需要用到两栏的排版,甚至一页内容同时包含一栏和两栏的排版,这种格式怎么设置呢?具体步骤如下:首先是两栏排版的设置,直接点击Word文件上方工具栏【布局】,选择【分栏】下面的【...

Word怎么分页?这三个方法可以帮到你

我们不仅可以利用Word编辑文档,还可以编辑文集呢。但是有时候会出现两个部分的文章长短不一,我们需要对文档进行分页处理。这样可以方便我们对文档进行其他操作。那么Word怎么分页呢?大家可以采用下面这...

Word内容稍超一页,如何优化至单页打印?

如何将两页纸的内容,缩到一页打印呢?有时候一页纸多一点内容,我们完全可以缩一下,放到一页来打印。...

[word] word 表格如何跨行显示表头、标题

word表格如何跨行显示表头、标题在Word中的表格如果过长的话,会跨行显示在另一页,如果想要在其它页面上也显示表头,更直观的查看数据。难道要一个个复制表头吗?当然不是,教你简单的方法操作设置Wo...

Word表格跨页如何续上表?(word如何让表格跨页不断掉)

长文档的表格跨页时,你会发现页末空白太多了,这时要怎么调整?选中整张表格,右击【表格属性】,点击【行】选项,之后勾选【允许跨页断行】,点击确定即可解决空白问题。...

Word怎么连续自动生成页码,操作步骤来了!

Word怎么连续自动生成页码,操作步骤来了!...

word文档怎么把两页合并成一页内容?教你4种方法

word怎么把两页合并成一页?word怎么把两页合并成一页?用四种方法演示一下。·方法一:把这一个文档合并成一页,按ctrl加a全选文档,然后右键点击段落,弹出的界面行距改成固定值,磅值可以改小一点,...

如何将Word中的一页的纸张方向设置为横向?这里提供详细步骤

默认情况下,MicrosoftWord将页面定向为纵向视图。虽然这在大多数情况下都很好,但你可能拥有在横向视图中看起来更好的页面或页面组。以下是实现这一目标的两种方法。无论使用哪种方法,请注意,如果...

Word横竖混排你会玩吗?(word横排竖排混合)

我们在用Word排版的时候,一般都是竖版格式,但偶尔会需要到一些特殊的版式要求,比如文档中插入的一个表格,横向的内容比较多,这时就需要用到横版,否则表格显示不全。这种横竖版混排的要求,在Word20...

取消回复欢迎 发表评论: