University Restaurant Recommendation and Review System: Implementation with SpringBoot, Vue, and uniapp

Technical Stack Overview

Backend Framework: SpringBoot

SpringBoot provides embedded servers such as Tomcat, Jetty, and Undertow, eliminating the need for separate installations. Its auto-configuration feature automatically configures the application based on dependencies present in the project. This significantly simplifies the setup process by removing the need for manual configuration of each component. The framework offers numerous built-in features and extensions including Spring Data, Spring Security, and Spring Cloud, enabling developers to build applications more efficiently. These tools facilitate easier integration with other technologies and provide a solid foundation for scalable enterprise solutions.

Frontend Framework: Vue.js

Vue.js utilizes a virtual DOM as its core technology, which is an in-memory data structure enabling efficient DOM manipulation. The framework implements reactive data binding, virtual DOM, and component-based architecture, providing developers with a flexible and maintainable development approach. When data changes, the UI automatically updates, allowing developers to focus on data processing rather than manual UI updates. This approach results in a development experience that is both streamlined and efficient.

Persistence Layer Framework: MyBatis-Plus

MyBatis-Plus is an enhancement tool built upon the MyBatis framework, designed to simplify database operations. As an open-source Java framework, it supports multiple databases icnluding MySQL, Oracle, SQL Server, and PostgreSQL. The framework provides extensive APIs and annotations that enable ORM operations through minimal configuration, significantly reducing manual SQL coding. Additionally, MyBatis-Plus includes a code generator that automatically creates entity classes, Mapper interfaces, and XML mapping files, streamlining the development process. It also supports practical features such as pagination queries, dynamic queries, optimistic locking, and performance analysis, allowing developers to perform efficient data operations and quickly develop high-quality data access layers.

System Testing Methodology

Testing Objectives

System testing serves as a critical quality assurance phase in the development lifecycle. Its primary purpose is to identify and resolve system issues from multiple perspectives. Through comprehensive testing, defects are discovered and rectified to ensure the system meets quality standards. The testing process verifies that the system fulfills customer requirements while identifying areas for improvement. Effective testing evaluates system functionality, completeness, and logical flow. A thorough testing process significantly enhances system quality and user experience. The goal is to validate that the system adheres to the requirements specification and identifies any discrepancies or conflicts.

Functional Testing Approach

The system underwent black-box testing focused on functional modules, using methods such as interface interactions, boundary value testing, and validation of required versus optional fields. Test cases were developed and executed to validate system behavior.

Login Functionality Test Cases

Input Data Expected Result Actual Result Analysis
Username: admin, Password: 123456, Captcha: Correct System login successful User successfully logged in Matches expected result
Username: admin, Password: wrongpass, Captcha: Correct Password error message Displays "Incorrect password" message Matches expected result
Username: admin, Password: 123456, Captcha: Incorrect Captcha error message Displays "Invalid captcha" message Matches expected result
Username: empty, Password: 123456, Captcha: Correct Username required message Displays "Username is required" message Matches expected result
Username: admin, Password: empty, Captcha: Correct Password required message Displays "Password is required" message Matches expected result

User Management Functionality Test Cases

Input Data Expected Result Actual Result Analysis
Complete user information User added successfully, appears in list User appears in the user list Matches expected result
Modified user information Update successful, changes reflected User informasion updated successfully Matches expected result
Selected user for deletion Confirmation dialog, user removed after confirmation System prompts for confirmation, user removed Matches expected result
User creation without username Username required validation message Displays "Username cannot be blank" message Matches expected result
Creation with existing username Duplicate username error message Displays "Username already exists" message Matches expected result

Testing Conclusion

The system was primarily tested using black-box testing methodology, with test cases developed to simulate user interactions and validate functional flows. This comprehensive testing approach ensures system correctness. System testing is essential for improving system usability and functionality. The testing process aimed to verify that all functional modules met the initial design requirements and that their underlying logic was sound. Given the system's focus on user-friendly operation, complex logic processing was intentionally minimized. All testing scenarios were aligned with user requirements, with issues addressed from a user perspective. The final test results confirm that the implemented system meets both functional and performance design specifications.

