Spring Boot 3与Vue3全栈实践:构建企业级电商系统

# Spring Boot 3与Vue3全栈实践:构建企业级电商系统


在数字化转型的浪潮中,电商系统作为企业核心业务平台,其技术架构的现代化程度直接影响着业务发展。基于Spring Boot 3与Vue3的全栈技术栈,为企业级商城系统提供了高性能、可扩展的解决方案。


## 后端架构设计与核心模块


Spring Boot 3提供了现代化的Java开发体验,结合Spring Security 6和Spring Data JPA 3构建稳定的后端服务。


```java

// ProductController.java - 商品管理API

package com.mall.product.controller;


import com.mall.product.dto.*;

import com.mall.product.service.ProductService;

import io.swagger.v3.oas.annotations.Operation;

import io.swagger.v3.oas.annotations.security.SecurityRequirement;

import jakarta.validation.Valid;

import lombok.RequiredArgsConstructor;

import org.springframework.data.domain.Page;

import org.springframework.data.domain.Pageable;

import org.springframework.http.HttpStatus;

import org.springframework.http.ResponseEntity;

import org.springframework.security.access.prepost.PreAuthorize;

import org.springframework.web.bind.annotation.*;


import java.util.List;


@RestController

@RequestMapping("/api/v1/products")

@RequiredArgsConstructor

@SecurityRequirement(name = "bearerAuth")

public class ProductController {

    

    private final ProductService productService;

    

    @Operation(summary = "分页查询商品列表")

    @GetMapping

    public ResponseEntity> listProducts(

            @RequestParam(required = false) Long categoryId,

            @RequestParam(required = false) String keyword,

            @RequestParam(required = false) Integer minPrice,

            @RequestParam(required = false) Integer maxPrice,

            @RequestParam(required = false, defaultValue = "false") Boolean onSale,

            Pageable pageable) {

        

        ProductQueryDTO query = ProductQueryDTO.builder()

                .categoryId(categoryId)

                .keyword(keyword)

                .minPrice(minPrice)

                .maxPrice(maxPrice)

                .onSale(onSale)

                .build();

        

        Page products = productService.findProducts(query, pageable);

        return ResponseEntity.ok(products);

    }

    

    @Operation(summary = "获取商品详情")

    @GetMapping("/{productId}")

    public ResponseEntity getProductDetail(@PathVariable Long productId) {

        ProductDetailDTO product = productService.getProductDetail(productId);

        return ResponseEntity.ok(product);

    }

    

    @Operation(summary = "创建商品")

    @PostMapping

    @PreAuthorize("hasRole('ADMIN')")

    public ResponseEntity createProduct(@Valid @RequestBody CreateProductDTO createDTO) {

        ProductDTO product = productService.createProduct(createDTO);

        return ResponseEntity.status(HttpStatus.CREATED).body(product);

    }

    

    @Operation(summary = "更新商品信息")

    @PutMapping("/{productId}")

    @PreAuthorize("hasRole('ADMIN')")

    public ResponseEntity updateProduct(

            @PathVariable Long productId,

            @Valid @RequestBody UpdateProductDTO updateDTO) {

        

        ProductDTO product = productService.updateProduct(productId, updateDTO);

        return ResponseEntity.ok(product);

    }

    

    @Operation(summary = "批量更新商品状态")

    @PatchMapping("/batch-status")

    @PreAuthorize("hasRole('ADMIN')")

    public ResponseEntity batchUpdateStatus(

            @Valid @RequestBody BatchStatusUpdateDTO updateDTO) {

        

        productService.batchUpdateStatus(updateDTO);

        return ResponseEntity.ok().build();

    }

    

    @Operation(summary = "获取商品库存")

    @GetMapping("/{productId}/inventory")

    public ResponseEntity getProductInventory(@PathVariable Long productId) {

        InventoryDTO inventory = productService.getInventory(productId);

        return ResponseEntity.ok(inventory);

    }

    

    @Operation(summary = "调整商品库存")

    @PostMapping("/{productId}/inventory/adjust")

    @PreAuthorize("hasRole('ADMIN')")

    public ResponseEntity adjustInventory(

            @PathVariable Long productId,

            @Valid @RequestBody InventoryAdjustDTO adjustDTO) {

        

        InventoryDTO inventory = productService.adjustInventory(productId, adjustDTO);

        return ResponseEntity.ok(inventory);

    }

}


// ProductService.java - 商品服务层

@Service

@RequiredArgsConstructor

@Transactional(readOnly = true)

public class ProductService {

    

    private final ProductRepository productRepository;

    private final CategoryRepository categoryRepository;

    private final InventoryRepository inventoryRepository;

    private final ProductMapper productMapper;

    private final CacheManager cacheManager;

    

    @Transactional

    public ProductDTO createProduct(CreateProductDTO createDTO) {

        // 验证分类是否存在

        Category category = categoryRepository.findById(createDTO.getCategoryId())

                .orElseThrow(() -> new ResourceNotFoundException("分类不存在"));

        

        // 创建商品

        Product product = Product.builder()

                .name(createDTO.getName())

                .description(createDTO.getDescription())

                .price(createDTO.getPrice())

                .originalPrice(createDTO.getOriginalPrice())

                .category(category)

                .images(createDTO.getImages())

                .specifications(createDTO.getSpecifications())

                .status(ProductStatus.DRAFT)

                .build();

        

        // 保存商品

        Product savedProduct = productRepository.save(product);

        

        // 初始化库存

        Inventory inventory = Inventory.builder()

                .product(savedProduct)

                .sku(createDTO.getSku())

                .stock(createDTO.getInitialStock())

                .lockStock(0)

                .warningStock(10)

                .build();

        

        inventoryRepository.save(inventory);

        

        // 清除缓存

        evictProductCache(savedProduct.getId());

        

        return productMapper.toDTO(savedProduct);

    }

    

    public Page findProducts(ProductQueryDTO query, Pageable pageable) {

        String cacheKey = generateCacheKey(query, pageable);

        

        // 尝试从缓存获取

        Cache cache = cacheManager.getCache("products");

        if (cache != null) {

            Page cached = cache.get(cacheKey, Page.class);

            if (cached != null) {

                return cached;

            }

        }

        

        // 构建查询条件

        Specification spec = Specification.where(null);

        

        if (query.getCategoryId() != null) {

            spec = spec.and((root, cq, cb) -> 

                cb.equal(root.get("category").get("id"), query.getCategoryId()));

        }

        

        if (StringUtils.hasText(query.getKeyword())) {

            spec = spec.and((root, cq, cb) -> 

                cb.or(

                    cb.like(root.get("name"), "%" + query.getKeyword() + "%"),

                    cb.like(root.get("description"), "%" + query.getKeyword() + "%")

                ));

        }

        

        if (query.getMinPrice() != null) {

            spec = spec.and((root, cq, cb) -> 

                cb.greaterThanOrEqualTo(root.get("price"), query.getMinPrice()));

        }

        

        if (query.getMaxPrice() != null) {

            spec = spec.and((root, cq, cb) -> 

                cb.lessThanOrEqualTo(root.get("price"), query.getMaxPrice()));

        }

        

        if (query.getOnSale() != null) {

            spec = spec.and((root, cq, cb) -> 

                cb.equal(root.get("status"), ProductStatus.ON_SALE));

        }

        

        // 执行查询

        Page products = productRepository.findAll(spec, pageable);

        Page result = products.map(productMapper::toDTO);

        

        // 缓存结果

        if (cache != null) {

            cache.put(cacheKey, result);

        }

        

        return result;

    }

    

    private void evictProductCache(Long productId) {

        Cache cache = cacheManager.getCache("products");

        if (cache != null) {

            cache.evictIfPresent("product:" + productId);

            cache.evictIfPresent("product_detail:" + productId);

        }

    }

}

```


