Springframework之ResponseBodyAdvice——响应拦截处理

       补充这篇博文是因为 在SpringBoot之HandlerInterceptor拦截器的使用 ——(一) 中提到 postHandle 方法有机会修改ModelAndView ,但是实际情况却是 无法修改 。原因是 @ResponseBody 注释或者返回 ResponseEntity的方法在先于postHandle方法之前将响应提交给HandlerAdapter(调用handler和Interceptor方法者),所以之后的修改就无效了。那么在这里我将采用实现 ResponseBodyAdvice 接口的方式来 修改ResponseBody

ResponseBodyAdvice简介

       ResponseBodyAdvice接口,其实是对加了 @RestController (也就是 @Controller + @ResponseBody )注解的处理器将要返回的值进行 增强处理
       可以用于规范化前后端调用的响应格式,也可以用作统一签名等操作。
       ResponseBodyAdvice其实也就是采用了 AOP 的思想,对返回值进行一次修改。

ResponseBodyAdvice方法介绍

public interface ResponseBodyAdvice<T> {
	// 该方法可以用于制定准入规则,只有当该方法返回True时,才会进入beforeBodyWrite方法
    boolean supports(MethodParameter var1, Class<? extends HttpMessageConverter<?>> var2);

	// var1 也就是我们的返回值,主要就是针对其进行修改
    @Nullable
    T beforeBodyWrite(@Nullable T var1, MethodParameter var2, MediaType var3, Class<? extends HttpMessageConverter<?>> var4, ServerHttpRequest var5, ServerHttpResponse var6);
}

自定义我们的ResponseBodyAdvice

  • 假定我这里去实现一个统一签名,然后返回给接口调用方的处理器
package com.zhibo.core;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.zhibo.common.response.Response;
import com.zhibo.security.util.MD5Util;
import com.zhibo.core.annotation.SignAdvice;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
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.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.reflect.Method;
import java.util.Objects;

@Slf4j
@ControllerAdvice("com.zhibo.controller.v3")// 此处可以限制需要拦截的包路径,不填写为全部拦截进入supports 方法验证
public class MyResponseBodyAdvice implements ResponseBodyAdvice<Response> {
	//签名KEY
    private final static String SIGN_KEY = "zhibo_lv";

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        //根据自定义注解判断方法上是否有指定需要拦截,当然这里也可以什么都不写直接返回true,根据自身业务场景做限制校验即可
        Method method = methodParameter.getMethod();
        SignAdvice ra = method.getAnnotation(SignAdvice.class);
        return Objects.nonNull(ra);
    }

    @Override
    public Response beforeBodyWrite(Response rsp, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        if (null == rsp) return null;
        // 打印未加签名前的Response
        log.info("未加签名前的Response:  {}",JSON.toJSONString(rsp));
        SignResponse signRsp = new SignResponse(rsp);

        signRsp.setDateTime(System.nanoTime());
        //自己随便弄个加密算法
        StringBuilder sbd = new StringBuilder();
        SignAdvice ra = methodParameter.getMethod().getAnnotation(SignAdvice.class);
        sbd.append(signRsp.getCode())
                .append(signRsp.getDateTime())
                .append(signRsp.getMessage())
                .append(JSON.toJSONString(signRsp.getResult(), SerializerFeature.MapSortField))
                .append(StringUtils.isBlank(ra.signKey()) ? SIGN_KEY : ra.signKey());
        signRsp.setSign(MD5Util.md5(sbd.toString()));
        log.info("添加签名后的Response:  {}",JSON.toJSONString(signRsp));
        return signRsp;
    }
}

自定义注解类

package com.zhibo.core.annotation;

import javax.ws.rs.NameBinding;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author <a href="mailto:zhibo.lv@xxxxxxxx.com">zhibo.lv</a>
 * Response自动签名
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@NameBinding
public @interface SignAdvice
{
	/**
	 * 自定义签名KEY
	 * 如不指定则使用系统默认KEY
	 */
	String signKey() default "";

}

Controller测试代码

package com.zhibo.controller.v3;

import com.zhibo.common.response.Response;
import com.zhibo.core.annotation.SignAdvice;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@ResponseBody
@Api(tags = "测试SignResponse", description = "测试SignResponse")
public class SignResponseController {

    @SignAdvice(signKey="signKey:zhibo testDemo")
    @GetMapping(value="/v3/noauth/sign/test")
    @ApiOperation(value = "/v3/noauth/sign/test", notes = "测试SignResponse")
    public Response<String> testDemo() {
        Response<String> response = new Response<>();
        response.setCode(0);
        response.setMessage("Success");
        response.setResult("点赞三连你最帅");
        return response;
    }
}

调用接口执行结果在这里插入图片描述

在这里插入图片描述
你的点赞就是我创作的最大动力,如果写的不错,来个三连行不行

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhibo_lv

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值