System Overview
This project outlines the architecture and implementation of a second-hand trading platform designed specifically for campus environments. The system utilizes a WeChat Mini Program for the client interface, ensuring easy access for students without additional installations. The backend is powered by Spring Boot, providing a robust RESTful API, while Vue.js handles administrative dashboard interactions. Data persistence is managed through MyBatis, ensuring efficient database operations.
Technology Stack
Backend: Spring Boot
Spring Boot simplifies the development of stand-alone, production-grade Spring based Applications. It embeds servers like Tomcat directly, removing the need for external deployment configurations. Its auto-configuration mechanism detects classpath dependencies to set up beans automatically. This reduces boilerplate code and accelerates the development lifecycle. Features like Spring Security and Spring Data integrate seamlessly, offering comprehensive tools for monitoring, testing, and deployment.
Below is an example of a basic health check controller implemented in Spring Boot:
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 PlatformHealthController {
public static void main(String[] args) {
SpringApplication.run(PlatformHealthController.class, args);
}
@GetMapping("/api/status")
public String checkSystemStatus() {
return "System Operational";
}
}
This class serves as the entry point. The @SpringBootApplication annotation enables auto-configuration, while @RestController designates the class as a web controller. The checkSystemStatus method maps to the /api/status endpoint, returning a simple confirmation string when invoked.
Frontend: Vue.js
Vue.js is utilized for its reactive data-binding capabilities and component-based architecture. It employs a virtual DOM to optimize rendering performence. When the state changes, Vue efficiently updates only the necessary parts of the UI, allowing developers to focus on logic rather than manual DOM manipulation.
The following snippet demonstrates a basic reactive component:
<html>
<head>
<title>Vue Interaction Demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="interface">
<h2>{{ statusText }}</h2>
<button @click="toggleStatus">Update Status</button>
</div>
<script>
var vm = new Vue({
el: '#interface',
data: {
statusText: 'System Idle'
},
methods: {
toggleStatus: function() {
this.statusText = 'System Active';
}
}
});
</script>
</body>
</html>
In this example, the Vue instance binds to the #interface element. The statusText property is displayed using mustache syntax. Clicking the button triggers toggleStatus, which updates the data property, causing the UI to refresh automatically.
Persistence: MyBatis
MyBatis acts as the persistence layer, bridging Java objects and database records. It separates SQL logic from Java code using XML mappers or annotations. This separation enhences maintainability and allows for dynamic SQL generation based on runtime parameters. Additionally, MyBatis supports caching mechanisms to reduce database load and offers plugin architecture for extensibility.
Quality Assurance and Testing
Rigorous testing is conducted to ensure system stability and reliability. The testing phase focuses on identifying defects early and validating that the software meets user requirements. Both functional and non-functional aspects are evaluated to guarantee a smooth user experience.
Testing Objectives
The primary goal of system testing is to validate the software against the requirement specifications. It serves as the final verification step before deployment. By simulating real-world usage scenarios, the team ensures that the system behaves as expected under various conditions. This process minimizes the risk of post-deployment failures and enhances overall user satisfaction.
Functional Test Cases
Black-box testing methods are employed to verify functional modules. Test cases cover boundary values, mandatory fields, and logical flows.
Authentication Module Testing
The login functionality validates user credentials against stored records. Role-based access control is also verified.
| Input Data | Expected Outcome | Actual Outcome | Analysis |
|---|---|---|---|
| User: admin, Pass: secret123, Captcha: Valid | Acces Granted | Access Granted | Pass |
| User: admin, Pass: wrongpass, Captcha: Valid | Access Denied | Invalid Credentials | Pass |
| User: admin, Pass: secret123, Captcha: Invalid | Access Denied | Invalid Captcha | Pass |
| User: [Empty], Pass: secret123, Captcha: Valid | Validation Error | Username Required | Pass |
User Management Testing
Administrative functions such as creating, updating, and removing user accounts are tested extensively.
1. Account Creation
| Input Data | Expected Outcome | Actual Outcome | Analysis |
|---|---|---|---|
| User: student01, Pass: pass123, Role: User | Creation Success | User Added to List | Pass |
| User: student01, Pass: pass123, Role: User | Duplicate Error | User Exists Warning | Pass |
2. Account Modification
| Input Data | Expected Outcome | Actual Outcome | Analysis |
|---|---|---|---|
| Select student01, Change Pass to new456 | Update Success | Password Changed | Pass |
| Select student01, Clear Username | Update Failed | Field Cannot Be Empty | Pass |
3. Account Deletion
| Input Data | Expected Outcome | Actual Outcome | Analysis |
|---|---|---|---|
| Select student01, Confirm Delete | Record Removed | User Deleted | Pass |
| Select student02, Cancel Delete | Operation Aborted | User Retained | Pass |
Core Implementation Details
The authentication mechanism relies on token-based security. Upon successful credential verification, a unique token is generated and returned to the client. Subsequent requests must include this token for authorization.
// Custom annotation to bypass security checks
@PublicAccess
@PostMapping(value = "/authenticate")
public Response verifyCredentials(String accountId, String secret, String code, HttpServletRequest req) {
// Retrieve account record
AccountRecord account = accountService.findByUsername(accountId);
// Validate existence and secret
if(account == null || !account.getSecret().equals(secret)) {
return Response.fail("Invalid credentials");
}
// Create session token
String authToken = authManager.createSession(account.getId(), accountId, "accounts", account.getRole());
return Response.success().add("authToken", authToken);
}
// Session token generation logic
@Override
public String createSession(Long uid, String uname, String tableName, String role) {
// Check for existing session
AuthSession existing = this.findByUserId(uid, role);
// Generate random string
String newToken = Utility.generateRandomString(32);
// Set expiration (1 hour)
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.HOUR_OF_DAY, 1);
if(existing != null) {
// Update existing session
existing.setToken(newToken);
existing.setExpiryTime(cal.getTime());
this.updateRecord(existing);
} else {
// Create new session record
this.insertRecord(new AuthSession(uid, uname, tableName, role, newToken, cal.getTime()));
}
return newToken;
}
/**
* Security Interceptor for Token Validation
*/
@Component
public class SecurityFilter implements HandlerInterceptor {
public static final String AUTH_HEADER_KEY = "Authorization";
@Autowired
private AuthManager authManager;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// Enable CORS
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, Authorization, Origin, Content-Type");
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
// Handle preflight
if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
response.setStatus(HttpStatus.OK.value());
return false;
}
// Check for public access annotation
PublicAccess accessAnnotation;
if (handler instanceof HandlerMethod) {
accessAnnotation = ((HandlerMethod) handler).getMethodAnnotation(PublicAccess.class);
} else {
return true;
}
// Extract token from header
String token = request.getHeader(AUTH_HEADER_KEY);
// Skip validation if public
if(accessAnnotation != null) {
return true;
}
// Validate token
AuthSession session = null;
if(StringUtils.isNotBlank(token)) {
session = authManager.getSessionByToken(token);
}
if(session != null) {
// Store user context in session
request.getSession().setAttribute("uid", session.getUserId());
request.getSession().setAttribute("role", session.getRole());
request.getSession().setAttribute("table", session.getTableName());
request.getSession().setAttribute("uname", session.getUsername());
return true;
}
// Return 401 on failure
PrintWriter writer = null;
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
try {
writer = response.getWriter();
writer.print(JSONObject.toJSONString(Response.fail(401, "Authentication Required")));
} finally {
if(writer != null){
writer.close();
}
}
return false;
}
}
Database Schema Design
The database design follows normalized principles to ensure data integrity. Below is the schema for the item listings table.
-- ----------------------------
-- Table structure for marketplace_items
-- ----------------------------
DROP TABLE IF EXISTS `marketplace_items`;
CREATE TABLE `marketplace_items` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Primary Key',
`title` varchar(100) NOT NULL COMMENT 'Item Title',
`amount` decimal(10, 2) NOT NULL COMMENT 'Listing Price',
`details` varchar(200) DEFAULT NULL COMMENT 'Item Description',
`quantity` int(11) NOT NULL COMMENT 'Available Stock',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Record Creation Time',
`modified_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Last Update Time',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='Marketplace Items Table';
Key fields include:
id: Auto-incrementing primary identifier.title: Name of the item, mandatory field.amount: Monetary value stored with precision.details: Text description of the item condition or features.quantity: Current inventory count.created_atandmodified_at: Timestamps for auditing changes.
Sample data insertion:
INSERT INTO `marketplace_items` (`title`, `amount`, `details`, `quantity`)
VALUES ('Laptop Stand', 25.50, 'Aluminum adjustable stand', 20);
INSERT INTO `marketplace_items` (`title`, `amount`, `details`, `quantity`)
VALUES ('Textbook: Calculus', 15.00, 'Used condition, good shape', 5);
INSERT INTO `marketplace_items` (`title`, `amount`, `details`, `quantity`)
VALUES ('Wireless Mouse', 10.99, 'Logitech brand, wireless', 30);