跳转到内容

JQuick Transform Function

jquick-transform-function 是 JQuick 生态的通用数据转换函数库。它提供一个统一的函数注册中心 JQuickMethodInvocationManager,把字段类型转换、码值翻译、脱敏校验、条件判断等逻辑收敛为「按名称调用的函数」,业务代码里不必再反复编写同类转换分支。

库为纯 Java 实现,JDK 8+,无重型第三方依赖;函数通过 JDK 原生 SPI(java.util.ServiceLoader)发现与加载,不依赖 Spring 容器,普通 Java 工程、Spring / Spring Boot 工程均可直接引入,已在达梦(DM)、KingbaseES 等国产数据库配套场景中使用。

Maven 坐标:io.github.paohaijiao:jquick-transform-function:1.4.0(Maven Central 最新发布版)。

  • 259 个内置函数:字符串、数学、日期时间、条件、类型转换、业务(身份证 / 手机号 / 银行卡)、集合、数组、位运算、布尔、随机数、JSON、加解密(AES/RSA/ECC)、几何与向量、扩展转换、码值翻译共 16 大类。
  • 原生 Java SPI 扩展:自定义转换函数实现接口并在 META-INF/services/ 注册即可,插件式扩展,不改源码。
  • 可覆盖内置函数:注册同名函数(或更高优先级)即可替换内置实现。
  • 统一调用入口:线程安全单例 JQuickMethodInvocationManager,按名称调用任意函数。
  • Lambda 一行注册:简单函数可用 Lambda 直接注册,不必新建类文件。
  • 零侵入、轻量级:JDK 8+,不绑定任何框架,遗留系统可平滑引入。
  • 生态直接复用:jquick-sql、jquick-excel 均已直接依赖本组件,函数可在 SQL 与 Excel 导入导出中直接使用。

Maven:

<dependency>
<groupId>io.github.paohaijiao</groupId>
<artifactId>jquick-transform-function</artifactId>
<version>1.4.0</version>
</dependency>

Gradle:

implementation 'io.github.paohaijiao:jquick-transform-function:1.4.0'

以下示例可直接编译运行,无需任何初始化代码——首次调用时注册中心自动通过 SPI 加载全部内置函数。

package demo;
import com.github.paohaijiao.function.manager.JQuickMethodInvocationManager;
/**
* jquick-transform-function 最简示例
*/
public class TransformQuickStart {
public static void main(String[] args) {
// 获取线程安全的注册中心单例
JQuickMethodInvocationManager manager = JQuickMethodInvocationManager.getInstance();
// 字符串函数:转大写
Object upper = manager.invoke("toUpper", "hello"); // HELLO
// 数学函数:多参数求和
Object sum = manager.invoke("add", 10, 20, 30); // 30.0
// 字符串截取
Object sub = manager.invoke("substring", "hello world", 0, 5); // hello
// 业务函数:手机号脱敏
Object masked = manager.invoke("phoneMask", "13812345678"); // 138****5678
System.out.println(upper + " / " + sum + " / " + sub + " / " + masked);
// 运行期打印全部已注册函数(259 个),便于排查函数名
manager.printRegisteredMethods();
}
}

以下每个函数都给出可直接复制的调用 demo。代码块中的 manager 即快速上手中获取的 JQuickMethodInvocationManager 单例,行尾注释为调用结果或返回内容。

基础判断与比较:

// 空串 / 空白判断
manager.invoke("isBlank", " "); // true
manager.invoke("isString", 1); // false
manager.invoke("length", "hello"); // 5
// 字符构成判断
manager.invoke("isAlpha", "abc"); // true
manager.invoke("isAlphaNumeric", "ab1"); // true
manager.invoke("isNumeric", "123"); // true
// 包含与查找
manager.invoke("contains", "hello", "ell"); // true
manager.invoke("indexOf", "hello", "l"); // 2
manager.invoke("indexOf", "hello", "l", 3); // 3(从下标 3 开始找)
manager.invoke("matches", "abc123", "[a-z]+\\d+"); // true
// 比较
manager.invoke("compareTo", "abc", "abd"); // -1
manager.invoke("compareTo", "ABC", "abc", true); // 0(忽略大小写)
manager.invoke("equalsIgnoreCase", "AbC", "aBc"); // true
manager.invoke("equalsAny", "a", "b", "a"); // true
// 编辑距离(Levenshtein):最少单字符增删改次数
manager.invoke("levenshtein", "kitten", "sitting"); // 3

