三七作为我国传统中药材中的瑰宝,其药用价值在《本草纲目》中就有详细记载。随着现代人对健康养生的重视程度不断提高,三七的市场需求呈现爆发式增长。然而传统的线下销售模式存在信息不对称、流通环节多、价格不透明等问题。去年我在云南文山考察时,亲眼看到当地药农因为中间商压价而面临优质三七滞销的困境,这促使我决定开发这个原产地直连消费者的电商平台。
这个基于SpringBoot的三七销售平台,本质上是一个垂直领域的B2C电商系统,但相比综合电商平台,我们更注重三七这个单一品类的深度运营。平台直接对接云南文山、广西靖西等三七主产地的种植户和合作社,砍掉所有中间环节,让消费者能以实惠价格买到道地药材,同时保障药农获得合理收益。
在框架选型阶段,我们对比了传统的SSM架构和SpringBoot。最终选择SpringBoot主要基于以下几个实际考量:
快速启动优势:三七有明确的采收季节(每年9-11月),平台需要在采收季前完成开发和测试。SpringBoot的starter依赖和自动配置让我们在两周内就搭建起了基础框架,而同样的工作用SSM至少需要三周。
微服务友好性:考虑到未来可能对接多个产地的ERP系统,我们采用了模块化设计。比如将用户服务、商品服务、订单服务拆分为独立模块,通过Feign进行通信。这种架构下,SpringCloud生态的天然兼容性成为决定性因素。
运维便捷性:产地合作社的技术能力有限,SpringBoot的嵌入式Tomcat和统一配置管理大大降低了部署难度。我们甚至为合作社开发了一键部署脚本,只需执行java -jar命令即可启动服务。
三七商品有其特殊属性需要特别设计:
sql复制CREATE TABLE `sanqi_product` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`product_no` varchar(32) NOT NULL COMMENT '三七专属编码规则:SQ+产地代码+等级+年份',
`origin_id` int(11) NOT NULL COMMENT '原产地ID(文山/靖西等)',
`grade` tinyint(4) NOT NULL COMMENT '20头/30头等规格',
`drying_method` tinyint(4) NOT NULL COMMENT '晒干/烘干等加工方式',
`storage_years` smallint(6) NOT NULL COMMENT '储藏年限',
`pesticide_residue` decimal(10,2) DEFAULT NULL COMMENT '农残检测值',
`heavy_metal` decimal(10,2) DEFAULT NULL COMMENT '重金属检测值',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_product_no` (`product_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
注意:三七商品的唯一编码采用"SQ+产地拼音首字母+等级+年份"的规则,例如SQ-WS-30-2023表示2023年产文山30头三七。这种编码方式既便于人工识别,又满足系统检索需求。
消费者最关心的是三七的真实产地和质量。我们开发了完整的溯源功能:
区块链存证:使用Hyperledger Fabric记录种植、采收、检测、物流等关键环节数据。每个商品详情页都展示不可篡改的溯源二维码。
检测报告可视化:将第三方检测机构的农残、重金属等报告通过PDF.js在线展示,并提取关键指标用图表呈现:
java复制public Map<String, Object> parseDetectionReport(MultipartFile file) {
// 使用Apache PDFBox解析PDF
PDDocument document = PDDocument.load(file.getInputStream());
PDFTextStripper stripper = new PDFTextStripper();
String text = stripper.getText(document);
// 正则匹配关键指标
Pattern pattern = Pattern.compile("农药残留量:(\\d+\\.?\\d+)mg/kg");
Matcher matcher = pattern.matcher(text);
Map<String, Object> result = new HashMap<>();
if(matcher.find()) {
result.put("pesticide", Double.parseDouble(matcher.group(1)));
}
// 其他指标解析...
return result;
}
针对三七大宗交易需求,我们实现了两种特殊交易方式:
预售众筹:消费者可以提前半年以优惠价预订新产季三七,我们按订单量组织产地直采。采用Escrow账户管理资金,采收后15天内发货。
竞拍交易:对于稀有品种(如15头春七),采用荷兰式拍卖。核心算法如下:
java复制public void startAuction(Long productId, BigDecimal startPrice,
BigDecimal minPrice, BigDecimal step,
Duration duration) {
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
AtomicReference<BigDecimal> currentPrice = new AtomicReference<>(startPrice);
executor.scheduleAtFixedRate(() -> {
BigDecimal newPrice = currentPrice.get().subtract(step);
if(newPrice.compareTo(minPrice) >= 0) {
currentPrice.set(newPrice);
redisTemplate.opsForValue().set("auction:"+productId, newPrice);
websocketPushPriceUpdate(productId, newPrice);
} else {
executor.shutdown();
completeAuction(productId);
}
}, 0, 30, TimeUnit.SECONDS); // 每30秒降价一次
}
三七商品需要展示大量细节图片(断面、芦头、皱纹等),我们采用以下方案:
java复制Thumbnails.of(originalFile)
.size(800, 800)
.outputFormat("jpg")
.outputQuality(0.8)
.asBufferedImage();
针对三七商品"读多写少"的特点,设计多级缓存:
java复制Caffeine.newBuilder()
.maximumWeight(100_000)
.weigher((Long key, Product value) ->
value.getImages().size() * 10 + 100) // 图片越多占用权重越大
.build();
java复制public String sm4Encrypt(String plainText, String key) {
SM4Engine engine = new SM4Engine();
engine.init(true, new KeyParameter(key.getBytes()));
byte[] input = plainText.getBytes(StandardCharsets.UTF_8);
byte[] output = new byte[input.length];
for(int i=0; i<input.length; i+=16) {
engine.processBlock(input, i, output, i);
}
return Base64.getEncoder().encodeToString(output);
}
我们为每件商品配备NFC防伪标签,消费者可以用手机感应读取芯片内加密的产地信息。芯片采用SM7算法签名,无法伪造。
考虑到部分产区网络条件较差,我们开发了边缘计算方案:
离线模式:使用SQLite存储本地数据,网络恢复后自动同步到中心数据库。
轻量级客户端:为合作社开发的简易客户端只有15MB大小,可在低配电脑运行。
业务监控:跟踪各产地销售情况,当库存低于安全阈值时自动预警。
性能监控:通过Micrometer收集JVM指标,Grafana展示关键数据:
code复制management.endpoints.web.exposure.include=health,metrics,prometheus
management.metrics.export.prometheus.enabled=true
java复制spring.jackson.time-zone=GMT+8
spring.jpa.properties.hibernate.jdbc.time_zone=GMT+8
图片存储:曾用Base64直接存数据库,导致查询性能下降。后改为文件存储+数据库存路径。
短信轰炸:注册接口未做限流,被恶意调用发送验证码。增加滑动窗口限流后解决:
java复制@RateLimiter(value = 1, timeout = 5000, unit = TimeUnit.MINUTES)
public void sendVerifyCode(String phone) {
// 发送逻辑
}
这个项目给我最深的体会是:技术方案必须贴合业务场景。比如三七需要特殊的商品属性字段,交易模式要考虑药材行业特点。单纯套用通用电商方案会水土不服。下一步我们计划接入更多中药材品种,但会保持每个品类的专业特性。