1. 项目概述:全渠道多用户商城的技术架构
这套基于Java技术栈的多用户商城系统,是我过去三年在电商领域摸爬滚打的实战结晶。不同于传统的单商户电商平台,B2B2C模式需要同时支持平台运营方、入驻商家和终端消费者三类角色,技术复杂度呈指数级增长。系统采用SpringBoot+Vue+Uniapp的全家桶组合,实现了PC、H5、小程序、APP四端全覆盖,日均承载订单量可达10万+级别。
核心架构设计遵循"前后端分离+多端适配"原则。后端采用经典的领域驱动设计(DDD)分层架构,将业务逻辑划分为商品、订单、支付、会员等限界上下文。前端则根据终端特性差异化处理:管理后台和H5站点使用Vue3+TypeScript实现,小程序和APP端则通过Uniapp实现跨端开发。这种架构选择既保证了开发效率,又能针对不同平台做深度优化。
技术选型背后的思考:SpringBoot的约定优于配置特性大幅减少了XML配置,配合SpringCloud Alibaba生态可以快速搭建分布式系统;Vue的响应式特性非常适合电商这类交互复杂的场景;Uniapp则解决了多端重复开发的核心痛点。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 权限系统设计与实现
2.1 多租户权限模型
在B2B2C场景下,权限系统需要解决三个维度的控制问题:
- 角色维度:平台管理员、商家管理员、普通用户等
- 数据维度:租户(商家)数据隔离
- 操作维度:不同终端的功能权限差异
我们基于Spring Security进行了深度定制,关键改进点包括:
java复制// 自定义的租户权限投票器
public class TenantVoter implements AccessDecisionVoter<FilterInvocation> {
@Override
public int vote(Authentication authentication, FilterInvocation fi,
Collection<ConfigAttribute> attributes) {
// 获取当前请求的租户上下文
String currentTenant = TenantContext.getCurrentTenant();
// 验证用户是否有访问该租户数据的权限
if(!user.getTenants().contains(currentTenant)) {
return ACCESS_DENIED;
}
return ACCESS_GRANTED;
}
}
2.2 动态权限控制方案
权限数据存储在MySQL中,通过缓存优化查询性能:
- 权限表设计采用RBAC模型,包含user、role、permission三张核心表
- 使用Redis缓存用户权限树,设置5分钟过期时间
- 采用Redisson分布式锁保证缓存重建时的线程安全
java复制// 权限缓存加载示例
public List<Permission> loadUserPermissions(Long userId) {
String cacheKey = "user:perms:" + userId;
List<Permission> cached = redisTemplate.opsForValue().get(cacheKey);
if(cached != null) return cached;
RLock lock = redissonClient.getLock("LOCK:" + cacheKey);
try {
lock.lock(10, TimeUnit.SECONDS);
// 双重检查锁
cached = redisTemplate.opsForValue().get(cacheKey);
if(cached == null) {
cached = permissionMapper.selectByUserId(userId);
redisTemplate.opsForValue().set(cacheKey, cached, 5, TimeUnit.MINUTES);
}
return cached;
} finally {
lock.unlock();
}
}
3. 商品与库存管理
3.1 商品模型设计
电商系统的商品模型复杂度往往被低估。我们的设计包含以下核心实体:
- SPU(Standard Product Unit):标准化产品单元,如iPhone 13
- SKU(Stock Keeping Unit):库存量单位,如iPhone 13 128G 黑色
- 商品分类:三级类目体系,支持多维度筛选
- 商品属性:关键属性、销售属性、非关键属性
java复制// 商品发布服务示例
public class ProductPublishService {
@Transactional
public void publishSpu(SpuDTO spuDto) {
// 1. 保存SPU基本信息
Spu spu = convertSpu(spuDto);
spuMapper.insert(spu);
// 2. 处理SKU数据
spuDto.getSkus().forEach(skuDto -> {
Sku sku = convertSku(skuDto);
sku.setSpuId(spu.getId());
skuMapper.insert(sku);
// 3. 初始化库存
stockMapper.initStock(sku.getId(), skuDto.getStock());
});
// 4. 发布商品审核事件
eventPublisher.publishEvent(new ProductAuditEvent(spu.getId()));
}
}
3.2 高并发库存控制
库存扣减是电商系统的核心难点,我们采用多级缓存+分布式锁的方案:
- 第一层:本地缓存库存余量(Guava Cache)
- 第二层:Redis缓存库存计数
- 第三层:数据库最终一致性
java复制// 库存扣减服务
public class InventoryService {
public boolean deductStock(Long skuId, int quantity) {
// 本地缓存检查
Integer localStock = localCache.getIfPresent(skuId);
if(localStock != null && localStock < quantity) {
return false;
}
// Redis原子操作
String lockKey = "stock:lock:" + skuId;
String stockKey = "stock:count:" + skuId;
return redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) {
// 使用Lua脚本保证原子性
String script = "if redis.call('exists', KEYS[1]) == 0 then " +
"local stock = tonumber(redis.call('get', KEYS[2])) " +
"if stock >= tonumber(ARGV[1]) then " +
"redis.call('decrby', KEYS[2], ARGV[1]) " +
"return 1 end end " +
"return 0";
Boolean result = connection.eval(
script.getBytes(),
ReturnType.BOOLEAN,
2,
lockKey.getBytes(),
stockKey.getBytes(),
String.valueOf(quantity).getBytes()
);
return result;
}
});
}
}
4. 订单与支付系统
4.1 订单状态机设计
订单生命周期管理采用状态机模式,核心状态包括:
- 待支付
- 已支付/待发货
- 已发货/待收货
- 已完成
- 已取消
- 已退款
java复制// 订单状态机配置
public class OrderStateMachineConfig {
@Bean
public StateMachine<OrderState, OrderEvent> stateMachine() {
StateMachineBuilder.Builder<OrderState, OrderEvent> builder =
StateMachineBuilder.builder();
builder.configureStates()
.withStates()
.initial(OrderState.UNPAID)
.states(EnumSet.allOf(OrderState.class));
builder.configureTransitions()
.withExternal()
.source(OrderState.UNPAID).target(OrderState.PAID)
.event(OrderEvent.PAY_SUCCESS)
.and()
.withExternal()
.source(OrderState.PAID).target(OrderState.SHIPPED)
.event(OrderEvent.SHIP)
.and()
// 其他状态转换...
return builder.build();
}
}
4.2 多支付渠道整合
支付模块采用策略模式+工厂模式,支持微信支付、支付宝、银联等多种支付方式:
java复制// 支付策略接口
public interface PaymentStrategy {
PaymentResult pay(PaymentRequest request);
PaymentResult query(String orderNo);
PaymentResult refund(RefundRequest request);
}
// 支付上下文
public class PaymentContext {
private PaymentStrategy strategy;
public PaymentContext(PaymentType type) {
this.strategy = PaymentStrategyFactory.getStrategy(type);
}
public PaymentResult executePay(PaymentRequest request) {
return strategy.pay(request);
}
}
// 微信支付实现
public class WechatPayment implements PaymentStrategy {
@Override
public PaymentResult pay(PaymentRequest request) {
// 构建微信支付请求参数
Map<String, String> params = new HashMap<>();
params.put("appid", wechatConfig.getAppId());
params.put("mch_id", wechatConfig.getMchId());
params.put("nonce_str", generateNonce());
// 其他参数...
// 调用微信支付接口
String response = wechatClient.unifiedOrder(params);
return parseResponse(response);
}
}
5. 多端适配实践
5.1 响应式前端架构
PC/H5端采用Vue3组合式API实现响应式交互,核心设计包括:
- 基于Pinia的状态管理
- 动态路由权限控制
- 组件级代码分割
javascript复制// 商品筛选组件示例
export default {
setup() {
const filterState = reactive({
priceRange: [0, 1000],
categories: [],
brands: []
});
const products = ref([]);
watchEffect(async () => {
const params = {
minPrice: filterState.priceRange[0],
maxPrice: filterState.priceRange[1],
categories: filterState.categories.join(','),
brands: filterState.brands.join(',')
};
products.value = await api.searchProducts(params);
});
return { filterState, products };
}
}
5.2 Uniapp跨端开发
小程序和APP端通过Uniapp实现代码复用,关键技巧包括:
- 条件编译处理平台差异
- 通用组件抽象
- 原生能力扩展
javascript复制// 支付功能跨端实现
function pay(order) {
// #ifdef MP-WEIXIN
wx.requestPayment({
timeStamp: order.timeStamp,
nonceStr: order.nonceStr,
package: order.package,
signType: 'MD5',
paySign: order.paySign,
success: () => resolve(),
fail: () => reject()
});
// #endif
// #ifdef APP-PLUS
plus.payment.request('wxpay', order, () => {
resolve();
}, (err) => {
reject(err);
});
// #endif
}
6. 性能优化实战
6.1 缓存策略设计
多级缓存架构显著提升了系统性能:
- 浏览器缓存:静态资源设置长期缓存
- CDN加速:图片等大文件通过CDN分发
- 应用缓存:Redis集群缓存热点数据
- 本地缓存:Guava Cache缓存少量高频数据
java复制// 多级缓存实现示例
public class ProductCacheService {
@Cacheable(value = "product", key = "#id")
public Product getProduct(Long id) {
// 先查Redis
String redisKey = "product:" + id;
Product product = redisTemplate.opsForValue().get(redisKey);
if(product != null) return product;
// 再查数据库
product = productMapper.selectById(id);
if(product != null) {
redisTemplate.opsForValue().set(
redisKey,
product,
30,
TimeUnit.MINUTES
);
}
return product;
}
}
6.2 数据库优化
MySQL优化措施包括:
- 分库分表:订单表按用户ID哈希分片
- 索引优化:为所有查询条件建立合适索引
- 读写分离:主库写,从库读
- SQL调优:避免全表扫描和临时表
sql复制-- 订单表分片设计
CREATE TABLE `t_order_0` (
`id` bigint(20) NOT NULL COMMENT '订单ID',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`order_no` varchar(32) NOT NULL COMMENT '订单编号',
`total_amount` decimal(10,2) NOT NULL COMMENT '订单总额',
`status` tinyint(4) NOT NULL COMMENT '订单状态',
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_order_no` (`order_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
7. 踩坑经验与解决方案
7.1 微信支付证书加载问题
在集群环境下,微信支付证书加载可能出现竞争条件。我们的解决方案是:
- 将证书文件上传至分布式文件系统(如MinIO)
- 应用启动时下载证书到本地临时目录
- 使用Redisson分布式锁保证多节点同步
java复制// 微信证书加载方案
public class WxpayCertManager {
private final RedissonClient redissonClient;
private final FileStorageService fileStorage;
@PostConstruct
public void initCert() {
RLock lock = redissonClient.getLock("wxpay:cert:lock");
try {
lock.lock(30, TimeUnit.SECONDS);
File certFile = new File("/tmp/apiclient_cert.p12");
if(!certFile.exists()) {
byte[] certBytes = fileStorage.download("wxpay/cert.p12");
Files.write(certFile.toPath(), certBytes);
}
} finally {
lock.unlock();
}
}
}
7.2 分布式事务一致性
在订单创建和库存扣减的场景中,我们采用以下方案保证一致性:
- 本地消息表:记录事务状态
- 定时任务补偿:处理失败的事务
- 最终一致性:允许短暂的不一致
java复制// 分布式事务实现
public class OrderCreateService {
@Transactional
public void createOrder(OrderDTO orderDTO) {
// 1. 创建订单记录
Order order = convertOrder(orderDTO);
orderMapper.insert(order);
// 2. 扣减库存(TCC模式)
inventoryService.prepareDeduct(order.getItems());
// 3. 记录事务状态
transactionLogService.log(
order.getId(),
TransactionType.ORDER_CREATE,
TransactionStatus.PREPARED
);
// 4. 提交事务(第二阶段)
eventPublisher.publishEvent(new OrderCreatedEvent(order.getId()));
}
}
7.3 图片上传优化
多端图片上传面临的主要挑战:
- 不同平台的上传API差异
- 文件大小限制不同
- 安全策略要求不同
我们的解决方案:
- 统一使用七牛云作为存储后端
- 前端根据平台特性适配上传组件
- 服务端签发临时上传凭证
javascript复制// 统一上传组件实现
export function uploadFile(file) {
// 获取服务端签名
const token = await api.getUploadToken();
// #ifdef H5
return h5Upload(file, token);
// #endif
// #ifdef MP-WEIXIN
return wxUpload(file, token);
// #endif
// #ifdef APP-PLUS
return appUpload(file, token);
// #endif
}
8. 监控与运维体系
8.1 全链路监控
系统监控体系包含:
- 应用性能监控(APM):Skywalking
- 日志收集:ELK栈
- 指标监控:Prometheus + Grafana
- 告警通知:企业微信机器人
yaml复制# Skywalking agent配置示例
agent.service_name=${SW_SERVICE_NAME:mall-service}
collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:skywalking-oap:11800}
logging.level=${SW_LOGGING_LEVEL:INFO}
8.2 容器化部署
采用Docker+Kubernetes实现容器化部署:
- 多环境配置分离(dev/test/prod)
- 滚动更新策略
- HPA自动扩缩容
dockerfile复制# Dockerfile示例
FROM openjdk:11-jre
WORKDIR /app
COPY target/mall-service.jar .
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "mall-service.jar"]
9. 安全防护措施
9.1 常见攻击防护
- SQL注入:MyBatis使用预编译
- XSS攻击:前端DOMPurify过滤
- CSRF防护:Spring Security默认启用
- 暴力破解:登录接口限流
java复制// 登录限流配置
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/login").permitAll()
.and()
.addFilterBefore(new RateLimitFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
// 限流过滤器
public class RateLimitFilter extends OncePerRequestFilter {
private final RateLimiter limiter = RateLimiter.create(10); // 10次/秒
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) {
if(!limiter.tryAcquire()) {
response.sendError(429, "Too many requests");
return;
}
chain.doFilter(request, response);
}
}
9.2 数据安全策略
- 敏感数据加密存储(AES-256)
- 通信全链路HTTPS
- 日志脱敏处理
- 定期安全审计
java复制// 数据加密示例
public class AesEncryptor {
private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
public String encrypt(String data, String key) {
Cipher cipher = Cipher.getInstance(ALGORITHM);
// 初始化向量
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
// 设置加密密钥
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
// 加密数据
byte[] encrypted = cipher.doFinal(data.getBytes());
return Base64.getEncoder().encodeToString(iv) + ":" +
Base64.getEncoder().encodeToString(encrypted);
}
}
10. 扩展性与未来演进
10.1 微服务化改造
随着业务规模扩大,系统正在向微服务架构演进:
- 按业务领域拆分服务
- 引入Service Mesh进行服务治理
- 采用领域事件实现服务间通信
java复制// 领域事件发布示例
public class OrderService {
private final DomainEventPublisher eventPublisher;
@Transactional
public void cancelOrder(Long orderId) {
Order order = orderRepository.findById(orderId);
order.cancel();
orderRepository.save(order);
// 发布领域事件
eventPublisher.publish(new OrderCancelledEvent(
order.getId(),
order.getUserId(),
order.getTotalAmount()
));
}
}
10.2 新技术融合
正在探索的技术方向:
- 服务端渲染(SSR)提升首屏性能
- WebAssembly优化计算密集型任务
- 边缘计算降低延迟
javascript复制// WebAssembly示例
const wasmModule = new WebAssembly.Module(wasmCode);
const wasmInstance = new WebAssembly.Instance(wasmModule);
const { calculateDiscount } = wasmInstance.exports;
// 调用WASM计算优惠
const discount = calculateDiscount(
totalAmount,
userLevel,
couponValue
);
这套多用户商城系统从零到一的建设过程,让我深刻体会到架构设计需要平衡短期需求和长期演进。技术选型没有银弹,最重要的是根据团队能力和业务发展阶段做出合适选择。在后续迭代中,我们计划引入更多云原生技术,同时保持核心业务逻辑的稳定性和可维护性。
