当前位置:

首页 > 编程开发 > SpringBoot统一接口返回及全局异常如何处理

SpringBoot统一接口返回及全局异常如何处理

一、SpringBoot不使用统一返回格式默认情况下,SpringBoot会有如下三种返回情况。1.1使用字符串返回@GetMapping("/getUserName")publicStringgetUserName(){  return"HuaGe";}调用接口返回结果:HuaGe1.2使用实体类返回@GetMapping("/getUserName")publicUsergetUserName(){  returnnewUser("HuaGe",18,"男");

本文目录

    一、SpringBoot不使用统一返回格式

    默认情况下,SpringBoot会有如下三种返回情况。

    1.1 使用字符串返回

    @GetMapping("/getUserName")
    public String getUserName(){
        return "HuaGe";
    }

    调用接口返回结果:

    HuaGe

    1.2 使用实体类返回

    @GetMapping("/getUserName")
    public User getUserName(){
        return new User("HuaGe",18,"男");
    }

    调用接口返回结果:

    {
      "name": "HuaGe",
      "age": "18",
      "性别": "男", 
    }

    1.3 异常情况下返回

    @GetMapping("/getUserName")
    public static String getUserName(){
        HashMap hashMap = Maps.newHashMap();
        return hashMap.get(0).toString();
    }

    模拟一个空指针异常,在不做任何异常处理的情况下,可以看下SpringBoot的默认返回结果:

    {
        "timestamp": "2021-08-09T06:56:41.524+00:00",
        "status": 500,
        "error": "Internal Server Error",
        "path": "/sysUser/getUserName"
    }

    对于上面这几种情况,如果整个项目没有定义统一的返回格式,五个后台开发人员定义五种返回格式,这样不仅代码臃肿,前后端对接效率低,而且还会有一些意向不到的情况发生,比如前端直接显示异常详情等,这给用户的体验是非常差的。

    二、基础玩法

    项目中最常见到的是封装一个工具类,类中定义需要返回的字段信息,把需要返回前端的接口信息,通过该类进行封装,这样就可以解决返回格式不统一的现象了。

    2.1 参数说明

    • code: 状态码,后台可以维护一套统一的状态码;

    • message: 描述信息,接口调用成功/失败的提示信息;

    • data: 返回数据。

    2.2 流程说明

    • 新建Result类

    public class Result {
        
        private int code;
        
        private String message;
        
        private T data;
    
        public Result() {}
        public Result(int code, String message) {
            this.code = code;
            this.message = message;
        }
        
        /**
         * 成功
         */
        public static  Result success(T data) {
            Result result = new Result();
            result.setCode(ResultMsgEnum.SUCCESS.getCode());
            result.setMessage(ResultMsgEnum.SUCCESS.getMessage());
            result.setData(data);
            return result;
        }
    
        /**
         * 失败
         */
        public static  Result error(int code, String message) {
            return new Result(code, message);
        }
    }

    定义返回状态码

    public enum ResultMsgEnum {
        SUCCESS(0, "成功"),
        FAIL(-1, "失败"),
        AUTH_ERROR(502, "授权失败!"),
        SERVER_BUSY(503, "服务器正忙,请稍后再试!"),
        DATABASE_OPERATION_FAILED(504, "数据库操作失败");
        private int code;
        private String message;
    
        ResultMsgEnum(int code, String message) {
            this.code = code;
            this.message = message;
        }
        public int getCode() {
            return this.code;
        }
        
        public String getMessage() {
            return this.message;
        }
    }
    • 使用方式

    上面两步定义了数据返回格式和状态码,接下来就要看下在接口中如何使用了。

    @GetMapping("/getUserName")
    public Result getUserName(){
        return Result.success("huage");
    }

    调用结果如下,可以看到是我们在Result中定义的参数类型。

    {
        "code": 0,
        "message": "成功",
        "data": "huage"
    }

    这样写虽然能够满足日常需求,而且我相信很多小伙伴也是这么用的,但是如果我们有大量的接口,然后在每一个接口中都使用Result.success来包装返回信息,会新增很多重复代码,显得不够优雅,甚至都不好意思拿出去显摆。 肯定会有一种方式能够再一次提高代码逼格,实现最优解。

    三、进阶用法

    基本用法学会后,接下来看点究极版本,主要用到如下两个知识点,用法简单,无论是拿出来教学妹,还是指点小姐姐,都是必备技能。

    3.1 类介绍

    • ResponseBodyAdvice: 该接口是SpringMVC 4.1提供的,它允许在 执行 @ResponseBody后自定义返回数据,用来封装统一数据格式返回;

    • @RestControllerAdvice: 该注解是对Controller进行增强的,可以全局捕获抛出的异常。

    3.2 用法说明

    • 新建ResponseAdvice类;

    • 实现ResponseBodyAdvice接口,实现supports、beforeBodyWrite方法;

    • 该类用于统一封装controller中接口的返回结果。

    @RestControllerAdvice
    public class ResponseAdvice implements ResponseBodyAdvice {
        @Autowired
        private ObjectMapper objectMapper;
    
        /**
         * 是否开启功能 true:是 
         */
        @Override
        public boolean supports(MethodParameter methodParameter, Class> aClass) {
            return true;
        }
    
        /**
         * 处理返回结果
         */
        @Override
        public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
            //处理字符串类型数据
            if(o instanceof String){
                try {
                    return objectMapper.writeValueAsString(Result.success(o));
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
            }
            return Result.success(o);
        }
    }

    我们可以通过getUserName接口测试一下,会发现和直接使用Result返回的结果是一致的。

    不过,细心的小伙伴们肯定注意到了,在ResponseAdvice我们全部使用了Result.success(o)来处理结果,对于error类型的结果未做处理。我们来看下,发生异常情况时,返回结果是什么样呢?继续使用上面HashMap空指针异常的代码,测试结果如下:

    {
        "code": 0,
        "message": "成功",
        "data": {
            "timestamp": "2021-08-09T09:33:26.805+00:00",
            "status": 405,
            "error": "Method Not Allowed",
            "path": "/sysUser/getUserName"
        }
    }

    虽然格式上没有毛病,但是在code、data字段的具体数据上是不友好或不正确的。不处理好这些事情,会严重影响自己在前端妹妹心中的高大形象的,这是决不能容忍的。

    3.3 全局异常处理器

    以前我们遇到异常时,第一时间想到的应该是try..catch..finnal吧,不过这种方式会导致大量代码重复,维护困难,逻辑臃肿等问题,这不是我们想要的结果。

    今天我们要用的全局异常处理方式,用起来是比较简单的。首先新增一个类,增加@RestControllerAdvice注解,该注解的作用花哥上面已经介绍过,就不再唠叨了。

    @RestControllerAdvice
    public class CustomerExceptionHandler {
        
    }

    如果我们有想要拦截的异常类型,就新增一个方法,使用@ExceptionHandler注解修饰,注解参数为目标异常类型。

    例如:controller中接口发生Exception异常时,就会进入到Execption方法中进行捕获,将杂乱的异常信息,转换成指定格式后交给ResponseAdvice方法进行统一格式封装并返回给前端小伙伴。

    @RestControllerAdvice
    @Slf4j
    public class CustomerExceptionHandler {
    
        @ExceptionHandler(AuthException.class)
        public String ErrorHandler(AuthorizationException e) {
            log.error("没有通过权限验证!", e);
            return "没有通过权限验证!";
        }
    
        @ExceptionHandler(Exception.class)
        public Result Execption(Exception e) {
            log.error("未知异常!", e);
            return Result.error(ResultMsgEnum.SERVER_BUSY.getCode(),ResultMsgEnum.SERVER_BUSY.getMessage());
        }
    }

    再次调用接口getUserName查看返回结果,会发现还是有一些问题,因为我们在CustomerExceptionHandler中已经将接口返回结果封装成Result类型,而代码执行到统一结果返回类ResponseAdvice时,又会结果再次封装,就出现了如下问题。

    {
        "code": 0,
        "message": "成功",
        "data": {
            "code": 503,
            "message": "服务器正忙,请稍后再试!",
            "data": null
        }
    }

    3.4 统一返回结果处理类最终版

    解决上述问题非常简单,只要在beforeBodyWrite中增加一条判断即可。

    @RestControllerAdvice
    public class ResponseAdvice implements ResponseBodyAdvice {
        @Autowired
        private ObjectMapper objectMapper;
    
        /**
         * 是否开启功能 true:开启
         */
        @Override
        public boolean supports(MethodParameter methodParameter, Class> aClass) {
            return true;
        }
    
        /**
         * 处理返回结果
         */
        @Override
        public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
            //处理字符串类型数据
            if(o instanceof String){
                try {
                    return objectMapper.writeValueAsString(Result.success(o));
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
            }
            //返回类型是否已经封装
            if(o instanceof Result){
                return o;
            }
            return Result.success(o);
        }
    }                        
                                                    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
                                                    
    作者最新文章
    编程开发
    相关文章 更多
    springBoot项目常用目录有哪些
    springBoot项目常用目录有哪些

    springBoot项目常用目录springBoot项目的目录结构及名规范介绍基于SpringBoot开发时的目录结构及命名规范,通过介绍能够为你解决,在实际项目中如何规划目录结构?如何命名目录更规范?各个目录分别代表什么含义?等三个问题。目录说明servicex//项目名|-admin-ui//管理服务前端代码(一般将UI和SERVICE放到一个工程中,便于管理)|-servicex-auth//模块1|-servicex-common//模块2|-servicex-gateway//模块3|-serv

    解析SpringBoot和SpringMVC之间的异同
    解析SpringBoot和SpringMVC之间的异同

    解析SpringBoot和SpringMVC之间的异同SpringBoot和SpringMVC是Java领域中非常重要的开发框架。虽然它们都属于Spring框架的一部分,但是在使用和功能上有一些明显的区别。本文将对SpringBoot和SpringMVC进行比较,解析它们之间的异同。首先,让我们来了解一下SpringBoot。SpringBo

    探索SpringCloud和SpringBoot在微服务领域的不同应用方式
    探索SpringCloud和SpringBoot在微服务领域的不同应用方式

    近年来,随着云计算和分布式架构的兴起,微服务架构的应用越来越广泛。而SpringCloud和SpringBoot作为Java开发中的两个重要框架,对于微服务的实现起到了重要的作用。然而,很多人对于它们在微服务领域的不同应用方式还存在一定的疑惑。本文将从不同的角度探索SpringCloud和SpringBoot在微服务中的应用方式。首先,我们来了解一下Spri

    SpringBoot和SpringMVC有何区别?
    SpringBoot和SpringMVC有何区别?

    SpringBoot与SpringMVC的不同之处在哪里?SpringBoot和SpringMVC是两个非常流行的Java开发框架,用于构建Web应用程序。尽管它们经常分别被使用,但它们之间的不同之处也是很明显的。首先,SpringBoot可以被看作是一个Spring框架的扩展或者增强版。它旨在简化Spring应用程序的初始化和配置过程,以帮助开发人

    比较SpringBoot和SpringMVC的异同
    比较SpringBoot和SpringMVC的异同

    SpringBoot和SpringMVC都是Java开发中常用的框架,但它们之间有一些明显的差异。本文将探究这两个框架的特点和用途,并对它们的差异进行比较。首先,我们来了解一下SpringBoot。SpringBoot是由Pivotal团队开发的,它旨在简化基于Spring框架的应用程序的创建和部署。它提供了一种快速、轻量级的方式来构建独立的、可执行

    SpringBoot与SpringMVC的不同点是什么?
    SpringBoot与SpringMVC的不同点是什么?

    SpringBoot和SpringMVC是Java开发中常用的两个框架,它们都是由Spring框架所提供的,但在功能和使用方式上有着一些区别。本文将分别介绍SpringBoot和SpringMVC的特点和区别。一、SpringBoot的特点:简化配置:SpringBoot通过约定优于配置的原则,大大简化了项目的配置过程。它可以自动配置项目所需要的参数,开发人

    比较和选择指南:SpringCloud与SpringBoot的功能比较
    比较和选择指南:SpringCloud与SpringBoot的功能比较

    SpringCloud和SpringBoot是目前Java领域中最热门的开源框架,它们分别提供了一套完善的微服务架构和快速构建应用程序的解决方案。本文将对它们的功能进行比较,并给出选择指南,以帮助读者了解它们的优势和适用场景。SpringBoot是一个用于开发Java应用程序的框架,它提供了一个简化的开发流程,集成了大量常用的功能和组件,减少了开发者的工作量

    SpringCloud与SpringBoot:分析它们之间的相似与不同
    SpringCloud与SpringBoot:分析它们之间的相似与不同

    深入剖析SpringCloud和SpringBoot的异同引言:在构建企业级应用程序时,Spring框架已经成为开发者们的首选。它提供了一种简单而强大的方式来构建独立于平台的应用程序。Spring框架由两个核心模块组成:SpringBoot和SpringCloud。虽然它们都可以帮助开发者快速搭建应用程序,但它们的目标和用途存在一些差异。本文将深入剖析Spr

    从架构角度看SpringCloud与SpringBoot的差异
    从架构角度看SpringCloud与SpringBoot的差异

    从架构角度看SpringCloud与SpringBoot的差异引言:在当今的互联网时代,构建分布式系统已经成为了一种必要的需求。而SpringBoot和SpringCloud正是为了满足这个需求而诞生的。尽管它们都是由Spring框架所提供的解决方案,但从架构角度来看,它们存在着一些重要的差异。本文将从架构的角度出发,对SpringBoot和SpringCl

    Java API 开发中使用 SpringBoot 的利弊分析
    Java API 开发中使用 SpringBoot 的利弊分析

    JavaAPI开发中使用SpringBoot的利弊分析随着互联网的快速发展和技术的不断更新迭代,Java技术在开发中的广泛应用引起了人们的重视。而SpringBoot作为一种微服务架构的解决方案,已经逐渐成为Java开发中的热门选择。那么,在JavaAPI开发中使用SpringBoot,到底有哪些利弊呢?下面来分析一下。利:简化开发

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。

    为什么要购买正版软件?
    01 官方授权

    授权来源透明,订单与许可信息可随时查询。

    02 即时交付

    付款成功后自动发放激活信息,支持订单追踪。

    03 中文协助

    安装、激活、迁移与续费问题都有专人响应。

    04 长期可用

    提供升级提醒与授权管理,换机时也能轻松迁移。

    网站备案号:苏ICP备2026018738号-1 联系邮箱:bd@zhengruan.com 网站地图

    Copyright ©2018-2026