springboot整合之统一结果返回

news2025/1/10 23:45:47

特别说明:本次项目整合基于idea进行的,如果使用Eclipse可能操作会略有不同,不过总的来说不影响。

springboot整合之如何选择版本及项目搭建

springboot整合之版本号统一管理 

springboot整合mybatis-plus+durid数据库连接池

springboot整合swagger

springboot整合mybatis代码快速生成

springboot整合之统一结果返回

springboot整合之统一异常处理

springboot整合之logback日志配置

springboot整合pagehelper分页

springboot整合本地缓存

springboot整合redis + redisson

springboot整合elasticsearch

springboot整合rabbitMq

springboot整合canal实现缓存一致性

springboot整合springSecurity(前后端不分离版本)

一、为什么要对结果进行统一的返回

可能有很多小伙伴不理解为什么我们要对结果进行统一的返回,我们之前那种直接返回结果不也挺好的吗?

类似于上面这种,我们是直接就给接口调用方返回了用户信息,这样也不能说有问题,但是不够优雅。比如说现在用户请求参数错了,我们该怎么返回? 

 这样以来,接口调用方还要根据内容去判断我们的返回结果,如果说不同的错误返回的信息又是不一样的,比如现在这个返回“当前用户不存在,参数错误”,另一个接口返回“权限不足,请申请权限后操作!”,那这样对接口调用方来说简直就是痛苦面具。

所以为了我们的接口调用返回结果更加优雅,我们可以采取统一返回结果。我们在结果里面加上状态码,消息以及返回的数据。这样接口调用方就能够根据我们的返回状态码来判定结果的状态,然后根据状态去判定显示结果还是显示错误提示。这样就会显得优雅一点。具体实现也很简单。下面我们就一步一步来实现一下。

二、准备需要的目录结构

我们首先在项目里新建下面的几个包,以备后用。简单说明一下:common就是打算以后把公共的类就放到这里面来,enums就是放我们用到的枚举类,response就是放我们的返回结果类,utils存放工具类。

三、创建统一返回结果类

按照我们上面说的,这个类有三个成员属性,分别是:status用来标记请求状态,msg用来返回消息,如果成功就返回“OK”,失败就返回错误消息提示。data用来返回数据。这里面我还增加了一个常量 SUCCESS,用来表示200,表示请求成功的状态。定义为了public类型,后面方便我们在别的类调用。本来也打算把401,403,404,500这些常见的状态也都定义进来的。但是考虑了一下,打算把常见的错误状态做成枚举,避免大家重复定义,用起来更加简单方便一点。

package com.example.springbootdemo.common.response;

import com.example.springbootdemo.common.enums.ErrorCodeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

/**
 * @description: Result 统一返回结果<br>
 * @date: 2022/12/27 0027 下午 1:09 <br>
 * @author: William <br>
 * @version: 1.0 <br>
 */
@Data
@ApiModel(value="统一返回结果对象", description="")
public class Result {

    /**
     *操作成功
     */
    public static final int SUCCESS = 200;

    /**
     * 响应业务状态
     */
    @ApiModelProperty(value = "响应业务状态")
    private Integer status;

    /**
     * 响应消息
     */
    @ApiModelProperty(value = "响应消息")
    private String msg;

    /**
     * 响应中的数据
     */
    @ApiModelProperty(value = "响应中的数据")
    private Object data;



    /**
     * description: Result  默认无参构造<br>
     * @version: 1.0
     * @date: 2022/12/27 0027 下午 1:21
     * @author: William
     */
    public Result() {

    }

    /**
     * description: Result  只包含返回数据构造方法<br>
     * @version: 1.0
     * @date: 2022/12/27 0027 下午 1:22
     * @author: William
     * @param data   需要返回数据
     */
    public Result(Object data) {
        this.status = SUCCESS;
        this.msg = "OK";
        this.data = data;
    }

