Technology Stack
Backend Framework: SpringBoot
Spring Boot integrates application servers such as Tomcat, Jetty, and Undertow, eliminating the need for manual installation and configuration. A key advantage of Spring Boot is its auto-configuration capability. It automatically configures the application based on the dependencies in the project, simplifying the setup process significantly. Additionally, Spring Boot offers a wide range of out-of-the-box features and plugins, including Spring Data, Spring Security, and Spring Cloud. These tools accelerate application development and facilitate easier integration with other technologies.
Frontend Framework: Vue
Vue.js utilizes a virtual DOM at its core, a technique that enables efficient DOM manipulation. It employs modern technologies such as reactive data binding and component-based architecture, providing developers with a flexible, efficient, and maintainable development model. When data changes, the user interface updates automatically, allowing developers to focus more on data processing rather than manual UI updates. This design exemplifies Vue's simplicity, flexibility, and high performance.
Persistence Layer Framework: MyBatis-Plus
MyBatis-Plus is an enhancement tool built upon the MyBatis framework, designed to streamline MyBatis development. As an open-source Java framework, it supports multiple databases including MySQL, Oracle, SQL Server, and PostgreSQL. MyBatis-Plus provides a rich set of APIs and annotations, enabling ORM operations with minimal configuration, thus reducing the need for manual SQL writing. It also includes a code generator that can automatically create entity classes, Mapper interfaces, and XML mapping files, greatly simplifying the development workflow. The framework supports features like pagination, dynamic queries, optimsitic locking, and performance analysis, making it a practical tool for efficient data operations.
System Testing
The primary objective of system testing is to identify potential issues from multiple perspectives, ensure defects are corrected, and verify that the system meets specified requirements. The process involves functional testing to uncover and fix flaws, confirming the system's reliability before deployment.
Testing Objectives
System testing is a crucial and rigorous phase in the software development lifecycle, serving as the final checkpoint for quality and reliability. Its goal is to enhance user experience by preemptively addressing issues. Testers must consider diverse scenarios to uncover defects. A thorough testing process reveals system quality, functional completeness, and logical coherence. The ultimate aim is to validate compliance with the requirement specifications and to detect any discrepancies.
Functional Testing
Functional modules are tested using methods such as boundary value analysis and input validation for required and optional fields, employing a black-box testing approach. Test cases are designed and executed, with results documented.
Login Function Test Plan: The system verifies user credentials against stored data. Incorrect inputs trigger appropriate error messages. Role-based access control is also validated.
| Input Data | Expected Result | Actual Result | Result Analysis |
|---|---|---|---|
| Username: admin, Password: 123456, Code: valid | Login successful | Login successful | As expected |
| Username: admin, Password: 111111, Code: valid | Password error | Password error | As expected |
| Username: admin, Password: 123456, Code: invalid | Captcha error | Captcha error | As expected |
| Username: (empty), Password: 123456, Code: valid | Username required | Username required | As expected |
| Username: admin, Password: (empty), Code: valid | Password error | Password error | As expected |
User Management Test Plan: Tests include adding, editing, deleting, and searching users. Adding a user validates required fields and checks for duplicate usernames. Deleting a user confirms the operation, and editing verifies data persistence.
| Input Data | Expected Result | Actual Result | Result Analysis |
|---|---|---|---|
| Complete user information | Add success, user appears in list | User added to list | As expected |
| Modify user details | Edit success, changes reflected | User details updated | As expected |
| Select delete user | Confirmation prompt, then deletion | User deleted after confirmation | As expected |
| Add user with missing username | Username required error | Username required error | As expected |
| Add user with existing username | Add fails, duplicate error | Add fails, duplicate error | As expected |
Test Conclusion
The system underwent comprehensive black-box testing with scenarios simulating real user interactions. All test cases were executed to verify functional correctness. The testing process ensures the system meets initial design specifications, with all functionalities operating as intended.
Code Implementation Examples
@IgnoreAuth
@PostMapping("/login")
public ApiResponse authenticate(@RequestParam String username, @RequestParam String password, @RequestParam String captcha, HttpServletRequest request) {
UserEntity currentUser = userDao.queryOne(new QueryWrapper<UserEntity>().eq("username", username));
if(currentUser == null || !currentUser.getPassword().equals(password)) {
return ApiResponse.error("Incorrect username or password");
}
String authToken = tokenService.createToken(currentUser.getId(), username, "user", currentUser.getRole());
return ApiResponse.ok().put("token", authToken);
}
@Override
public String createToken(Long userId, String userName, String tableName, String role) {
TokenEntity existingToken = this.selectOne(new QueryWrapper<TokenEntity>().eq("user_id", userId).eq("role", role));
String newToken = RandomStringUtil.generate(32);
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(Calendar.HOUR, 1);
Date expirationTime = calendar.getTime();
if(existingToken != null) {
existingToken.setToken(newToken);
existingToken.setExpiryTime(expirationTime);
this.updateById(existingToken);
} else {
this.insert(new TokenEntity(userId, userName, tableName, role, newToken, expirationTime));
}
return newToken;
}
@Component
public class AuthInterceptor implements HandlerInterceptor {
public static final String AUTH_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-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Origin, Content-Type, Accept");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
if (RequestMethod.OPTIONS.name().equals(request.getMethod())) {
response.setStatus(HttpStatus.OK.value());
return false;
}
IgnoreAuth authAnnotation;
if (handler instanceof HandlerMethod) {
authAnnotation = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAuth.class);
} else {
return true;
}
// Skip authentication for methods annotated with @IgnoreAuth
if(authAnnotation != null) {
return true;
}
String token = request.getHeader(AUTH_TOKEN_HEADER);
TokenEntity tokenRecord = null;
if(StringUtils.isNotBlank(token)) {
tokenRecord = tokenService.getTokenRecord(token);
}
if(tokenRecord != null) {
request.getSession().setAttribute("userId", tokenRecord.getUserId());
request.getSession().setAttribute("userRole", tokenRecord.getRole());
request.getSession().setAttribute("userTable", tokenRecord.getTableName());
request.getSession().setAttribute("userName", tokenRecord.getUsername());
return true;
}
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
try (PrintWriter writer = response.getWriter()) {
writer.print(JSONObject.toJSONString(ApiResponse.error(401, "Authentication required")));
}
return false;
}
}
Database Schema Example
-- ----------------------------
-- Token table structure
-- ----------------------------
DROP TABLE IF EXISTS `user_token`;
CREATE TABLE `user_token` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Primary Key',
`user_id` bigint(20) NOT NULL COMMENT 'User ID',
`username` varchar(100) NOT NULL COMMENT 'Username',
`table_name` varchar(100) DEFAULT NULL COMMENT 'Associated Table',
`role` varchar(100) DEFAULT NULL COMMENT 'User Role',
`token` varchar(200) NOT NULL COMMENT 'Authentication Token',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation Time',
`expires_at` timestamp NOT NULL COMMENT 'Expiration Time',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;