截取、填充与掩码:

// 拼接
manager.invoke("concat", "a", "b", "c"); // abc
// 截取
manager.invoke("left", "hello", 2); // he
manager.invoke("right", "hello", 2); // lo
manager.invoke("mid", "hello", 1, 3); // ell
manager.invoke("substring", "hello world", 0, 5); // hello
manager.invoke("substringBefore", "a,b,c", ","); // a
manager.invoke("substringAfter", "a,b,c", ","); // b,c
manager.invoke("substringBetween", "a[b]c", "[", "]"); // b
// 填充对齐
manager.invoke("leftPad", "7", 3, "0"); // 007
manager.invoke("rightPad", "ab", 4, "."); // ab..
manager.invoke("centerPad", "ab", 6); // " ab "
// 掩码:mask 下标区间为 [start, end)
manager.invoke("mask", "13812345678", 3, 7); // 138****5678
manager.invoke("maskEmail", "[email protected]"); // te***@example.com
// 缩写:maxWidth 包含省略号本身
manager.invoke("abbreviate", "abcdefg", 6); // abc...

替换、转换与聚合:

// 重复
manager.invoke("repeat", "ab", 2, "-"); // ab-ab
manager.invoke("repeatChar", "-", 3); // ---
// 替换
manager.invoke("replace", "hello world", "world", "java"); // hello java
manager.invoke("replaceAll", "a1b2c3", "\\d", "#"); // a#b#c#
// 反转与大小写
manager.invoke("reverse", "abc"); // cba
manager.invoke("swapCase", "Hello"); // hELLO
manager.invoke("toUpper", "hello"); // HELLO
manager.invoke("toLower", "HELLO"); // hello
manager.invoke("trim", " hi "); // hi
manager.invoke("capitalize", "hello"); // Hello
manager.invoke("uncapitalize", "Hello"); // hello
// 命名风格转换
manager.invoke("toCamelCase", "user_name"); // userName
manager.invoke("toSnakeCase", "userName"); // user_name
manager.invoke("toString", 123); // 123
// 去除
manager.invoke("removeStart", "userName", "user"); // Name
manager.invoke("removeEnd", "demo.txt", ".txt"); // demo
manager.invoke("removeWhitespace", " a b\tc "); // abc
manager.invoke("removeDuplicates", "aabbcc"); // abc(去除相邻重复)
manager.invoke("uniqueChars", "abac"); // abc(按首次出现保留唯一)
// 分词与统计
manager.invoke("wordCount", "hello world"); // 2
manager.invoke("tokenize", "a,b;c", ",;"); // [a, b, c]
manager.invoke("split", "a,b,c", ","); // [a, b, c]
manager.invoke("splitByLength", "abcdef", 2); // [ab, cd, ef]
manager.invoke("countChar", "banana", "a"); // 3
manager.invoke("countMatches", "aaa", "a"); // 3
// 聚合连接:第一个参数为分隔符
manager.invoke("groupConcat", ",", "a", "b", "c"); // a,b,c
manager.invoke("stringAgg", "-", "a", "b", "c"); // a-b-c
// 格式化:底层为 String.format
manager.invoke("format", "%s=%d", "age", 18); // age=18
// 相似度(返回 0~100 的相似度数值)
manager.invoke("similarity", "abc", "abd");
// 转义与编解码
manager.invoke("escapeHtml", "<a>"); // &lt;a&gt;
manager.invoke("unescapeHtml", "&lt;"); // <
manager.invoke("escapeRegex", "a.b"); // a\.b
manager.invoke("encodeUrl", "a b&c"); // a%20%26c
manager.invoke("decodeUrl", "a%20b"); // a b
manager.invoke("base64Encode", "hello"); // aGVsbG8=
manager.invoke("base64Decode", "aGVsbG8="); // hello
manager.invoke("md5", "hello"); // 5d41402abc4b2a76b9719d911017c592

四则与取整:

