Skip to content

核心功能开发

1. 用户服务开发

1.1 实体类

java
@Entity
@Table(name = "users")
@EntityListeners(AuditingEntityListener.class)
public class User {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(nullable = false, unique = true, length = 50)
    private String username;
    
    @Column(nullable = false)
    private String password;
    
    @Column(unique = true, length = 100)
    private String email;
    
    @Column(length = 20)
    private String phone;
    
    @Enumerated(EnumType.STRING)
    private UserStatus status = UserStatus.ACTIVE;
    
    @CreatedDate
    @Column(name = "created_at", updatable = false)
    private LocalDateTime createdAt;
    
    @LastModifiedDate
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;
    
    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private List<UserAddress> addresses = new ArrayList<>();
}

public enum UserStatus {
    ACTIVE, INACTIVE, LOCKED
}

1.2 Repository

java
public interface UserRepository extends JpaRepository<User, Long> {
    
    Optional<User> findByUsername(String username);
    
    Optional<User> findByEmail(String email);
    
    boolean existsByUsername(String username);
    
    boolean existsByEmail(String email);
}

1.3 Service

java
@Service
@Transactional
public class UserService {
    
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    
    public User create(UserRequest request) {
        if (userRepository.existsByUsername(request.username())) {
            throw new BusinessException("用户名已存在");
        }
        
        if (userRepository.existsByEmail(request.email())) {
            throw new BusinessException("邮箱已被注册");
        }
        
        User user = new User();
        user.setUsername(request.username());
        user.setPassword(passwordEncoder.encode(request.password()));
        user.setEmail(request.email());
        user.setPhone(request.phone());
        
        return userRepository.save(user);
    }
    
    @Transactional(readOnly = true)
    public User findById(Long id) {
        return userRepository.findById(id)
            .orElseThrow(() -> new ResourceNotFoundException("用户不存在"));
    }
    
    @Transactional(readOnly = true)
    public Page<User> findAll(int page, int size) {
        return userRepository.findAll(PageRequest.of(page, size));
    }
    
    public User update(Long id, UserRequest request) {
        User user = findById(id);
        
        if (!user.getUsername().equals(request.username()) && 
            userRepository.existsByUsername(request.username())) {
            throw new BusinessException("用户名已存在");
        }
        
        user.setUsername(request.username());
        user.setEmail(request.email());
        user.setPhone(request.phone());
        
        return userRepository.save(user);
    }
    
    public void delete(Long id) {
        User user = findById(id);
        user.setStatus(UserStatus.INACTIVE);
        userRepository.save(user);
    }
}

1.4 Controller

java
@RestController
@RequestMapping("/users")
public class UserController {
    
    private final UserService userService;
    
    @PostMapping
    public ResponseEntity<ApiResponse<User>> create(@Valid @RequestBody UserRequest request) {
        User user = userService.create(request);
        return ResponseEntity.status(HttpStatus.CREATED)
                .body(ApiResponse.success("创建成功", user));
    }
    
    @GetMapping("/{id}")
    public ApiResponse<User> findById(@PathVariable Long id) {
        return ApiResponse.success(userService.findById(id));
    }
    
    @GetMapping
    public ApiResponse<Page<User>> findAll(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size) {
        return ApiResponse.success(userService.findAll(page, size));
    }
    
    @PutMapping("/{id}")
    public ApiResponse<User> update(@PathVariable Long id, 
                                   @Valid @RequestBody UserRequest request) {
        return ApiResponse.success(userService.update(id, request));
    }
    
    @DeleteMapping("/{id}")
    public ApiResponse<Void> delete(@PathVariable Long id) {
        userService.delete(id);
        return ApiResponse.success(null);
    }
}

2. 商品服务开发

2.1 实体类

java
@Entity
@Table(name = "products")
public class Product {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(nullable = false, length = 200)
    private String name;
    
    @Column(columnDefinition = "TEXT")
    private String description;
    
    @Column(nullable = false, precision = 10, scale = 2)
    private BigDecimal price;
    
    @Column(nullable = false)
    private Integer stock = 0;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "category_id")
    private Category category;
    
    @Column(name = "image_url", length = 500)
    private String imageUrl;
    
    @Enumerated(EnumType.STRING)
    private ProductStatus status = ProductStatus.ACTIVE;
    
    @CreatedDate
    @Column(name = "created_at", updatable = false)
    private LocalDateTime createdAt;
    
    @LastModifiedDate
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;
}

public enum ProductStatus {
    ACTIVE, INACTIVE, OUT_OF_STOCK
}

2.2 商品搜索

java
@Service
public class ProductService {
    
    private final ProductRepository productRepository;
    
