Technical Stacks
Backend Framework SpringBoot
Spring Boot is a development framework based on Spring Framework, with multiple built-in servers like Tomcat, Jetty and Undertow that require no additional installation or configuration. Its core auto-configuration feature automatically sets up applications based on project dependencies, greatly simplifying development workflows. It also offers rich out-of-the-box components including Spring Data, Spring Security and Spring Cloud, enabling rapid application building and easy integration with other technologies. Additional benefits include flexible configuration management, fast development and deployment, strong community support, monitoring and diagnostic tools, and reliable testing support, making it a popular choice for building high-quality, maintainable applications.
Sample core code:
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 FamilyFinanceApplication {
public static void main(String[] args) {
SpringApplication.run(FamilyFinanceApplication.class, args);
}
@GetMapping("/api/health")
public String checkHealth() {
return "Service is running normally";
}
}
This code defines the entry class for a Spring Boot application, marked with @SpringBootApplication and @RestController. The checkHealth method maps to the /api/health endpoint, returning a service status string when accessed. Starting the app via SpringApplication.run launches the embedded server, and visiting http://localhost:8080/api/health will return the status message.
Frontend Framework Vue.js
Vue.js is a popular JavaScript framework featuring reactive data binding, virtual DOM, and component-based architecture. Its reactive system automatically updates UI components when underlying data changes, letting developers focus on data logic rather than manual DOM manipulation. The virtual DOM optimizes rendering performance by minimizing actual DOM updates.
Sample Vue.js implementation:
<html>
<head>
<title>Family Finance Dashboard</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h3>Current Monthly Expense: {{ monthlyExpense }}</h3>
<button @click="refreshExpense">Refresh Data</button>
</div>
<script>
const financeApp = new Vue({
el: '#app',
data: {
monthlyExpense: '$0.00'
},
methods: {
refreshExpense() {
this.monthlyExpense = '$1,245.67';
}
}
});
</script>
</body>
</html>
This example creates a Vue instance bound to the #app element. It initializes monthlyExpense to $0.00, and updates the value when the button is clicked. The reactive binding automatically refreshes the displayed text without manual DOM changes.
Persistence Layer MyBatis
MyBatis is an open-source persistence framework that separates SQL statements from Java code via XML or annotations, decoupling data access logic from business code. Key advantages include:
- Simplified database operations with automatic Java object-to-database table mapping, reducing manual SQL writing
- Dynamic SQL support for generating tailored queries based on runtime conditions
- Built-in first-level and second-level caching to reduce database load
- Extensible plugin system for custom functionality
System Testing
To ensure high system quality, comprehensive testing was conducted across multiple dimensions to identify and resolve defects, ensuring system integrity and reliability. Functional testing was used to validate all modules, verify alignment with user requirements, and assess system performance.
System Testing Objectives
System testing is a critical final step in the development lifecycle, serving as the last checkpoint to ensure system quality and reliability. Its core goals include:
- Preventing user-facing issues and improving user experience
- Identifying defects by simulating real-world usage scenarios
- Validating that the system meets specified requirements and aligns with user needs
- Evaluating overall system quality and logical flow
Testing was conducted from a user perspective to avoid irrelevant scenarios, ensuring actual results match expected outcomes.
System Functional Testing
Black-box testing was used to validate all functional modules, including input boundary testing, required field validation, and scenario simulation. Test cases were written and executed for each module.
Login Function Test Cases
| Input Data | Expected Result | Actual Result | Analysis |
|---|---|---|---|
| Username: admin, Password: 123456, Valid Captcha | Successful login | Successful login | Match |
| Username: admin, Password: wrongpass, Valid Captcha | Password error prompt | "Incorrect username or password" | Match |
| Username: admin, Password:123456, Invalid Captcha | Captcha error prompt | "Invalid captcha" | Match |
| Empty Username, Password:123456, Valid Captcha | Required username prompt | "Please enter username" | Match |
| Username: admin, Empty Password, Valid Captcha | Required password prompt | "Please enter password" | Match |
User Management Function Tests
Add User Test Cases
| Input Data | Expected Result | Actual Result | Analysis |
|---|---|---|---|
| Username: user01, Password: 123456, Role: Regular User | User added to list | User01 appears in user list | Match |
| Duplicate Username: user01, Password:123456, Role: Regular User | Duplicate username error | "Username already exists" | Match |
| Empty Username | Required username error | "Please enter username" | Match |
Edit User Test Cases
| Input Data | Expected Result | Actual Result | Analysis |
|---|---|---|---|
| Edit user01 password to 654321 | Password updated successfully | User01 password changed to 654321 | Match |
| Edit user01 role to Admin | Role updated successfully | User01 role set to Admin | Match |
| Clear username during edit | Required username error | "Please enter username" | Match |
Delete User Test Cases
| Input Data | Expected Result | Actual Result | Analysis |
|---|---|---|---|
| Delete user01, confirm prompt | User removed from list | User01 deleted successfully | Match |
| Delete user01, cancel prompt | User remains in list | User01 not deleted | Match |
System Testing Conclusion
Black-box testing was used to validate all system functions by simulating user interactions. All test cases passed, confirming that the system meets design requirements and functional specifications, with correct logical flow and reliable performance. The testing process ensured the system is ready for user use with high quality and stability.
Code Reference Examples
// Custom annotation to skip authentication
@IgnoreAuth
@PostMapping("/api/auth/login")
public Result login(String username, String password, String captcha, HttpServletRequest request) {
// Fetch user by username
UserEntity user = userService.selectOne(new EntityWrapper<UserEntity>().eq("username", username));
// Validate user existence and password
if (user == null || !user.getPassword().equals(password)) {
return Result.error("Invalid username or password");
}
// Generate authentication token
String token = tokenService.generateToken(user.getId(), username, "users", user.getRole());
return Result.ok().put("token", token);
}
@Override
public String generateToken(Long userId, String username, String tableName, String userRole) {
// Check for existing valid token
TokenEntity existingToken = this.selectOne(new EntityWrapper<TokenEntity>()
.eq("userid", userId)
.eq("role", userRole));
// Generate random 32-character token
String newToken = CommonUtil.generateRandomString(32);
// Set token expiration to 1 hour from now
Calendar expiryTime = Calendar.getInstance();
expiryTime.add(Calendar.HOUR_OF_DAY, 1);
if (existingToken != null) {
existingToken.setToken(newToken);
existingToken.setExpiratedtime(expiryTime.getTime());
this.updateById(existingToken);
} else {
this.insert(new TokenEntity(userId, username, tableName, userRole, newToken, expiryTime.getTime()));
}
return newToken;
}
/**
* Token-based authentication interceptor
*/
@Component
public class AuthInterceptor implements HandlerInterceptor {
public static final String TOKEN_HEADER = "Authorization";
@Autowired
private TokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// Configure CORS headers
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, " + TOKEN_HEADER + ", Origin, Content-Type");
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
// Handle preflight OPTIONS requests
if (HttpMethod.OPTIONS.name().equals(request.getMethod())) {
response.setStatus(HttpStatus.OK.value());
return false;
}
// Skip authentication for methods with @IgnoreAuth annotation
IgnoreAuth skipAuth = null;
if (handler instanceof HandlerMethod) {
skipAuth = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAuth.class);
}
if (skipAuth != null) {
return true;
}
// Extract token from request header
String token = request.getHeader(TOKEN_HEADER);
if (!StringUtils.hasText(token)) {
return handleAuthFailure(response);
}
// Validate token
TokenEntity validToken = tokenService.getValidToken(token);
if (validToken != null) {
// Attach user info to request session
request.getSession().setAttribute("userId", validToken.getUserid());
request.getSession().setAttribute("userRole", validToken.getRole());
return true;
}
return handleAuthFailure(response);
}
private boolean handleAuthFailure(HttpServletResponse response) throws IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
try (PrintWriter writer = response.getWriter()) {
writer.print(JSONObject.toJSONString(Result.error(401, "Please login first")));
}
return false;
}
}
Database Reference
Sample financial record table schema:
DROP TABLE IF EXISTS `finance_record`;
CREATE TABLE `finance_record` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Primary Key',
`record_type` tinyint(1) NOT NULL COMMENT 'Record Type: 0=Expense, 1=Income',
`amount` decimal(12,2) NOT NULL COMMENT 'Transaction Amount',
`category` varchar(50) NOT NULL COMMENT 'Transaction Category',
`description` varchar(200) DEFAULT NULL COMMENT 'Transaction Notes',
`transaction_date` datetime NOT NULL COMMENT 'Transaction Time',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation Time',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update Time',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='Financial Transaction Records';
-- Sample insert data
INSERT INTO `finance_record` (`record_type`, `amount`, `category`, `description`, `transaction_date`)
VALUES
(0, 79.99, 'Groceries', 'Weekly grocery shopping', '2024-05-15 10:30:00'),
(1, 2500.00, 'Salary', 'Monthly salary deposit', '2024-05-01 09:00:00'),
(0, 129.99, 'Entertainment', 'Movie ticket purchase', '2024-05-20 19:00:00');