宠物用品电商平台作为垂直细分领域的典型代表,近年来随着养宠人群的扩大呈现爆发式增长。这个基于SpringBoot+Vue的宠物用品交易平台系统,采用了主流的前后端分离架构,为中小型宠物用品商家提供了完整的电商解决方案。
我在实际开发中发现,宠物用品交易与传统电商相比有几个显著特点:商品品类特殊(如宠物食品有严格的保质期要求)、用户决策周期长(需要比较成分、适口性等)、复购率高(主粮等消耗品)。这些特性在系统设计时都需要特别考虑。
Spring Boot 2.7.x作为后端框架,主要基于以下考量:
数据库设计时特别注意了宠物用品的特殊属性:
sql复制CREATE TABLE `pet_product` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`category_id` int(11) NOT NULL COMMENT '食品/玩具/清洁等分类',
`shelf_life` int(11) DEFAULT NULL COMMENT '保质期(天)',
`ingredient` text COMMENT '成分表',
`for_pet_type` varchar(20) DEFAULT NULL COMMENT '适用宠物类型',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Vue 3.x + Element Plus的组合带来了以下优势:
一个典型的商品卡片组件实现:
vue复制<template>
<el-card class="product-card" @click="goDetail">
<el-image :src="product.cover" fit="cover" lazy />
<div class="price">{{ product.price | currency }}</div>
<div class="title">{{ product.name }}</div>
<el-tag v-if="product.shelfLife < 30" type="warning">临期商品</el-tag>
</el-card>
</template>
采用RBAC模型实现多级权限控制,核心设计包括:
关键的安全配置类:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/api/seller/**").hasAnyRole("SELLER","ADMIN")
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()));
}
}
针对宠物用品特点实现了:
后台管理接口示例:
java复制@RestController
@RequestMapping("/api/product")
public class ProductController {
@Autowired
private ProductService productService;
@PostMapping
@PreAuthorize("hasRole('SELLER')")
public R addProduct(@Valid @RequestBody ProductDTO dto) {
return R.ok().put("data", productService.saveProduct(dto));
}
@GetMapping("/expiring")
public R getExpiringProducts(@RequestParam int days) {
return R.ok().put("data", productService.findExpiringProducts(days));
}
}
基于用户行为数据实现:
推荐服务核心逻辑:
java复制public List<Product> recommendProducts(Long userId) {
// 1. 获取用户最近浏览
List<Long> viewHistory = redisTemplate.opsForList()
.range("user:view:"+userId, 0, 10);
// 2. 查找相似用户
Set<Long> similarUsers = findSimilarUsers(userId);
// 3. 合并推荐结果
return mergeRecommendations(viewHistory, similarUsers);
}
针对宠物食品的特殊性设计了:
订单状态机实现:
java复制public enum OrderStatus {
UNPAID(1, "待支付") {
@Override
public boolean canChangeTo(OrderStatus next) {
return next == PAID || next == CANCELLED;
}
},
PAID(2, "已支付") {
@Override
public boolean canChangeTo(OrderStatus next) {
return next == SHIPPED || next == REFUNDING;
}
};
// 其他状态省略...
}
采用多级缓存架构:
缓存配置示例:
java复制@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
manager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(1000));
return manager;
}
}
针对电商场景特别优化:
分库分表配置:
yaml复制spring:
shardingsphere:
datasource:
names: ds0,ds1
sharding:
tables:
product:
actual-data-nodes: ds$->{0..1}.product_$->{0..15}
table-strategy:
inline:
sharding-column: id
algorithm-expression: product_$->{id % 16}
实现方案:
支付验证逻辑:
java复制public boolean verifyPayment(PaymentDTO dto) {
// 1. 验证签名
if (!signatureService.verify(dto.getSign())) {
throw new BusinessException("签名验证失败");
}
// 2. 防重放检查
if (redisTemplate.opsForValue().setIfAbsent(
"payment:nonce:"+dto.getNonce(), "1", 5, TimeUnit.MINUTES)) {
throw new BusinessException("重复的支付请求");
}
// 3. 金额一致性校验
Order order = orderService.getById(dto.getOrderId());
return order.getAmount().compareTo(dto.getAmount()) == 0;
}
建立的风险规则包括:
风控拦截器实现:
java复制@Component
public class RiskControlInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
String ip = getClientIP(request);
String action = request.getRequestURI();
// 检查IP行为频率
if (riskService.checkFrequency(ip, action) > THRESHOLD) {
response.sendError(429, "操作过于频繁");
return false;
}
return true;
}
}
采用Docker Compose编排服务:
yaml复制version: '3'
services:
app:
image: petstore-backend:${TAG}
ports:
- "8080:8080"
depends_on:
- redis
- mysql
redis:
image: redis:6-alpine
ports:
- "6379:6379"
搭建的监控维度包括:
Prometheus配置示例:
yaml复制scrape_configs:
- job_name: 'petstore'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['app:8080']
在实际开发中遇到几个典型问题:
宠物食品保质期问题:
最初只在数据库记录过期日期,后发现需要同时存储生产日期和保质期天数,因为用户需要知道商品还有多久过期。解决方案是增加两个字段,并在商品详情页动态计算剩余天数。
多规格商品处理:
宠物食品常有不同重量规格,初期设计为独立商品导致重复信息太多。重构后采用主商品+SKU的模式,通过JSON字段存储规格属性:
java复制@Data
public class ProductSku {
private Long id;
private String spec; // {"weight":"5kg","flavor":"牛肉"}
private BigDecimal price;
private Integer stock;
}
java复制public boolean placeOrder(OrderDTO dto) {
String lockKey = "product:" + dto.getProductId();
try {
// 获取分布式锁
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
if (!locked) {
throw new BusinessException("系统繁忙,请重试");
}
// 乐观锁更新库存
int updated = productMapper.reduceStock(
dto.getProductId(),
dto.getQuantity(),
product.getVersion());
return updated > 0;
} finally {
redisTemplate.delete(lockKey);
}
}