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

全局统一返回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

原文地址:https://www.cnblogs.com/gdjlc/p/12077593.html

时间: 2024-09-29 23:04:50

spring boot 2 全局统一返回RESTful风格数据、统一异常处理的相关文章

Spring Boot中使用Swagger2生成RESTful API文档(转)

效果如下图所示: 添加Swagger2依赖 在pom.xml中加入Swagger2的依赖 <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <versi

Spring Boot 中全局异常处理器

Spring Boot 中全局异常处理器,就是把错误异常统一处理的方法.等价于Springmvc中的异常处理器. 步骤一:基于前面的springBoot入门小demo修改 步骤二:修改HelloController类 修改HelloController,使得访问/hello一定会产生异常: some exception package cn.xdf.springboot.web; import java.text.DateFormat; import java.util.Date; import

spring boot 配置全局日期类型转换器

首先自定义一个类型转换器 import org.springframework.core.convert.converter.Converter;import org.springframework.stereotype.Component; import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date; @Componentpublic class MyDataConvert im

Spring Boot 揭秘与实战(二) 数据缓存篇 - 快速入门

文章目录 1. 声明式缓存 2. Spring Boot默认集成CacheManager 3. 默认的 ConcurrenMapCacheManager 4. 实战演练5. 扩展阅读 4.1. Maven 依赖 4.2. 开启缓存支持 4.3. 服务层 4.4. 控制层 4.5. 运行 4.6. 课后作业 6. 源代码 为了提高性能,减少数据库的压力,使用缓存是非常好的手段之一.本文,讲解 Spring Boot 如何集成缓存管理. 声明式缓存 Spring 定义 CacheManager 和

Spring Boot、微服务架构和大数据

一文读懂 Spring Boot.微服务架构和大数据治理三者之间的故事 https://www.cnblogs.com/ityouknow/p/9034377.html 微服务架构 微服务的诞生并非偶然,它是在互联网高速发展,技术日新月异的变化以及传统架构无法适应快速变化等多重因素的推动下诞生的产物.互联网时代的产品通常有两类特点:需求变化快和用户群体庞大,在这种情况下,如何从系统架构的角度出发,构建灵活.易扩展的系统,快速应对需求的变化:同时,随着用户的增加,如何保证系统的可伸缩性.高可用性,

SpringMVC 统一返回JSON格式数据到前端

有时在给APP做接口功能的时候,都是返回JSON格式的数据,所以最好的只好在工程设置一个统一的数据返回方式 在SpringMVC 直接配置XML可以产生这种配置,比较简单 Spring的版本我用的是4.3.3的 <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter&qu

Spring Boot 揭秘与实战(二) 数据存储篇 - MongoDB

文章目录 1. 环境依赖 2. 数据源 2.1. 方案一 使用 Spring Boot 默认配置 2.2. 方案二 手动创建 3. 使用mongoTemplate操作4. 总结 3.1. 实体对象 3.2. DAO相关 3.3. Service相关 3.4. Controller相关 5. 源代码 本文讲解Spring Boot基础下,如何使用MongoDB,编写数据访问. 环境依赖 修改 POM 文件,添加spring-boot-starter-data-mongodb依赖. <depende

Spring Boot 揭秘与实战(二) 数据存储篇 - ElasticSearch

文章目录 1. 版本须知 2. 环境依赖 3. 数据源 3.1. 方案一 使用 Spring Boot 默认配置 3.2. 方案二 手动创建 4. 业务操作5. 总结 4.1. 实体对象 4.2. DAO相关 4.3. Service相关 4.4. Controller相关 6. 源代码 本文讲解Spring Boot基础下,如何使用 ElasticSearch,实现全文搜索. 版本须知 spring data elasticSearch 的版本与Spring boot.Elasticsearc

Spring Boot 揭秘与实战(二) 数据存储篇 - Redis

文章目录 1. 环境依赖 2. 数据源 2.1. 方案一 使用 Spring Boot 默认配置 2.2. 方案二 手动创建 3. 使用 redisTemplate 操作4. 总结 3.1. 工具类 3.2. 测试类 3.3. 单元测试用例 5. 源代码 本文讲解Spring Boot基础下,如何整合Redis,编写数据访问. 环境依赖 修改 POM 文件,添加 spring-boot-starter-redis 依赖. <dependency> <groupId>org.spri