Implementation Code Examples

Authentication Controller

@SkipAuth
@PostMapping("/authenticate")
public Response authenticate(String username, String password, String captcha, HttpServletRequest request) {
   UserEntity user = userService.queryOne(new QueryWrapper<userentity>().eq("username", username));
   if(user == null || !user.getPassword().equals(password)) {
      return Response.error("Invalid username or password");
   }
   String authToken = tokenService.generateToken(user.getId(), username, "users", user.getRole());
   return Response.success().put("authToken", authToken);
}</userentity>

Token Service Implementation

@Override
public String generateToken(Long userId, String username, String tableName, String role) {
   TokenEntity existingToken = this.selectOne(new QueryWrapper<tokenentity>()
        .eq("userId", userId)
        .eq("role", role));
   
   String newToken = SecurityUtils.generateRandomString(32);
   Calendar calendar = Calendar.getInstance();   
   calendar.setTime(new Date());   
   calendar.add(Calendar.HOUR_OF_DAY, 1);
   
   if(existingToken != null) {
      existingToken.setToken(newToken);
      existingToken.setExpirationTime(calendar.getTime());
      this.updateById(existingToken);
   } else {
      this.insert(new TokenEntity(userId, username, tableName, role, newToken, calendar.getTime()));
   }
   return newToken;
}</tokenentity>

Security Interceptor

@Component
public class SecurityInterceptor implements HandlerInterceptor {

    public static final String AUTH_TOKEN_HEADER = "Authorization";

    @Autowired
    private TokenService tokenService;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // Enable cross-origin requests
        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,request-source,Authorization, Origin,imgType, Content-Type, cache-control,postman-token,Cookie, Accept");
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        
        // Handle preflight OPTIONS requests
        if(request.getMethod().equals(HttpMethod.OPTIONS.name())) {
            response.setStatus(HttpStatus.OK.value());
            return false;
        }
        
        SkipAuth annotation;
        if(handler instanceof HandlerMethod) {
            annotation = ((HandlerMethod) handler).getMethodAnnotation(SkipAuth.class);
        } else {
            return true;
        }

        // Retrieve token from header
        String token = request.getHeader(AUTH_TOKEN_HEADER);
        
        // Allow access for methods without authentication requirement
        if(annotation != null) {
            return true;
        }
        
        TokenEntity tokenEntity = null;
        if(StringUtils.isNotBlank(token)) {
            tokenEntity = tokenService.validateToken(token);
        }
        
        if(tokenEntity != null) {
            request.getSession().setAttribute("userId", tokenEntity.getUserId());
            request.getSession().setAttribute("role", tokenEntity.getRole());
            request.getSession().setAttribute("tableName", tokenEntity.getTableName());
            request.getSession().setAttribute("username", tokenEntity.getUsername());
            return true;
        }
        
        PrintWriter writer = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try {
            writer = response.getWriter();
            writer.print(JsonUtils.toJsonString(Response.error(401, "Authentication required")));
        } finally {
            if(writer != null) {
                writer.close();
            }
        }
        return false;
    }
}

Database Schema

<code-- authentication_tokens="" auto_increment="" bigint="" btree="" charset="utf8" comment="" create="" current_timestamp="" default="" drop="" engine="InnoDB" exists="" for="" identifier="" if="" insert="" into="" key="" name="" not="" null="" primary="" records="" role="" row_format="COMPACT" sample="" structure="" table="" timestamp="" token="" using="" values="" varchar=""></code-->

Tags: SpringBoot Vue.js mybatis-plus university restaurant system Authentication

Posted on Tue, 04 Aug 2026 16:40:46 +0000 by jrolands