Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 9636|回复: 0

spring boot 2 全局统一返回RESTful风格数据、统一异常处理

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-4-19 02:21:04 | 显示全部楼层 |阅读模式

    全局统一返回RESTful风格数据,主要是实现ResponseBodyAdvice接口的方法,对返回值在输出之前进行修改。
    使用注解@RestControllerAdvice拦截异常并统一处理。

    开发环境:
    IntelliJ IDEA 2019.2.2
    jdk1.8
    Spring Boot 2.2.2

    1、创建一个SpringBoot项目,pom.xml引用的依赖包如下

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.62</version>
            </dependency>

    2、定义一个返回类

    package com.example.response.entity;
    
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.ToString;
    
    import java.io.Serializable;
    
    @Data
    @NoArgsConstructor
    @ToString
    public class ResponseData<T> implements Serializable {
        /**
         * 状态码:0-成功,1-失败
         * */
        private int code;
    
        /**
         * 错误消息,如果成功可为空或SUCCESS
         * */
        private String msg;
    
        /**
         * 返回结果数据
         * */
        private T data;
    
        public static ResponseData success() {
            return success(null);
        }
    
        public static ResponseData success(Object data) {
            ResponseData result = new ResponseData();
            result.setCode(0);
            result.setMsg("SUCCESS");
            result.setData(data);
            return result;
        }
    
        public static ResponseData fail(String msg) {
            return fail(msg,null);
        }
    
        public static ResponseData fail(String msg, Object data) {
            ResponseData result = new ResponseData();
            result.setCode(1);
            result.setMsg(msg);
            result.setData(data);
            return result;
        }
    }

    3、统一拦截接口返回数据

    新建一个类GlobalResponseHandler,用注解@RestControllerAdvice,并且实现ResponseBodyAdvice接口的方法,其中方法supports可以判断哪些需要拦截,方法beforeBodyWrite可以对返回值在输出之前进行修改,从而实现返回统一的接口数据。

    package com.example.response.config;
    
    import com.alibaba.fastjson.JSON;
    import com.example.response.entity.ResponseData;
    import org.springframework.core.MethodParameter;
    import org.springframework.http.MediaType;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.http.server.ServerHttpRequest;
    import org.springframework.http.server.ServerHttpResponse;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
    
    /**
     * 实现ResponseBodyAdvice接口,可以对返回值在输出之前进行修改
     */
    @RestControllerAdvice
    public class GlobalResponseHandler implements ResponseBodyAdvice<Object> {
    
        //判断支持的类型
        @Override
        public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
            // 检查注解是否存在,存在则忽略拦截
            if (methodParameter.getDeclaringClass().isAnnotationPresent(IgnorReponseAdvice.class)) {
                return false;
            }
            if (methodParameter.getMethod().isAnnotationPresent(IgnorReponseAdvice.class)) {
                return false;
            }
            return true;
        }
    
        @Override
        public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
            // 判断为null构建ResponseData对象进行返回
            if (o == null) {
                return ResponseData.success();
            }
            // 判断是ResponseData子类或其本身就返回Object o本身,因为有可能是接口返回时创建了ResponseData,这里避免再次封装
            if (o instanceof ResponseData) {
                return (ResponseData<Object>) o;
            }
            // String特殊处理,否则会抛异常
            if (o instanceof String) {
                return JSON.toJSON(ResponseData.success(o)).toString();
            }
            return ResponseData.success(o);
        }
    }
    新建自定义注解IgnorReponseAdvice
    package com.example.response.config;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface IgnorReponseAdvice {
    }

    4、统一异常处理

    package com.example.response.exception;
    import com.example.response.entity.ResponseData;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    
    @RestControllerAdvice
    public class GlobalExceptionHandler {
        @ExceptionHandler(Exception.class)
        public ResponseData exceptionHandler(Exception e) {
            e.printStackTrace();
            return ResponseData.fail("服务器异常:" + e.getMessage());
        }
    }

    5、新建一个测试用的实体类

    package com.example.response.entity;
    
    import lombok.Data;
    
    @Data
    public class User {
        private Long userId;
        private String userName;
        public User(Long userId, String userName){
            this.userId = userId;
            this.userName = userName;
        }
    }

    6、新建一个测试用的控制器类

    package com.example.response.controller;
    
    import com.example.response.config.IgnorReponseAdvice;
    import com.example.response.entity.ResponseData;
    import com.example.response.entity.User;
    import org.springframework.web.bind.annotation.*;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @RestController
    public class DemoController {
        @GetMapping("user")
        public User user() {
            User u = new User(100L, "u1");
            return u;
        }
    
        @GetMapping("userList")
        public List<User> userList(){
            List<User> list = new ArrayList<User>();
            list.add(new User(100L, "u1"));
            list.add(new User(200L, "u2"));
            return list;
        }
    
        @GetMapping("test1")
        public String test1(){
            return "test1";
        }
    
        @GetMapping("test2")
        public ResponseData test2(){
            return ResponseData.success("test2");
        }
    
        @IgnorReponseAdvice
        @GetMapping("test3")
        public String test3() {
            return "test3";
        }
    
        @GetMapping("test4")
        public String test4() {
            Integer x = 1 / 0;
            return x.toString();
        }
    
        @GetMapping("test5")
        public String test5() throws Exception {
            throw new Exception("自定义异常信息");
        }
    }

    7、用Postman测试

    (1)请求http://localhost:8080/user,返回

    {
        "code": 0,
        "msg": "SUCCESS",
        "data": {
            "userId": 100,
            "userName": "u1"
        }
    }

    (2)请求http://localhost:8080/userList,返回

    {
        "code": 0,
        "msg": "SUCCESS",
        "data": [
            {
                "userId": 100,
                "userName": "u1"
            },
            {
                "userId": 200,
                "userName": "u2"
            }
        ]
    }

    (3)请求http://localhost:8080/tes1,返回

    {"msg":"SUCCESS","code":0,"data":"test1"}

    (4)请求http://localhost:8080/test2,返回

    {
        "code": 0,
        "msg": "SUCCESS",
        "data": "test2"
    }

    (5)请求http://localhost:8080/test3,返回

    test3

    (6)请求http://localhost:8080/test4,返回

    {
        "code": 1,
        "msg": "服务器异常:/ by zero",
        "data": null
    }

    (7)请求http://localhost:8080/test5,返回

    {
        "code": 1,
        "msg": "服务器异常:自定义异常信息",
        "data": null
    }

      

    参考文章:
    https://blog.csdn.net/lrt890424/article/details/83624761
    https://www.cnblogs.com/Purgeyao/p/11599810.html

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-5 07:46 , Processed in 0.063579 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表