后台框架-统一数据格式2

在上一篇中,当在Controller类中需要返回统一格式的数据时,需要实例化一个R,有时候觉得还是不够简洁,那有没有一种方法Controller中直接返回对象,但是返回的对象统一保存到如下格式的data中?

ResponseBodyAdvice

ResponseBodyAdvice 是 Spring MVC 框架中的一个接口,它允许你在响应体被写入之前对其进行处理。这对于实现自定义的响应格式、压缩响应、加密响应等场景非常有用。

ResponseBodyAdvice 接口有两个主要方法:

supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType): 这个方法用于判断当前 ResponseBodyAdvice 是否适用于特定的方法返回类型和 HTTP 消息转换器类型。如果返回 true,则 beforeBodyWrite 方法将被调用;如果返回 false,则不会被调用。

beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response): 这个方法在响应体被写入之前被调用。你可以在这个方法中对响应体进行修改,例如修改响应头、修改响应体内容等。这个方法的返回值将作为最终的响应体被写入。

要使用 ResponseBodyAdvice,你需要创建一个类并实现这个接口,然后将其注册为一个 Spring Bean。下面是一个简单的示例:

@ControllerAdvice

public class CustomResponseBodyAdvice implements ResponseBodyAdvice {

复制代码
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    // 根据需要判断是否应用到指定的方法返回类型和转换器类型
    return true;
}

@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                              Class<? extends HttpMessageConverter<?>> selectedConverterType,
                              ServerHttpRequest request, ServerHttpResponse response) {
    // 在这里对响应体进行处理,例如包装成自定义的响应格式
    CustomResponseWrapper customResponse = new CustomResponseWrapper(body);
    return customResponse;
}

}

以下为示例代码:

java 复制代码
package org.example.web.web;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.example.web.model.R;
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.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.Map;

/**
 * 对controller 层中 ResponseBody 注解方法,进行增强拦截
 */
@ControllerAdvice
public class ResultResponseAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 返回true表示对所有Controller的返回值进行处理
        return true;
    }

    /**
     * 如果开启,就会对返回结果进行处理
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {
        // 设置响应类型为json
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8);
        if (body instanceof R) {
            // 如果body返回的是ResultMsg类型的对象,不进行增强处理
            return body;
        }
        if (body instanceof String) {
            // 如果body返回的是String类型的对象,单独处理
            return toJson(body);
        }
        if (body instanceof Map) {
            // 对异常进行统一处理
            Map<String, Object> map = (Map<String, Object>) body;
            if (map.containsKey("code") && map.containsKey("message")) {
                if ((int)map.get("code") == 200) {
                    return R.ok(map.get("message").toString());
                } else {
                    return R.error((int)map.get("code"), map.get("message").toString());
                }
            } else {
                return R.ok(map);
            }
        }
        return R.ok(body);
    }

    private Object toJson(Object body) {
        try {
            return new ObjectMapper().writeValueAsString(R.ok(body));
        } catch (JsonProcessingException e) {
            throw new RuntimeException("无法转发json格式", e);
        }
    }
}

示例

这样当在Controller中类似这样的处理时,返回的结果就更加简洁了。

java 复制代码
    @RequestMapping("/user")
    @ResponseBody
    public R<User> user() {
        User user = User.builder().id("1").username("test").name("张三").age(20).createTime(new Date()).build();
        return R.ok(user);
    }

    @RequestMapping("/user2")
    @ResponseBody
    public User user2() {
        return User.builder().id("1").username("test").name("张三").age(20).createTime(new Date()).build();
    }

浏览器访问截图如下:

可见这种写法更简洁统一。

相关推荐
前端精髓6 小时前
NestJS 是什么(对着 Spring Boot 一起学习)
spring boot·后端·学习
武哥聊编程8 小时前
【AI实战项目】基于SpringAI+Springboot+Vue的AI面试刷题训练平台
vue.js·人工智能·spring boot·springai
vipxieliang8 小时前
固定电话验证详解:区号、号码、分机号的完整验证
java·spring boot
步行cgn8 小时前
Spring Boot 主入口类上的 @Enable 和 @Scan 注解详解
java·spring boot·后端
xixingzhe29 小时前
SpringBoot DDD 实战入门文档
spring boot·spring·ddd
杨运交11 小时前
[069][公共模块]Spring Boot 全局异常处理与参数校验实战(下):校验异常精细化处理与 WebFlux 适配
java·spring boot·后端
行者-全栈开发11 小时前
Spring Boot + FFmpeg 视频批量处理实战:压缩、HLS切片与异步任务引擎
spring boot·ffmpeg·异步处理·视频压缩·hls切片·批量任务·redis队列
Andya_net11 小时前
Spring Boot | 条件注解完全指南:从 @Conditional 到 @ConditionalOnExpression 的原理、实践与避坑
spring boot·后端·python
小荷才露尖尖角,早有蜻蜓立上头12 小时前
class java.util.LinkedHashMap cannot be cast to xxx
java·spring boot
MZA66613 小时前
Spring Boot 实战:基于自定义注解 + AOP 实现 Kafka 消息无侵入异步上送
java·spring boot·kafka