    /**
     * description: Result 包含所有参数的构造方法<br>
     * @version: 1.0
     * @date: 2022/12/27 0027 下午 1:23
     * @author: William
     * @param status    状态
     * @param msg       消息
     * @param data      数据
     */
    public Result(Integer status, String msg, Object data) {
        this.status = status;
        this.msg = msg;
        this.data = data;
    }

    public static Result ok() {
        return new Result(null);
    }

    public static Result ok(Object data) {
        return new Result(data);
    }

    /**
     * description: error 异常时返回方法<br>
     * @version: 1.0
     * @date: 2022/12/27 0027 下午 1:25
     * @author: William
     * @param errorCodeEnum   异常枚举对象
     * @return com.example.springbootdemo.common.response.Result
     */
    public static Result error(ErrorCodeEnum errorCodeEnum) {
        return new Result(errorCodeEnum.getValue(), errorCodeEnum.getMessage(), "");
    }

    public static Result build(Integer status, String msg) {
        return new Result(status, msg, null);
    }

    public static Result build(Integer status, String msg, Object data) {
        return new Result(status, msg, data);
    }

}

四、创建统一异常枚举类

package com.example.springbootdemo.common.enums;


import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

/**
 * description:  错误信息枚举类规定:编写时按照模块分类,每个模块写到一起,便于修改和维护返回状态根据Http状态码定义来 <br>
 * @version: 1.0
 * @date: 2022/12/27 0027 下午 1:18
 * @author: William
 */
@NoArgsConstructor
@Getter
@AllArgsConstructor
public enum ErrorCodeEnum {

    //公共模块
    UNAUTHORIZED(401,"未认证"),
    FORBIDDEN(401,"未授权"),
    ILLEGAL_VALUE(404,"参数非法"),
    OPERATION_FAILED(404,"操作失败");

    int value;
    String message;
}

五、修改测试接口

到上面第四步完成我们的统一结果返回就算封装好了,接下来我们就能够使用我们自己定义的统一返回结果类了。我们来修改一下userController,把之前的返回字符串改为返回同意结果返回。

这里有个点跟大家讲一下,因为我这就是demo,并不是真正的业务,我就把查询用户放到了controller里面了,如果是正式项目,大家把查询还是要放到业务层service里面去做。

package com.example.springbootdemo.controller;


import cn.hutool.core.bean.BeanUtil;
import com.example.springbootdemo.common.enums.ErrorCodeEnum;
import com.example.springbootdemo.common.response.Result;
import com.example.springbootdemo.entity.User;
import com.example.springbootdemo.service.UserService;
import com.example.springbootdemo.vo.UserVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author William
 * @since 2022-12-27
 */
@Api(tags = "用户相关接口")
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;



    /**
     * description: userInfo 过根据用户ID获取用户信息<br>
     * @version: 1.0
     * @date: 2022/12/27 0027 下午 2:30
     * @author: William
     * @param id   用户ID
     * @return com.example.springbootdemo.common.response.Result
     */
    @ApiOperation(value = "根据用户ID获取用户信息")
    @GetMapping("/{id}")
    public Result userInfo(@PathVariable("id") Integer id){
        if(id == null || id <= 0){
            return Result.error(ErrorCodeEnum.ILLEGAL_VALUE);
        }
        User user = userService.getById(id);
        if(user == null){
            return Result.error(ErrorCodeEnum.ILLEGAL_VALUE);
        }
        return Result.ok(user);
    }

}

六、启动测试

操作完成后我们就可以启动测试了。

 启动成功,接下来我们打开swagger来测试一把。首先我们输入一个不存在的用户试一下(我这里把前两条数据给删除了,所以输入1和2是不存在的,你们看一下自己的数据库进行测试就好)

 可以看到当前的结果是

{
  "status": 404,
  "msg": "参数非法",
  "data": ""
}

这样看起来是不是就舒服多了。然后我们再来看一下正常的

 怎么样是不是体验感一下就上来了。

七、遗留问题解决

