简介本资源是一套基于Java实现的六爻起卦排盘小程序完整源码面向对周易文化与编程实践交叉领域感兴趣的开发者、传统文化爱好者及高校计算机相关专业学生旨在以现代编程方式还原传统六爻占卜的核心逻辑解决手工起卦繁琐、解读门槛高、学习成本大的问题。压缩包共17个文件含3个核心Java源文件实现起卦、爻位生成与卦象解析、5个编译后class文件、7个XML配置与构建文件含pom.xml及IDEA工程配置以及2个.gitignore文件整体仅28KB轻量易读结构清晰体现面向对象设计思想。已有263人学习下载代码严格遵循六爻规则模拟硬币起卦、纳甲装干支、世应定位、动爻判断等关键步骤并封装为可扩展模块附带完整Maven项目结构与标准目录组织便于快速理解算法流程、调试卦例或二次开发个性化解读功能。 做这个小程序之前我翻了不少开源项目结果发现网上流传的六爻起卦排盘源码大多有几个通病要么只处理了“起卦”这一步排盘全靠前端写死要么后端用脚本语言写得飞快但碰到干支历法、纳甲这些规则就全靠硬编码更常见的是代码根本没有工程结构拿到手根本跑不起来。所以这次我干脆用 Java 完整实现了一套六爻起卦排盘的后端逻辑再配合微信小程序做交互界面把起卦、装卦、纳甲、排六亲六神、定世应这一整条链路打通源码整理出来分享给大家。先说清楚这个项目解决什么问题它不是一个只用于演示的“静态卦表”而是一个正经可运行的规则引擎。用户在小程序里选择起卦方式输入时间或数字或者直接手动摇卦后端拿到请求后按传统六爻规则完成排盘返回结构化的卦象数据前端负责展示和分享。项目的定位是传统文化数字化工具适合对周易民俗文化感兴趣的 Java 开发者、小程序开发者以及想研究古典术数规则如何落地为代码的人参考学习。1. 项目概述与整体设计1.1 起卦排盘到底在做什么很多人第一次接触六爻代码项目时容易把“起卦”和“排盘”混为一谈。其实从计算机角度拆开看它们是完全不同层次的工作。起卦负责解决“输入怎么变成六个爻”的问题常见的输入来源有三种时间、数字、人为随机。时间起卦按农历年、月、日、时推算数字再通过取模运算得到上卦、下卦和动爻数字起卦则直接用用户输入的数字做同样的映射手动摇卦是让用户模拟抛六次铜钱每次产生一个阴爻或阳爻。起卦的输出是一组爻序列比如从初爻到上爻分别是“少阳、少阴、老阳、少阴、少阴、少阳”。排盘则是把这一组爻序列展开成一张完整的盘面它要做的事包括根据本卦确定所属八宫给六个爻配上地支和天干标出世爻和应爻根据宫位五行和卦宫五行的生克关系排出六亲再根据起卦日的天干排出六神。这些规则环环相扣一个地支记错就会引发连锁错误所以代码实现里最关键的是把规则表沉淀成可校验的数据结构而不是散落在一堆 if else 里。1.2 技术选型Java 后端加小程序前端既然要处理复杂的卦象规则后端语言我毫不犹豫选了 Java。原因很朴素第一Java 的工程化生态成熟Spring Boot 一键启动接口调试、日志、异常处理都有现成方案第二它处理日期和数学运算非常稳定尤其适合干支历法这类需要大量日期偏移计算的场景第三面向对象建模可以把“卦”“爻”“盘面”这些概念映射得很自然。前端为什么选微信小程序核心是因为分发方便用户不用安装 App分享一个卡片就能打开非常契合这类轻量工具型应用。小程序端使用原生框架开发组件丰富radio 单选框、button、canvas 绘制这类需求都有成熟方案不需要引入额外 UI 库。完整源码分为两个目录backend 是 Java 后端工程frontend 是小程序工程。我用 Spring Boot 提供 REST 接口用 Hutool 的日期工具辅助农历计算小程序端则全部使用原生组件没有额外依赖。整体架构前后端分离接口只返回 JSON 数据以后如果想把算法迁移到其他前端后端代码完全不用改动。1.3 项目目录结构与源码模块划分拿到源码后建议先看目录结构整个项目的模块划分是这样的liuyao-app/ ├── backend/ │ ├── pom.xml │ └── src/main/java/com/liuyao/ │ ├── LiuYaoApplication.java │ ├── controller/ │ │ └── GuaController.java │ ├── service/ │ │ ├── QiGuaService.java │ │ ├── PaiPanService.java │ │ └── LiuYaoService.java │ ├── model/ │ │ ├── Gua.java │ │ ├── Yao.java │ │ └── PaiPanResult.java │ ├── enums/ │ │ ├── YinYangEnum.java │ │ ├── WuQinEnum.java │ │ └── LiuShenEnum.java │ ├── constant/ │ │ └── GuaConstant.java │ └── util/ │ ├── CalendarUtil.java │ └── GanZhiUtil.java └── frontend/ ├── app.json ├── pages/ │ ├── index/ │ │ ├── index.wxml │ │ ├── index.wxss │ │ ├── index.js │ │ └── index.json │ └── result/ │ ├── result.wxml │ ├── result.wxss │ ├── result.js │ └── result.json └── utils/ └── request.js这个结构是我在实际迭代中逐步调整出来的。最初我把所有规则都写在 Controller 里结果发现一个接口上千行根本没法维护。后来拆成了 service 层负责业务流程util 层负责纯算法model 层定义数据模型枚举类维护固定规则代码才变得清爽。建议你在二次开发时不要破坏这个分层尤其是“算法工具类”和“业务编排”一定要分离排盘规则后续大概率要调整分开了改起来才不伤筋动骨。2. 起卦排盘核心算法解析2.1 三种起卦方式的规则拆解时间起卦是最常用也最稳定的方式。传统规则是这样的先算出当前的农历年、月、日、时以农历年支的地支序数作为年数农历月数作为月数农历日数作为日数时辰的地支序数作为时数。上卦取“年数 月数 日数”除以 8 的余数下卦取“年数 月数 日数 时数”除以 8 的余数动爻取“年数 月数 日数 时数”除以 6 的余数。除尽时按余数 8 或 6 处理这个细节特别容易写错。数字起卦的逻辑和它类似区别在于数字来源。通常支持两种输入方式输入一个数字或者是三个数字。一个数字时直接按 8 取上卦按 6 取动爻下卦则需要再补充一个数字三个数字时第一个数取上卦第二个数取下卦第三个数取动爻。为了统一我的实现里支持任意个数的数字输入通过参数动态截取前两个参与卦象计算最后一个参与动爻计算。手动摇卦是最有仪式感的方式小程序端模拟六次掷币每次生成一个爻。传统规则里铜钱正面记为“阳”反面记为“阴”三枚铜钱组合出四种结果三个正面为老阳三个反面为老阴两正一反为少阳两反一正为少阴。其中老阳和老阴属于动爻会有变卦的后续逻辑。后端设计上手动摇卦与前两种方式的差异在于“输入源不同”一旦拿到六个爻的阴阳属性后面的排盘流程完全一致所以代码里我把“生成爻序列”和“排盘”拆分成了两个服务方便复用。2.2 装卦阶段纳甲、世应、六亲、六神拿到本卦的六个爻之后排盘就开始了。第一步是确定卦宫。六十四卦被分为八宫每宫八个卦由本宫卦八纯卦逐爻变化衍生出来。先通过本卦的上下卦组合查表得到它属于哪一宫这是后续所有排盘信息的基础。我在 GuaConstant 里用了一张静态映射表把六十四卦的上下卦组合映射到宫位和世应位置这张表是整个排盘规则的核心建议你调试时多花时间核对。第二步是纳甲也就是给每个爻配上地支。纳甲规则按卦宫分阴阳乾卦内卦三爻配子、寅、辰外卦三爻配午、申、戌坤卦内卦配未、巳、卯外卦配丑、亥、酉。其他六卦的纳甲规则也都有章可循。我实现时没有把六十四卦的地支全写死而是按“内卦三爻和外卦三爻分别查表”的方式动态拼接这样既减少出错也方便调试。第三步定世应。世爻表示卦主应爻表示对方它们的固定位置由卦在八宫中的排列顺序决定。例如八纯卦世爻在第六爻一世卦在初爻二世卦在二爻依此类推。我把每个卦的世应位置直接放在常量表里排盘时按宫位查表得到位置下标。第四步排六亲。六亲的依据是卦宫五行和每一爻地支五行的生克关系生我者为父母我生者为子孙克我者为官鬼我克者为妻财比和者为兄弟。这里宫位五行的“我”加上爻地支的五行关系用五行生克表就能推导出。第五步排六神。六神按起卦日的天干确定顺序甲乙日起青龙丙丁日起朱雀戊日起勾陈己日起腾蛇庚辛日起白虎壬癸日起玄武。然后从初爻到上爻按固定顺序排列分别是青龙、朱雀、勾陈、腾蛇、白虎、玄武。2.3 排盘数据流与结果输出模型整条数据流可以概括为输入源 - 爻序列 - 本卦 - 变卦 - 宫位 - 纳甲 - 世应 - 六亲 - 六神 - 结构化结果。我用 Gua 对象表示一个卦里面包含六个 Yao 对象每个 Yao 对象记录阴阳属性、是否为动爻、对应地支、五行、六亲、六神、世应标记。排盘结果对象 PaiPanResult 则持有本卦、变卦、起卦时间、起卦方式、世应位置等元信息最终序列化为 JSON 返回前端。前端只需要拿到这份结构化的 JSON就可以按自己的设计渲染任意风格不用关心计算逻辑。这里有一个关键点动爻。如果起卦结果里有动爻就需要额外生成一个变卦。变卦规则很简单动爻的阴阳属性翻转即可老阳变阴老阴变阳。如果六个爻全部是静爻则没有变卦。实际项目中动爻数量直接影响排盘结果的复杂程度所以后端返回数据时我会把“本卦”“变卦”“动爻列表”分开字段方便前端做差异化展示。3. 关键代码实现与细节拆解3.1 干支历法与农历日期的计算六爻排盘离不开干支尤其是日干支因为六神排列以日干为基准。Java 标准库没有直接提供农历和干支计算能力所以我封装了一个 CalendarUtil核心思路是用“基准日期偏移”的方式计算。实现上我以某个已知干支的日期为基准点计算目标日期与基准点的天数差然后对 60 取模得到目标日期的干支序号。需要注意的是时间的获取必须统一使用 Asia/Shanghai 时区否则不同的服务器时区会导致结果偏差。农历部分的处理相对麻烦因为有闰月概念。Hutool 的 ChineseDate 组件支持农历和公历互转在实际开发中我直接复用它。如果你不想引入额外依赖也可以把农历全年数据表硬编码进常量类但那样代码量会膨胀而且容易出错。我在项目里用的是亨特尔算法配合 ChineseDate既保证准确度也降低了维护成本。3.2 时间起卦的实现代码时间起卦的入口在 QiGuaService核心逻辑可以浓缩成下面这段代码。注意这里的重点是取模运算的细节处理尤其是“除尽按 8 或按 6”的问题。public Gua qiguaByTime(LocalDateTime dateTime, ZoneId zone) { // 1. 转农历获取农历年支、月、日、时 ChineseDate chineseDate CalendarUtil.toChineseDate(dateTime, zone); int yearZhi GanZhiUtil.getYearZhiIndex(chineseDate.getYear()); int month chineseDate.getMonth(); int day chineseDate.getDay(); int hourZhi GanZhiUtil.getHourZhiIndex(dateTime.getHour()); // 2. 计算上卦、下卦、动爻 int upGua (yearZhi month day) % 8; if (upGua 0) { upGua 8; } int downGua (yearZhi month day hourZhi) % 8; if (downGua 0) { downGua 8; } int dongYao (yearZhi month day hourZhi) % 6; if (dongYao 0) { dongYao 6; } // 3. 根据上下卦数字得到本卦六爻再翻转动爻得到变卦 Gua benGua GuaConstant.buildGuaByNumber(upGua, downGua, dongYao); benGua.setDongYaoIndex(dongYao); Gua bianGua benGua.copy(); bianGua.flipYao(dongYao - 1); // 4. 后续由 PaiPanService 继续完成装卦 return benGua; }这段代码看起来简单但有几个容易踩的坑。第一年月日时数字的来源必须统一比如年必须用“年支的序数”而不是农历年份本身否则结果完全不同。第二上卦和下卦的计算公式不一样别把时数加到上卦里。第三动爻取 6 时代表第六爻动数组下标要减 1别越界。3.3 摇卦随机数与并发处理手动摇卦的随机性处理我一开始用的是 Math.random()后来在压测时发现并发请求下容易出现“连续摇出同样六个爻”的诡异情况。原因是 Math.random() 底层用的 Random 并不是强随机而且多线程共享同一个 Random 实例时会出现竞争问题。换成 SecureRandom 之后问题明显改善。SecureRandom 属于密码学安全的随机数生成器生成质量更高但调用开销也更大。考虑到摇卦操作的并发量并不会特别高直接使用 SecureRandom 是划算的。如果后续要支撑高并发可以在项目里用 ThreadLocal 持有 SecureRandom 实例避免每次请求都重新初始化。摇卦的映射逻辑是这样的每次生成一个 0 到 3 的随机整数0 代表三个反面老阴1 代表两正一反少阳2 代表两反一正少阴3 代表三个正面老阳。这个映射顺序要和小程序端的动画效果保持一致否则会出现“前端显示正面后端却记为反面”的错位。3.4 排盘数据结构设计与前端对接我把排盘结果的数据模型设计成了三层嵌套结构第一层是本次排盘的整体信息第二层是本卦和变卦第三层是每个爻的细节。这样设计的好处是前端拿到一份 JSON 就能一次性渲染完整盘面不需要多次请求。public class PaiPanResult { private Gua benGua; private Gua bianGua; private String qiGuaType; // 起卦方式 private String dateTime; // 起卦时间 private Integer shiYaoIndex; // 世爻位置 private Integer yingYaoIndex; // 应爻位置 } public class Gua { private String guaName; // 卦名 private String guaGong; // 所属宫 private ListYao yaos; // 六个爻 private Integer dongYaoIndex; // 动爻位置无则为 null } public class Yao { private Integer index; // 爻位置0 到 5 private YinYang yinYang; // 阴阳 private String diZhi; // 地支 private String wuXing; // 五行 private String wuQin; // 六亲 private String liuShen; // 六神 private Boolean isDong; // 是否动爻 private Boolean isShi; // 是否世爻 private Boolean isYing; // 是否应爻 }这样设计后后端代码的职责非常清晰QiGuaService 只负责产出本卦和变卦PaiPanService 负责给卦里的每个爻补齐纳甲、六亲、六神、世应信息Controller 则负责拼装响应。小程序端拿到这份 JSON 后直接循环渲染六个爻的卡片就能得到一个完整的盘面。4. 小程序前端的交互与展示实现4.1 起卦交互页面与单选框使用小程序首页的设计很直白顶部标题中间一个 radio-group 让用户选择起卦方式下方根据选择动态显示不同的输入区底部是“开始排盘”按钮。radio-group 的具体用法是在 radio-group 里放多个 radio 组件每个 radio 的 value 是字符串通过 bindchange 事件取到用户选中的值。实际开发中有一个容易忽略的细节radio 的 value 是字符串类型如果你在后端接口里期望接收整数前端必须先用 parseInt 转换否则很容易出现类型不匹配的问题。三种起卦方式的输入区是动态切换的。时间起卦方式不需要输入任何内容直接读取手机本地时间由后端计算农历和干支数字起卦方式需要用户输入一个或三个数字手动摇卦方式则显示“开始摇卦”按钮点击一次生成一爻一共点六次。动态切换用 wx:if 和 wx:elif 控制注意每个输入区都要有独立的 data 绑定避免切换时残留上一次的数据。4.2 后端请求封装与状态管理小程序请求后端统一走 utils/request.js 封装函数内部使用 wx.request 发送请求并统一处理 loading、错误提示和超时。封装的核心是返回一个 Promise这样页面代码可以用 async/await 风格编写逻辑会更清爽。接口地址配置在小程序后台的“开发设置”里需要加入 request 合法域名。本地开发时可以在开发者工具里勾选“不校验合法域名”但上线前一定要换成 HTTPS 域名。我在项目里用了一个最小代码片段来展示请求封装逻辑function post(url, data) { return new Promise((resolve, reject) { wx.request({ url: BASE_URL url, method: POST, data: data, timeout: 10000, success: (res) { if (res.data.code 0) { resolve(res.data.data); } else { wx.showToast({ title: res.data.msg, icon: none }); reject(res.data); } }, fail: (err) reject(err) }); }); }这里有个交互细节要提醒时间起卦时前端拿到的本地时间可能和服务器时间有偏差严谨的做法是前端请求一个时间同步接口用服务器时间作为起卦时间否则用户手机时间不准会直接影响排盘结果。我在实际开发中增加了这个时间校准逻辑虽然多了一次请求但结果准确性提升很多。4.3 卦象渲染与分享输出结果页的盘面展示是整个小程序的门面。我采用了列表卡片形式每一行代表一个爻显示六神、六亲、地支、世应标记并用不同的背景色区分阳爻和阴爻。动爻则用特殊边框高亮让用户一眼就能看出变卦的位置。六爻的卦象符号我用简单字符来绘制阳爻显示为一条实线阴爻显示为两条短线在 canvas 里绘制会更加美观不过普通场景下 view 组件加上 CSS 也能实现不错的效果。考虑到小程序的包体积和渲染性能我没有引入图表库全部用基础组件实现。分享功能利用小程序的 button open-typeshare 即可onShareAppMessage 里拼接当前页面的参数。为了让分享出去的卡片包含盘面信息我会在分享路径中带上排盘结果的 id接收方打开时通过 id 请求后端重新拉取数据。这里一定要注意不要在分享路径里塞太多参数否则 URL 长度超限会报错。5. 常见问题与排查实录5.1 时间计算中的时区与闰月坑我调试时遇到最诡异的问题是本地运行正常部署到云服务器后时间起卦的结果和本地差了整整一个时辰。排查了大半天最终发现是服务器默认时区是 UTC而中国用的东八区LocalDateTime 转 Date 时偏移了 8 小时。解决办法是启动类里显式指定时区或者统一使用带时区的 ZonedDateTime。第二个坑是闰月。农历闰月会导致月份数字不连续直接拿 ChineseDate.getMonth() 在闰月年份会得到特殊标记。Hutool 的 ChineseDate 在处理闰月时会返回闰月标记你必须判断当前是否处于闰月否则“闰四月”会被当成“五月”计算起卦结果全错。建议给 CalendarUtil 增加一个返回值对象既包含月序数也包含是否闰月标记方便上层做判断。5.2 并发场景下的随机数与限流时间起卦接口本身是无状态的但手动摇卦因为涉及随机数生成器并发时会概率性出现重复随机序列。前面提到换用 SecureRandom 后问题减少但还有一个隐患如果同一用户在一秒内连续点击“开始排盘”后端拿到的时间完全相同时间起卦的结果也一样这是符合传统规则的但从产品体验看用户会觉得异常。我的处理方式是接口幂等同一用户在同一分钟内的重复请求直接返回最近一次的结果而不是重新计算。实现上用一个 Caffeine 本地缓存key 是用户 id 加分钟时间戳value 是上一次排盘结果。这个方法也顺带降低了后端压力一举两得。5.3 小程序审核与渲染性能优化小程序上线时审核最关注的是类目和描述。我给这个工具设的类目是“工具 信息查询”描述里明确写出“传统文化排盘演示结果仅供学习交流”避免使用“占卜预测”这类敏感词这样能减少审核被驳回的概率。渲染性能上也有一个经验要分享六十四卦的卦名数据在结果页高频使用如果每次加载都请求后端用户流量消耗大而且白屏时间长。我后来把卦名、卦宫、纳甲表这些稳定的静态数据做成了本地 JSON直接随小程序包加载启动时读到全局变量里。只有真正的排盘请求才走后端接口这样体验会流畅很多。如果你后续想把项目扩展到更多平台可以把前端改成 uni-app 或 Taro后端完全不用动。因为接口层已经足够通用任何能发 HTTP 请求的客户端都能接入。这也是我在设计初期坚持前后端分离的原因。这个项目做完之后我最大的感受是传统文化里的很多规则模型一旦拆解成清晰的映射关系落地的难度其实比想象中要低。真正的坑往往藏在细节里比如时区、闰月、取模边界、随机数并发这些才是考验工程经验的地方。后续我还打算把排盘结果的解释库补上做成一个完整的文化学习工具。源码里的目录结构、枚举设计和常量表都是我踩过坑之后沉淀下来的希望能帮你少走一点弯路。本文还有配套的精品资源点击获取