Fading Coder

One Final Commit for the Last Sprint

Home > Notes > Content

Design and Implementation of a Deep-Processed Agricultural Product Promotion Platform Using Spring Boot and Vue.js

Notes May 10 3

System Architecture and Technology Stack

The backend architecture relies on Spring Boot to eliminate complex XML configurations, utilizing its auto-configuration capabilities to integrate embedded Tomcat servers seamlessly. This approach simplifies dependency management and accelerates the initial setup process. The frontend is constructed with Vue.js, leveraging its component-based structure and virtual DOM for efficient DOM manipulation and a reactive user experience. Data persistence is managed by MyBatis-Plus, an enhancement of the MyBatis framework, which significantly reduces boilerplate SQL code through powerful CRUD interfaces and pagination plugins.

System Testing Strategy

System testing serves as a critical phase to ensure software quality and reliability. The primary objective is to identify defects and verify that the system functionality aligns with the requirement specifications. This process involves simulating various user scenarios to validate logic flows and data integrity.

Login Functionality Test Cases

The authentication module was subjected to black-box testing to verify security and feedback mechanisms. The test scenarios included valid inputs, incorrect credentials, and empty field validations.

Test InputExpected OutcomeActual OutcomeStatus
Username: admin, Password: 123456, Captcha: ValidSuccessful login redirectRedirected to dashboardPass
Username: admin, Password: wrong_pass, Captcha: ValidError: Incorrect passwordError message displayedPass
Username: admin, Password: 123456, Captcha: InvalidError: Captcha mismatchError message displayedPass
Username: [Empty], Password: 123456Error: Username requiredPrompt for usernamePass

User Management Functionality Test Cases

User management capabilities, including creation, modification, and deletion, were tested for data consistency and constraint handling.

Test ActionExpected OutcomeActual OutcomeStatus
Submit new user with valid dataUser added to databaseUser appears in listPass
Submit new user with existing IDError: Duplicate IDDuplicate error shownPass
Delete selected userConfirmation prompt, then removalUser removed from viewPass
Update user detailsData refreshed in viewChanges saved successfullyPass

Core Code Implementation

Authentication Controller

The login endpoint validates user credentials and issues a token for session management.

@RestController
@RequestMapping("/api/auth")
public class AuthController {

    @Autowired
    private SysUserService userService;
    @Autowired
    private TokenService tokenService;

    @PostMapping("/login")
    public R<Map<String, Object>> login(@RequestBody LoginForm form) {
        // Validate user existence
        SysUserEntity user = userService.getOne(
            new QueryWrapper<SysUserEntity>().eq("username", form.getUsername())
        );

        if (user == null || !user.getPassword().equals(form.getPassword())) {
            return R.error("Invalid credentials");
        }

        // Generate and return token
        String token = tokenService.generateToken(user.getId(), user.getUsername(), "sys_user", user.getRole());
        return R.ok().put("token", token);
    }
}

Token Generation Service

This service handles the creation and renewal of session tokens, ensuring they are stored and tracked correctly.

@Service
public class TokenServiceImpl implements TokenService {

    @Autowired
    private TokenDao tokenDao;

    @Override
    public String generateToken(Long userId, String username, String table, String role) {
        TokenEntity existing = tokenDao.selectOne(
            new QueryWrapper<TokenEntity>().eq("user_id", userId)
        );
        
        String newToken = UUID.randomUUID().toString().replace("-", "");
        Date expiryTime = DateUtils.addHours(new Date(), 2); // 2 hours expiry

        if (existing != null) {
            existing.setToken(newToken);
            existing.setExpireTime(expiryTime);
            tokenDao.updateById(existing);
        } else {
            TokenEntity record = new TokenEntity();
            record.setUserId(userId);
            record.setToken(newToken);
            record.setExpireTime(expiryTime);
            tokenDao.insert(record);
        }
        return newToken;
    }
}

Authorization Interceptor

The interceptor checks for valid tokens in request headers before allowing access to protected resources.

@Component
public class AuthInterceptor implements HandlerInterceptor {

    public static final String HEADER_TOKEN = "X-Auth-Token";

    @Autowired
    private TokenService tokenService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // Handle CORS preflight requests
        if (HttpMethod.OPTIONS.name().equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            return true;
        }

        // Check for SkipAuth annotation
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            if (handlerMethod.getMethodAnnotation(PublicAccess.class) != null) {
                return true;
            }
        }

        String token = request.getHeader(HEADER_TOKEN);
        if (StringUtils.isBlank(token)) {
            throw new UnauthorizedException("Missing authentication token");
        }

        TokenEntity tokenData = tokenService.getByToken(token);
        if (tokenData == null || tokenData.getExpireTime().before(new Date())) {
            throw new UnauthorizedException("Token expired or invalid");
        }

        // Store user info in session context
        request.setAttribute("currentUser", tokenData.getUserId());
        return true;
    }
}

Database Schema Design

The token table stores active session details to manage user login states effectively.

-- Table structure for sys_token
DROP TABLE IF EXISTS `sys_token`;
CREATE TABLE `sys_token` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NOT NULL COMMENT 'User Primary Key',
  `username` varchar(100) NOT NULL COMMENT 'Username',
  `token` varchar(200) NOT NULL COMMENT 'Access Token',
  `role` varchar(50) DEFAULT NULL COMMENT 'User Role',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `expire_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Expiration Time',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_token` (`token`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='User Token Management';
Tags: Spring Boot

Related Articles

Designing Alertmanager Templates for Prometheus Notifications

How to craft Alertmanager templates to format alert messages, improving clarity and presentation. Alertmanager uses Go’s text/template engine with additional helper functions. Alerting rules referenc...

Deploying a Maven Web Application to Tomcat 9 Using the Tomcat Manager

Tomcat 9 does not provide a dedicated Maven plugin. The Tomcat Manager interface, however, is backward-compatible, so the Tomcat 7 Maven Plugin can be used to deploy to Tomcat 9. This guide shows two...

Skipping Errors in MySQL Asynchronous Replication

When a replica halts because the SQL thread encounters an error, you can resume replication by skipping the problematic event(s). Two common approaches are available. Methods to Skip Errors 1) Skip a...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.