@ControllerAdvice,ResponseBodyAdvice 统一处理返回值/响应体

本文介绍Spring框架中ResponseBodyAdvice接口的应用实例,展示了如何利用该接口修改控制器方法的响应体,适用于Spring 4.1及以上版本。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ResponseBodyAdvice是spring4.1的新特性,其作用是在响应体写出之前做一些处理;比如,修改返回值、加密等。

我在项目中的用到@ControllerAdvice,ResponseBodyAdvice的目的,是为每个请求的返回json中修改一个属性值。

ResponseBodyAdvice 接口源码:

package org.springframework.web.servlet.mvc.method.annotation;
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;
/**
 * Allows customizing the response after the execution of an {@code @ResponseBody}
 * or an {@code ResponseEntity} controller method but before the body is written
 * with an {@code HttpMessageConverter}.
Implementations may be may be registered directly with
 * {@code RequestMappingHandlerAdapter} and {@code ExceptionHandlerExceptionResolver}
 * or more likely annotated with {@code @ControllerAdvice} in which case they
 * will be auto-detected by both.
 *
 * @author Rossen Stoyanchev
 * @since 4.1
 */
public interface ResponseBodyAdvice {
    /**
     * Whether this component supports the given controller method return type
     * and the selected {@code HttpMessageConverter} type.
     * @param returnType the return type
     * @param converterType the selected converter type
     * @return {@code true} if {@link #beforeBodyWrite} should be invoked, {@code false} otherwise
     */
    boolean supports(MethodParameter returnType, Class> converterType);

    /**
     * Invoked after an {@code HttpMessageConverter} is selected and just before
     * its write method is invoked.
     * @param body the body to be written
     * @param returnType the return type of the controller method
     * @param selectedContentType the content type selected through content negotiation
     * @param selectedConverterType the converter type selected to write to the response
     * @param request the current request
     * @param response the current response
     * @return the body that was passed in or a modified, possibly new instance
     */
    T beforeBodyWrite(T body, MethodParameter returnType, MediaType selectedContentType,
            Class> selectedConverterType,
            ServerHttpRequest request, ServerHttpResponse response);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

实现的示例:

package com.xxx;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import com.xxx.Messages;
/**
 * 处理 返回值
 * @Description:TODO
 * @author lh
 * @time:2015-8-31 上午11:24:08
 */

@ControllerAdvice
public class MyResponseBodyAdvice implements ResponseBodyAdvice{

    @Override
    public Object beforeBodyWrite(Object returnValue, MethodParameter methodParameter,
            MediaType mediaType, Class clas, ServerHttpRequest serverHttpRequest,
            ServerHttpResponse serverHttpResponse) {
        //通过 ServerHttpRequest的实现类ServletServerHttpRequest 获得HttpServletRequest  
        //ServletServerHttpRequest sshr=(ServletServerHttpRequest) serverHttpRequest;
        //此处获取到request 是为了取到在拦截器里面设置的一个对象 是我项目需要,可以忽略
        //HttpServletRequest request=   sshr.getServletRequest();

        //将返回值returnValue转成我需要的类型Message<?>  方便统一修改其中的某个属性  
        // Messages是我自定义的一个类
       Messages<?> msg=(Messages<?>) returnValue;
        //统一修改返回值/响应体
        msg.setXXX("测试修改返回值");
        //返回修改后的值
        return msg;
    }

    @Override
    public boolean supports(MethodParameter methodParameter, Class clas) {
        //获取当前处理请求的controller的方法
        String methodName=methodParameter.getMethod().getName(); 
        // 不拦截/不需要处理返回值 的方法
        String method= "loginCheck"; //如登录
        //不拦截
        return !method.equals(methodName);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

这样得到的处理过的返回值,属性xxx的值都是“测试修改返回值”;

### 实现 `ResponseBodyAdvice` 接口修改返回体内容 在 Spring Boot 中,`ResponseBodyAdvice` 是一个接口,允许开发者在将控制器方法返回值写入 HTTP 响应体之前对其进行修改。通过实现该接口,可以对所有带有 `@ResponseBody` 或返回值为 `ResponseEntity` 的方法进行统一的响应数据处理。 #### 1. 定义统一响应体结构 首先,定义一个统一响应体结构类,用于封装返回的数据。以下是一个示例: ```java public class Result<T> { private int code; private String message; private T data; private long timestamp; public Result() { this.timestamp = System.currentTimeMillis(); } public static <T> Result<T> success(T data) { Result<T> result = new Result<>(); result.setCode(200); result.setMessage("Success"); result.setData(data); return result; } public static <T> Result<T> error(int code, String message) { Result<T> result = new Result<>(); result.setCode(code); result.setMessage(message); return result; } // Getter and Setter methods public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public T getData() { return data; } public void setData(T data) { this.data = data; } public long getTimestamp() { return timestamp; } } ``` #### 2. 实现 `ResponseBodyAdvice` 接口 接下来,创建一个类实现 `ResponseBodyAdvice` 接口,并重写其两个方法:`supports` 和 `beforeBodyWrite`。 ```java 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; @ControllerAdvice public class CustomResponseAdvice implements ResponseBodyAdvice<Object> { @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) { // 如果返回值已经是 Result 类型,则直接返回 if (body instanceof Result) { return body; } // 否则将返回值封装为 Result 类型 return Result.success(body); } } ``` #### 3. 使用示例 在控制器中使用时,无需额外操作,返回的数据会被自动封装为 `Result` 对象。 ```java import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ExampleController { @GetMapping("/example") public String example() { return "Hello, World!"; } } ``` 当访问 `/example` 接口时,实际返回的内容会被封装为如下格式: ```json { "code": 200, "message": "Success", "data": "Hello, World!", "timestamp": 1698765432123 } ``` #### 注意事项 - 如果某些接口不需要被封装,可以在 `supports` 方法中添加逻辑判断,跳过这些接口[^1]。 - 可以根据实际需求扩展 `Result` 类,例如添加更多的字段或方法[^4]。 - 在 `beforeBodyWrite` 方法中,可以通过检查返回值类型来决定是否进行封装[^5]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值