## 前端Vue3架构设计


Vue3的Composition API和TypeScript支持为大型前端应用提供了更好的类型安全和代码组织。


```vue



```


## 购物车与订单处理


```java

// OrderService.java - 订单服务

@Service

@RequiredArgsConstructor

@Transactional

public class OrderService {

    

    private final OrderRepository orderRepository;

    private final OrderItemRepository orderItemRepository;

    private final ProductRepository productRepository;

    private final InventoryService inventoryService;

    private final PaymentService paymentService;

    private final MessageQueueService messageQueueService;

    private final OrderMapper orderMapper;

    

    @Transactional

    public OrderDTO createOrder(CreateOrderDTO createDTO, Long userId) {

        // 验证购物车商品

        List cartItems = createDTO.getItems();

        validateCartItems(cartItems);

        

        // 锁定库存

        List lockResults = inventoryService.lockInventory(cartItems);

        

        try {

            // 计算订单总金额

            BigDecimal totalAmount = calculateOrderTotal(cartItems);

            BigDecimal discountAmount = calculateDiscount(createDTO.getCouponCode(), totalAmount);

            BigDecimal finalAmount = totalAmount.subtract(discountAmount);

            

            // 创建订单

            Order order = Order.builder()

                    .orderNumber(generateOrderNumber())

                    .userId(userId)

                    .totalAmount(totalAmount)

                    .discountAmount(discountAmount)

                    .finalAmount(finalAmount)

                    .shippingAddress(createDTO.getShippingAddress())

                    .contactInfo(createDTO.getContactInfo())

                    .status(OrderStatus.PENDING_PAYMENT)

                    .paymentMethod(createDTO.getPaymentMethod())

                    .build();

            

            Order savedOrder = orderRepository.save(order);

            

            // 创建订单项

            List orderItems = createOrderItems(savedOrder, cartItems);

            orderItemRepository.saveAll(orderItems);

            

            // 生成支付订单

            PaymentDTO paymentDTO = paymentService.createPayment(

                PaymentRequestDTO.builder()

                    .orderId(savedOrder.getId())

                    .amount(finalAmount)

                    .paymentMethod(createDTO.getPaymentMethod())

                    .subject("商城订单支付")

                    .build()

            );

            

            // 更新订单支付信息

            savedOrder.setPaymentId(paymentDTO.getPaymentId());

            savedOrder.setPaymentStatus(paymentDTO.getStatus());

            orderRepository.save(savedOrder);

            

            // 发送订单创建事件

            messageQueueService.sendOrderCreatedEvent(savedOrder.getId());

            

            return orderMapper.toDTO(savedOrder);

            

        } catch (Exception e) {

            // 解锁库存

            inventoryService.unlockInventory(lockResults);

            throw new BusinessException("订单创建失败", e);

        }

    }

    

    @Transactional

    public void processOrderPayment(Long orderId, PaymentResultDTO paymentResult) {

        Order order = orderRepository.findById(orderId)

                .orElseThrow(() -> new ResourceNotFoundException("订单不存在"));

        

        if (order.getStatus() != OrderStatus.PENDING_PAYMENT) {

            throw new BusinessException("订单状态不正确");

        }

        

        if (paymentResult.isSuccess()) {

            // 支付成功,更新订单状态

            order.setStatus(OrderStatus.PAID);

            order.setPaidAt(LocalDateTime.now());

            order.setPaymentStatus(PaymentStatus.SUCCESS);

            

            // 扣减库存

            List items = orderItemRepository.findByOrderId(orderId);

            inventoryService.reduceInventory(items);

            

            // 发送订单支付成功事件

            messageQueueService.sendOrderPaidEvent(orderId);

            

        } else {

            // 支付失败,解锁库存

            order.setStatus(OrderStatus.PAYMENT_FAILED);

            order.setPaymentStatus(PaymentStatus.FAILED);

            

            List items = orderItemRepository.findByOrderId(orderId);

            inventoryService.unlockInventoryByOrder(items);

        }

        

        orderRepository.save(order);

    }

    

    @Transactional

    public void cancelOrder(Long orderId, Long userId) {

        Order order = orderRepository.findByIdAndUserId(orderId, userId)

                .orElseThrow(() -> new ResourceNotFoundException("订单不存在"));

        

        if (!order.isCancellable()) {

            throw new BusinessException("当前订单状态不可取消");

        }

        

        order.setStatus(OrderStatus.CANCELLED);

        order.setCancelledAt(LocalDateTime.now());

        

        // 解锁库存

        List items = orderItemRepository.findByOrderId(orderId);

        inventoryService.unlockInventoryByOrder(items);

        

        orderRepository.save(order);

        

        // 发送订单取消事件

        messageQueueService.sendOrderCancelledEvent(orderId);

    }

    

    private void validateCartItems(List cartItems) {

        if (cartItems == null || cartItems.isEmpty()) {

            throw new BusinessException("购物车为空");

        }

        

        for (CartItemDTO item : cartItems) {

            Product product = productRepository.findById(item.getProductId())

                    .orElseThrow(() -> new ResourceNotFoundException("商品不存在"));

            

            if (!product.isOnSale()) {

                throw new BusinessException("商品" + product.getName() + "已下架");

            }

            

            if (product.getPrice().compareTo(item.getPrice()) != 0) {

                throw new BusinessException("商品价格已发生变化");

            }

        }

    }

    

    private String generateOrderNumber() {

        return "ORD" + System.currentTimeMillis() + RandomUtils.nextInt(1000, 9999);

    }

}

```


