Developing a University Innovation and Entrepreneurship Platform Competition Management Subsystem with Spring Boot, Vue.js, and Uni-app
This article details the development of a competition management subsystem for a university innovation and entrepreneurship platform. The project utilizes a robust technology stack, including Spring Boot for the backend, Vue.js for the frontend web interface, and Uni-app for cross-platform mobile application development.
Technology Stack Overview
Backend Framework: Spring Boot
Spring Boot simplifies the development of production-ready Spring applications. Its key advantages include embedded servers (Tomcat, Jetty, Undertow) eliminating the need for external installations, powerful auto-configuration capabilities that adapt to project dependencies, and a rich ecosystem of starters for rapid integration of functionalities like data access (Spring Data), security (Spring Security), and microservices (Spring Cloud). Spring Boot's flexible configuration management, swift development and deployment cycles, strong community support, built-in monitoring tools, and reliable testing support make it an excellent choice for building high-quality, scalable, and maintainable applications.
Here's a minimal Spring Boot application example:
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 InnovationPlatformApplication {
public static void main(String[] args) {
SpringApplication.run(InnovationPlatformApplication.class, args);
}
@GetMapping("/status")
public String getStatus() {
return "Platform service is operational.";
}
}
This code snippet defines the entry point for a Spring Boot application. The @SpringBootApplication annotation enables auto-configuration and component scanning, while @RestController marks it as a controller handling web requests. The /status endpoint provides a simple health check.
Frontend Framework: Vue.js
Vue.js is a progressive JavaScript framework renowned for its flexibility and ease of integration. Its core strength lies in its reactivity system and component-based architecture, which efficiently updates the Document Object Model (DOM). Developers can focus on data logic without manual DOM manipulation, leading to more efficient development.
Consider this basic Vue.js example:
<html>
<head>
<title>Vue.js Competition UI</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="competitionApp">
<h3>{{ competitionTitle }}</h3>
<button @click="updateTitle">Refresh Title</button>
</div>
<script>
var competitionApp = new Vue({
el: '#competitionApp',
data: {
competitionTitle: 'University Entrepreneurship Challenge'
},
methods: {
updateTitle: function() {
this.competitionTitle = 'Upcoming Competition Details';
}
}
});
</script>
</body>
</html>
This HTML snippet demonstrates a Vue instance bound to a div. The competitionTitle data property is reactive and displayed using {{ competitionTitle }}. The updateTitle method modifies this property, and Vue automatically updates the UI.
Persistence Layer: MyBatis
MyBatis is a popular persistence framework that streamlines database interactions. It decouples SQL statements from Java code, allowing for flexible management through XML or annotations. Key benefits include simplified data mapping, dynamic SQL generation for complex queries, efficient caching mechanisms (first and second-level), and a plugin architecture for extensibility.
System Testing
Rigorous testing is essential to ensure the quality and reliability of the competition management subsystem. The testing strategy encompasses functional, usability, and performance aspects to identify and rectify defects, ultimately enhancing the user experience.
System Testing Objectives
The primary goal of system testing is to validate that the subsystem meets all specified requirements and functions correctly from an end-user perspective. This involves simulating various usage scenarios to uncover potential issues and insure a seamless user experience. Testing also serves to evaluate the overall system quality, completeness of features, and logical flow.
Functional Testing Example: User Authentication
Functional testing verifies individual components and features. For user authentication, we test login scenarios:
| Input Data (Username, Password, Captcha) | Expected Result | Actual Result | Analysis |
|---|---|---|---|
| admin, securePass123, valid | Successful login as administrator | Login successful, admin dashboard displayed | Match |
| admin, wrongPass, valid | Error: Invalid credentials | Error message: "Invalid username or password" | Match |
| user, correctPass, invalid | Error: Invalid captcha | Error message: "Invalid captcha" | Match |
| , correctPass, valid | Error: Username is required | Error message: "Username cannot be empty" | Match |
Functional Testing Example: Participant Management
Testing participant management includes adding, editing, and deleting participants:
Add Participant Test Cases:
| Input Data (Name, Email, Team) | Expected Result | Actual Result | Analysis |
|---|---|---|---|
| Alice, alice@example.com, Alpha | Participant added successfully | Alice appears in the participant list | Match |
| Bob, bob@example.com, Beta | Participant added succesfully | Bob appears in the participant list | Match |
| Alice, alice_updated@example.com, Alpha | Add failed: Participant 'Alice' already exists | Add failed: "Participant 'Alice' already exists" | Match |
| , charlie@example.com, Gamma | Add failed: Name is required | Add failed: "Participant name cannot be empty" | Match |
Edit Participant Test Cases:
| Action | Expected Result | Actual Result | Analysis |
|---|---|---|---|
| Select Alice, change email to alice.new@example.com | Edit successful, email updated | Alice's email is now alice.new@example.com | Match |
| Select Bob, change team to Delta | Edit successful, team updated | Bob's team is now Delta | Match |
| Select Alice, clear name | Edit failed: Name is required | Edit failed: "Participant name cannot be empty" | Match |
Delete Participant Test Cases:
| Action | Expected Result | Actual Result | Analysis |
|---|---|---|---|
| Select Alice for deletion, confirm | Deletion successful, Alice removed | Alice is removed from the participant list | Match |
| Select Bob for deletion, cancel | Deletion cancelled, Bob remains | Bob remains in the participant list | Match |
System Testing Conclusion
Through comprehensive black-box testing, simulating user interactions, and executing test cases, the subsystem's functional correctness and logical flow have been validated. System testing is crucial for refining the application, ensuring it meets design specifications, and providing a intuitive user experience tailored to participant needs.
Code Snippets
Authentication and Token Generation (Java/Spring Boot)
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.Date;
// Assuming User and Token entities/services exist
// import com.example.platform.entity.UsersEntity;
// import com.example.platform.entity.TokenEntity;
// import com.example.platform.service.UserService;
// import com.example.platform.service.TokenService;
@Component
public class SecurityInterceptor implements HandlerInterceptor {
public static final String AUTH_TOKEN_HEADER = "X-Auth-Token";
@Autowired
private TokenService tokenService; // Assume this service handles token operations
// @Autowired
// private UserService userService; // Assume this service handles user operations
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// CORS handling
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Auth-Token");
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
if (request.getMethod().equals("OPTIONS")) {
response.setStatus(HttpStatus.OK.value());
return false;
}
// Check for custom annotation to skip authentication
HandlerMethod handlerMethod = (HandlerMethod) handler;
if (handlerMethod.getMethodAnnotation(IgnoreAuth.class) != null) {
return true;
}
// Get token from header
String authToken = request.getHeader(AUTH_TOKEN_HEADER);
if (authToken == null || authToken.isEmpty()) {
return unauthorizedResponse(response, "Authentication token is missing.");
}
TokenEntity tokenDetails = tokenService.getTokenDetails(authToken);
if (tokenDetails == null || tokenDetails.getExpirationTime().before(new Date())) {
return unauthorizedResponse(response, "Invalid or expired authentication token.");
}
// Optionally, fetch user details and set them in the request or session
// UsersEntity user = userService.getUserById(tokenDetails.getUserId());
request.setAttribute("userId", tokenDetails.getUserId());
request.setAttribute("userRole", tokenDetails.getRole());
request.setAttribute("userTable", tokenDetails.getTableName());
request.setAttribute("username", tokenDetails.getUsername());
return true;
}
private boolean unauthorizedResponse(HttpServletResponse response, String message) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json; charset=utf-8");
try (PrintWriter writer = response.getWriter()) {
JSONObject jsonResponse = new JSONObject();
jsonResponse.put("code", 401);
jsonResponse.put("msg", message);
writer.print(jsonResponse.toJSONString());
} catch (Exception e) {
// Log error
}
return false;
}
// Other HandlerInterceptor methods (postHandle, afterCompletion) can be implemented if needed
// ...
}
// Assuming TokenService interface and implementation
interface TokenService {
TokenEntity getTokenDetails(String token);
String createOrUpdateToken(Long userId, String username, String tableName, String role);
}
// Assuming TokenEntity class
class TokenEntity {
private Long userId;
private String username;
private String tableName;
private String role;
private String tokenValue;
private Date expirationTime;
// Constructor, getters, setters...
public Long getUserId() { return userId; }
public String getUsername() { return username; }
public String getTableName() { return tableName; }
public String getRole() { return role; }
public Date getExpirationTime() { return expirationTime; }
// ...
}
// Assuming IgnoreAuth annotation exists
@interface IgnoreAuth {}
// Example of Login Endpoint
// @RestController
// @RequestMapping("/auth")
// public class AuthController {
// @Autowired
// private UserService userService;
// @Autowired
// private TokenService tokenService;
// @IgnoreAuth // This endpoint does not require authentication
// @PostMapping("/login")
// public R login(String username, String password, String captcha) {
// // User validation logic...
// UsersEntity user = userService.findUserByUsername(username);
// if (user == null || !user.getPassword().equals(password)) {
// return R.error("Invalid username or password.");
// }
// // Generate token
// String token = tokenService.createOrUpdateToken(user.getId(), user.getUsername(), "users", user.getRole());
// return R.ok().put("token", token);
// }
// }
This Java code implements an authentication interceptor. The SecurityInterceptor checks for a custom token in the request headers. If a valid, non-expired token is found, user details are extracted and made available. The @IgnoreAuth annotation allows specific endpoints, like login, to bypass this authentication check. The interceptor also handles CORS requests and returns a 401 Unauthorized response for failed authentication attempts.
Database Schema Example: Product Table
A sample product table schema for managing items within the platform:
-- ----------------------------
-- Table structure for inventory_item
-- ----------------------------
DROP TABLE IF EXISTS `inventory_item`;
CREATE TABLE `inventory_item` (
`item_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'Unique identifier for the item',
`item_name` VARCHAR(120) NOT NULL COMMENT 'Name of the product',
`unit_price` DECIMAL(10, 2) NOT NULL COMMENT 'Price per unit',
`item_details` VARCHAR(255) DEFAULT NULL COMMENT 'Detailed description of the item',
`quantity_on_hand` INT(11) NOT NULL COMMENT 'Current stock level',
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Timestamp of item creation',
`modified_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Timestamp of last modification',
PRIMARY KEY (`item_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Table storing product and inventory information';
-- Sample data insertion
INSERT INTO `inventory_item` (`item_name`, `unit_price`, `item_details`, `quantity_on_hand`)
VALUES ('Pro Gaming Laptop', 1599.99, 'High-performance laptop for gaming enthusiasts', 75);
INSERT INTO `inventory_item` (`item_name`, `unit_price`, `item_details`, `quantity_on_hand`)
VALUES ('4K Monitor', 450.00, '27-inch 4K UHD monitor with vibrant colors', 120);
INSERT INTO `inventory_item` (`item_name`, `unit_price`, `item_details`, `quantity_on_hand`)
VALUES ('Ergonomic Mechanical Keyboard', 120.50, 'RGB backlit mechanical keyboard with tactile switches', 200);
This SQL defines an inventory\_item table with fields for item identification, pricing, description, stock levels, and timestamps for creation and modification. Sample data demonstrates how to populate this table.