Design and Implementation of a Personal Finance System Using Java, Spring Boot, and Vue
The increasing demand for personal financial management has led to the development of personal finance systems. These systems provide a convenient and effective way for individuals to manage income, expenses, investments, and savings. The rapid growth of financial technology (Fintech) supports these systems with internet, mobile devices, data analysis, and artificial intelligence technologies. They offer features like account management, budget planning, investment advice, and financial analysis, delivering intelligent and personalized services. Many people lack sufficient knowledge and experience in financial management, leading to risks and waste. Personal finance systems help improve financial literacy through education, budgeting tools, and account analysis. Traditional banking services often fail to meet diverse and personalized needs, but these systems provide customized solutions with personalized account settings and intelligent data analysis. The openness of financial markets and the popularity of internet and mobile payments accelerate their development, offering more choices and better experiences from both traditional institutions and new Fintech platforms.
Backend Framework: Spring Boot
Spring Boot includes built-in servers like Tomcat, Jetty, and Undertow, allowing direct use without additional installation and configuration. A key advantage is its auto-configuration capability, which automatically sets up applications based on project dependencies, simplifying configuration. It also provides many out-of-the-box features and plugins, such as Spring Data, Spring Security, and Spring Cloud, enabling faster development and easier integration with other technologies. As a popular framework, its auto-configuration, built-in servers, and plugins help developers build high-quality applications quickly and efficiently.
Frontend Framework: Vue
Vue.js utilizes virtual DOM technology, a memory data structure that enables efficient DOM operations. It employs reactive data binding, virtual DOM, and componentization, offering a flexible, efficient, and maintainable development model. When data changes, the UI updates automatically, allowing developers to focus on data processing rather than manual UI updates, making Vue concise, flexible, and efficient.
Database: MySQL
MySQL is an open-source relational database management system (RDBMS) widely used in backend development, data storage, and retrieval. Its open-source nature allows free use, modification, and distribusion of source code, making it a preferred choice for many developers and organizations. MySQL supports multiple platforms, including Windows, Linux, and macOS, providing flexibility for various development and deployment environments. A large community offers extensive documentation, forums, and tools, enhancing its usability.
System Testing
System testing is essential in the development cycle to ensure quality and reliability. It serves as the final check before deployment, aiming to prevent user issues and enhance experience. Testing should consider multiple angles and scenarios to identify and resolve defects, ensuring the system meets requirements and functions correctly.
System Testing Objectives
Testing verifies that the system meets specification requirements and identifies any inconsistencies. It should focus on user perspectives, avoiding unrealistic scenarios to prevent wasted time and mismatched results.
System Functional Testing
Functional modules are tested through methods like clicking, inputting boundary values, and validating required fields using black-box testing. Test cases are written and executed to derive conclusions.
Login Function Testing Scheme: When logging in, the system validates credentials like username and password. Users must input data matching stored database entries; errors prompt corrections. The interface also validates role permissions, with erors for incorrect role selections. Login test cases are shown in the table below.
| Input Data | Expected Result | Actual Result | Result Analysis |
|---|---|---|---|
| Username: admin, Password: 123456, Captcha: correct | Login successful | Login successful | Matches expected |
| Username: admin, Password: 111111, Captcha: correct | Password error | Password error, re-enter | Matches expected |
| Username: admin, Password: 123456, Captcha: incorrect | Captcha error | Captcha information error | Matches expected |
| Username: empty, Password: 123456, Captcha: correct | Username required | Please enter username | Matches expected |
| Username: admin, Password: empty, Captcha: correct | Password error | Password error, re-enter | Matches expected |
User Management Function Testing Scheme: User management includes add, edit, delete, and search functions. When adding a user, required fields are validated for non-emptiness; adding existing user information checks for duplicate username prompts; deleting user information verifies system confirmation; editing user information ensures changes are displayed. User management test cases are shown in the table below.
| Input Data | Expected Result | Actual Result | Result Analysis |
|---|---|---|---|
| Fill in basic user information | Add successful, displayed in list | User appears in list | Matches expected |
| Modify user information | Edit successful, information updated | User information modified | Matches expected |
| Select delete user | System asks for confirmation, user deleted after confirm | System asks for confirmation, user not found after confirm | Matches expected |
| Add user without username | Prompt username cannot be empty | Prompt username cannot be empty | Matches expected |
| Fill in existing username | Add failed, prompt duplicate username | Add failed, prompt duplicate username | Matches expected |
System Testing Conclusion
This system primarily uses black-box testing, simulating user operations to write and execute test cases, ensuring corect system flow. Testing is crucial for system improvement and higher usability. It validates that functional modules meet initial design concepts and logic correctness. The system does not require complex logic processing for ease of use. The ultimate goal revolves around user experience, with all scenarios aligned to user needs. After testing, the system meets design requirements in functionality and performance.
Code Reference
@IgnoreAuth
@PostMapping("/authenticate")
public Response authenticateUser(String userIdentifier, String secretCode, String verificationCode, HttpServletRequest req) {
UserAccount account = accountService.fetchUser(new EntityWrapper<UserAccount>().eq("userIdentifier", userIdentifier));
if (account == null || !account.getSecretCode().equals(secretCode)) {
return Response.error("Invalid credentials");
}
String authToken = authTokenService.createToken(account.getId(), userIdentifier, "userAccounts", account.getRole());
return Response.ok().withData("authToken", authToken);
}
@Override
public String createToken(Long accountId, String userIdentifier, String tableName, String role) {
AuthTokenEntity tokenEntry = this.fetchOne(new EntityWrapper<AuthTokenEntity>().eq("accountId", accountId).eq("role", role));
String newToken = Utility.generateRandomString(32);
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(Calendar.HOUR_OF_DAY, 1);
if (tokenEntry != null) {
tokenEntry.setToken(newToken);
tokenEntry.setExpirationTime(calendar.getTime());
this.updateById(tokenEntry);
} else {
this.insert(new AuthTokenEntity(accountId, userIdentifier, tableName, role, newToken, calendar.getTime()));
}
return newToken;
}
@Component
public class AuthInterceptor implements HandlerInterceptor {
public static final String AUTH_TOKEN_HEADER = "Auth-Token";
@Autowired
private AuthTokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
resp.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
resp.setHeader("Access-Control-Max-Age", "3600");
resp.setHeader("Access-Control-Allow-Credentials", "true");
resp.setHeader("Access-Control-Allow-Headers", "x-requested-with,request-source,Auth-Token, Origin,imgType, Content-Type, cache-control,postman-token,Cookie, Accept,authorization");
resp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
if (req.getMethod().equals(RequestMethod.OPTIONS.name())) {
resp.setStatus(HttpStatus.OK.value());
return false;
}
IgnoreAuth annotation;
if (handler instanceof HandlerMethod) {
annotation = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAuth.class);
} else {
return true;
}
String token = req.getHeader(AUTH_TOKEN_HEADER);
if (annotation != null) {
return true;
}
AuthTokenEntity tokenEntry = null;
if (StringUtils.isNotBlank(token)) {
tokenEntry = tokenService.getTokenEntry(token);
}
if (tokenEntry != null) {
req.getSession().setAttribute("accountId", tokenEntry.getAccountId());
req.getSession().setAttribute("role", tokenEntry.getRole());
req.getSession().setAttribute("tableName", tokenEntry.getTableName());
req.getSession().setAttribute("userIdentifier", tokenEntry.getUserIdentifier());
return true;
}
PrintWriter writer = null;
resp.setCharacterEncoding("UTF-8");
resp.setContentType("application/json; charset=utf-8");
try {
writer = resp.getWriter();
writer.print(JSONObject.toJSONString(Response.error(401, "Authentication required")));
} finally {
if (writer != null) {
writer.close();
}
}
return false;
}
}
Database Reference
-- ----------------------------
-- Table structure for auth_token
-- ----------------------------
DROP TABLE IF EXISTS `auth_token`;
CREATE TABLE `auth_token` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Primary key',
`account_id` bigint(20) NOT NULL COMMENT 'Account ID',
`user_identifier` varchar(100) NOT NULL COMMENT 'User identifier',
`table_name` varchar(100) DEFAULT NULL COMMENT 'Table name',
`role` varchar(100) DEFAULT NULL COMMENT 'Role',
`token` varchar(200) NOT NULL COMMENT 'Token',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation time',
`expires_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Expiration time',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='Token table';
-- ----------------------------
-- Records of auth_token
-- ----------------------------
INSERT INTO `auth_token` VALUES ('9', '23', 'cd01', 'student', 'Student', 'al6svx5qkei1wljry5o1npswhdpqcpcg', '2023-02-23 21:46:45', '2023-03-15 14:01:36');
INSERT INTO `auth_token` VALUES ('10', '11', 'xh01', 'student', 'Student', 'fahmrd9bkhqy04sq0fzrl4h9m86cu6kx', '2023-02-27 18:33:52', '2023-03-17 18:27:42');
INSERT INTO `auth_token` VALUES ('11', '17', 'ch01', 'student', 'Student', 'u5km44scxvzuv5yumdah2lhva0gp4393', '2023-02-27 18:46:19', '2023-02-27 19:48:58');
INSERT INTO `auth_token` VALUES ('12', '1', 'admin', 'user_accounts', 'Administrator', 'h1pqzsb9bldh93m92j9m2sljy9bt1wdh', '2023-02-27 19:37:01', '2023-03-17 18:23:02');
INSERT INTO `auth_token` VALUES ('13', '21', 'xiaohao', 'club_leader', 'Club Leader', 'zdm7j8h1wnfe27pkxyiuzvxxy27ykl2a', '2023-02-27 19:38:07', '2023-03-17 18:25:20');
INSERT INTO `auth_token` VALUES ('14', '27', 'djy01', 'student', 'Student', 'g3teq4335pe21nwuwj2sqkrpqoabqomm', '2023-03-15 12:56:17', '2023-03-15 14:00:16');
INSERT INTO `auth_token` VALUES ('15', '29', 'dajiyue', 'club_leader', 'Club Leader', '0vb1x9xn7riewlp5ddma5ro7lp4u8m9j', '2023-03-15 12:58:08', '2023-03-15 14:03:48');