    public Page<Product> search(ProductQuery query, int page, int size) {
        Specification<Product> spec = (root, q, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            if (query.name() != null && !query.name().isEmpty()) {
                predicates.add(cb.like(root.get("name"), 
                    "%" + query.name() + "%"));
            }
            
            if (query.categoryId() != null) {
                predicates.add(cb.equal(root.get("category").get("id"), 
                    query.categoryId()));
            }
            
            if (query.minPrice() != null) {
                predicates.add(cb.greaterThanOrEqualTo(
                    root.get("price"), query.minPrice()));
            }
            
            if (query.maxPrice() != null) {
                predicates.add(cb.lessThanOrEqualTo(
                    root.get("price"), query.maxPrice()));
            }
            
            if (query.status() != null) {
                predicates.add(cb.equal(root.get("status"), query.status()));
            }
            
            return cb.and(predicates.toArray(new Predicate[0]));
        };
        
        return productRepository.findAll(spec, PageRequest.of(page, size));
    }
}

3. 订单服务开发

3.1 实体类

java
@Entity
@Table(name = "orders")
public class Order {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "order_no", nullable = false, unique = true, length = 50)
    private String orderNo;
    
    @Column(name = "user_id", nullable = false)
    private Long userId;
    
    @Column(name = "total_amount", nullable = false, precision = 10, scale = 2)
    private BigDecimal totalAmount;
    
    @Enumerated(EnumType.STRING)
    private OrderStatus status = OrderStatus.PENDING;
    
    @Enumerated(EnumType.STRING)
    @Column(name = "payment_status")
    private PaymentStatus paymentStatus = PaymentStatus.UNPAID;
    
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<OrderItem> items = new ArrayList<>();
    
    @CreatedDate
    @Column(name = "created_at", updatable = false)
    private LocalDateTime createdAt;
    
    @LastModifiedDate
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;
    
    public void calculateTotalAmount() {
        this.totalAmount = items.stream()
            .map(OrderItem::getAmount)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
}

@Entity
@Table(name = "order_items")
public class OrderItem {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "order_id", nullable = false)
    private Order order;
    
    @Column(name = "product_id", nullable = false)
    private Long productId;
    
    @Column(name = "product_name", nullable = false, length = 200)
    private String productName;
    
    @Column(nullable = false)
    private Integer quantity;
    
    @Column(nullable = false, precision = 10, scale = 2)
    private BigDecimal price;
    
    @Column(nullable = false, precision = 10, scale = 2)
    private BigDecimal amount;
    
    @PrePersist
    public void calculateAmount() {
        this.amount = price.multiply(BigDecimal.valueOf(quantity));
    }
}

3.2 订单创建

java
@Service
public class OrderService {
    
    private final OrderRepository orderRepository;
    private final ProductClient productClient;
    private final InventoryClient inventoryClient;
    
    @GlobalTransactional(name = "create-order")
    public Order create(OrderRequest request) {
        // 生成订单号
        String orderNo = generateOrderNo();
        
        // 创建订单
        Order order = new Order();
        order.setOrderNo(orderNo);
        order.setUserId(request.getUserId());
        
        // 添加订单项
        for (OrderItemRequest item : request.getItems()) {
            Product product = productClient.getProduct(item.getProductId());
            
            OrderItem orderItem = new OrderItem();
            orderItem.setOrder(order);
            orderItem.setProductId(product.getId());
            orderItem.setProductName(product.getName());
            orderItem.setQuantity(item.getQuantity());
            orderItem.setPrice(product.getPrice());
            
            order.getItems().add(orderItem);
            
            // 扣减库存
            inventoryClient.deductStock(item.getProductId(), item.getQuantity());
        }
        
        // 计算总金额
        order.calculateTotalAmount();
        
        return orderRepository.save(order);
    }
    
    private String generateOrderNo() {
        String timestamp = LocalDateTime.now()
            .format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        String random = String.format("%04d", new Random().nextInt(10000));
        return timestamp + random;
    }
}

4. 库存服务开发

4.1 库存扣减

java
@Service
public class InventoryService {
    
    private final InventoryRepository inventoryRepository;
    private final RedisTemplate<String, Object> redisTemplate;
    
    private static final String STOCK_KEY_PREFIX = "stock:";
    
    @Transactional
    public boolean deductStock(Long productId, Integer quantity) {
        String key = STOCK_KEY_PREFIX + productId;
        
        // 使用 Redis 原子操作扣减库存
        Long remaining = redisTemplate.opsForValue().decrement(key, quantity);
        
        if (remaining < 0) {
            // 库存不足,回滚
            redisTemplate.opsForValue().increment(key, quantity);
            throw new BusinessException("库存不足");
        }
        
        // 更新数据库
        Inventory inventory = inventoryRepository.findByProductId(productId);
        inventory.setStock(inventory.getStock() - quantity);
        inventoryRepository.save(inventory);
        
        return true;
    }
    
    @Transactional
    public void restoreStock(Long productId, Integer quantity) {
        String key = STOCK_KEY_PREFIX + productId;
        redisTemplate.opsForValue().increment(key, quantity);
        
        Inventory inventory = inventoryRepository.findByProductId(productId);
        inventory.setStock(inventory.getStock() + quantity);
        inventoryRepository.save(inventory);
    }
}

5. 小结

本章完成了核心功能开发:

内容要点
用户服务CRUD、注册登录
商品服务商品管理、搜索
订单服务订单创建、状态管理
库存服务库存扣减、恢复

下一章将学习服务集成。