Building a WeChat Mini Program Ordering System with Spring Boot and Vue.js
Spring Boot is a development framework built on top of the Spring Framework. It simplifies configuration by embedding servers like Tomcat and provides powerful auto-configuration based on project dependencies. This framework offers out-of-the-box features and plugins such as Spring Data and Spring Security, enabling rapid application development and easy integration with other technologies. Its flexible configuration management, quick deployment, strong community support, and robust testing tools make it a popular choice for building scalable and maintainable applications.
A basic Spring Boot application structure is illustrated below:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@GetMapping("/greet")
public String sendGreeting() {
return "Welcome to the application!";
}
}
The @SpringBootApplication annotation marks this class as the application's entry point. The @RestController annotation designates it as a controller for handling RESTful requests. The sendGreeting method, mapped to the /greet endpoint via @GetMapping, returns a simple string response. Running the application starts an embedded server, allowing access to the endpoint.
Vue.js is a progressive JavaScript framework for building user interfaces. Its core advantages include reactive data binding and a virtual DOM, which enable efficient UI updates. The component-based architecture promotes reusability and maintainability.
The following example demonstrates basic Vue.js functionality:
<!DOCTYPE html>
<html>
<head>
<title>Vue Example</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
<h3>{{ greetingText }}</h3>
<button @click="updateGreeting">Update Text</button>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
greetingText: 'Hello from Vue!'
}
},
methods: {
updateGreeting() {
this.greetingText = 'Vue.js is reactive!';
}
}
}).mount('#app');
</script>
</body>
</html>
This code creates a Vue application instance bound to the #app element. The greetingText data property is displayed in the template. Clicking the button triggers the updateGreeting method, which changes the greetingText value, and Vue automatically updates the DOM to reflect the change.
MyBatis is a persistance framework that simplifies database interactions by separating SQL statements from Java code. It uses XML or annotations to map Java objects to database tables. Key features include dynamic SQL support, caching mechanisms to improve performance, and a plugin system for extensibility.
Comprehensive testing is essential to ensure system quality and reliability. The primary goal is to identify defects from multiple perspectives, simulate various user scenarios, and verify that the system meets specified requirements. Testing helps improve the final product's stability and user experience.
Functional testing involves validating system modules using techniques like boundary value analysis and equivalence partitioning. Test cases are designed and executed to verify expected behavior.
For example, login functionality can be tested with the following cases:
| Input Data (Username, Password, Captcha) | Expected Result | Actual Result | Analysis |
|---|---|---|---|
| admin, correct_pwd, valid_captcha | Successful login | Successful login | Pass |
| admin, wrong_pwd, valid_captcha | Password error | Password error | Pass |
| admin, correct_pwd, invalid_captcha | Captcha error | Captcha error | Pass |
| (empty), correct_pwd, valid_captcha | Username required | Username required | Pass |
| admin, (empty), valid_captcha | Password error | Password error | Pass |
User management functions, including addition, modification, and deletion, should also be rigorously tested.
| Function | Input Data | Expected Result | Actual Result | Analysis |
|---|---|---|---|---|
| Add User | new_user, pwd123, User | User added to list | User added to list | Pass |
| Add User | existing_user, pwd123, User | Username exists error | Username exists error | Pass |
| Edit User | Select user, change password | Password updated | Password updated | Pass |
| Delete User | Select user, confirm | User removed | User removed | Pass |
Black-box testing, which simulates end-user interactions, is a primary method for validating system workflows. The testing process aims to confirm that all functional modules operate correctly according to design specifications and user requirements. The final test results demonstrate that the system meets functional and performance objectives.
The following Java code illustrates a login endpoint and token-based authentication interceptor:
// Login endpoint ignoring auth check
@IgnoreAuth
@PostMapping("/signin")
public Result loginUser(@RequestParam String uid,
@RequestParam String pwd,
HttpServletRequest req) {
// Fetch user by username
UserAccount account = accountService.query()
.eq("username", uid).one();
if (account == null || !account.getPassword().equals(pwd)) {
return Result.error("Invalid credentials");
}
// Generate authentication token
String authToken = tokenUtil.createToken(account.getId(),
uid,
account.getRole());
return Result.ok().put("token", authToken);
}
// Token generation logic
public String createToken(Long userId,
String username,
String role) {
// Check for existing token
AuthToken existing = tokenDao.selectOne(new QueryWrapper<AuthToken>()
.eq("user_id", userId).eq("role", role));
String newToken = RandomStringUtils.randomAlphanumeric(32);
Calendar expiry = Calendar.getInstance();
expiry.add(Calendar.HOUR, 1);
if (existing != null) {
existing.setTokenValue(newToken);
existing.setExpiryTime(expiry.getTime());
tokenDao.updateById(existing);
} else {
AuthToken newRecord = new AuthToken();
newRecord.setUserId(userId);
newRecord.setUsername(username);
newRecord.setRole(role);
newRecord.setTokenValue(newToken);
newRecord.setExpiryTime(expiry.getTime());
tokenDao.insert(newRecord);
}
return newToken;
}
// Authentication interceptor
@Component
public class AuthInterceptor implements HandlerInterceptor {
public static final String AUTH_HEADER = "X-Auth-Token";
@Autowired
private TokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// Handle CORS preflight requests
if (HttpMethod.OPTIONS.name().equals(request.getMethod())) {
response.setStatus(HttpStatus.OK.value());
return false;
}
IgnoreAuth ignoreAuth = null;
if (handler instanceof HandlerMethod) {
ignoreAuth = ((HandlerMethod) handler)
.getMethodAnnotation(IgnoreAuth.class);
}
// Bypass auth for methods annotated with @IgnoreAuth
if (ignoreAuth != null) {
return true;
}
String token = request.getHeader(AUTH_HEADER);
AuthToken tokenEntity = tokenService.getByToken(token);
if (tokenEntity != null) {
// Store user context in request session
request.getSession().setAttribute("userId",
tokenEntity.getUserId());
request.getSession().setAttribute("role",
tokenEntity.getRole());
return true;
}
// Authentication failed
response.setContentType("application/json;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
out.write(JSON.toJSONString(
Result.error(401, "Authentication required")));
}
return false;
}
}
The @IgnoreAuth annotation marks endpoints that do not require authentication, such as login. The login endpoint validates user credentials and issues a token. The AuthInterceptor checks for a valid token in the request header for protected endpoints, returning a 401 error if authentication fails.
A sample database table for storing product information is defined as follows:
CREATE TABLE `product` (
`id` BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT 'Primary Key',
`product_name` VARCHAR(200) NOT NULL COMMENT 'Product Name',
`unit_price` DECIMAL(12,2) NOT NULL COMMENT 'Price',
`details` TEXT COMMENT 'Description',
`inventory` INT NOT NULL DEFAULT 0 COMMENT 'Stock Quantity',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Product Catalog';
This table includes fields for product ID, name, price, description, stock level, and timestamps for creation and updates.
Sample data insertion:
INSERT INTO `product` (`product_name`, `unit_price`, `details`, `inventory`)
VALUES ('Wireless Headphones', 89.99, 'Noise-cancelling over-ear headphones', 200);
INSERT INTO `product` (`product_name`, `unit_price`, `details`, `inventory`)
VALUES ('Laptop Stand', 34.50, 'Adjustable aluminum stand', 150);