diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/R.java b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/R.java index cc5a6ef4d..0dee9033a 100644 --- a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/R.java +++ b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/R.java @@ -86,7 +86,7 @@ public class R implements Serializable { return restResult(data, CommonConstants.FAIL, msg); } - private static R restResult(T data, int code, String msg) { + static R restResult(T data, int code, String msg) { R apiResult = new R<>(); apiResult.setCode(code); apiResult.setData(data); diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/RetOps.java b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/RetOps.java new file mode 100644 index 000000000..a52c97741 --- /dev/null +++ b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/RetOps.java @@ -0,0 +1,257 @@ +/* + * + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + * + */ + +package com.pig4cloud.pigx.common.core.util; + +import cn.hutool.core.util.ObjectUtil; +import com.pig4cloud.pigx.common.core.constant.CommonConstants; + +import java.util.Arrays; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * 简化{@code R} 的访问操作,例子
+ * R result = R.ok(0);
+ * // 链式操作: 断言然后消费
+ * RetOps.of(result)
+ * 		.assertCode(-1,r -> new RuntimeException("error "+r.getCode()))
+ * 		.assertDataNotEmpty(r -> new IllegalStateException("oops!"))
+ * 		.useData(System.out::println);
+ * // 访问原始值
+ * RetOps.of(result).getData().orElse(null);
+ * 
+ * + * @author CJ (power4j@outlook.com) + * @date 2022/5/12 + * @since 4.4 + */ +public class RetOps { + + /** 状态码为成功 */ + public static final Predicate> CODE_SUCCESS = r -> CommonConstants.SUCCESS == r.getCode(); + + /** 数据有值 */ + public static final Predicate> HAS_DATA = r -> ObjectUtil.isNotEmpty(r.getData()); + + /** 数据有值,并且包含元素 */ + public static final Predicate> HAS_ELEMENT = r -> ObjectUtil.isNotEmpty(r.getData()); + + /** 状态码为成功并且有值 */ + public static final Predicate> DATA_AVAILABLE = CODE_SUCCESS.and(HAS_DATA); + + private final R original; + + // ~ 初始化 + // =================================================================================================== + + RetOps(R original) { + this.original = original; + } + + public static RetOps of(R original) { + return new RetOps<>(Objects.requireNonNull(original)); + } + + // ~ 杂项方法 + // =================================================================================================== + + /** + * 观察原始值 + * @return R + */ + public R peek() { + return original; + } + + /** + * 读取{@code code}的值 + * @return 返回code的值 + */ + public int getCode() { + return original.getCode(); + } + + /** + * 读取{@code data}的值 + * @return 返回 Optional 包装的data + */ + public Optional getData() { + return Optional.of(original.getData()); + } + + /** + * 读取{@code msg}的值 + * @return 返回Optional包装的 msg + */ + public Optional getMsg() { + return Optional.of(original.getMsg()); + } + + /** + * 对{@code code}的值进行相等性测试 + * @param value 基准值 + * @return 返回ture表示相等 + */ + public boolean codeEquals(int value) { + return original.getCode() == value; + } + + /** + * 对{@code code}的值进行相等性测试 + * @param value 基准值 + * @return 返回ture表示不相等 + */ + public boolean codeNotEquals(int value) { + return !codeEquals(value); + } + + /** + * 是否成功 + * @return 返回ture表示成功 + * @see CommonConstants#SUCCESS + */ + public boolean isSuccess() { + return codeEquals(CommonConstants.SUCCESS); + } + + /** + * 是否失败 + * @return 返回ture表示失败 + */ + public boolean notSuccess() { + return !isSuccess(); + } + + // ~ 链式操作 + // =================================================================================================== + + /** + * 断言{@code code}的值 + * @param expect 预期的值 + * @param func 用户函数,负责创建异常对象 + * @param 异常类型 + * @return 返回实例,以便于继续进行链式操作 + * @throws Ex 断言失败时抛出 + */ + public RetOps assertCode(int expect, Function, ? extends Ex> func) + throws Ex { + if (codeNotEquals(expect)) { + throw func.apply(original); + } + return this; + } + + /** + * 断言成功 + * @param func 用户函数,负责创建异常对象 + * @param 异常类型 + * @return 返回实例,以便于继续进行链式操作 + * @throws Ex 断言失败时抛出 + */ + public RetOps assertSuccess(Function, ? extends Ex> func) throws Ex { + return assertCode(CommonConstants.SUCCESS, func); + } + + /** + * 断言业务数据有值 + * @param func 用户函数,负责创建异常对象 + * @param 异常类型 + * @return 返回实例,以便于继续进行链式操作 + * @throws Ex 断言失败时抛出 + */ + public RetOps assertDataNotNull(Function, ? extends Ex> func) throws Ex { + if (Objects.isNull(original.getData())) { + throw func.apply(original); + } + return this; + } + + /** + * 断言业务数据有值,并且包含元素 + * @param func 用户函数,负责创建异常对象 + * @param 异常类型 + * @return 返回实例,以便于继续进行链式操作 + * @throws Ex 断言失败时抛出 + */ + public RetOps assertDataNotEmpty(Function, ? extends Ex> func) throws Ex { + if (ObjectUtil.isNotEmpty(original.getData())) { + throw func.apply(original); + } + return this; + } + + /** + * 断言业务数据有值,并且包含元素 + * @param mapper 业务数据转换函数 + * @param 数据类型 + * @return 返回新实例,以便于继续进行链式操作 + */ + public RetOps map(Function mapper) { + R result = R.restResult(mapper.apply(original.getData()), original.getCode(), original.getMsg()); + return of(result); + } + + // ~ 数据消费 + // =================================================================================================== + + /** + * 消费数据,注意此方法保证数据可用 + * @param consumer 消费函数 + */ + public void useData(Consumer consumer) { + consumer.accept(original.getData()); + } + + /** + * 条件消费(错误代码匹配某个值) + * @param consumer 消费函数 + * @param codes 错误代码集合,匹配任意一个则调用消费函数 + */ + public void useDataOnCode(Consumer consumer, int... codes) { + useDataIf(o -> Arrays.stream(codes).filter(c -> original.getCode() == c).findFirst().isPresent(), consumer); + } + + /** + * 条件消费(错误代码表示成功) + * @param consumer 消费函数 + */ + public void useDataIfSuccess(Consumer consumer) { + useDataIf(CODE_SUCCESS, consumer); + } + + /** + * 条件消费 + * @param predicate 断言函数 + * @param consumer 消费函数,断言函数返回{@code true}时被调用 + * @see RetOps#CODE_SUCCESS + * @see RetOps#HAS_DATA + * @see RetOps#HAS_ELEMENT + * @see RetOps#DATA_AVAILABLE + */ + public void useDataIf(Predicate> predicate, Consumer consumer) { + if (predicate.test(original)) { + consumer.accept(original.getData()); + } + } + +}