2

前言

[TOC]

一般来说,http请求的状态码,只是表明请求是否有问题,不能表明错再哪里了.比如用户只是业务问题,需要给个警告,但是http的状态码不能说明业务问题.于是很多系统都采用了类似如下的响应体

{
    code: xxx,
    msg: xxx,
    data: xxxxxx
}

我也是需要这样的响应体.但是webflux需要你返回Mono对象或者Flux对象.才符合响应式开发的必要条件.

所以常规的直接把内容放到响应体中是不可取的.需要再封装.

解决方案

第一种(亲测问题巨多)

  • 在webflux处理响应信息的时候,通过切面替换webflux即将要返回的响应内容,包装一个响应体.
  • 优点

    • 侵入性小
  • 缺点

    • 接受类型众多需要适配

      • 本代码中只适配了2种常规类型
      • 一旦用户返回Flux或者其他内容直接报错了.
    • 问题巨多不一一描述了

第二种(相对完美的方案)

  • 依靠响应体的方法,把响应内容再加工
  • 优点

    • 不影响webflux源码
    • 基本没有任何问题
    • 只需要修改响应体代码
  • 缺点

    • 侵入性(一般响应体也是这样,所以也不太算缺点)

第一个方案

参考:https://blog.csdn.net/xuguangyuansh/article/details/100288216
他的是kotlin版的.
所以我写了一个java sringboot版的.

// 响应体
@Data
@ToString
public class ResponseInfo<T> implements Serializable {
    String msg;
    Integer code;
    Object data;
    
    public static <T> ResponseInfo<T> ok (T monoBody) {
        final ResponseInfo<T> responseInfo = new ResponseInfo<>();
        responseInfo.setCode(0);
        responseInfo.setData(monoBody);
        responseInfo.setMsg("ok");
        return responseInfo;
    }
}

// 切面bean,统一替换.
/**
 * webflux响应信息统一切换
 */
@Aspect
@Component
@ConditionalOnClass(name = {"org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler"})
public class ResponseBodyResultHandlerAspect {

    @SneakyThrows
    @Around(value = "execution(* org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler.handleResult(..)) && args(exchange, result)", argNames = "point,exchange,result")
    public Object handleResult(ProceedingJoinPoint point, ServerWebExchange exchange, HandlerResult result) {
        final Mono responseMono = ((Mono) result.getReturnValue()).map(responseValue -> responseValue instanceof ResponseInfo ? responseValue : ResponseInfo.ok(responseValue));
        return point.proceed(Arrays.asList(
                exchange,
                new HandlerResult(result.getHandler(), responseMono, result.getReturnTypeSource())
        ).toArray());
    }
}

// 控制层
@RestController
@RequestMapping("/test")
public class UserController {

    @GetMapping("/oop")
    public Mono getStr() {
        // 模拟获取数据的Mono序列
        final Mono<String> data = Mono.just("test");
        return data;
    }
}

第二个方案

自己写的.

// 装饰Mono的响应体工具类,自己修改一下自己的响应体对象也可以
@Data
@ToString
public class ResponseInfo<T> implements Serializable {
    String msg;
    Integer code;
    Object data;

    public static <T> Mono<ResponseInfo<T>> ok (Mono<T> monoBody) {
        return responseBodyCreate(monoBody,0,null);
    }

    public static <T> Mono<ResponseInfo<T>> ok (Mono<T> monoBody, String msg) {
        return responseBodyCreate(monoBody,0,msg);
    }

    public static <T> Mono<ResponseInfo<T>> ok (Mono<T> monoBody, int code, String msg) {
        return responseBodyCreate(monoBody,code,msg);
    }

    public static <T> Mono<ResponseInfo<T>> failed (Mono<T> monoBody) {
        return responseBodyCreate(monoBody,0,null);
    }

    public static <T> Mono<ResponseInfo<T>> failed (Mono<T> monoBody, String msg) {
        return responseBodyCreate(monoBody,0,msg);
    }

    public static <T> Mono<ResponseInfo<T>> failed (Mono<T> monoBody, int code, String msg) {
        return responseBodyCreate(monoBody,code,msg);
    }

    private static <T> Mono<ResponseInfo<T>> responseBodyCreate(Mono<T> monoData, int code, String msg) {
        return monoData.map(data-> {
            final ResponseInfo<T> responseInfo = new ResponseInfo<>();
            responseInfo.setCode(code);
            responseInfo.setData(data);
            responseInfo.setMsg(msg);
            return responseInfo;
        });
    }
}
// 控制层
@RestController
@RequestMapping("/test")
public class UserController {
    @GetMapping("/oop")
    public Mono getStr() {
        // 模拟获取数据
        final Mono<String> data = Mono.just("test");
        return ResponseInfo.ok(data);
        
        // 简写
        // return ResponseInfo.ok(Mono.just("test"));
    }
}

结束语

约束语?不存在的,如果有帮助就请给个赞把.感谢!!


zzzzgc
10 声望0 粉丝

全栈开发技术人员,java开发的独立开发者.技术栈java,vue,html,js.基础运维.