Building an Enterprise HR Management System with Spring Boot, Vue.js, and UniApp
Backend Framework: Spring Boot
Spring Boot streamlines Java application development by embedding servers like Tomcat and providing auto-configuration. This reduces boilerplate code and accelerates setup. Its ecosystem includes Spring Data, Spring Security, and Spring Cloud for easy integration and extension.
A simple controller example demonstrates its RESTful capabilities:
package com.example.hrapp;
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 AppLauncher {
public static void main(String[] args) {
SpringApplication.run(AppLauncher.class, args);
}
@GetMapping("/greeting")
public String getGreeting() {
return "Welcome to the HR System";
}
}
This class initializes the application and defines an endpoint that returns a welcome message.
Frontend Framework: Vue.js
Vue.js offers a reactive and component-based architecture for building user interfaces. Its virtual DOM enables efficient updates, and its declarative syntax simplifies state management.
A basic Vue component example:
<!DOCTYPE html>
<html>
<head>
<title>Vue Component Demo</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
<p>{{ welcomeText }}</p>
<button @click="updateText">Update Message</button>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
welcomeText: 'HR System Dashboard'
}
},
methods: {
updateText() {
this.welcomeText = 'Data updated successfully.';
}
}
}).mount('#app');
</script>
</body>
</html>
This component displays a message that changes when the button is clicked, showcasing Vue's reactivity.
Persistence Layer: MyBatis
MyBatis separates SQL from Java code using XML or annotations. It supports dynamic SQL, caching, and simplifies database operations through object-relational mapping.
System Testing Approach
Comprehensive testing ensures system reliability. Black-box testing validates functionality from the user's perspective without examining internal code.
Login Function Test Cases
Test scenarios for authentication:
| Input Data (Username, Password, Captcha) | Expected Result | Actual Result | Analysis |
|---|---|---|---|
| admin, correctPass, validCode | Successful login | Login succeeded | Pass |
| admin, wrongPass, validCode | Password error | "Invalid password" displayed | Pass |
| admin, correctPass, invalidCode | Captcha error | "Invalid captcha" displayed | Pass |
| (empty), correctPass, validCode | Username required | "Username required" prompt | Pass |
| admin, (empty), validCode | Password error | "Invalid password" displayed | Pass |
User Management Test Cases
Add User:
| Input Data (Username, Password, Role) | Expected Result | Actual Result | Analysis |
|---|---|---|---|
| john_doe, pass123, Employee | User added to list | User appears in list | Pass |
| jane_doe, pass456, Manager | User added to list | User appears in list | Pass |
| john_doe, pass789, Employee | Duplicate error | "Username exists" error | Pass |
| (empty), pass123, Employee | Validation error | "Username required" error | Pass |
Edit User:
| Action | Expected Result | Actual Result | Analysis |
|---|---|---|---|
| Udpate john_doe's password | Password changed | Password updated in system | Pass |
| Change jane_doe's role to Admin | Role updated | Role changed to Admin | Pass |
| Clear username field | Validation error | "Username required" error | Pass |
Delete User:
| Action | Expected Result | Actual Result | Analysis |
|---|---|---|---|
| Delete john_doe with confirmation | User removed | User no longer in list | Pass |
| Delete jane_doe, cancel operation | User retained | User remains in list | Pass |
Authentication Implementation Example
Java code for token-based authentication:
// Controller method for login
@PostMapping("/authenticate")
public ResponseModel loginUser(@RequestParam String user,
@RequestParam String pass,
HttpServletRequest req) {
EmployeeEntity emp = empService.findOne(
new QueryWrapper<EmployeeEntity>().eq("username", user)
);
if (emp == null || !emp.getPassword().equals(pass)) {
return ResponseModel.error("Invalid credentials");
}
String authToken = tokenProvider.createToken(emp.getId(),
emp.getUsername(),
"employees",
emp.getRole());
return ResponseModel.ok().addData("token", authToken);
}
// Token generation service
@Service
public class TokenManager {
public String createToken(Long uid, String name,
String table, String role) {
String randomToken = RandomStringUtils.randomAlphanumeric(32);
Calendar expiry = Calendar.getInstance();
expiry.add(Calendar.HOUR, 1);
// Store or update token in database
return randomToken;
}
}
// Interceptor for authorization
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest req,
HttpServletResponse res,
Object handler) throws Exception {
// Handle CORS
if (req.getMethod().equals("OPTIONS")) {
res.setStatus(HttpServletResponse.SC_OK);
return false;
}
String token = req.getHeader("Authorization");
if (token == null || !validateToken(token)) {
sendError(res, "Authentication required");
return false;
}
return true;
}
private void sendError(HttpServletResponse res, String msg)
throws IOException {
res.setStatus(401);
res.getWriter().write(msg);
}
}
This code handles user login, tokan issuance, and request authorization.
Data base Schema Example
SQL for a core HR table:
CREATE TABLE employee (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
employee_code VARCHAR(20) UNIQUE NOT NULL,
full_name VARCHAR(100) NOT NULL,
department_id INT,
position VARCHAR(50),
hire_date DATE,
salary DECIMAL(12,2),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_dept (department_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Employee records';
-- Sample data insertion
INSERT INTO employee (employee_code, full_name, department_id, position, hire_date, salary)
VALUES ('EMP001', 'Alice Johnson', 1, 'Software Engineer', '2023-01-15', 75000.00);
INSERT INTO employee (employee_code, full_name, department_id, position, hire_date, salary)
VALUES ('EMP002', 'Bob Smith', 2, 'HR Manager', '2022-08-01', 85000.00);