Building a Full-Stack Sales System with Spring Boot, Vue.js, and UniApp

Backend Framework Implementation

Spring Boot serves as the foundational framework for the backend architecture, offering significant advantages for rapid development. By embedding servers like Tomcat or Jetty, it eliminates the need for manual container configuration. The framework's auto-configuration mechanism intelligently adjusts the application context based on discovered dependencies, drastically reducing boilerplate code. Furthermore, the ecosystem provides seamless integration with tools like Spring Data for persistence and Spring Security for access control, ensuring a scalable and maintainable codebase.

Below is a simplified representation of a RESTful controller configured within the Spring Boot environment:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
import java.util.Map;

@SpringBootApplication
@RestController
@RequestMapping("/api/v1")
public class SalesSystemApplication {

    public static void main(String[] args) {
        SpringApplication.run(SalesSystemApplication.class, args);
    }

    @GetMapping("/health")
    public Map<String, String> systemHealthCheck() {
        return Collections.singletonMap("status", "operational");
    }
}

In this snippet, the SalesSystemApplication class serves as the entry point. The @RestController annotation marks the class as a controller where every method returns a domain object instead of a view. The systemHealthCheck method responds to HTTP GET requests on the /api/v1/health endpoint, returning a JSON status indicator.

Frontend Framework Utilization

Vue.js is employed for the client-side interface, leveraging its reactive data binding and component-based architecture. The framework's virtual DOM optimizes rendering performance by minimizing direct manipulations of the actual DOM. This approach allows developers to focus on data logic, as the UI updates automatically when the underlying state changes.

The following example demonstrates the reactivity of Vue.js using a simple interactive component:


<html>
<head>
  <title>Inventory Control</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
  <div id="app">
    <h3>Product: {{ currentItem }}</h3>
    <p>Availability: {{ isAvailable ? 'In Stock' : 'Sold Out' }}</p>
    <button @click="toggleStatus">Update Status</button>
  </div>

  <script>
    new Vue({
      el: '#app',
      data: {
        currentItem: 'Stainless Steel Pot',
        isAvailable: true
      },
      methods: {
        toggleStatus: function() {
          this.isAvailable = !this.isAvailable;
        }
      }
    });
  </script>
</body>
</html>

This script initializes a Vue instance bound to the DOM element with the ID app. The data object holds the state, and the toggleStatus method modifies this state. The double curly braces {{ }} handle the interpolation, ensuring the view reflects the current data state immediately upon interaction.

Persistence Layer Strategy

MyBatis is utilized as the persistence framework to decouple SQL queries from Java logic. By mapping methods to XML statements or annotations, MyBatis provides fine-grained control over SQL execution while maintaining simplicity. Key benefits include dynamic SQL generation for complex queries, a robust caching mechanism to reduce database load, and a plugin architecture that allows for custom interceptors and extensions.

System Verification and Testing

Testing Objectives

Comprehensive testing is essential to validate system stability and functionality. The primary goal is to ensure the application meets all specified requirements without defects. By simulating real-world user scenarios, the testing process identifies logic errors and usability issues, ensuring that the final product delivers a reliable and intuitive experience.

Functional Testing Execution

Functional tests focus on verifying the behavior of specific modules. Black-box testing techniques are applied, where inputs are provided and outputs are compared against expected results without examining the internal code structure.

Login Authentication Tests

Input DataExpected ResultActual ResultStatus
Username: admin / Pass: admin123 / Captcha: ValidSuccess, redirect to dashboardSuccessfully logged inPass
Username: admin / Pass: wrongpass / Captcha: ValidError: Invalid credentialsDisplayed error messagePass
Username: admin / Pass: admin123 / Captcha: InvalidError: Captcha mismatchDisplayed error messagePass
Username: (empty) / Pass: admin123 / Captcha: ValidError: Username requiredDisplayed validation messagePass

Employee Management Tests

Creation Test Cases:

Input DataExpected ResultActual ResultStatus
User: staff01 / Role: ManagerUser created successfullyUser visible in listPass
User: staff01 / Role: ManagerError: Duplicate userSystem rejected duplicatePass
User: (empty) / Role: ClerkError: Username requiredValidation error shownPass

Modification Test Cases:

ActionExpected ResultActual ResultStatus
Update staff01 role to AdminPermissions updatedRole changed in DBPass
Set staff01 username to emptyError: Field requiredUpdate preventedPass

Security Implementation Details

