Developing a Food Snatching and Sharing Platform for WeChat Mini Program Users

Given the widespread adoption of WeChat, the client side of this platform is developed as a WeChat Mini Program to align with real-world usage scenarios.

1. Implementing WeChat Login (Controller Layer)

@PostMapping("/wechat-login")
@ApiOperation("WeChat user authentication")
public Result<AuthResponseVO> authenticate(@RequestBody WechatAuthDTO authDTO) {
    log.info("WeChat login attempt with code: {}", authDTO.getWxCode());
    
    // Authenticate user via WeChat
    AppUser user = userAccountService.handleWechatAuth(authDTO);

    // Generate JWT token for the user
    Map<String, Object> claims = new HashMap<>();
    claims.put(JwtClaimsConstant.USER_KEY, user.getUserId());
    String jwtToken = JwtUtil.generateToken(jwtConfig.getSecret(), jwtConfig.getExpiration(), claims);

    AuthResponseVO response = AuthResponseVO.builder()
            .userId(user.getUserId())
            .wechatOpenId(user.getWechatOpenId())
            .accessToken(jwtToken)
            .build();

    return Result.success(response);
}

2. Backend Processing and User Registration (Service Layer)

The Java back end intercepts the login request from the Mini Program. It validates the user; if the user is new, the system persists the data and returns the user details to the client.

public AppUser handleWechatAuth(WechatAuthDTO authDTO) {
    String openId = retrieveOpenId(authDTO.getWxCode());

    // Validate OpenID retrieval
    if (openId == null) {
        throw new AuthenticationException(MessageConstant.AUTH_FAILED);
    }

    // Check if user exists
    AppUser existingUser = userRepository.findByOpenId(openId);
    if (existingUser == null) {
        // Auto-register new user
        existingUser = AppUser.builder()
                .wechatOpenId(openId)
                .registeredAt(LocalDateTime.now())
                .build();
        userRepository.saveNewUser(existingUser);
    }
    return existingUser;
}

3. Database Persistence (MySQL)

<insert id="saveNewUser" useGeneratedKeys="true" keyProperty="userId">
    INSERT INTO app_user (wechat_open_id, full_name, mobile, gender, identity_no, profile_pic, registered_at)
    VALUES (#{wechatOpenId}, #{fullName}, #{mobile}, #{gender}, #{identityNo}, #{profilePic}, #{registeredAt})
</insert>

4. Shopping Cart Functionality

The virtual shopping cart mirrors a physical one, storing data in a dedicated table for standard CRUD operations.

When adding an item, the system checks for existing records. If found, it increments the quantity. Otherwise, it identifeis whether the item is a single dish or a combo meal and inserts a new record accordingly.

API Endpoint

// Add item to cart
@PostMapping("/cart/add")
public Result addItem(@RequestBody CartItemDTO itemDTO) {
    cartService.processCartAddition(itemDTO);
    return Result.success();
}

Service Implementation

/**
 * Adds an item to the shopping cart.
 */
public void processCartAddition(CartItemDTO itemDTO) {
    CartItem cartItem = new CartItem();
    BeanUtils.copyProperties(itemDTO, cartItem);
    Long currentUserId = UserContext.getActiveUserId();
    cartItem.setUserId(currentUserId);

    List<CartItem> existingItems = cartMapper.findItems(cartItem);
    
    if (existingItems != null && !existingItems.isEmpty()) {
        // Update quantity if item exists
        CartItem currentItem = existingItems.get(0);
        currentItem.setQuantity(currentItem.getQuantity() + 1);
        cartMapper.updateQuantity(currentItem);
    } else {
        // Insert new item
        Long dishId = itemDTO.getDishId();
        if (dishId != null) {
            Dish dishDetails = dishRepo.findById(dishId);
            cartItem.setItemName(dishDetails.getName());
            cartItem.setImageUrl(dishDetails.getImage());
            cartItem.setPrice(dishDetails.getCost());
        } else {
            Long comboId = itemDTO.getComboId();
            Combo comboDetails = comboRepo.findById(comboId);
            cartItem.setItemName(comboDetails.getName());
            cartItem.setImageUrl(comboDetails.getImage());
            cartItem.setPrice(comboDetails.getCost());
        }
        cartItem.setQuantity(1);
        cartItem.setAddedAt(LocalDateTime.now());
        cartMapper.insertItem(cartItem);
    }
}

Data Access Layer

/**
 * Dynamic query for cart items
 */
List<CartItem> findItems(CartItem cartItem);

/**
 * Update item quantity
 */
@Update("UPDATE user_cart SET quantity = #{quantity} WHERE cart_id = #{cartId}")
void updateQuantity(CartItem cartItem);

/**
 * Insert new cart item
 */
@Insert("INSERT INTO user_cart(item_name, image_url, user_id, dish_id, combo_id, flavor, price, added_at) " +
        "VALUES (#{itemName}, #{imageUrl}, #{userId}, #{dishId}, #{comboId}, #{flavor}, #{price}, #{addedAt})")
void insertItem(CartItem cartItem);

5. Viewing and Clearing the Cart

Retrieving or clearing the cart involves simple GET and DELETE requests to query or remove data.

// Retrieve cart contents
@GetMapping("/cart/view")
public Result<List<CartItem>> viewCart() {
    List<CartItem> contents = cartService.getCartContents();
    return Result.success(contents);
}

// Empty the cart
@DeleteMapping("/cart/empty")
public Result emptyCart() {
    cartService.clearUserCart();
    return Result.success();
}
/**
 * Fetch current cart contents
 */
public List<CartItem> getCartContents() {
    Long currentUserId = UserContext.getActiveUserId();
    CartItem query = CartItem.builder().userId(currentUserId).build();
    return cartMapper.findItems(query);
}

/**
 * Clear all items for the user
 */
public void clearUserCart() {
    Long currentUserId = UserContext.getActiveUserId();
    cartMapper.removeAllByUser(currentUserId);
}

Tags: WeChat Mini Program WeChat Login JWT Spring Boot MyBatis

Posted on Mon, 15 Jun 2026 16:51:24 +0000 by skter4938