// 四则(多参数依次参与运算)
manager.invoke("add", 10, 20); // 30.0
manager.invoke("subtract", 30, 10); // 20.0
manager.invoke("multiply", 3, 4); // 12.0
manager.invoke("divide", 10, 4); // 2.5
manager.invoke("mod", 10, 3); // 1.0
manager.invoke("abs", -5); // 绝对值 5
// 取整
manager.invoke("round", 3.5); // 4.0
manager.invoke("roundTo", 3.14159, 2); // 3.14
manager.invoke("ceil", 3.1); // 4.0
manager.invoke("ceilTo", 3.11, 1); // 3.2
manager.invoke("floor", 3.9); // 3.0
manager.invoke("floorTo", 3.19, 1); // 3.1
manager.invoke("signum", -8); // -1.0

聚合与统计:

// 求和、均值、极值
manager.invoke("sum", 1, 2, 3); // 6.0
manager.invoke("avg", 10, 20, 30); // 20.0
manager.invoke("max", 3, 1, 2); // 3.0
manager.invoke("min", 3, 1, 2); // 1.0
manager.invoke("greatest", 3, 7, 2); // 7.0
manager.invoke("least", 3, 7, 2); // 2.0
manager.invoke("product", 2, 3, 4); // 24.0
manager.invoke("range", 1, 9, 3); // 8.0
// 中位数、众数、百分位(返回对应统计值)
manager.invoke("median", 1, 2, 3, 4); // 2.5
manager.invoke("mode", 1, 1, 2);
manager.invoke("percentile", 1, 2, 3, 4, 5, 6, 7, 8, 9, 50);
// 方差与标准差(返回对应统计值)
manager.invoke("variance", 2, 4, 4, 4, 5, 5, 7, 9);
manager.invoke("stdDev", 2, 4, 4, 4, 5, 5, 7, 9);
// 计数
manager.invoke("count", 1, 2, 3); // 3
manager.invoke("countNonNull", null, 1, null); // 1
manager.invoke("countDistinct", 1, 1, 2, 3, 3); // 3
manager.invoke("isNumber", "12.3"); // true

幂、对数与三角函数:

// 幂与开方
manager.invoke("pow", 2, 10); // 1024.0
manager.invoke("sqrt", 16); // 4.0
manager.invoke("exp", 1); // 2.718281828459045
manager.invoke("expm1", 0); // 0.0
// 对数
manager.invoke("log", Math.E); // 1.0
manager.invoke("log10", 1000); // 3.0
manager.invoke("log1p", 0); // 0.0
// 三角函数(角度参数为弧度)
manager.invoke("sin", Math.PI / 2); // 1.0
manager.invoke("cos", 0); // 1.0
manager.invoke("tan", Math.PI / 4); // 0.9999999999999999
manager.invoke("asin", 1); // 1.5707963267948966(π/2)
manager.invoke("acos", 1); // 0.0
manager.invoke("atan", 1); // 0.7853981633974483(π/4)
manager.invoke("atan2", 1, 1); // 0.7853981633974483
manager.invoke("sinh", 0); // 0.0
manager.invoke("cosh", 0); // 1.0
manager.invoke("tanh", 0); // 0.0
// 角度弧度互换
manager.invoke("toRadians", 180); // 3.141592653589793
manager.invoke("toDegrees", Math.PI); // 180.0
// 常量
manager.invoke("pi"); // 3.141592653589793
manager.invoke("e"); // 2.718281828459045

类型转换与进制:

// 数值类型转换(第二个参数为默认值)
manager.invoke("toInt", "12"); // 12
manager.invoke("toLong", "12"); // 12
manager.invoke("toFloat", "12"); // 12.0
manager.invoke("toDouble", "12"); // 12.0
// 进制转换
manager.invoke("toBinary", 10); // 1010
manager.invoke("toHex", 255); // ff
manager.invoke("toOctal", 8); // 10
manager.invoke("parseBinary", "1010"); // 10
manager.invoke("parseHex", "ff"); // 255
// 按 pattern 输出数字字符串
manager.invoke("toNumberString", 3.14, "0.0");
// 浮点数最小精度单位
manager.invoke("ulp", 1.0); // 2.220446049250313E-16

下列 demo 以固定基准日期调用:date = 2026-09-30,datetime = 2026-09-30 10:30:00(均为周三)。