。。。突然返现一个严重的问题,就是大家有没有发现我们竟然把用户密码给返回出来了!!!这岂不是要出大问题。我们在返回用户数据的时候一定要格外的小心,因为一不小心就会发生用户信息泄露的事故。这里我们来改造一下吧。我们现在先假设前端只需要返回id和userName.

因为等下我们需要将用户信息copy到userVo中,所以我们需要用到一个工具类,这里我给大家推荐一个我觉得非常好用的工具类,那就是hutool工具包,相信不少小伙伴都用过。两个字好用!!但是有一个问题就是这个里面工具类非常的多,如果有代码洁癖那么不太建议引入。可以自己按照要求来写就好。像我们经常用到的框架或者中间件,感兴趣的小伙伴可以研究一下源码,你会发现他们基本上都是自己封装工具类,不会引入其他jar包。这样主要是为了框架更加轻量级,不需要引入其他jar包即可使用,还有就是用到什么就封装什么,不会导致项目里面存在没有用的代码。减少代码打包的体积,以及运行的速度。言归正传,我们还是先把我们的问题给解决了。

1.引入hutool工具包

        <hutool.version>5.8.7</hutool.version>   
        <!--hutool工具-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>

2.新建UserVo类

package com.example.springbootdemo.vo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;

/**
 * @description: UserVo <br>
 * @date: 2022/12/27 0027 下午 2:39 <br>
 * @author: William <br>
 * @version: 1.0 <br>
 */
@Data
@ApiModel(value = "用户信息对象")
public class UserVo implements Serializable {

    /**
     * 用户ID
     */
    @ApiModelProperty(value = "用户ID")
    private Long id;

    /**
     * 用户名
     */
    @ApiModelProperty(value = "用户名")
    private String userName;
}

3.修改测试类

package com.example.springbootdemo.controller;


import cn.hutool.core.bean.BeanUtil;
import com.example.springbootdemo.common.enums.ErrorCodeEnum;
import com.example.springbootdemo.common.response.Result;
import com.example.springbootdemo.entity.User;
import com.example.springbootdemo.service.UserService;
import com.example.springbootdemo.vo.UserVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author William
 * @since 2022-12-27
 */
@Api(tags = "用户相关接口")
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;



    /**
     * description: userInfo 过根据用户ID获取用户信息<br>
     * @version: 1.0
     * @date: 2022/12/27 0027 下午 2:30
     * @author: William
     * @param id   用户ID
     * @return com.example.springbootdemo.common.response.Result
     */
    @ApiOperation(value = "根据用户ID获取用户信息")
    @GetMapping("/{id}")
    public Result userInfo(@PathVariable("id") Integer id){
        if(id == null || id <= 0){
            return Result.error(ErrorCodeEnum.ILLEGAL_VALUE);
        }
        User user = userService.getById(id);
        if(user == null){
            return Result.error(ErrorCodeEnum.ILLEGAL_VALUE);
        }
        UserVo userVo = new UserVo();
        BeanUtil.copyProperties(user, userVo);
        return Result.ok(userVo);
    }

}

OK,我们再来重新启动测试一把。

 可以看到,现在就只返回了需要的信息。

好了,到这里我们的统一返回结果就OK了。如果对你有所帮助,希望你能够给个点赞和关注呦,多谢啦~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/118406.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

树与二叉树(遍历)

一、树 树结构是一种非常重要的非线性数据结构&#xff0c;该结构中的一个数据元素可以有两个或者两个以上的直接后继元素。 1、树的定义 树是由 n(n>0)个有限结点组成一个具有层次关系的集合&#xff0c;当 n0时称为空树&#xff0c;当 n>0时称为非空树。 对于非空树来…

水上交通AIS常见问题解决方案

水上交通AIS常见问题解决方案 AIS无信号的几种情况 情况一&#xff1a;AIS未开启。 解决方法&#xff1a;开启AIS设备。 情况二&#xff1a;AIS开启但MMSI码和证书不一致。 解决方法&#xff1a;船长向直属海事部门申请MMSI码&#xff0c;并请专业人员将正确的MMSI码写入AIS设…

