Implementing Device Modeling (Thing Model) in KCloud-Platform-IoT: Clean Architecture Guide

KCloud-Platform-IoT implements device modeling through a four-layer clean architecture separating Domain, Application, Infrastructure, and Client concerns, using ThingModelE as the core entity with MyBatis-Plus persistence and bidirectional DTO conversion.

The Thing Model (device-model) serves as the central entity describing device data points, events, and commands in the koushenhai/kcloud-platform-iot repository. This implementation demonstrates how to structure complex IoT domain logic using Spring Boot, MyBatis-Plus, and strict layer isolation. Understanding this architecture allows developers to extend device capabilities while maintaining testable, maintainable code boundaries.

Clean Architecture Layers Overview

The implementation strictly follows clean architecture principles with four distinct layers. Each layer has specific responsibilities and dependency directions pointing inward toward the Domain.

  • Domain: Encapsulates business rules, validation, and entity definitions in ThingModelE
  • Application: Orchestrates use-cases through ThingModelDomainService
  • Infrastructure: Handles MySQL persistence via MyBatis-Plus and entity conversion
  • Client: Defines API contracts with command objects like ThingModelSaveCmd

This structure ensures that business logic remains independent of storage mechanisms and transport protocols.

Domain Layer: Entities and Validation

The Domain layer contains the pure business logic for device modeling, isolated from external frameworks.

ThingModelE Entity Definition

The ThingModelE class in laokou-service/laokou-iot/laokou-iot-domain/src/main/java/org/laokou/iot/thingModel/model/ThingModelE.java represents the logical state of a device model:

public class ThingModelE {
    private Long id;
    private String name;
    private String code;
    private String dataType;          // integer, string, decimal, boolean
    private Integer category;         // 1=属性, 2=事件
    private String type;              // read/write/report
    private Integer sort;
    private String specs;             // rule description
    private String remark;
    private OperateType operateType;  // SAVE or MODIFY
    
    public void checkThingModelParam() throws Exception { 
        // validation hook implementation
    }
}

Validation and Factory Patterns

ThingModelParamValidator enforces uniqueness constraints on the code and name fields during insertion and ensures required fields are present. Located in laokou-service/laokou-iot/laokou-iot-app/src/main/java/org/laokou/iot/thingModel/service/validator/ThingModelParamValidator.java, this validator prevents duplicate device model definitions.

ThingModelFactory provides Spring-managed prototype instantiation of ThingModelE entities, located in the domain module's factory package. This pattern decouples entity creation from the application layer.

Application Layer: Use Case Orchestration

The ThingModelDomainService class in laokou-service/laokou-iot/laokou-iot-domain/src/main/java/org/laokou/iot/thingModel/ability/ThingModelDomainService.java coordinates all Thing Model operations. It validates entities using ThingModelParamValidator before delegating to the infrastructure gateway.

Key methods include:

  • createThingModel(ThingModelE entity) – Handles new device model creation
  • updateThingModel(ThingModelE entity) – Manages modification workflows
  • deleteThingModel(Long[] ids) – Executes batch deletion

This service acts as the transactional boundary, ensuring business rules execute atomically before persistence.

Infrastructure Layer: Persistence and Conversion

Infrastructure concerns are isolated in the laokou-iot-infrastructure module, implementing the repository pattern through MyBatis-Plus.

Data Objects and Database Mapping

ThingModelDO in laokou-service/laokou-iot/laokou-iot-infrastructure/src/main/java/org/laokou/iot/thingModel/gatewayimpl/database/dataobject/ThingModelDO.java maps directly to the iot_thing_model table. The corresponding ThingModelMapper interface extends MyBatis-Plus BaseMapper for CRUD operations.

Gateway Implementation

The ThingModelGateway interface defines the port used by the domain layer, while ThingModelGatewayImpl in gatewayimpl/ThingModelGatewayImpl.java provides the concrete implementation. This adapter converts domain entities to data objects and orchestrates database transactions through ThingModelMapper.insert().

Type Conversion Strategy