import java.time.LocalDate;
import java.time.LocalDateTime;
LocalDate date = LocalDate.of(2026, 9, 30);
LocalDateTime datetime = LocalDateTime.of(2026, 9, 30, 10, 30, 0);
// 当前时间
manager.invoke("now"); // 当前 LocalDateTime
manager.invoke("today"); // 当前 LocalDate
manager.invoke("timestamp"); // 当前毫秒时间戳
// 取年/月/日(不传参数则取当前日期)
manager.invoke("year", date); // 2026
manager.invoke("month", date); // 9
manager.invoke("day", date); // 30
// 取时/分/秒
manager.invoke("hour", datetime); // 10
manager.invoke("minute", datetime); // 30
manager.invoke("second", datetime); // 0
// 周/年中序号:周一=1
manager.invoke("dayOfWeek", date); // 3(周三)
manager.invoke("dayOfYear", date); // 273
manager.invoke("weekOfYear", date); // 年内周序号

日期运算与格式化:

// 日期加减
manager.invoke("addDays", date, 7); // 2026-10-07
manager.invoke("addMonths", date, 1); // 2026-10-30
manager.invoke("addYears", date, 1); // 2027-09-30
manager.invoke("addHours", datetime, 2); // 2026-09-30 12:30
manager.invoke("addMinutes", datetime, 15); // 2026-09-30 10:45
manager.invoke("addSeconds", datetime, 30); // 2026-09-30 10:30:30
// 格式化与解析
manager.invoke("formatDate", date, "yyyy/MM/dd"); // 2026/09/30
manager.invoke("parseDate", "2026-09-30", "yyyy-MM-dd"); // LocalDate
manager.invoke("toIsoString", date); // 2026-09-30

边界、比较与差值:

// 起止边界
manager.invoke("startOfDay", date); // 2026-09-30 00:00
manager.invoke("endOfDay", date); // 2026-09-30 23:59:59
manager.invoke("startOfMonth", date); // 2026-09-01
manager.invoke("endOfMonth", date); // 2026-09-30
manager.invoke("startOfYear", date); // 2026-01-01
manager.invoke("endOfYear", date); // 2026-12-31
// 先后与同日判断
manager.invoke("isAfter", date, date.minusDays(1)); // true
manager.invoke("isBefore", date, date.plusDays(1)); // true
manager.invoke("isSameDay", datetime, date); // true
manager.invoke("isWeekend", date); // false
manager.invoke("isLeapYear", 2026); // false
manager.invoke("isDate", "2026-09-30"); // true(可解析为日期)
// 差值
manager.invoke("daysBetween", date, date.plusDays(10)); // 10
manager.invoke("hoursBetween", datetime, datetime.plusHours(5)); // 5
manager.invoke("monthsBetween", date, date.plusMonths(3)); // 3
manager.invoke("yearsBetween", date, date.plusYears(2)); // 2
// 年龄:按出生日期与参考日期计算(不传参考日期则取今天)
manager.invoke("age", LocalDate.of(2000, 1, 1), date);

比较运算与范围:

// 相等 / 不等(第三个参数控制是否忽略大小写)
manager.invoke("eq", 1, 1); // true
manager.invoke("eq", "Abc", "abc", true); // true
manager.invoke("ne", 1, 2); // true
// 大小比较
manager.invoke("gt", 2, 1); // true
manager.invoke("gte", 2, 2); // true
manager.invoke("lt", 1, 2); // true
manager.invoke("lte", 2, 2); // true
// 范围:第四个参数控制是否包含边界
manager.invoke("between", 5, 1, 10); // true
manager.invoke("between", 10, 1, 10, false); // false(不含上边界)

分支与空值:

// 三元判断
manager.invoke("if", true, "通过", "不通过"); // 通过
// 多条件:条件与结果成对出现,最后一个为兜底值
int score = 75;
manager.invoke("ifElse", score >= 90, "A", score >= 60, "B", "C"); // B
manager.invoke("caseWhen", score < 60, "不及格", score < 80, "良", "优"); // 良
// 值匹配分支
int status = 2;
manager.invoke("switch", status, 1, "待支付", 2, "已支付", "已取消"); // 已支付
// 空值处理
manager.invoke("coalesce", null, null, "default"); // default
manager.invoke("nvl", null, 0); // 0
manager.invoke("defaultIfNull", null, "默认值"); // 默认值
// 字符串转布尔
manager.invoke("toBoolean", "true"); // true
// 字符串转日期(第二个参数为解析格式)
manager.invoke("toDate", "2026-09-30", "yyyy-MM-dd"); // LocalDate
manager.invoke("toDateTime", "2026-09-30 10:30:00", "yyyy-MM-dd HH:mm:ss"); // LocalDateTime
// 转短整数(第二个参数为默认值)
manager.invoke("toShort", "12"); // 12

身份证相关:

String idCard = "11010119900307077X";
// 校验与信息提取
manager.invoke("idCardValidate", idCard); // 是否有效
manager.invoke("idCardInfo", idCard, "region"); // 归属地
manager.invoke("idCardInfo", idCard, "age"); // 年龄
manager.invoke("idCardGender", idCard, "M/F"); // M(按 format 返回)
manager.invoke("idCardBirthday", idCard, "yyyy-MM-dd"); // 1990-03-07
manager.invoke("idCardAge", idCard); // 年龄数值

手机、邮箱、银行卡与性别:

// 手机
manager.invoke("phoneValidate", "13812345678"); // true
manager.invoke("phoneMask", "13812345678"); // 138****5678
manager.invoke("phoneMask", "13812345678", 3, 4); // 同上(默认保留前3后4)
manager.invoke("phoneInfo", "13812345678", "carrier"); // 运营商信息
// 邮箱
manager.invoke("isEmail", "[email protected]"); // true
manager.invoke("emailMask", "[email protected]"); // te***@example.com
// 银行卡(默认保留前4后4)
manager.invoke("bankCardValidate", "6222021234567890"); // 是否有效(Luhn)
manager.invoke("bankCardMask", "6222021234567890"); // 6222********7890
// 性别码值转名称:支持 M/F、1/0、男/女、male/female
manager.invoke("genderName", "M"); // 男
import java.util.Arrays;
import java.util.List;
List<String> list = Arrays.asList("a", "b", "c");
// 空判断:支持 String / Collection / Map / Array
manager.invoke("isEmpty", ""); // true
manager.invoke("isEmpty", list); // false
// 长度:集合、数组、Map、字符串均可
manager.invoke("size", list); // 3
// 按分隔符连接集合元素
manager.invoke("join", list, "-"); // a-b-c
// 判断是否为数组或列表
manager.invoke("isArray", new int[]{1, 2, 3}); // true
manager.invoke("isArray", "abc"); // false
// 6 的二进制为 110,3 为 011
manager.invoke("bitAnd", 6, 3); // 2(110 & 011 = 010)
manager.invoke("bitOr", 6, 3); // 7(110 | 011 = 111)
manager.invoke("bitXor", 6, 3); // 5(110 ^ 011 = 101)
// 判断是否为布尔值
manager.invoke("isBoolean", true); // true
manager.invoke("isBoolean", "true"); // false
// 生成 Base64 密钥;加密、解密使用同一把密钥
String aesKey = (String) manager.invoke("aesGenerateKey");
String aesCipher = (String) manager.invoke("aesEncrypt", "敏感数据", aesKey);
String aesPlain = (String) manager.invoke("aesDecrypt", aesCipher, aesKey);
// aesPlain = 敏感数据
import java.util.Map;
// 生成密钥对,返回 Map:含 publicKey、privateKey(均为 Base64)
Map<?, ?> rsaPair = (Map<?, ?>) manager.invoke("rsaGenerateKeyPair");
String rsaCipher = (String) manager.invoke("rsaEncrypt", "敏感数据", rsaPair.get("publicKey"));
String rsaPlain = (String) manager.invoke("rsaDecrypt", rsaCipher, rsaPair.get("privateKey"));
// rsaPlain = 敏感数据
import java.util.Map;
// 生成 ECC 密钥对,返回 Map:含 publicKey、privateKey
Map<?, ?> eccPair = (Map<?, ?>) manager.invoke("eccGenerateKeyPair");
String eccCipher = (String) manager.invoke("eccEncrypt", "敏感数据", eccPair.get("publicKey"));
String eccPlain = (String) manager.invoke("eccDecrypt", eccCipher, eccPair.get("privateKey"));
// eccPlain = 敏感数据
import java.util.Arrays;
import java.util.List;
// 随机整数/长整数/浮点数:支持无参、单上界、上下界三种形式
manager.invoke("randomInt"); // 随机整数
manager.invoke("randomInt", 100); // [0, 100)
manager.invoke("randomInt", 1, 100); // [1, 100)
manager.invoke("randomLong", 1L, 1000L); // [1, 1000)
manager.invoke("randomDouble", 0.0, 1.0); // [0.0, 1.0)
// 按概率生成布尔值:参数为 true 的概率
manager.invoke("randomBoolean"); // 等概率
manager.invoke("randomBoolean", 0.8); // 80% 为 true
// 随机字符串 / UUID
manager.invoke("randomString", 8); // 8 位随机字符串
manager.invoke("randomUUID"); // 标准 UUID
manager.invoke("randomUUID", true); // 去掉连字符的 UUID
// 随机颜色:type 支持 hex / rgb / preset
manager.invoke("randomColor"); // #RRGGBB
manager.invoke("randomColor", "rgb"); // rgb(r, g, b)
manager.invoke("randomColor", "preset"); // 预置颜色之一
// 随机日期:在起止日期之间(第三个参数为日期格式)
manager.invoke("randomDate", "2026-01-01", "2026-12-31", "yyyy-MM-dd");
// 随机选取
List<String> candidates = Arrays.asList("a", "b", "c", "d");
manager.invoke("randomChoice", candidates); // 列表中随机一个
manager.invoke("random", candidates); // 同上,数组/列表随机取一
manager.invoke("randomSample", candidates, 2); // 随机取 2 个
manager.invoke("randomIntArray", 5, 1, 10); // 长度为 5 的随机整数数组
// 打乱顺序(返回打乱后的列表)
manager.invoke("shuffle", candidates);
// 对象序列化为 JSON 字符串
manager.invoke("toJson", userObject); // JSON 文本
// 强制类型转换:第二个参数为目标 Class
manager.invoke("cast", "123", Integer.class); // 123
// 数字格式化与反解析(pattern 为 DecimalFormat 格式)
manager.invoke("formatNumber", 1234.567, "#,##0.00"); // 1,234.57
manager.invoke("parseNumber", "1,234.57", "#,##0.00"); // 1234.57
// 货币 / 百分比(第二个参数分别为 locale、保留小数位)
manager.invoke("toCurrency", 1234.5); // 货币格式文本
manager.invoke("toPercentage", 0.85, 2); // 85.00%
// 包装为数组 / 列表
manager.invoke("toArray", 1, 2, 3); // [1, 2, 3]
manager.invoke("toList", 1, 2, 3); // [1, 2, 3]
// 类型名称
manager.invoke("typeOf", "abc"); // String
// 范围判断(与 condition 类 between 用法一致)
manager.invoke("between", 5, 1, 10); // true