数据结构之堆的实现以及实现堆排序和建堆解决Top K问题

文章目录前言1.堆的相关介绍1.什么是堆2.堆的结构2.堆的相关接口具体实现1.堆的声明和堆的初始化2.堆插入数据和删除数据3.堆的其他函数接口3.堆的实际运用1.建堆算法2.堆的应用之堆排序3.堆解决Top k问题4.总结前言 之前对树的相关知识概念进行了简单介绍&#xff0c;本文将实…

odps-jdbc提交MaxCompute数据源SQL报错HTTP/1.0 is not allowed

概述 最近负责的一款数据产品。有个功能&#xff1a;选择某个数据源&#xff0c;比如阿里云的MaxCompute数据源&#xff0c;然后手写SQL&#xff0c;点击自动生成字段&#xff08;即获取前置SQL里的查询字段。前置SQL可以有drop then create table动作子句&#xff0c;但是最后…

【PS-选区速成】快速选择工具、魔棒工具、对象选择工具

目录 快速选择工具 1、位置 2、3种模式&#xff1a;新选区、添加到选区、从选区减去 3、画笔的设置参数 画笔大小&#xff1a;识别的范围 硬度&#xff1a;边缘的识别能力 间距&#xff1a;识别的连贯程度 跟【选区工具】配套使用的快捷键 1、按【ALT】减区 2、放大…

数据结构之排序【快速排序和归并排序的非递归代码实现及分析】

引言&#xff1a; 今天因为要写论文&#xff0c;所以现在有点迟了&#xff0c;并且此时是北京时间&#xff1a;2022/12/28/1:41 ,我发现晚睡我真的是专业的&#xff0c;当然睡觉我也是专业的&#xff0c;懂的都懂&#xff0c;现在有点迟加上天大寒&#xff0c;手指不可屈伸&am…

android之View的滑动

其实不管是哪种滑动方式&#xff0c;基本思想都是类似的&#xff1a;当点击事件传递到View时&#xff0c;系统记下触摸点的坐标&#xff0c;手指移动的时候&#xff0c;系统记下移动后的坐标&#xff0c;并计算出偏移量&#xff0c;并通过偏移量来修改View的坐标。 下面我们来…

黑客比程序员高在哪里?

黑客其实和一般的程序员一样&#xff0c;但是他们的关注点不一样。黑客关注的是如何破坏&#xff0c;通过这些有创造性的破坏来获取利益&#xff0c;展现自己的能力。而程序员关注的是如何创造&#xff0c;通过创造来获取利益&#xff0c;展现自己的能力。 就如同一个硬币的两…

CCF BDCI|算能赛题决赛选手说明论文-01

基于TPU平台实现人群密度估计 加速器队伍 黄显钧 个人名义参赛 中国-广东广州peterhuang0323qq.com 团队简介 加速器队伍队长&#xff1a;黄显钧&#xff0c;现任某科技公司的高级工程师&#xff0c;技术栈涉足嵌入式全栈开发&#xff0c;AI 开发等领域&#xff0c;对技术充满…

云桌面 Vscode 远程debug python

云桌面 Vscode 远程debug python1、进入云桌面2、下载VScode配套软件3、挂载本地磁盘4、安装软件4.1 安装VScode4.2 安装插件vsix文件4.3 在服务端安装vscode server5、VScode 配置6、远程调试6.1 python解释器选择6.2 设置debug7. mtu 配置Author: 沧海一阳1、进入云桌面 根据…

傻白入门芯片设计,盘点计算机体系结构顶会

目录 一、集成电路/半导体领域的三大顶会&#xff1a; &#xff08;1&#xff09;ISSCC &#xff08;2&#xff09;IEDM &#xff08;3&#xff09;VLSI 二、计算机体系结构四大顶会 &#xff08;1&#xff09;ISCA &#xff08;2&#xff09;HPCA &#xff08;3&#x…

