Technology Stack
Backend Framework: Spring Boot
Spring Boot simplifies application setup by embedding servers like Tomcat, Jetty, or Undertow, eliminating the need for manual installation and configuration. Its auto-configuration feature intelligently configures the application based on project dependencies, reducing boilerplate code. The framework offers a rich ecosystem of out-of-the-box functionalities and plugins, including Spring Data, Spring Security, and Spring Cloud. These tools accelerate development and facilitate seamless integration with other technologies, making Spring Boot a popular choice for building robust and scalable applications efficiently.
Frontend Framework: Vue.js
Vue.js utilizes a virtual DOM to enable efficient DOM manipulations. This in-memory data structure, cobmined with reactive data binding and component-based architecture, provides a flexible and maintainable development model. When data changes, the UI updates automatically, allowing developers to focus on business logic rather than manual DOM updates. This approach ensures a streamlined, efficient, and intuitive development experience.
Persistence Layer: MyBatis-Plus
MyBatis-Plus is an enhancement tool built on MyBatis, designed to simplify database operations in Java applications. It supports multiple databases such as MySQL, Oracle, and PostgreSQL. By offering a comprehensive set of APIs and annotations, it minimizes the need for handwritten SQL. Additionally, MyBatis-Plus includes a code generator that automatically produces entity classes, Mapper interfaces, and XML mapping files, streamlining the development workflow. Features like pagination, dynamic queries, optimistic locking, and performance analysis further enhance productivity, enabling rapid development of high-quality data access layers.
System Testing
Testing aims to identify and rectify defects from various perspectives, ensuring the system meets requirements and functions correctly. The process validates that the system aligns with user needs, with any issues promptly addressed.
Testing Objectives
System testing is a critical phase in the development lifecycle, serving as the final checkpoint for quality and reliability. It focuses on preempting user-facing problems to improve the overall experience. By simulating diverse scenarios, testers uncover defects and assess system robustness, functionality, and logical coherence. Effective testing confirms compliance with specifications and highlights discrepancies, always prioritizing real-world user interactions to avoid unrealistic test cases that could skew results.
Functional Testing
Functional modules undergo black-box testing via actions like clicks, input validation with boundary values, and checks for required fields. Test cases guide the process, with outcomes documented for analysis.
Login Function Test The login process verifies user credentials against stored data. Incorrect inputs trigger appropriate error messages, and role-based access is enforced. Sample test cases include:
| Input Data | Expected Result | Actual Result | Analysis |
|---|---|---|---|
| Username: admin, Password: secret123, Captcha: correct | System access granted | Login successful | Matches expectation |
| Username: admin, Password: wrongpass, Captcha: correct | Password error | Password incorrect message displayed | As expected |
| Username: admin, Password: secret123, Captcha: incorrect | Captcha error | Captcha validation failed | Consistent with design |
| Username: empty, Password: secret123, Captcha: correct | Username required | Prompt for username input | Correct behavior |
| Username: admin, Password: empty, Captcha: correct | Password error | Password incorrect message displayed | Expected outcome |
User Management Test This covers add, edit, delete, and search functionalities. Validation includes non-empty checks for required fields and duplicate user prevention. Example test cases:
| Input Data | Expected Result | Actual Result | Analysis |
|---|---|---|---|
| Provide user details | User added and visible in list | User appears in listing | Success |
| Modify user information | Changes saved and reflected | Information updated correctly | As intended |
| Select user for deletion | Confirmation prompt, then removal | User no longer found after deletion | Works properly |
| Add user without username | Username required error | Error message shown | Validated |
| Enter existing username | Duplicate user error | Addition blocked with duplicate warning | Prevents conflicts |
Testing Conclusion
Black-box testing, guided by user-centric test cases, validates system functionality and logical flow. The process ensures the platform operates correctly and meets design specifications, with an emphasis on usability and straightforward logic. Final results confirm that the system satisfies both functional and performance criteria.
Code Examples
@IgnoreAuth
@PostMapping("/authenticate")
public Response login(String user, String pass, String code, HttpServletRequest req) {
UserEntity account = userService.queryOne(new QueryWrapper<UserEntity>().eq("user_name", user));
if (account == null || !account.getPass().equals(pass)) {
return Response.error("Invalid credentials");
}
String authToken = tokenService.createToken(account.getId(), user, "users", account.getRole());
return Response.ok().put("authToken", authToken);
}
@Override
public String createToken(Long uid, String name, String table, String role) {
TokenEntity existing = this.selectOne(new QueryWrapper<TokenEntity>().eq("user_id", uid).eq("role", role));
String newToken = RandomUtil.generateString(32);
Calendar expiry = Calendar.getInstance();
expiry.add(Calendar.HOUR, 1);
if (existing != null) {
existing.setToken(newToken);
existing.setExpiry(expiry.getTime());
this.updateById(existing);
} else {
this.insert(new TokenEntity(uid, name, table, role, newToken, expiry.getTime()));
}
return newToken;
}
@Component
public class AuthInterceptor implements HandlerInterceptor {
private static final String AUTH_HEADER = "Auth-Token";
@Autowired
private TokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object obj) 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, Token, Origin, Content-Type, Cookie, Accept, authorization");
resp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
if (req.getMethod().equals(HttpMethod.OPTIONS.name())) {
resp.setStatus(HttpStatus.OK.value());
return false;
}
IgnoreAuth annotation;
if (obj instanceof HandlerMethod) {
annotation = ((HandlerMethod) obj).getMethodAnnotation(IgnoreAuth.class);
} else {
return true;
}
String token = req.getHeader(AUTH_HEADER);
if (annotation != null) {
return true;
}
TokenEntity tokenData = null;
if (StringUtils.isNotBlank(token)) {
tokenData = tokenService.getToken(token);
}
if (tokenData != null) {
req.getSession().setAttribute("userId", tokenData.getUserId());
req.getSession().setAttribute("role", tokenData.getRole());
req.getSession().setAttribute("tableName", tokenData.getTable());
req.getSession().setAttribute("username", tokenData.getUsername());
return true;
}
resp.setCharacterEncoding("UTF-8");
resp.setContentType("application/json; charset=utf-8");
try (PrintWriter out = resp.getWriter()) {
out.print(JSONObject.toJSONString(Response.error(401, "Authentication required")));
}
return false;
}
}
Database Schema
-- Token table structure
DROP TABLE IF EXISTS `auth_token`;
CREATE TABLE `auth_token` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) NOT NULL,
`username` varchar(100) NOT NULL,
`table_name` varchar(100) DEFAULT NULL,
`role` varchar(100) DEFAULT NULL,
`token` varchar(200) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`expires_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- Sample token records
INSERT INTO `auth_token` VALUES
(1, 101, 'user01', 'residents', 'Owner', 'abc123def456ghi789', '2023-05-01 10:00:00', '2023-05-01 11:00:00'),
(2, 102, 'admin01', 'users', 'Admin', 'xyz789uvw456rst123', '2023-05-01 10:05:00', '2023-05-01 11:05:00');