## 用户认证与安全配置


```java

// SecurityConfig.java - 安全配置

@Configuration

@EnableWebSecurity

@EnableMethodSecurity

@RequiredArgsConstructor

public class SecurityConfig {

    

    private final UserDetailsService userDetailsService;

    private final JwtAuthenticationFilter jwtAuthenticationFilter;

    

    @Bean

    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http

            .csrf(AbstractHttpConfigurer::disable)

            .authorizeHttpRequests(auth -> auth

                .requestMatchers(

                    "/api/v1/auth/**",

                    "/api/v1/products/**",

                    "/api/v1/categories/**",

                    "/swagger-ui/**",

                    "/v3/api-docs/**",

                    "/webjars/**"

                ).permitAll()

                .requestMatchers("/api/v1/admin/**").hasRole("ADMIN")

                .requestMatchers("/api/v1/user/**").hasAnyRole("USER", "ADMIN")

                .anyRequest().authenticated()

            )

            .sessionManagement(session -> session

                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)

            )

            .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)

            .exceptionHandling(exception -> exception

                .authenticationEntryPoint(new JwtAuthenticationEntryPoint())

                .accessDeniedHandler(new JwtAccessDeniedHandler())

            );

        

        return http.build();

    }

    

    @Bean

    public PasswordEncoder passwordEncoder() {

        return new BCryptPasswordEncoder();

    }

    

    @Bean

    public AuthenticationManager authenticationManager(

            AuthenticationConfiguration authConfig) throws Exception {

        return authConfig.getAuthenticationManager();

    }

}

<"9z.p5k3.org.cn"><"2h.p5k3.org.cn"><"x7.p5k3.org.cn">

// JwtService.java - JWT令牌服务

@Service

@RequiredArgsConstructor

public class JwtService {

    

    @Value("${jwt.secret}")

    private String secretKey;

    

    @Value("${jwt.expiration}")

    private Long expiration;

    

    public String generateToken(UserDetails userDetails) {

        Map claims = new HashMap<>();

        claims.put("username", userDetails.getUsername());

        claims.put("authorities", userDetails.getAuthorities().stream()

                .map(GrantedAuthority::getAuthority)

                .collect(Collectors.toList()));

        

        return Jwts.builder()

                .setClaims(claims)

                .setSubject(userDetails.getUsername())

                .setIssuedAt(new Date())

                .setExpiration(new Date(System.currentTimeMillis() + expiration))

                .signWith(getSigningKey(), SignatureAlgorithm.HS256)

                .compact();

    }

    

    public boolean validateToken(String token) {

        try {

            Jwts.parserBuilder()

                    .setSigningKey(getSigningKey())

                    .build()

                    .parseClaimsJws(token);

            return true;

        } catch (JwtException | IllegalArgumentException e) {

            return false;

        }

    }

    

    public String extractUsername(String token) {

        return extractAllClaims(token).getSubject();

    }

    

    public List extractAuthorities(String token) {

        List authorities = extractAllClaims(token).get("authorities", List.class);

        return authorities.stream()

                .map(SimpleGrantedAuthority::new)

                .collect(Collectors.toList());

    }

    

    private Claims extractAllClaims(String token) {

        return Jwts.parserBuilder()

                .setSigningKey(getSigningKey())

                .build()

                .parseClaimsJws(token)

                .getBody();

    }

    

    private Key getSigningKey() {

        byte[] keyBytes = Decoders.BASE64.decode(secretKey);

        return Keys.hmacShaKeyFor(keyBytes);

    }

}

```


