Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Full-Stack Food Ordering Platform: Technical Design and Cross-Platform Implementation

Tech May 12 3

System Architecture

The platform adopts a microservices-oriented architecture with clear separation between data layer, business logic, and presentation tiers. The server-side levergaes Spring Boot 2.x with embedded Tomcat containerization, providing RESTful API endpoints for client consumption. Frontend implementation spans two domains: a responsive web dashboard built with Vue.js 3.x composition API, and a lightweight WeChat mini-program developed using uni-app framework for cross-platform compilation.

Backend Infrastructure

Authentication Mechanism

The security layer implements JWT-style token authentication with custom interceptors. User credentials undergo validation against encrypted storage before session tokens are generated with temporal constraints.

@RestController
@RequestMapping("/api/v1/auth")
public class AuthenticationController {

    @AnonymousAccess
    @PostMapping("/signin")
    public ResponseEntity<AuthResult> authenticate(
            @RequestParam String account,
            @RequestParam String credentials,
            @RequestParam String verificationCode,
            HttpServletRequest request) {
        
        AccountProfile profile = accountService.findByAccountName(account);
        if (profile == null || !passwordEncoder.matches(credentials, profile.getEncryptedPassword())) {
            return ResponseEntity.status(401).body(AuthResult.failure("Invalid credentials"));
        }
        
        String sessionToken = tokenManager.createToken(
            profile.getId(), 
            account, 
            profile.getUserType(), 
            profile.getAccessLevel()
        );
        
        return ResponseEntity.ok(AuthResult.success(sessionToken));
    }
}

@Service
public class TokenManager {
    
    public String createToken(Long userId, String accountName, String tableIdentifier, String accessRole) {
        SessionToken existingToken = tokenRepository.findByUserIdAndRole(userId, accessRole);
        String jwtToken = RandomStringUtils.secureRandomAlphanumeric(32);
        Instant expiration = Instant.now().plus(1, ChronoUnit.HOURS);
        
        if (existingToken != null) {
            existingToken.setTokenValue(jwtToken);
            existingToken.setExpiresAt(Date.from(expiration));
            tokenRepository.update(existingToken);
        } else {
            SessionToken newToken = new SessionToken();
            newToken.setUserId(userId);
            newToken.setAccountName(accountName);
            newToken.setSourceTable(tableIdentifier);
            newToken.setRoleType(accessRole);
            newToken.setTokenValue(jwtToken);
            newToken.setExpiresAt(Date.from(expiration));
            tokenRepository.save(newToken);
        }
        return jwtToken;
    }
}

Request Interception

The platform utilizes Spring HandlerInterceptor to enforce authentication boundaries and handle cross-origin resource sharing (CORS) preflight requests.

@Component
public class SecurityInterceptor implements HandlerInterceptor {

    private static final String AUTH_HEADER = "Authorization";
    
    @Autowired
    private TokenManager tokenManager;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
                            Object handler) throws Exception {
        
        configureCorsHeaders(response, request);
        
        if (RequestMethod.OPTIONS.name().equals(request.getMethod())) {
            response.setStatus(HttpServlet.SC_OK);
            return false;
        }
        
        if (handler instanceof HandlerMethod) {
            HandlerMethod method = (HandlerMethod) handler;
            if (method.hasMethodAnnotation(AnonymousAccess.class)) {
                return true;
            }
        }
        
        String bearerToken = request.getHeader(AUTH_HEADER);
        if (!StringUtils.hasText(bearerToken)) {
            sendUnauthorizedResponse(response);
            return false;
        }
        
        SessionToken tokenData = tokenManager.validateToken(bearerToken);
        if (tokenData == null || tokenData.isExpired()) {
            sendUnauthorizedResponse(response);
            return false;
        }
        
        request.setAttribute("currentUserId", tokenData.getUserId());
        request.setAttribute("userRole", tokenData.getRoleType());
        request.setAttribute("sourceTable", tokenData.getSourceTable());
        request.setAttribute("accountName", tokenData.getAccountName());
        
        return true;
    }
    
    private void configureCorsHeaders(HttpServletResponse response, HttpServletRequest request) {
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Headers", 
            "Origin, Content-Type, Accept, Authorization, X-Requested-With");
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
    }
    
    private void sendUnauthorizedResponse(HttpServletResponse response) throws IOException {
        response.setStatus(HttpServlet.SC_UNAUTHORIZED);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write("{\"code\":401,\"message\":\"Authentication required\"}");
    }
}

Data Persistence Layer

MyBatis-Plus serves as the ORM framework, offering enhanced CRUD operations and dynamic SQL generation capabilities. The token storage schema maintains session state with expiration tracking.

DROP TABLE IF EXISTS `user_sessions`;
CREATE TABLE `user_sessions` (
  `session_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NOT NULL COMMENT 'Reference to user account',
  `account_name` varchar(100) NOT NULL,
  `entity_table` varchar(100) DEFAULT NULL COMMENT 'Source table discriminator',
  `privilege_level` varchar(100) DEFAULT NULL,
  `access_token` varchar(200) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `valid_until` timestamp NOT NULL DEFAULT '1970-01-01 00:00:00',
  PRIMARY KEY (`session_id`) USING BTREE,
  KEY `idx_token` (`access_token`),
  KEY `idx_user` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Frontend Implementation

Web Dashboard (Vue.js)

The administrative interface utilizes Vue 3 with Composition API, implementing virtual DOM diffing for efficient rendering. State management handles real-time order notifications and menu updates through WebSocket connections.

Mobile Client (uni-app)

The WeChat mini-program shares business logic across iOS and Android through uni-app's Vue-based syntax. Native API wrappers handle payment gateways, geolocation services, and push notifications while maintaining consistent UI components.

Quality Assurance

Functional Verification

Black-box testing validates business workflows without examining internal structures. Test scenarios cover authentication boundaries, data validation rules, and transaction integrity.

Authentication Test Matrix:

Input Scenario Expected Behavior Validation
Valid credentials + correct verification Session established, token returned Pass
Valid username, invalid password Access denied, error message displayed Pass
Empty username field Client-side validation triggers Pass
Expired session token 401 Unauthorized response Pass

User Management Verification:

Operation Test Case Outcome
Create user Duplicate username rejection System prevents collision
Update profile Data persistence verification Changes reflect immediately
Delete account Cascade validation Related records handled appropriately
Permission change Role-based access control Privileges update dynamically

Performance Validation

Load testing confirms the Spring Boot embedded containre handles concurrent order submissions. Connection pooling and MyBatis-Plus query optimization ensure sub-second response times for menu browsing and checkout processes under peak traffic conditions.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.