图形面积与周长:

// 圆:πr² 与 2πr
manager.invoke("areaCircle", 2); // 12.566370614359172
manager.invoke("circumference", 2); // 12.566370614359172
// 矩形:长 × 宽
manager.invoke("areaRectangle", 3, 4); // 12.0
// 三角形:底 × 高 / 2;三边形式按海伦公式计算
manager.invoke("areaTriangle", 3, 4); // 6.0
manager.invoke("areaTriangle", 3, 4, 5); // 6.0
// 数值限幅
manager.invoke("clamp", 15, 0, 10); // 10

数论与排列:

// 阶乘、组合、排列
manager.invoke("factorial", 5); // 120
manager.invoke("combination", 5, 2); // 10(C(5,2))
manager.invoke("permutation", 5, 2); // 20(P(5,2))
manager.invoke("fibonacci", 10); // 55
// 公约数、公倍数
manager.invoke("gcd", 12, 18); // 6
manager.invoke("lcm", 4, 6); // 12
// 素数与 2 的幂
manager.invoke("isPrime", 7); // true
manager.invoke("isPowerOfTwo", 16); // true
// 直角三角形斜边长
manager.invoke("hypot", 3, 4); // 5.0

插值、映射与向量:

import java.util.Arrays;
// 线性插值:t=0 返回 a,t=1 返回 b
manager.invoke("lerp", 0, 10, 0.5); // 5.0
// 数值范围映射:把 [fromLow, fromHigh] 映射到 [toLow, toHigh]
manager.invoke("map", 5, 0, 10, 0, 100); // 50.0
// 两点距离:2D 四个参数 / 3D 六个参数
manager.invoke("distance", 0, 0, 3, 4); // 5.0
// 向量叉积(2D 标量):x1*y2 - y1*x2
manager.invoke("cross", 1, 0, 0, 1); // 1
// 向量点积:向量以 List 传入
manager.invoke("dot", Arrays.asList(1, 2), Arrays.asList(3, 4)); // 11.0
// 复数运算:返回 [实部, 虚部]
manager.invoke("complexAdd", 1, 2, 3, 4); // [4, 6]
manager.invoke("complexMultiply", 1, 2, 3, 4); // [-5, 10]
// 矩阵加法:矩阵以二维 List 传入
manager.invoke("matrixAdd",
Arrays.asList(Arrays.asList(1, 2)),
Arrays.asList(Arrays.asList(3, 4))); // [[4, 6]]
import com.github.paohaijiao.param.JContext;
// 字典数据存放在 JContext 中:key 为码值,value 为显示文本
JContext context = new JContext();
context.put("M", "男");
context.put("F", "女");
// translate(context, 码值) 返回字典文本
manager.invoke("translate", context, "M"); // 男
manager.invoke("translate", context, "F"); // 女