ThingModelConvertor handles bidirectional mapping between three representations:

  • ThingModelE (Domain entity)
  • ThingModelDO (Infrastructure data object)
  • ThingModelCO (Client presentation object)

Located in gatewayimpl/convertor/ThingModelConvertor.java, this class ensures type safety when crossing architectural boundaries.

Client Layer: API Contracts

The Client layer defines the external API surface through command objects and service interfaces.

ThingModelsServiceI in laokou-service/laokou-iot/laokou-iot-client/src/main/java/org/laokou/iot/thingModel/api/ThingModelsServiceI.java declares the service contract implemented by HTTP controllers.

Command classes carry request data:

  • ThingModelSaveCmd – Create new model requests
  • ThingModelModifyCmd – Update existing models
  • ThingModelRemoveCmd – Delete by ID arrays
  • ThingModelPageQry – Paginated queries

ThingModelCO serves as the client-side representation for API responses, located in the dto/clientobject package.

Practical Implementation Example

Below is a complete controller implementation demonstrating the end-to-end flow for creating a Thing Model:

@RestController
@RequestMapping("/thing-model")
public class ThingModelController {

    @Autowired
    private ThingModelDomainService thingModelDomainService;

    @PostMapping
    public Result<Long> create(@RequestBody ThingModelSaveCmd cmd) throws Exception {
        // Convert command to domain entity using infrastructure convertor
        ThingModelE entity = ThingModelConvertor.toEntity(cmd.getCo(), true);
        
        // Execute domain logic with validation and persistence
        thingModelDomainService.createThingModel(entity);
        
        // Return generated primary key assigned by MyBatis-Plus
        return Result.success(entity.getPrimaryKey());
    }
}

The execution flow follows this sequence:

  1. API Layer receives ThingModelSaveCmd extending CommonCommand
  2. ThingModelConvertor.toEntity() transforms the command into ThingModelE
  3. ThingModelDomainService.createThingModel() validates via ThingModelParamValidator and delegates to the gateway
  4. ThingModelGatewayImpl converts to ThingModelDO and inserts via ThingModelMapper

Update operations follow an identical pattern using ThingModelModifyCmd and updateThingModel(), while deletion accepts ID arrays through deleteThingModel().

Summary

The Thing Model implementation in KCloud-Platform-IoT demonstrates production-ready clean architecture for IoT device management:

  • Domain isolation keeps business rules in ThingModelE and ThingModelParamValidator independent of frameworks
  • Application orchestration through ThingModelDomainService provides clear use-case boundaries
  • Infrastructure abstraction via ThingModelGatewayImpl and MyBatis-Plus enables swappable persistence strategies
  • Client contracts using command objects (ThingModelSaveCmd, ThingModelModifyCmd) ensure API stability

The conversion flow between ThingModelCO, ThingModelE, and ThingModelDO maintains type safety across all four architectural layers.

Frequently Asked Questions

How does KCloud-Platform-IoT validate Thing Model uniqueness?

The platform validates uniqueness through ThingModelParamValidator in the Application layer, which checks that the combination of code and name fields does not already exist in the iot_thing_model table before allowing insertion. This prevents duplicate device model definitions while keeping validation logic out of the infrastructure layer.

What database table stores the Thing Model entities?

Thing Model data persists to the iot_thing_model table via ThingModelDO and ThingModelMapper in the Infrastructure layer. The implementation uses MyBatis-Plus for CRUD operations, with the gateway pattern abstracting database specifics from the Domain layer.

Can the Thing Model support custom data types beyond integer, string, decimal, and boolean?

Yes. While the reference implementation includes standard IoT data types (integer, string, decimal, boolean) in the dataType field of ThingModelE, the domain model is extensible. Developers can modify the validation logic in checkThingModelParam() and update the database schema to support additional complex types or structured specifications within the specs JSON field.

How does the architecture handle the conversion between API requests and database entities?

The architecture uses ThingModelConvertor to handle bidirectional mapping between three representations: ThingModelCO (Client/API), ThingModelE (Domain), and ThingModelDO (Infrastructure). This conversion happens at the architectural boundaries—when entering the Domain from the Client layer and when persisting to the database through the Gateway implementation.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →