简介本资源是一套基于SpringBoot的Java后台管理系统源码面向需要将SAP系统数据与外部系统打通的企业开发者和Java后端学习者。项目整合Spring、Spring MVC、MyBatis-Plus、Druid、Shiro、Thymeleaf、Quartz等技术栈核心亮点是通过sapjco3调用SAP的RFC函数实现数据获取与回传并以接口形式对外提供服务同时借助Quartz完成定时同步任务前端采用轻量级路由与MVVM方案实现单页面、响应式、简约的后台界面。压缩包共336个文件以98个java源码、41个js脚本、28个html页面、25个css样式为主另含xml、yml、properties配置及sql脚本、字体与本地库文件整体约9.46MB结构完整便于二次开发。目前已有432人学习下载适合想掌握SAP RFC集成、权限控制与定时任务调度的中高级开发者参考借鉴。1. 从一次接口对账说起这套 SAP 集成方案到底解决什么问题做过企业系统对接的工程师大概都遇到过这种场景业务系统里跑完一轮采购入库财务同事拿着 SAP 里的凭证号来对账两边数据对不上查日志发现 RFC 调用超时了但业务单据已经提交SAP 那边却没收到。这种「业务已提交、SAP 未落账」的中间态是 SAP 集成项目里最典型的翻车现场。这套方案要解决的核心问题就是用 SpringBoot MyBatis Thymeleaf Quartz 2 Shiro sapjco 搭一套 Web 系统把与 SAP 的 RFC 交互做成可管理、可重试、可审计的闭环而不是散落在业务代码里的几行 JCo 调用。它适合正在做企业级系统集成毕设的学生也适合需要交付一套 SAP 外围系统方案的从业者。关键词 JavaScript 在这里的角色是前端交互层Thymeleaf 模板里嵌的校验和异步请求都靠它兜底。2. 技术选型与总体架构六个组件各自扛什么活2.1 为什么是这套组合而不是别的先把选型逻辑讲清楚不然后面模块划分没有依据。SpringBoot 负责容器和自动装配省掉大量 XMLMyBatis 做数据持久化因为 SAP 交互日志、任务记录、用户权限这些表结构相对固定用注解加 XML 混合写 SQL 比 JPA 更可控Thymeleaf 做服务端渲染适合后台管理类页面不需要前后端分离那套构建链Quartz 2 承担定时任务和失败重试调度Shiro 管认证授权sapjco 是 SAP 官方提供的 Java 连接器负责 RFC 调用。这里有个容易踩的坑sapjco 的本地库文件.so 或 .dll必须和 JVM 架构匹配32 位 JDK 配 64 位 sapjco 直接报 UnsatisfiedLinkError。我一般会在项目启动时加一个环境自检把 sapjco3.jar 和本地库路径打印出来省得部署到服务器才发现。2.2 分层结构与模块职责整体分四层接入层Controller Thymeleaf、业务层Service、集成层SAP RFC 调用封装、调度层Quartz Job。每层职责边界要卡死尤其是集成层所有 JCo 连接、目标系统、仓库对象的获取和销毁都必须在这一层完成业务层不允许直接碰 JCoDestination。// 集成层SAP RFC 调用统一封装 Component public class SapRfcExecutor { // 从连接池获取目标避免每次新建连接 public JCoFunction execute(String functionName, MapString, Object params) { JCoDestination destination null; try { destination JCoDestinationManager.getDestination(SAP_PRD); JCoFunction function destination.getRepository().getFunction(functionName); if (function null) { throw new RuntimeException(RFC 函数不存在: functionName); } // 参数填充按 SAP 结构逐字段映射 params.forEach((k, v) - function.getImportParameterList().setValue(k, v)); function.execute(destination); return function; } catch (JCoException e) { // 记录失败日志交给 Quartz 重试 throw new SapRfcException(RFC 调用失败: functionName, e); } } }这段代码的关键点在于目标系统通过JCoDestinationManager获取连接参数配在sapjco3.properties或环境变量里函数不存在时直接抛异常而不是返回 null避免上层空指针异常统一包装成自定义异常方便 Quartz 判断是否重试。参数映射那块SAP 的 import 参数有严格类型字符串长度超了会截断数字类型传错会报转换异常这些都要在 Service 层做前置校验。2.3 数据库表设计要点MyBatis 这边至少需要四张核心表用户权限表Shiro 用、RFC 调用日志表、定时任务配置表、业务单据与 SAP 凭证映射表。日志表要记录请求参数、返回消息、耗时、状态方便对账时追溯。任务配置表存 Cron 表达式和重试次数上限。映射表是解决「业务已提交、SAP 未落账」的关键每条业务单据生成一个唯一请求号SAP 返回凭证号后回写重试时先查映射表判断是否已成功。3. RFC 交互模块实现从连接管理到异常重试3.1 连接池与目标系统配置sapjco 本身没有连接池概念但JCoDestination是线程安全的可以复用。我一般会在 SpringBoot 启动时初始化一个JCoDestination单例配在Configuration里而不是每次调用都getDestination。连接参数包括 ASHOST、SYSNR、CLIENT、USER、PASSWD、LANG这些敏感信息不要硬编码走环境变量或配置中心。# application.yml 中 SAP 连接配置 sap: destination: SAP_PRD ashost: ${SAP_ASHOST} sysnr: 00 client: 100 user: ${SAP_USER} passwd: ${SAP_PASSWD} lang: ZH pool: max-active: 10 max-wait: 5000参数说明sysnr是 SAP 系统编号两位字符串client是客户端号通常三位pool那块是自定义的连接等待参数sapjco 原生不支持需要在封装层用信号量控制并发。如果并发量不大直接复用单例目标即可不用过度设计。3.2 同步调用与异步任务的分工不是所有 RFC 都适合同步调。查询类接口比如查物料主数据可以同步用户点一下等两秒能接受但创建采购订单、过账这类写操作建议走 Quartz 异步任务。流程是业务层先落本地单据状态置为「待同步」然后触发 Quartz JobJob 里调 RFC成功回写凭证号失败按策略重试。// Quartz Job异步执行 RFC 并处理重试 public class SapSyncJob implements Job { Override public void execute(JobExecutionContext context) { Long billId context.getMergedJobDataMap().getLong(billId); Bill bill billMapper.selectById(billId); // 幂等检查已同步成功的直接跳过 if (SYNCED.equals(bill.getSyncStatus())) { return; } try { JCoFunction result sapRfcExecutor.execute(ZRFC_CREATE_PO, buildParams(bill)); String sapDocNo result.getExportParameterList().getString(EV_DOCNO); bill.setSapDocNo(sapDocNo); bill.setSyncStatus(SYNCED); billMapper.updateById(bill); } catch (SapRfcException e) { // 重试次数从 JobDataMap 取超过上限置为 FAILED int retry context.getMergedJobDataMap().getInt(retry); if (retry 3) { bill.setSyncStatus(FAILED); billMapper.updateById(bill); } else { // 重新调度延迟 5 分钟 scheduleRetry(billId, retry 1); } } } }这段逻辑的核心是幂等和重试上限。幂等靠syncStatus判断重试靠 Quartz 的JobDataMap传参。注意scheduleRetry要新建 Trigger不能复用原 Trigger否则会覆盖。重试间隔建议递增第一次 1 分钟第二次 5 分钟第三次 15 分钟给 SAP 侧足够的恢复时间。3.3 返回结果解析与错误码映射SAP RFC 的返回结构通常是EV_TYPES 成功 / E 错误、EV_MESSAGE消息文本、EV_DOCNO凭证号。解析时要先判EV_TYPE是 E 就直接抛业务异常不要往下走。错误码映射建议维护一张配置表把 SAP 的原始消息转成业务方能看懂的中文提示比如「物料不存在」对应「请检查物料编码是否正确」。4. 权限与页面层Shiro 和 Thymeleaf 怎么配合4.1 Shiro 认证授权的最小闭环Shiro 的配置分三块SecurityManager、Realm、FilterChainDefinitionMap。Realm 里做数据库查询doGetAuthenticationInfo校验用户名密码doGetAuthorizationInfo加载角色和权限。FilterChain 里把/sap/**路径拦下来要求sap:execute权限。Configuration public class ShiroConfig { Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean factory new ShiroFilterFactoryBean(); factory.setSecurityManager(securityManager); MapString, String chain new LinkedHashMap(); chain.put(/login, anon); chain.put(/sap/**, authc, perms[sap:execute]); chain.put(/**, authc); factory.setFilterChainDefinitionMap(chain); return factory; } }注意LinkedHashMap的顺序/**必须放最后否则前面的规则会被覆盖。权限字符串建议按「模块:操作」命名方便后期扩展。4.2 Thymeleaf 页面里的 JavaScript 交互Thymeleaf 负责渲染但页面上的异步操作、表单校验、RFC 调用进度轮询还是靠 JavaScript。比如触发同步后前端每隔 3 秒查一次任务状态成功就刷新列表失败就弹提示。// 轮询同步状态避免用户手动刷新 function pollSyncStatus(billId) { const timer setInterval(async () { const res await fetch(/sap/sync/status?billId${billId}); const data await res.json(); if (data.status SYNCED) { clearInterval(timer); location.reload(); } else if (data.status FAILED) { clearInterval(timer); alert(同步失败请联系管理员查看日志); } }, 3000); }这段代码的关键是clearInterval的时机成功和失败都要清否则轮询会一直跑。另外接口要加超时和最大轮询次数防止死循环。5. 避坑与常见问题排查5.1 RFC 调用超时但 SAP 实际已执行现象日志显示JCoException: timeout但 SAP 里凭证已经生成了。原因网络抖动或 SAP 侧处理慢客户端超时先返回服务端其实完成了。解决所有写操作必须做幂等用业务唯一请求号在 SAP 侧查重重试前先查一次是否已存在。5.2 sapjco 本地库加载失败现象启动报UnsatisfiedLinkError: no sapjco3 in java.library.path。原因本地库路径没配或架构不匹配。解决-Djava.library.path/path/to/sapjco启动参数加上确认 JDK 位数和库文件一致Linux 下还要检查LD_LIBRARY_PATH。5.3 Quartz 任务重复执行现象同一条单据被同步了两次SAP 里出现两张凭证。原因集群环境下多个节点同时触发或者 Trigger 配置了misfire策略不当。解决用数据库锁或 Quartz 的DisallowConcurrentExecution注解任务执行前先查状态。5.4 Shiro 权限缓存导致改权限不生效现象管理员改了用户权限但用户不重新登录还是旧权限。原因Shiro 默认缓存了 AuthorizationInfo。解决改权限后调shiroRealm.clearCachedAuthorizationInfo(principals)或者配一个较短的缓存过期时间。5.5 Thymeleaf 页面 JavaScript 被转义现象页面里写的script标签内容被当成文本显示。原因Thymeleaf 的th:inline没开或用了th:text输出。解决内联脚本用th:inlinejavascript或者把 JS 抽到独立文件用th:src引入。6. 验收与答辩怎么证明这套方案真的跑通了验收分三块功能、异常、性能。功能上至少跑通一条完整链路——登录、建单据、触发同步、SAP 生成凭证、回写凭证号、页面展示。异常上模拟 SAP 宕机、网络超时、权限不足三种场景看系统是否按预期重试或报错。性能上用 JMeter 压 50 并发同步请求观察响应时间和成功率。答辩时导师最爱问的是「你怎么保证不重复过账」。这时候把幂等设计讲清楚业务唯一请求号 SAP 侧查重 本地状态机。最好现场演示一次「手动把状态改回待同步再触发一次看 SAP 是否拒绝重复创建」。这个演示比任何 PPT 都有说服力。验收项合格标准验证方式RFC 同步成功率正常网络下 100%连续跑 20 条单据异常重试3 次内自动恢复模拟 SAP 短暂不可用幂等性重复触发不产生新凭证手动改状态后重跑权限控制无权限用户无法调用用低权限账号访问 /sap/**日志完整性每次调用有请求和返回记录查日志表条数我一般会在答辩前把「SAP 宕机后恢复」这个场景录成视频因为现场演示依赖 SAP 环境万一网络出问题就尴尬了。从那以后我每次做集成项目都强制走一遍「断网重试 幂等校验」的验收流程宁可多花半小时也不在答辩现场赌运气。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?