扩展只需三步:实现 → 注册 → 调用。

第一步:实现函数提供者。 推荐继承 JQuickBaseFunctionFunctionProvider,可直接使用 asString / asInt / asDouble / validateArgCount 等参数处理工具。

package com.example.function;
import com.github.paohaijiao.function.domain.JQuickBaseFunctionFunctionProvider;
import java.util.List;
/**
* 自定义函数:姓名脱敏
* maskName("张三") -> "张**"
*/
public class MaskNameFunctionProvider extends JQuickBaseFunctionFunctionProvider {
public MaskNameFunctionProvider() {
// 构造参数:函数名(调用时使用)、描述(前缀决定分组归属)
super("maskName", "[业务] 姓名脱敏,仅保留姓氏");
}
@Override
public Object invoke(List<Object> args) {
validateArgCount(args, 1);
String name = asString(args.get(0));
if (name == null || name.length() <= 1) {
return name;
}
return name.charAt(0) + "**";
}
}

第二步:注册 SPI。 创建文件 src/main/resources/META-INF/services/com.github.paohaijiao.function.core.JQuickMethodFunctionProvider,每行写一个实现类的全限定名:

com.example.function.MaskNameFunctionProvider

第三步:按名称调用。

Object masked = manager.invoke("maskName", "张三"); // 张**

简单函数也可以直接用 Lambda 注册,或用同名函数覆盖内置实现:

// 注册一个全新函数
manager.registerInvoker("doubleIt",
args -> ((Number) args.get(0)).doubleValue() * 2);
// 覆盖内置的 toUpper:返回结果追加感叹号
manager.registerOrReplaceInvoker("toUpper",
args -> String.valueOf(args.get(0)).toUpperCase() + "!",
"[覆盖] 自定义 toUpper");

jquick-sql 已直接依赖 jquick-transform-function。内置函数与按 SPI 注册的自定义函数,均可直接写在 SQL 语句中,由执行引擎按函数名从注册中心解析:

// 内置/自定义函数直接用于查询,无需额外注册动作
JQuickDataSet result = sql.execute(
"SELECT name, toCamelCase(name, '_') AS camel FROM users"
);

在 SQL 解析与审计场景中,函数调用本身是 AST 中的类型化节点,配合达梦、KingbaseES 等国产数据库做 SQL 审计、迁移改写时,可统一治理自定义函数。

搭配 jquick-excel:导入导出的数据清洗

Section titled “搭配 jquick-excel:导入导出的数据清洗”

jquick-excel 已直接依赖 jquick-transform-function。Excel DSL 中 TRANSFORM 表达式求值时会先按函数名从本组件的 SPI 注册中心查找,因此全部 259 个内置函数及自定义函数可直接用于导入导出:

-- 导出前:手机号脱敏、姓名脱敏
EXPORT WITH {
TRANSFORM = {"phone": "phoneMask(phone)", "name": "maskName(name)"}
}

导入时同理,可在读取入库前完成码值翻译、格式归一与字段清洗,业务侧无需再写转换代码。

  • 数据同步(ETL):异构系统间同步时做类型转换、码值字典翻译、格式归一。
  • 报表导出:Excel / PDF 报表导出前对手机号、银行卡、身份证等敏感字段脱敏。
  • 数据库字段值转换:在 SQL 内直接调用函数,把库内码值(如 1/0)转换为展示文本(如 是/否),适配达梦、KingbaseES 等国产库。
  • 数据清洗:对导入数据统一执行去空格、大小写规范、空值兜底、日期格式化等清洗规则。