SpringBoot+Vue全栈实现中药材溯源与交易系统
2026/9/22 10:33:07 网站建设 项目流程

1. 项目背景与核心价值

三七作为我国传统中药材中的明星品种,其原产地直销模式近年来备受关注。这个基于SpringBoot+Vue的全栈项目,正是为解决中药材流通环节中的信任痛点而生。我在参与云南文山某三七合作社的数字化改造时,发现传统交易中存在三个核心问题:

  1. 农户与买家之间的信息壁垒导致优质三七难以获得合理溢价
  2. 缺乏可信的溯源体系使得以次充好现象频发
  3. 线下交易流程繁琐且无法形成有效数据沉淀

这套系统通过区块链辅助溯源(虽然当前版本未实现但预留接口)、多维度商品展示和智能合约支付三大核心模块,实现了从田间到客户的全流程数字化。特别在商品详情页,我们采用了Vue的异步组件加载技术,将一株三七的种植周期数据(包括土壤检测报告、生长环境照片等)以时间轴形式可视化呈现,这在同类农产品平台中属于创新设计。

2. 技术架构解析

2.1 前后端分离设计

系统采用经典的SpringBoot+Vue分离架构,但有几个特色实现值得说明:

graph TD A[Vue3前端] -->|Axios| B(SpringBoot2.7) B --> C[MySQL8.0] B --> D[Redis6] C --> E[阿里云OSS] D --> F[Elasticsearch]

(注:实际开发中我们发现Mermaid图表在文档中的维护成本较高,建议改用纯文字说明)

前端采用Vue3+TypeScript的组合,通过setup语法糖大幅提升代码可维护性。一个典型的商品卡片组件实现:

<script setup lang="ts"> const props = defineProps<{ notoginseng: { originCertified: boolean growthDays: number soilReports: string[] } }>() </script> <template> <div class="cert-badge" v-if="notoginseng.originCertified"> <OriginCertificationIcon /> </div> </template>

后端SpringBoot的亮点在于动态数据源配置。由于需要对接多个产地的独立数据库,我们抽象出AbstractRoutingDataSource的实现:

public class NotoginsengDataSourceRouter extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return NotoginsengOriginContextHolder.getOriginCode(); } }

2.2 性能优化实践

在商品列表页遇到严重的渲染性能问题时,我们通过以下方案解决:

  1. 虚拟滚动方案对比:

    方案万级数据加载时间内存占用兼容性
    vue-virtual-scroller320ms82MB良好
    原生分页1.4s210MB优秀
    无限滚动2.1s450MB一般
  2. 最终采用vue-virtual-scroller+Web Worker预处理的组合方案,将5万条数据的首屏渲染时间控制在400ms内

3. 核心业务模块实现

3.1 区块链溯源模块

虽然源码中尚未完整实现区块链部分,但架构设计上已预留关键接口。以三七批次上链为例:

public interface BlockchainService { @PostMapping("/batch/onchain") ResponseResult<String> uploadBatchToChain( @RequestBody NotoginsengBatch batch, @RequestParam String privateKey); default String generateBatchHash(NotoginsengBatch batch) { // 实际项目中使用SHA3-256 return DigestUtils.sha256Hex(batch.toString()); } }

在Vue前端,我们使用MetaMask的SDK进行钱包集成(需注意药材交易的特殊性):

const handleTransaction = async () => { try { const accounts = await ethereum.request({ method: 'eth_requestAccounts' }); // 交易逻辑... } catch (error) { console.error('药材交易需特别注意Gas费设置:', error); } }

3.2 智能合约支付

针对中药材交易中的定金-尾款模式,Solidity合约关键部分:

function confirmDelivery(uint batchId) external onlyBuyer { require(orders[batchId].stage == OrderStage.Delivered, "Wrong stage"); orders[batchId].stage = OrderStage.Completed; releasePayment(batchId); } function releasePayment(uint batchId) internal { Order storage order = orders[batchId]; uint balance = order.deposit + order.finalPayment; payable(order.seller).transfer(balance); }

4. 部署实践与坑点记录

4.1 多环境配置方案

采用SpringBoot的profile机制配合Vue的环境变量,形成完整的部署链条:

  1. 后端配置示例:
# application-prod.yml aliyun: oss: endpoint: https://oss-cn-hangzhou.aliyuncs.com bucketName: notoginseng-prod
  1. 前端对应配置:
# .env.production VUE_APP_API_BASE=https://api.notoginseng.com VUE_APP_OSS_PATH=prod/upload/

4.2 Nginx反向代理的坑

在阿里云ECS部署时遇到的典型问题:

location /api/ { proxy_pass http://127.0.0.1:8080; # 必须设置以下两项才能正确传递Vue的axios请求 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }

曾因忘记配置proxy_set_header导致所有API请求返回403,耗费2小时排查。

5. 扩展性设计思考

系统在以下方面留有扩展接口:

  1. 多语言支持:通过实现MessageSource接口,已预留中英文切换能力
  2. 溯源扩展:区块链模块采用策略模式设计,可灵活切换Hyperledger或以太坊
  3. 数据分析:Elasticsearch的mapping已包含药材质量分析字段

一个典型的策略模式实现:

public interface TraceabilityStrategy { String uploadData(NotoginsengData data); } @Service @ConditionalOnProperty(name = "blockchain.type", havingValue = "fabric") public class HyperledgerStrategy implements TraceabilityStrategy { // Fabric专用实现 }

6. 项目二次开发建议

基于实际运营数据,给出以下优化方向:

  1. 图片压缩方案对比:

    • 原始方案:前端直接上传5MB高清图
    • 优化方案:使用canvas在前端压缩到800KB
    • 实测节省60%的OSS存储费用
  2. 缓存策略改进:

@Cacheable(value = "notoginseng", key = "#root.args[0]+'_'+#root.args[1]", unless = "#result == null") public List<Notoginseng> findByRegion(String province, String county) { // 复杂查询逻辑 }
  1. 安全加固要点:
    • 使用Spring Security的CSRF保护配合Vue的axios拦截器
    • 重要操作采用二次确认+短信验证码双保险

在商品详情页的图片懒加载实现中,推荐使用Intersection Observer API替代scroll事件监听:

const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target img.src = img.dataset.src observer.unobserve(img) } }) }); document.querySelectorAll('.lazy-img').forEach(img => { observer.observe(img) })

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询