The following Java implementation illustrates a secure authentication flow using token-based validation. It includes a login controller, a token generation service, and an interceptor for request filtering.

import org.springframework.web.bind.annotation.*;
import javax.servlet.http.*;
import java.util.*;

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

    @Autowired
    private SecurityTokenService tokenService;

    @Autowired
    private UserRepository userRepository;

    @PostMapping("/perform-login")
    public Map<String, Object> login(@RequestBody Map<String, String> payload, HttpServletRequest request) {
        String username = payload.get("username");
        String password = payload.get("password");

        UserEntity user = userRepository.findByUsername(username);
        
        if (user == null || !user.validatePassword(password)) {
            return Collections.singletonMap("error", "Invalid credentials provided");
        }

        String accessToken = tokenService.createSessionToken(user.getId(), user.getRole());
        Map<String, Object> response = new HashMap<>();
        response.put("token", accessToken);
        return response;
    }
}

@Service
public class SecurityTokenService {

    @Autowired
    private TokenRepository tokenRepository;

    public String createSessionToken(Long userId, String roleName) {
        String generatedKey = UUID.randomUUID().toString().replace("-", "");
        Date expiry = Date.from(LocalDateTime.now().plusHours(2).atZone(ZoneId.systemDefault()).toInstant());
        
        TokenEntity existingToken = tokenRepository.findByUserId(userId);
        if (existingToken != null) {
            existingToken.setKey(generatedKey);
            existingToken.setExpiryDate(expiry);
            tokenRepository.save(existingToken);
        } else {
            TokenEntity newToken = new TokenEntity(userId, roleName, generatedKey, expiry);
            tokenRepository.save(newToken);
        }
        return generatedKey;
    }
}

@Component
public class SecurityInterceptor implements HandlerInterceptor {

    public static final String AUTH_HEADER = "X-Auth-Token";

    @Autowired
    private SecurityTokenService tokenService;

    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
        res.setHeader("Access-Control-Allow-Origin", "*");
        res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        res.setHeader("Access-Control-Allow-Headers", "Content-Type, X-Auth-Token");

        if ("OPTIONS".equalsIgnoreCase(req.getMethod())) {
            res.setStatus(HttpServletResponse.SC_OK);
            return false;
        }

        if (handler instanceof HandlerMethod) {
            PublicAccess annotation = ((HandlerMethod) handler).getMethodAnnotation(PublicAccess.class);
            if (annotation != null) return true;
        }

        String requestToken = req.getHeader(AUTH_HEADER);
        if (requestToken == null || !tokenService.validateToken(requestToken)) {
            res.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication required");
            return false;
        }

        return true;
    }
}

Database Schema Design

The database schema is designed to efficiently manage product inventory. Below is the SQL definition for the product catalog table.

-- ----------------------------
-- Table structure for kitchenware_catalog
-- ----------------------------
DROP TABLE IF EXISTS `kitchenware_catalog`;
CREATE TABLE `kitchenware_catalog` (
  `item_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Unique Item Identifier',
  `item_name` varchar(150) NOT NULL COMMENT 'Name of the Kitchenware Product',
  `unit_price` decimal(12, 2) NOT NULL COMMENT 'Price per Unit',
  `item_specs` varchar(255) DEFAULT NULL COMMENT 'Product Specifications',
  `inventory_count` int(11) NOT NULL DEFAULT '0' COMMENT 'Available Quantity',
  `date_added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Record Creation Date',
  `last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Last Modification Date',
  PRIMARY KEY (`item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Kitchenware Product Inventory';

Example data insertion:

INSERT INTO `kitchenware_catalog` (`item_name`, `unit_price`, `item_specs`, `inventory_count`)
VALUES ('Commercial Chef Knife', 45.50, 'Stainless steel, 8 inch blade', 200);

INSERT INTO `kitchenware_catalog` (`item_name`, `unit_price`, `item_specs`, `inventory_count`)
VALUES ('Non-Stick Frying Pan', 32.99, 'Ceramic coating, 12 inch diameter', 150);

INSERT INTO `kitchenware_catalog` (`item_name`, `unit_price`, `item_specs`, `inventory_count`)
VALUES ('Digital Kitchen Scale', 25.00, 'Max capacity 5kg, LCD display', 80);

Tags: Spring Boot Vue.js UniApp Software Architecture System Testing

Posted on Fri, 18 Sep 2026 16:48:30 +0000 by yelvington