Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Property Management System Design and Implementation Using SpringBoot, Vue, and Uniapp

Tech 1

This article describes the technical implementation of a property management system designed for residential communities. The system adopts a modern three-tier architecture consisting of the presentation layer, business logic layer, and data access layer.

Backend Technology Stack

SpringBoot Framework

The backend is built on SpringBoot, which provides embedded servlet container support including Tomcat, Jetty, and Undertow. The framework's auto-configuration capability automatically sets up application components based on dependency relationships, significantly reducing manual configuration overhead.

SpringBoot integrates seamlessly with Spring Data, Spring Security, and other modules, enabling rapid development of enterprise applications. The annotation-driven development model and convention-over-configuration philosophy allow developers to focus on business logic rather than infrastructure setup.

MyBatisPlus Persistence Layer

MyBatisPlus serves as the ORM framework, supporting multiple database engines such as MySQL, Oracle, SQL Server, and PostgreSQL. The framework provides a rich set of APIs and annotations that simplify CRUD operations without requiring manual SQL writing.

Key features include:

  • Automatic code generation for entity classes, mapper interfaces, and XML mapping files
  • Built-in pagination support with efficient query optimization
  • Dynamic query capabilities for complex business scenarios
  • Optimistic locking mechanism for concurrent data access
  • Performance analysis tools for SQL optimization

Frontend Technology Stack

Vue.js Framework

The frontend utilizes Vue.js with its core virtual DOM technology. The virtual DOM creates an in-memory representation of the actual DOM structure, enabling efficient updates when application state changes. Vue's reactive data binding automatically synchronizes the UI with underlying data models, eliminating manual DOM manipulation.

The component-based architecture promotes code reusability and maintainability. Each component encapsulates its own template, styles, and behavior, facilitating modular development and testing.

Uniapp Cross-Platform Framework

Uniapp enables cross-platform deployment, allowing the same codebase to run on iOS, Android, and WeChat mini-programs. This significantly reduces development and maintenance costs while reaching a broader user base.

System Testing Approach

Testing Objectives

System testing serves as the final quality assurance checkpoint before production deployment. The primary goal is to identify defects and ensure the system meets specified requirements. Testing activities focus on verifying functional correctness, validating user workflows, and assessing system performance under expected load conditions.

Functional Testing Strategy

Black-box testing techniques are employed to validate system functionality without examining internal implementation details. Test cases are designed based on input boundary values, required field validation, and expected output verification.

Login Module Test Cases:

Test Scenario Expected Outcome Actual Result Status
Valid credentials with correct captcha System login success Login successful Pass
Valid username with incorrect password Password validation error Error message displayed Pass
Valid credentials with incorrect captcha Captcha validation failure Error message displayed Pass
Empty username with valid password Username required prompt Validation message shown Pass
Valid username with empty password Password required prompt Validation message shown Pass

User Management Test Cases:

Test Scenario Expected Outcome Actual Result Status
Complete user information submission User added successfully User visible in list Pass
Modify existing user details Update successful Changes persisted Pass
Delete selected user account Confirmation dialog, user removed User not found after deletion Pass
Submit form without username Validation error displayed Username required message Pass
Submit duplicate username Duplicate detection alert Error message shown Pass

Testing Conclusions

The system undergoes comprehensive testing to ensure functional requirements are met. All identified defects are addressed, and the system demonstrates acceptable performance characteristics. Testing validates that the system provides the intended functionality while maintaining data integrity and security standards.

Authentication Implementation

Token-Based Authentication

The system implements token-based authentication using JWT-style tokens stored in the database. The following Java code demonstrates the authentication interceptor configuration:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SkipVerification {
}

@RestController
@RequestMapping("/auth")
public class AuthenticationController {

    @Autowired
    private UserManagementService userService;

    @Autowired
    private SessionTokenService tokenService;

    @PostMapping("/signin")
    public ResponseEntity<Map<String, Object>> authenticate(
            @RequestParam String username,
            @RequestParam String password,
            @RequestParam String verificationCode,
            HttpServletRequest request) {
        
        UserAccount account = userService.findByUsername(username);
        
        if (account == null || !account.getPassword().equals(password)) {
            return ResponseEntity.badRequest()
                .body(Map.of("status", "error", "message", "Invalid credentials"));
        }
        
        String tokenValue = tokenService.createSessionToken(
            account.getId(),
            username,
            "user_account",
            account.getAccessLevel()
        );
        
        return ResponseEntity.ok(Map.of("status", "success", "token", tokenValue));
    }
}

Token Service Implementation