## 支付与第三方集成


```java

// PaymentService.java - 支付服务

@Service

@RequiredArgsConstructor

public class PaymentService {

    

    private final AlipayClient alipayClient;

    private final WechatPayClient wechatPayClient;

    private final PaymentRepository paymentRepository;

    private final OrderService orderService;

    

    @Async

    public PaymentDTO createPayment(PaymentRequestDTO request) {

        Payment payment = Payment.builder()

                .orderId(request.getOrderId())

                .amount(request.getAmount())

                .paymentMethod(request.getPaymentMethod())

                .status(PaymentStatus.PENDING)

                .subject(request.getSubject())

                .build();

        

        Payment savedPayment = paymentRepository.save(payment);

        

        // 根据支付方式调用不同的支付渠道

        PaymentResponse response;

        switch (request.getPaymentMethod()) {

            case ALIPAY:

                response = createAlipayPayment(savedPayment);

                break;

            case WECHAT_PAY:

                response = createWechatPayPayment(savedPayment);

                break;

            default:

                throw new BusinessException("不支持的支付方式");

        }

        

        savedPayment.setPaymentUrl(response.getPaymentUrl());

        savedPayment.setPaymentId(response.getPaymentId());

        paymentRepository.save(savedPayment);

        

        return PaymentDTO.builder()

                .paymentId(savedPayment.getId())

                .paymentUrl(response.getPaymentUrl())

                .paymentId(response.getPaymentId())

                .status(savedPayment.getStatus())

                .build();

    }

    

    private PaymentResponse createAlipayPayment(Payment payment) {

        try {

            AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();

            

            JSONObject bizContent = new JSONObject();

            bizContent.put("out_trade_no", payment.getId());

            bizContent.put("total_amount", payment.getAmount());

            bizContent.put("subject", payment.getSubject());

            bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");

            

            request.setBizContent(bizContent.toJSONString());

            request.setNotifyUrl(paymentCallbackProperties.getAlipayNotifyUrl());

            request.setReturnUrl(paymentCallbackProperties.getAlipayReturnUrl());

            

            AlipayTradePagePayResponse response = alipayClient.pageExecute(request);

            

            return PaymentResponse.builder()

                    .paymentUrl(response.getBody())

                    .paymentId(response.getTradeNo())

                    .build();

                    

        } catch (AlipayApiException e) {

            throw new PaymentException("支付宝支付创建失败", e);

        }

    }

    

    @EventListener

    public void handlePaymentNotification(PaymentNotificationEvent event) {

        // 验证支付通知的签名

        if (!verifyPaymentNotification(event)) {

            throw new SecurityException("支付通知签名验证失败");

        }

        

        PaymentResultDTO result = PaymentResultDTO.builder()

                .orderId(event.getOrderId())

                .paymentId(event.getPaymentId())

                .amount(event.getAmount())

                .success(event.isSuccess())

                .paymentTime(event.getPaymentTime())

                .build();

        

        // 更新订单支付状态

        orderService.processOrderPayment(result.getOrderId(), result);

    }

}

```


基于Spring Boot 3与Vue3的全栈企业级商城系统,通过现代化的技术栈和架构设计,实现了高性能、可扩展的电商平台。后端采用微服务架构和领域驱动设计,前端采用组件化开发和状态管理,同时集成支付、物流等第三方服务。在实际部署中,还需要考虑缓存策略、数据库优化、监控告警等运维层面,确保系统的高可用性和稳定性。


请使用浏览器的分享功能分享到微信等