42. 网络中的网络(NiN)

LeNet、AlexNet和VGG都有一个共同的设计模式&#xff1a;通过一系列的卷积层与汇聚层来提取空间结构特征&#xff1b;然后通过全连接层对特征的表征进行处理。 AlexNet和VGG对LeNet的改进主要在于如何扩大和加深这两个模块。 或者&#xff0c;可以想象在这个过程的早期使用全连…

利用GithubPage和Hexo搭建个人博客

title: 利用Github搭建个人博客 date: 2022-11-28 20:55:30 tags: [blogs] categories: Hexo 建立Git远程仓库 固定格式为&#xff1a;name.github.io ![]](https://img-blog.csdnimg.cn/fa9d7320d1cc422a8a79f2b41dd8458e.png) 开启Github Pages 设置github的token登陆 连接…

免费在线绘制高颜值,带填充的连贯堆叠柱状图

堆叠柱状图是我们日常工作中经常使用的一类图形。然而当分类较多时&#xff0c;堆叠柱状图看起来不是那么清晰&#xff0c;通过添加额外的连线&#xff0c;可以增加堆叠柱状图的颜值&#xff0c;给人一种连贯的感觉&#xff0c;并且能够更好地观察数据比例的变化。 图1. 堆叠柱…

1.8 异常 模块和包

文章目录了解异常异常的捕获方法为什么需要捕获异常捕获常规的异常捕获指定的异常捕获多个异常捕获所有的异常异常else异常的finally异常的传递Python模块模块的导入自定义模块测试模块\_all\_模块Python包了解异常 当我们的解释器运行时发生了一些没办法的操作&#xff0c;或…

初学Java web(十)

Filter和Listener 一.Filter 概念&#xff1a;Filter表示过滤器&#xff0c;是JavaWeb三大组件(Servlet、Filter、Listener)之一。 过滤器可以把对资源的请求拦截下来&#xff0c;从而实现一些特殊的功能。 过滤器一般完成一些通用的操作&#xff0c;比如&#xff1a;权限控…

新键盘到了,我的工作效率提升了数十倍

前言&#xff1a;快过年了&#xff0c;找到了一份满意的实习&#xff0c;正好旧的键盘坏掉了&#xff0c;最近入手了一款不错的机械键盘奖励自己。到货使用一段时间了&#xff0c;来一篇键盘开箱的博客做一个反馈。 新键盘使用感言&#xff1a;优良的键盘如图云上漫步&#xf…

白质中的BOLD信号激活检测问题

白质中BOLD信号的生理意义存在争议的两个主要原因&#xff1a; BOLD信号依赖于脑血流量CBF和脑血容量CBV&#xff0c;但是白质中的血流量和血容量比灰质中的少得多&#xff08;利用MRI估计的微血管数量&#xff1a;白质为10-192条/mm^2&#xff0c;灰质为99-761条/mm^2&#x…

【GUI界面】基于Python的WSG84三点定位系统(经纬度坐标与平面坐标转换法求解)

【GUI界面】基于Python的WSG84三点定位系统&#xff08;经纬度坐标与平面坐标转换法求解&#xff09; 方法汇总&#xff1a; blog.csdn.net/weixin_53403301/article/details/128441789 【精准三点定位求解汇总】利用Python或JavaScript高德地图开放平台实现精准三点定位&…

[开源工具]使用Fiddler简单计算QPS[新手开箱可用]

使用Fiddler简单计算QPS1.什么是QPS?2.怎么计算QPS?3.如何使用Fiddler得到一个API接口的QPS?3.1配置&#xff1a;打开Fiddler文件夹&#xff0c;点击Fiddler.exe运行fiddler进行配置4.如何得到本机的核心数?5.根据公式计算QPS?6.扩展计算单机可支撑PV(理论值)?1.什么是QP…