Logistics Management System Development and Technical Specification Based on Spring Boot + Vue.js
Backend: Spring Boot
Spring Boot embeds application servers including Tomcat, Jetty and Undertow out of the box, eliminating the need for separate server deployment and configuration. Its core auto-configuration mechanism dynamically loads matching configuration items based on introduced dependenceis, removing the complexity of manual bean registration and property configuration for developers. It also natively integrates with Spring ecosystem components such as Spring Data JPA, Spring Security and Spring Cloud, supporting rapid iteration of business logic and seamless extension for distributed architecture demands, which greatly reduces the threshold for building production-grade Java applications.
Frontend: Vue.js
Vue.js leverages virtual DOM technology to minimize real DOM manipulation overhead, improving page rendering efficiency significantly. It adopts responsive data binding, component-based development and diff algorithm optimization, enabling automatic UI synchronization when underlying data changes. Developers only need to focus on business data logic processing without manually manipulating DOM nodes, which effectively reduces code maintenance cost and improves development efficiency for medium and large front-end projects.
Persistence Layer: MyBatis-Plus
MyBatis-Plus is an enhanced tool built on top of native MyBatis, designed to simplify data access layer development. Its compatible with all mainstream relational databases including MySQL, Oracle, SQL Server and PostgreSQL, and provides a rich set of encapsulated CRUD APIs, annotation-based conditional constructors, and automatic paging plugins, eliminating the need to write repetitive basic SQL statements. Its built-in code generator can automatically generate entity classes, Mapper interfaces, service layer code and XML mapping files according to table structure, cutting down basic development workload by more than 60%. It also supports advanced features such as dynamic conditional query, optimistic locking, SQL performance monitoring and logical deletion, meeting diversified data operation demands in complex business scenarios.
System Testing
The core objective of system testing is to identify potential logic defects and function mismatches from multiple dimensions, modify discovered issues in time, and verify that all functions meet pre-defined requirement specifications before official launch.
Testing Objectives
System testing is a mandatory phase in the software development lifecycle, acting as the final checkpoint to ensure system stability and usability. It focuses on simulating real user operation scenarios to find hidden problems that may occur during actual use, so as to avoid abnormal usage experience for end users. The testing process also needs to verify the completeness of functional modules, rationality of business logic, and compliance with requirement documents, to ensure the final delivered system fully matches user expectations.
Functional Testing
Black-box testing method is adopted for functional verification, covering operation path clicking, boundary value input verification, required field verification and other scenarios. Test cases are compiled in advance for each functional module, and test results are recorded one by one according to execution of test cases.
Login Function Test Case
When a user attempts to log in, the system verifies the entered account, password and verification code against the data stored in the database, and checks whether the selected role matches the account permission. The specific test cases are as follows:
| Input Parameters | Expected Output | Actual Output | Result Verification |
|---|---|---|---|
| Username: admin, Password: Admin@123, Captcha: correct | Successful login to system backend | Normal login and jump to home page | Consistent with expectation |
| Username: admin, Password: 123456, Captcha: correct | Password mismatch prompt | Popup "Incorrect username or password" | Consistent with expectation |
| Username: admin, Password: Admin@123, Captcha: wrong | Captcha error prompt | Popup "Verification code input error" | Consistent with expectation |
| Username: empty, Password: Admin@123, Captcha: correct | Required field prompt | Popup "Username cannot be empty" | Consistent with expectation |
| Username: admin, Password: empty, Captcha: correct | Required field prompt | Popup "Password cannot be empty" | Consistent with expectation |
| Username: user01, Password: User@123, Selected role: Administrator | Permission mismatch prompt | Popup "Account does not have administrator permission" | Consistent with expectation |
User Management Function Test Case
User management module includes functions of adding, modifying, deleting and querying user information. The specific test cases are as follows:
| Operation Scenario | Expected Output | Actual Output | Result Verification |
|---|---|---|---|
| Fill in all required user information and submit | User added successfully, displayed in user list | New user appears in user list, information is complete | Consistent with expectation |
| Modify user phone number and submit | Modification takes effect immediately | User information in list shows updated phone number | Consistent with expectation |
| Select a user and click delete, confirm in popup | User is removed from system | Deleted user no longer appears in user list | Consistent with expectation |
| Submit add request without filling username | Non-null verification prompt | Popup "Username is a required field" | Consistent with expectation |
| Submit add request with existing username | Duplicate username prompt | Popup "Username already exists, please change" | Consistent with expectation |
Test Conclusion
All functional modules of the system have passed the black-box test verification, and all test case execution results are consistent with expected outputs. The system has complete functions, smooth business logic, and meets the design requirements in both function and performance indicators, which can be officially deployed for use.
Core Code Implementation
User Authentication Interface
@IgnoreAccessCheck
@PostMapping("/auth/login")
public ResponseResult authenticate(String account, String passwd, String verifyCode, HttpServletRequest req) {
AccountEntity accountInfo = accountService.getOne(new LambdaQueryWrapper<AccountEntity>().eq(AccountEntity::getAccountName, account));
if (accountInfo == null || !passwd.equals(accountInfo.getPassword())) {
return ResponseResult.fail("Invalid account or password");
}
String accessToken = tokenService.createAccessToken(accountInfo.getId(), account, accountInfo.getRole());
return ResponseResult.success().put("access_token", accessToken);
}
Token Generation Logic
@Override
public String createAccessToken(Long accountId, String accountName, String role) {
AccessTokenEntity existingToken = this.getOne(new LambdaQueryWrapper<AccessTokenEntity>()
.eq(AccessTokenEntity::getAccountId, accountId)
.eq(AccessTokenEntity::getRole, role));
String newToken = CommonUtil.generateRandomStr(32);
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(Calendar.HOUR, 2); // Set token valid for 2 hours
if (existingToken != null) {
existingToken.setToken(newToken);
existingToken.setExpireTime(calendar.getTime());
this.updateById(existingToken);
} else {
AccessTokenEntity newTokenEntity = new AccessTokenEntity();
newTokenEntity.setAccountId(accountId);
newTokenEntity.setAccountName(accountName);
newTokenEntity.setRole(role);
newTokenEntity.setToken(newToken);
newTokenEntity.setExpireTime(calendar.getTime());
this.save(newTokenEntity);
}
return newToken;
}
Request Authorization Interceptor
@Component
public class AuthInterceptor implements HandlerInterceptor {
public static final String ACCESS_TOKEN_HEADER = "Access-Token";
@Autowired
private AccessTokenService accessTokenService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// Configure cross-domain support
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Access-Token, Origin, Content-Type, Accept, Authorization");
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
// Directly return success for preflight OPTIONS request
if (RequestMethod.OPTIONS.name().equals(request.getMethod())) {
response.setStatus(HttpStatus.OK.value());
return false;
}
// Skip check for non-controller methods
if (!(handler instanceof HandlerMethod)) {
return true;
}
// Skip check for methods marked with ignore access annotation
IgnoreAccessCheck ignoreAnnotation = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAccessCheck.class);
if (ignoreAnnotation != null) {
return true;
}
// Extract token from request header
String token = request.getHeader(ACCESS_TOKEN_HEADER);
AccessTokenEntity validToken = null;
if (StringUtils.hasText(token)) {
validToken = accessTokenService.getValidToken(token);
}
if (validToken != null) {
request.getSession().setAttribute("loginAccountId", validToken.getAccountId());
request.getSession().setAttribute("loginRole", validToken.getRole());
request.getSession().setAttribute("loginAccountName", validToken.getAccountName());
return true;
}
// Return not logged in prompt if token is invalid
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=utf-8");
try (PrintWriter writer = response.getWriter()) {
writer.print(JSONObject.toJSONString(ResponseResult.fail(401, "Please log in first")));
}
return false;
}
}
Database Table Reference
Access Token Table
DROP TABLE IF EXISTS `access_token`;
CREATE TABLE `access_token` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Primary key ID',
`account_id` bigint(20) NOT NULL COMMENT 'Associated account ID',
`account_name` varchar(100) NOT NULL COMMENT 'Account name',
`role` varchar(100) DEFAULT NULL COMMENT 'Account permission role',
`token` varchar(200) NOT NULL COMMENT 'Access token string',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Token creation time',
`expire_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Token expiration time',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='Access token storage table';
INSERT INTO `access_token` VALUES
(1, 1, 'admin', 'ADMIN', 'kf93jd72nxl0wqpr8tyu1vb6nm23zx78', '2024-05-10 09:23:12', '2024-05-10 11:23:12'),
(2, 5, 'logistics01', 'LOGISTICS_STAFF', 'pl02mnbv65cxz87lkjhgf34dsaqw90er', '2024-05-10 10:01:45', '2024-05-10 12:01:45'),
(3, 12, 'warehouse03', 'WAREHOUSE_MANAGER', 'mn87bvcx45dfgh09jklp12aqwzx34edc', '2024-05-10 10:30:22', '2024-05-10 12:30:22'),
(4, 28, 'driver07', 'DELIVERY_STAFF', 'bv45cxz87lkj09mnpoi12uytr67ewq09', '2024-05-10 11:05:37', '2024-05-10 13:05:37');