Spring Boot 3.x 全栈电商实战:Vue 3 + MySQL 8 构建农产品交易平台

在数字化转型浪潮中,农产品电商平台正成为连接农户与消费者的重要桥梁。本文将带您从零开始构建一个基于Spring Boot 3.x的全栈电商系统,整合Vue 3前端框架与MySQL 8数据库,打造高性能、易维护的农产品交易解决方案。

1. 技术栈选型与项目初始化

现代电商平台需要兼顾开发效率与系统性能。我们选择的技术组合具备以下优势:

  • Spring Boot 3.x :提供自动配置、嵌入式容器等开箱即用特性,显著降低Java后端开发复杂度
  • Vue 3 :组合式API和响应式系统大幅提升前端开发体验
  • MySQL 8 :窗口函数、CTE等高级特性为复杂业务查询提供支持

1.1 项目初始化步骤

使用Spring Initializr创建基础项目结构:

# 通过curl快速生成项目
curl https://start.spring.io/starter.zip \
  -d dependencies=web,mysql,data-jpa \
  -d javaVersion=17 \
  -d packaging=jar \
  -d bootVersion=3.2.0 \
  -d artifactId=farm-product-platform \
  -o farm-product-platform.zip

关键依赖说明:

依赖项 版本 作用
spring-boot-starter-web 3.2.0 Web MVC支持
spring-boot-starter-data-jpa 3.2.0 ORM框架集成
mysql-connector-j 8.0.33 MySQL驱动
lombok 1.18.28 简化POJO编写

提示:建议使用Java 17+以获得完整的Spring Boot 3.x特性支持,包括Record类型和密封类等现代语言特性

2. 领域模型设计与数据库构建

农产品电商的核心实体包括商品、订单、用户三大模块,其ER关系如下图所示:

用户(User) ||--o{ 订单(Order) : "1:N"
订单(Order) ||--|{ 订单项(OrderItem) : "1:N"
商品(Product) ||--o{ 订单项(OrderItem) : "1:N"
商品(Product) }|--|| 商品类别(Category) : "N:1"

2.1 JPA实体设计示例

@Entity
@Table(name = "products")
@Getter @Setter
public class Product {
    @Id @GeneratedValue(strategy = IDENTITY)
    private Long id;
    
    @Column(nullable = false)
    private String name;
    
    @Column(columnDefinition = "TEXT")
    private String description;
    
    @Column(precision = 10, scale = 2)
    private BigDecimal price;
    
    @ManyToOne
    @JoinColumn(name = "category_id")
    private Category category;
    
    @Column(name = "stock_quantity")
    private Integer stockQuantity;
    
    @Column(name = "image_url")
    private String imageUrl;
    
    @CreationTimestamp
    private LocalDateTime createdAt;
}

2.2 数据库优化策略

针对农产品电商特点,我们采用以下MySQL优化方案:

  • 为高频查询字段创建组合索引:

    CREATE INDEX idx_product_search ON products(name, category_id, price);
    
  • 使用JSON类型存储商品扩展属性:

    ALTER TABLE products ADD COLUMN attributes JSON;
    
  • 配置连接池参数(application.yml):

    spring:
      datasource:
        hikari:
          maximum-pool-size: 20
          connection-timeout: 30000
          idle-timeout: 600000
          max-lifetime: 1800000
    

3. 核心业务逻辑实现

3.1 商品服务层设计

商品模块需要支持分页查询、条件筛选等典型电商功能:

@Service
@RequiredArgsConstructor
public class ProductService {
    private final ProductRepository productRepo;
    
    public Page<Product> searchProducts(ProductSearchCriteria criteria, Pageable pageable) {
        return productRepo.findAll((root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            if (StringUtils.hasText(criteria.getKeyword())) {
                predicates.add(cb.like(root.get("name"), "%" + criteria.getKeyword() + "%"));
            }
            
            if (criteria.getCategoryId() != null) {
                predicates.add(cb.equal(root.get("category").get("id"), criteria.getCategoryId()));
            }
            
            if (criteria.getMinPrice() != null) {
                predicates.add(cb.ge(root.get("price"), criteria.getMinPrice()));
            }
            
            return cb.and(predicates.toArray(new Predicate[0]));
        }, pageable);
    }
    
    @Transactional
    public void reduceStock(Long productId, int quantity) {
        Product product = productRepo.findById(productId)
            .orElseThrow(() -> new EntityNotFoundException("Product not found"));
        
        if (product.getStockQuantity() < quantity) {
            throw new BusinessException("Insufficient stock");
        }
        
        product.setStockQuantity(product.getStockQuantity() - quantity);
    }
}

3.2 订单处理流程

订单创建涉及库存校验、支付预处理等关键步骤:

@Transactional
public Order createOrder(OrderRequest request, Long userId) {
    // 1. 验证用户
    User user = userRepo.findById(userId)
        .orElseThrow(() -> new EntityNotFoundException("User not found"));
    
    // 2. 校验并锁定库存
    List<OrderItem> items = request.getItems().stream()
        .map(item -> {
            Product product = productService.getProduct(item.getProductId());
            productService.reduceStock(product.getId(), item.getQuantity());
            
            return OrderItem.builder()
                .product(product)
                .quantity(item.getQuantity())
                .unitPrice(product.getPrice())
                .build();
        }).collect(Collectors.toList());
    
    // 3. 计算总价
    BigDecimal totalAmount = items.stream()
        .map(item -> item.getUnitPrice().multiply(BigDecimal.valueOf(item.getQuantity())))
        .reduce(BigDecimal.ZERO, BigDecimal::add);
    
    // 4. 创建订单
    Order order = Order.builder()
        .user(user)
        .items(items)
        .totalAmount(totalAmount)
        .status(OrderStatus.CREATED)
        .shippingAddress(request.getShippingAddress())
        .build();
    
    return orderRepo.save(order);
}

4. 前后端协同开发

4.1 Vue 3前端工程配置

使用Vite创建Vue 3项目:

npm create vite@latest farm-product-frontend --template vue-ts

关键依赖配置(package.json片段):

{
  "dependencies": {
    "axios": "^1.3.4",
    "pinia": "^2.0.33",
    "vue-router": "^4.2.2",
    "element-plus": "^2.3.3"
  }
}

4.2 API接口设计规范

采用RESTful风格设计前后端交互接口:

资源 方法 路径 描述
商品 GET /api/products 分页查询商品
商品 GET /api/products/{id} 获取商品详情
订单 POST /api/orders 创建订单
订单 GET /api/orders/{id} 查询订单详情

4.3 跨域解决方案

Spring Boot配置CORS支持:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
            .allowedOrigins("http://localhost:5173")
            .allowedMethods("GET", "POST", "PUT", "DELETE")
            .allowCredentials(true)
            .maxAge(3600);
    }
}