@Service
public class SessionTokenService extends ServiceImpl<SessionTokenMapper, SessionTokenEntity> {

    public String createSessionToken(Long userId, String username, String tableName, String role) {
        SessionTokenEntity existingToken = this.getOne(
            new QueryWrapper<SessionTokenEntity>()
                .eq("user_id", userId)
                .eq("access_role", role)
        );
        
        String token = UUID.randomUUID().toString().replace("-", "");
        Calendar expiration = Calendar.getInstance();
        expiration.setTime(new Date());
        expiration.add(Calendar.HOUR_OF_DAY, 2);
        
        if (existingToken != null) {
            existingToken.setToken(token);
            existingToken.setExpirationTime(expiration.getTime());
            this.updateById(existingToken);
        } else {
            SessionTokenEntity newToken = new SessionTokenEntity();
            newToken.setUserId(userId);
            newToken.setUsername(username);
            newToken.setTableName(tableName);
            newToken.setAccessRole(role);
            newToken.setToken(token);
            newToken.setExpirationTime(expiration.getTime());
            this.save(newToken);
        }
        
        return token;
    }
}

Authorization Interceptor

@Component
public class AccessControlInterceptor implements HandlerInterceptor {

    public static final String AUTH_HEADER = "Authorization";

    @Autowired
    private SessionTokenService tokenService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
                            Object handler) throws IOException {
        
        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, Authorization, Content-Type, cache-control");
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        
        if (HttpMethod.OPTIONS.name().equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            return false;
        }
        
        SkipVerification skipAuth;
        if (handler instanceof HandlerMethod method) {
            skipAuth = method.getMethodAnnotation(SkipVerification.class);
        } else {
            return true;
        }
        
        if (skipAuth != null) {
            return true;
        }
        
        String token = request.getHeader(AUTH_HEADER);
        
        if (StringUtils.isEmpty(token)) {
            sendUnauthorizedResponse(response, "Authentication required");
            return false;
        }
        
        SessionTokenEntity tokenEntity = tokenService.validateToken(token);
        
        if (tokenEntity != null) {
            request.getSession().setAttribute("userId", tokenEntity.getUserId());
            request.getSession().setAttribute("role", tokenEntity.getAccessRole());
            request.getSession().setAttribute("tableName", tokenEntity.getTableName());
            request.getSession().setAttribute("username", tokenEntity.getUsername());
            return true;
        }
        
        sendUnauthorizedResponse(response, "Please login first");
        return false;
    }
    
    private void sendUnauthorizedResponse(HttpServletResponse response, String message) 
            throws IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.write("{\"status\":\"error\",\"code\":401,\"message\":\"" + message + "\"}");
        writer.flush();
    }
}

Database Schema

Token Storage Table

DROP TABLE IF EXISTS `session_token`;
CREATE TABLE `session_token` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Primary key',
  `user_id` bigint(20) NOT NULL COMMENT 'User identifier',
  `username` varchar(100) NOT NULL COMMENT 'Account name',
  `table_name` varchar(100) DEFAULT NULL COMMENT 'Related table',
  `access_role` varchar(100) DEFAULT NULL COMMENT 'User role',
  `token` varchar(200) NOT NULL COMMENT 'Session token',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation timestamp',
  `expiration_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Expiration timestamp',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX idx_user_role (`user_id`, `access_role`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT 
COMMENT='Session management table';

Sample token records:

INSERT INTO `session_token` VALUES 
('23', 'cd01', 'residents', 'resident', 'al6svx5qkei1wljry5o1npswhdpqcpcg', '2023-02-23 21:46:45', '2023-03-15 14:01:36'),
('11', 'xh01', 'residents', 'resident', 'fahmrd9bkhqy04sq0fzrl4h9m86cu6kx', '2023-02-27 18:33:52', '2023-03-17 18:27:42'),
('1', 'administrator', 'system_users', 'administrator', 'h1pqzsb9bldh93m92j9m2sljy9bt1wdh', '2023-02-27 19:37:01', '2023-03-17 18:23:02');

System Features

The property management system encompasses several core modules:

  • Resident Information Management: CRUD operations for resident records, contact information, and move-in/out tracking
  • Property Fee Management: Invoice generation, payment tracking, and financial reporting
  • Maintenance Request Processing: Work order creation, assignment, and completion tracking
  • Security Access Control: Visitor registration, patrol logs, and alarm management
  • Announcement System: Community notifications and message broadcasting
  • Data Analytics Dashboard: Occupancy rates, revenue summaries, and operational metrics

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.