使用 RequestBodyAdvice 和 ResponseBodyAdvice 对controller进行增强

这篇博客介绍了如何使用RequestBodyAdvice和ResponseBodyAdvice对Controller中的请求体和响应体进行增强处理。通过这两个注解,可以在读取请求参数前和响应返回前进行特定的转换操作,例如日期格式的国际化处理。示例代码展示了如何根据当前用户的时区调整时间字符串,确保日期在不同地区显示的一致性。
RequestBodyAdvice,对所有以@RequestBody的参数的方法进行增强
/**
 * 对所有以@RequestBody的参数的方法进行增强
 */
@Slf4j
@ControllerAdvice("com.haier.hopm.biz.service.controller")
public class DateTimeRequestBodyAdvice implements RequestBodyAdvice {

    @Autowired
    private RedisUtil redisUtil;

    //此处如果返回false , 则不执行当前Advice的业务
    @Override
    public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        I18nTimeHandle i18nTimeHandle = methodParameter.getMethodAnnotation(I18nTimeHandle.class);
        //controller上有 I18nTimeHandle 这个注解的方法才进行处理
        if (i18nTimeHandle != null) {
            return true;
        }
        return false;
    }

    /**
     * @title 读取参数前执行
     * @description 在此做些编码 / 解密 / 封装参数为对象的操作
     */
    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return httpInputMessage;
    }

    /**
     * @title 读取参数后执行
     * @author yuchen
     */
    @Override
    public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter,
                                Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        String responesBody = JSONObject.toJSONStringWithDateFormat(o, JSON.DEFFAULT_DATE_FORMAT);
        //获取请求json中时间字符串
        List<String> jsonStrDateStrList = DateZoneUtil.getJsonStrDateStr(responesBody);
        if (CollectionUtil.isEmpty(jsonStrDateStrList)) {
            return o;
        }
//        log.info("RequestBody-处理前:{}", responesBody);
        //获取的当前国家所在时区,如果Redis查不到,则默认 +8
        String timeZone = redisUtil.get(Constants.COUNTRY_TIME_ZONE + UserUtil.getCountryCode());
        String sourceTimeZone = StrUtil.isEmpty(timeZone) ? "+8" : timeZone;
        for (String originDate : jsonStrDateStrList) {
            //将前端传入的时间 转换成 东八区的时间
            String targetDate = DateZoneUtil.converDateGMT(originDate, sourceTimeZone, "+8");
            responesBody = StrUtil.replace(responesBody, originDate, targetDate);
        }
//        log.info("RequestBody-处理后:{}", responesBody);
        return JSONObject.parseObject(responesBody, type);

    }

    /**
     * @title 无请求时的处理
     */

    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter,
                                  Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return body;
    }
}

ResponseBodyAdvice ,对controller的响应体进行增强
/**
 * 对controller的响应体进行增强
 */
@Slf4j
@ControllerAdvice("com.haier.hopm.biz.service.controller")
public class DateTimeResponseBodyAdvice implements ResponseBodyAdvice {

    @Autowired
    private RedisUtil redisUtil;

    //此处如果返回false , 则不执行当前Advice的业务
    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass,
                                  ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        String responesBody = JSONObject.toJSONStringWithDateFormat(o, JSON.DEFFAULT_DATE_FORMAT);
        //获取请求json中时间字符串
        List<String> jsonStrDateStrList = DateZoneUtil.getJsonStrDateStr(responesBody);
        if (CollectionUtil.isEmpty(jsonStrDateStrList)) {
            return o;
        }
//        log.info("ResponseBody-处理前:{}", responesBody);
        //获取的当前国家所在时区,如果Redis查不到,则默认 +8
        String timeZone = redisUtil.get(Constants.COUNTRY_TIME_ZONE + UserUtil.getCountryCode());
        String sourceTimeZone = StrUtil.isEmpty(timeZone) ? "+8" : timeZone;
        for (String originDate : jsonStrDateStrList) {
            //将前端传入的时间 转换成 东八区的时间
            String targetDate = DateZoneUtil.converDateGMT(originDate, "+8", sourceTimeZone);
            responesBody = StrUtil.replace(responesBody, originDate, targetDate);
        }
//        log.info("ResponseBody-处理后:{}", responesBody);
        return JSONObject.parseObject(responesBody);
    }
}

### ResponseBodyAdvice 对未标注 @ResponseBody 方法的影响 在 Spring MVC 中,`ResponseBodyAdvice` 接口允许开发者自定义如何处理响应体的内容。然而,对于 `ResponseBodyAdvice` 是否会影响没有标注 `@ResponseBody` 的方法,这取决于具体的上下文环境。 当控制器类被标记为 `@RestController` 时,该类下的所有方法都隐含着 `@ResponseBody` 的效果[^1]。因此,在这种情况下,即使方法本身没有显式声明 `@ResponseBody` 注解,`ResponseBodyAdvice` 同样会对这些方法生效并对其进行增强处理。 但是,如果是在普通的 `@Controller` 下,并且具体的方法并未使用 `@ResponseBody` 进行修饰,则通常不会触发 `ResponseBodyAdvice` 的行为。这是因为只有当返回值需要通过 HTTP 响应体发送给客户端时——即存在 `@ResponseBody` 或者其变种形式(如 `@RestController`),才会涉及到 `RequestResponseBodyMethodProcessor` 来处理响应数据转换的工作流程[^2]。 为了进一步澄清这一点,可以考虑下面的例子: ```java @RestController public class MyController { private final MyResponseBodyAdvice myResponseBodyAdvice; public MyController(MyResponseBodyAdvice myResponseBodyAdvice) { this.myResponseBodyAdvice = myResponseBodyAdvice; } // 此处虽然没有显示加上@ResponseBody,但由于@RestController的存在, // 实际上已经具备了@ResponseBody的效果,所以会被MyResponseBodyAdvice所影响。 @GetMapping("/example") public String example() { return "Example"; } } ``` 在这个例子中,由于整个控制器都被标记成了 `@RestController`,所以即便 `/example` 路径对应的方法并没有单独加 `@ResponseBody`,它仍然受到 `MyResponseBodyAdvice` 的作用范围之内。 相反地,如果我们有一个传统的基于视图解析器的控制器(`@Controller`),其中某些方法确实不需要也不应该作为 JSON/XML 等格式的数据直接返回给前端应用的话,那么就没有必要让它们受制于 `ResponseBodyAdvice` 的干预。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值