5. 生产环境准备

5.1 性能优化措施

  • 启用JPA二级缓存(application.yml):

    spring:
      jpa:
        properties:
          hibernate:
            cache:
              use_second_level_cache: true
              region.factory_class: org.hibernate.cache.ehcache.EhCacheRegionFactory
    
  • 配置Gzip压缩(application.yml):

    server:
      compression:
        enabled: true
        mime-types: text/html,text/xml,text/plain,application/json,application/javascript
        min-response-size: 1024
    

5.2 监控与运维

集成Spring Boot Actuator:

@Configuration
@EnableWebSecurity
public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .requestMatchers(EndpointRequest.to("health")).permitAll()
            .requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ADMIN")
            .and().httpBasic();
    }
}

关键监控端点:

  • /actuator/health - 应用健康状态
  • /actuator/metrics - 性能指标
  • /actuator/prometheus - Prometheus格式指标

6. 项目部署实战

6.1 容器化部署方案

Docker Compose编排文件示例:

version: '3.8'

services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - DB_URL=jdbc:mysql://db:3306/farm_shop
    depends_on:
      - db

  db:
    image: mysql:8.0
    environment:
      - MYSQL_ROOT_PASSWORD=rootpass
      - MYSQL_DATABASE=farm_shop
    volumes:
      - mysql_data:/var/lib/mysql

volumes:
  mysql_data:

6.2 CI/CD流水线配置

GitHub Actions示例:

name: Build and Deploy

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    
    - name: Set up JDK 17
      uses: actions/setup-java@v3
      with:
        java-version: '17'
        distribution: 'temurin'
        
    - name: Build with Maven
      run: mvn -B package --file pom.xml
      
    - name: Build Docker image
      run: docker build -t farm-product-platform:${{ github.sha }} .
      
    - name: Log in to Docker Hub
      uses: docker/login-action@v2
      with:
        username: ${{ secrets.DOCKER_HUB_USERNAME }}
        password: ${{ secrets.DOCKER_HUB_TOKEN }}
        
    - name: Push image
      run: |
        docker tag farm-product-platform:${{ github.sha }} username/farm-product-platform:latest
        docker push username/farm-product-platform:latest

7. 进阶功能扩展

7.1 农产品溯源功能

通过区块链技术实现农产品溯源:

public interface BlockchainService {
    @PostMapping("/blockchain/record")
    String recordTraceData(@RequestBody TraceData data);
}

@Data
public class TraceData {
    private String productId;
    private String batchNumber;
    private String operation; // planting/harvesting/processing
    private LocalDateTime operationTime;
    private String operator;
    private String location;
}

7.2 智能推荐系统

基于用户行为的协同过滤推荐:

@Service
public class RecommendationService {
    private final UserBehaviorRepository behaviorRepo;
    
    public List<Product> recommendProducts(Long userId) {
        // 1. 获取相似用户
        Set<Long> similarUsers = findSimilarUsers(userId);
        
        // 2. 获取热门商品
        return behaviorRepo.findPopularProducts(similarUsers, PageRequest.of(0, 10));
    }
    
    private Set<Long> findSimilarUsers(Long userId) {
        // 实现相似度计算逻辑
    }
}

在实际项目开发中,我们发现Element Plus的表格组件与后端分页参数需要特殊处理才能完美配合。通过封装统一的PageResponse对象,可以简化前后端分页交互逻辑:

interface PageResponse<T> {
  content: T[];
  totalElements: number;
  pageNumber: number;
  pageSize: number;
}
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