Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Building a Community Elderly Care Service System with SpringBoot and Vue

Tech 1

Technology Stack Overview

Backend Framework: SpringBoot

SpringBoot simplifies application development by embedding servers like Tomcat, Jetty, and Undertow directly into the framework. This eliminates the need for external server installation and complex configuration. The auto-configuration mechanism automatically configures application components based on project dependencies, significantly reducing manual setup work. Additionally, SpringBoot integrates seamlessly with other Spring ecosystem projects such as Spring Data, Spring Security, and Spring Cloud, enabling rapid application development with minimal boilerplate code.

Frontend Framework: Vue.js

Vue.js leverages virtual DOM technology to optimize UI rendering performance. The framework implements reactive data binding, meaning any changes to the underlying data automatically reflect in the user interface. This declarative approach allows developers to focus on data manipulation rather than manual DOM updates. Vue's component-based architecture promotes code reusability and maintainability, making it an excellent choice for single-page applications.

Persistence Layer: MyBatis-Plus

MyBatis-Plus extends the MyBatis framework with enhanced features for database operations. It supports multiple database systems including MySQL, Oracle, SQL Server, and PostgreSQL. The framework provides a rich set of APIs and annotations that simplify ORM operations, reducing the need for handwritten SQL queries. MyBatis-Plus also includes a code generator that can automatically create entity classes, mapper interfaces, and XML mapping files, accelerating development speed. Additional features include pagination queries, dynamic query construction, optimistic locking, and performance analysis tools.

Authentication Implementation

Login Controller

The authentication module handles user login requests and token generation:

@PostMapping("/auth/login")
public ApiResponse authenticateUser(String loginName, String secretKey, String verifyCode, HttpServletRequest httpRequest) {
    UserAccount account = accountService.queryOne(new QueryWrapper<UserAccount>().eq("login_name", loginName));
    if (account == null || !account.getSecretKey().equals(secretKey)) {
        return ApiResponse.fail("Invalid credentials");
    }
    String authToken = authTokenService.createAuthToken(account.getId(), loginName, "user_accounts", account.getRoleType());
    return ApiResponse.success().put("authToken", authToken);
}

Token Generation Service

@Override
public String createAuthToken(Long accountId, String loginName, String entityTable, String roleType) {
    AuthTokenRecord record = this.fetchOne(new QueryWrapper<AuthTokenRecord>().eq("account_id", accountId).eq("role_type", roleType));
    String generatedToken = SecurityUtils.generateRandomKey(32);
    Calendar expiryCalendar = Calendar.getInstance();
    expiryCalendar.setTime(new Date());
    expiryCalendar.add(Calendar.HOUR_OF_DAY, 1);
    
    if (record != null) {
        record.setAuthToken(generatedToken);
        record.setExpiryTime(expiryCalendar.getTime());
        this.modifyById(record);
    } else {
        this.store(new AuthTokenRecord(accountId, loginName, entityTable, roleType, generatedToken, expiryCalendar.getTime()));
    }
    return generatedToken;
}

Authorization Interceptor

The interceptor validates tokens for protected endpoints:

@Component
public class TokenValidationInterceptor implements HandlerInterceptor {

    public static final String AUTH_HEADER = "AuthToken";

    @Autowired
    private AuthTokenService authTokenService;

    @Override
    public boolean preHandle(HttpServletRequest httpRequest, HttpServletResponse httpResponse, Object handler) throws Exception {
        httpResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        httpResponse.setHeader("Access-Control-Max-Age", "3600");
        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
        httpResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with,request-source,AuthToken,Origin,imgType,Content-Type,cache-control,postman-token,Cookie,Accept,authorization");
        httpResponse.setHeader("Access-Control-Allow-Origin", httpRequest.getHeader("Origin"));

        if (httpRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            httpResponse.setStatus(HttpStatus.OK.value());
            return false;
        }

        SkipAuth skipAnnotation = null;
        if (handler instanceof HandlerMethod) {
            skipAnnotation = ((HandlerMethod) handler).getMethodAnnotation(SkipAuth.class);
        } else {
            return true;
        }

        String authToken = httpRequest.getHeader(AUTH_HEADER);

        if (skipAnnotation != null) {
            return true;
        }

        AuthTokenRecord tokenRecord = null;
        if (StringUtils.isNotBlank(authToken)) {
            tokenRecord = authTokenService.fetchTokenRecord(authToken);
        }

        if (tokenRecord != null) {
            httpRequest.getSession().setAttribute("userId", tokenRecord.getAccountId());
            httpRequest.getSession().setAttribute("role", tokenRecord.getRoleType());
            httpRequest.getSession().setAttribute("tableName", tokenRecord.getEntityTable());
            httpRequest.getSession().setAttribute("username", tokenRecord.getLoginName());
            return true;
        }

        PrintWriter responseWriter = null;
        httpResponse.setCharacterEncoding("UTF-8");
        httpResponse.setContentType("application/json; charset=utf-8");
        try {
            responseWriter = httpResponse.getWriter();
            responseWriter.print(JSONObject.toJSONString(ApiResponse.fail(401, "Authentication required")));
        } finally {
            if (responseWriter != null) {
                responseWriter.close();
            }
        }
        return false;
    }
}

Database Schema

The token table stores authentication session information:

DROP TABLE IF EXISTS `auth_token`;
CREATE TABLE `auth_token` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Primary Key',
  `account_id` bigint(20) NOT NULL COMMENT 'Account ID',
  `login_name` varchar(100) NOT NULL COMMENT 'Login Name',
  `entity_table` varchar(100) DEFAULT NULL COMMENT 'Entity Table',
  `role_type` varchar(100) DEFAULT NULL COMMENT 'Role Type',
  `auth_token` varchar(200) NOT NULL COMMENT 'Authentication Token',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation Time',
  `expiry_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Expiry Time',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='Authentication Token Table';

System Testing

Testing Objectives

System testing validates that the application meets all functional requirements specified in the requirements document. The primary goal is to identify defects and inconsistencies from multiple perspectives. Testing ensures system quality, reliability, and user experience by simulating various usage scenarios and edge cases.

Login Functionality Testing

Login testing verifies authentication mechanisms through boundary value analysis and input validation:

Test InputExpected ResultActual ResultStatus
Username: admin, Password: admin123, Captcha: correctLogin successfulLogin successfulPass
Username: admin, Password: wrongpass, Captcha: correctPassword errorPassword error message displayedPass
Username: admin, Password: admin123, Captcha: incorrectCaptcha errorCaptcha error message displayedPass
Username: empty, Password: admin123, Captcha: correctUsername requiredUsername required message displayedPass
Username: admin, Password: empty, Captcha: correctPassword requiredPassword required message displayedPass

User Management Testing

User management testing covers CRUD operations and validation rules:

Test InputExpected ResultActual ResultStatus
Enter valid user detailsUser added successfully, displayed in listUser appears in listPass
Modify user informationChanges saved successfullyUpdated information displayedPass
Delete selected userConfirmation prompt, user removed after confirmationUser removed from systemPass
Submit without usernameValidation error for required fieldUsername required message shownPass
Enter duplicate usernameDuplicate entry rejectedDuplicate username error shownPass

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

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