zcloud_gbs_xinyi_gate/docs/开发指南.md

19 KiB
Raw Blame History

信义门禁开发指南

一、项目概览

项目
groupId com.zcloud.xinyigate
artifactId zcloud_gbs_xinyi_gate
包名 com.zcloud.xinyigate
应用名 jjb-saas-zcloud-xinyi-gate
网关名 xinyiGate
父POM com.jjb.saas:jjb-saas-parent:2.2.0-SNAPSHOT
公共库 com.zcloud.gbscommon:zcloud_gbscommon:1.0.0-SNAPSHOT
技术栈 Spring Boot 2.6 + Spring Cloud + Nacos + MyBatis-Plus + XXL-Job

二、模块结构

zcloud_gbs_xinyi_gate/
├── start/                    # 启动模块
│   └── src/main/
│       ├── java/.../Application.java          # Spring Boot 入口
│       └── resources/
│           ├── nacos.yml                       # Nacos配置开发
│           ├── nacos-prod.yml                  # Nacos配置生产
│           ├── bootstrap.yml                   # 引导配置
│           └── templates/xinyiGate/            # 前端模板
│
├── web-adapter/              # 适配层 - 接收外部请求
│   └── src/main/java/.../
│       ├── web/{module}/                       # REST Controller
│       │   └── XxxController.java
│       └── job/                                # 定时任务
│           └── XxxJob.java
│
├── web-app/                  # 应用层 - 业务编排
│   └── src/main/java/.../
│       ├── command/{module}/                   # 写操作执行器
│       │   ├── XxxAddExe.java
│       │   ├── XxxEditExe.java
│       │   └── XxxRemoveExe.java
│       ├── command/query/{module}/             # 读操作执行器
│       │   └── XxxQueryExe.java
│       ├── command/convertor/{module}/         # 对象转换器
│       │   └── XxxCoConvertor.java
│       └── service/{module}/                   # Service实现
│           └── XxxServiceImpl.java
│
├── web-client/               # 客户端层 - 接口定义 + DTO
│   └── src/main/java/.../
│       ├── api/{module}/                       # 服务接口
│       │   └── XxxServiceI.java
│       ├── dto/{module}/                       # 入参Cmd/Qry
│       │   ├── XxxAddCmd.java
│       │   ├── XxxEditCmd.java
│       │   └── XxxPageQry.java
│       ├── dto/clientobject/{module}/          # 出参CO
│       │   └── XxxCO.java
│       └── config/                             # 配置类
│
├── web-domain/               # 领域层 - 核心业务模型
│   └── src/main/java/.../
│       └── domain/
│           ├── model/{module}/                 # 领域实体
│           │   └── XxxE.java
│           ├── gateway/{module}/               # 网关接口
│           │   └── XxxGateway.java
│           ├── enums/                          # 枚举
│           └── util/                           # 领域工具
│
├── web-infrastructure/       # 基础设施层 - 数据库对接
│   └── src/main/
│       ├── java/.../
│       │   ├── gatewayimpl/{module}/           # 网关实现
│       │   │   └── XxxGatewayImpl.java
│       │   ├── persistence/
│       │   │   ├── dataobject/{module}/        # 数据对象
│       │   │   │   └── XxxDO.java
│       │   │   ├── mapper/{module}/            # Mapper接口
│       │   │   │   └── XxxMapper.java
│       │   │   ├── repository/{module}/        # Repository接口
│       │   │   │   └── XxxRepository.java
│       │   │   └── repository/impl/{module}/   # Repository实现
│       │   │       └── XxxRepositoryImpl.java
│       │   └── utils/                          # 工具类
│       └── resources/
│           ├── mapper/{module}/                # MyBatis XML
│           │   └── XxxMapper.xml
│           └── mybatis/mybatis-config.xml
│
└── pom.xml                   # 父POM

三、模块依赖关系

start → adapter → app → client → domain
                       ↓
                 infrastructure → domain
模块 可依赖
web-domain 无(纯核心,不依赖任何业务模块)
web-client web-domain
web-infrastructure web-domain
web-app web-client, web-infrastructure
web-adapter web-app, web-client
start web-adapter

四、调用链路

HTTP请求
  → Controller (adapter层参数校验、权限控制)
    → ServiceI (client层接口定义)
      → ServiceImpl (app层业务编排)
        → XxxExe (app层单一职责执行器)
          → XxxGateway (domain层网关接口)
            → XxxGatewayImpl (infrastructure层网关实现)
              → XxxMapper (infrastructure层MyBatis接口)
                → XxxMapper.xml (SQL映射)
                  → 数据库

五、各层代码模板

5.1 web-client — 服务接口 + DTO

服务接口 XxxServiceI.java

package com.zcloud.xinyigate.api.module;

import com.jjb.saas.framework.client.ResponseData;
import com.zcloud.xinyigate.dto.module.XxxAddCmd;
import com.zcloud.xinyigate.dto.module.XxxEditCmd;
import com.zcloud.xinyigate.dto.module.XxxPageQry;
import com.zcloud.xinyigate.dto.clientobject.module.XxxCO;

public interface XxxServiceI {

    ResponseData addXxx(XxxAddCmd cmd);

    ResponseData editXxx(XxxEditCmd cmd);

    ResponseData removeXxx(Long id);

    ResponseData<XxxCO> getXxx(Long id);

    ResponseData queryXxxPage(XxxPageQry qry);
}

新增命令 XxxAddCmd.java

package com.zcloud.xinyigate.dto.module;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.validation.constraints.NotBlank;

@Data
@ApiModel("Xxx新增命令")
public class XxxAddCmd {

    @NotBlank(message = "名称不能为空")
    @ApiModelProperty("名称")
    private String name;

    @ApiModelProperty("备注")
    private String remark;
}

分页查询 XxxPageQry.java

package com.zcloud.xinyigate.dto.module;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
@ApiModel("Xxx分页查询")
public class XxxPageQry {

    @ApiModelProperty("页码")
    private Integer pageIndex = 1;

    @ApiModelProperty("每页条数")
    private Integer pageSize = 10;

    @ApiModelProperty("名称(模糊查询)")
    private String name;
}

返回对象 XxxCO.java

package com.zcloud.xinyigate.dto.clientobject.module;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
@ApiModel("Xxx返回对象")
public class XxxCO {

    @ApiModelProperty("ID")
    private Long id;

    @ApiModelProperty("名称")
    private String name;

    @ApiModelProperty("备注")
    private String remark;
}

5.2 web-domain — 领域实体 + 网关接口

领域实体 XxxE.java

package com.zcloud.xinyigate.domain.model.module;

import lombok.Data;

@Data
public class XxxE {

    private Long id;
    private String name;
    private String remark;
}

网关接口 XxxGateway.java

package com.zcloud.xinyigate.domain.gateway.module;

import com.zcloud.xinyigate.domain.model.module.XxxE;

public interface XxxGateway {

    void add(XxxE xxxE);

    void edit(XxxE xxxE);

    void remove(Long id);

    XxxE getById(Long id);
}

5.3 web-app — Service实现 + 执行器

Service实现 XxxServiceImpl.java

package com.zcloud.xinyigate.service.module;

import com.jjb.saas.framework.client.ResponseData;
import com.zcloud.xinyigate.api.module.XxxServiceI;
import com.zcloud.xinyigate.command.module.XxxAddExe;
import com.zcloud.xinyigate.command.module.XxxEditExe;
import com.zcloud.xinyigate.command.query.module.XxxQueryExe;
import com.zcloud.xinyigate.dto.module.XxxAddCmd;
import com.zcloud.xinyigate.dto.module.XxxEditCmd;
import com.zcloud.xinyigate.dto.module.XxxPageQry;
import com.zcloud.xinyigate.dto.clientobject.module.XxxCO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class XxxServiceImpl implements XxxServiceI {

    private final XxxAddExe xxxAddExe;
    private final XxxEditExe xxxEditExe;
    private final XxxQueryExe xxxQueryExe;

    @Override
    public ResponseData addXxx(XxxAddCmd cmd) {
        xxxAddExe.execute(cmd);
        return ResponseData.success();
    }

    @Override
    public ResponseData editXxx(XxxEditCmd cmd) {
        xxxEditExe.execute(cmd);
        return ResponseData.success();
    }

    @Override
    public ResponseData removeXxx(Long id) {
        // 直接调用Gateway或写RemoveExe
        return ResponseData.success();
    }

    @Override
    public ResponseData<XxxCO> getXxx(Long id) {
        return ResponseData.success(xxxQueryExe.getById(id));
    }

    @Override
    public ResponseData queryXxxPage(XxxPageQry qry) {
        return ResponseData.success(xxxQueryExe.queryPage(qry));
    }
}

新增执行器 XxxAddExe.java

package com.zcloud.xinyigate.command.module;

import com.zcloud.xinyigate.domain.gateway.module.XxxGateway;
import com.zcloud.xinyigate.domain.model.module.XxxE;
import com.zcloud.xinyigate.dto.module.XxxAddCmd;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class XxxAddExe {

    private final XxxGateway xxxGateway;

    public void execute(XxxAddCmd cmd) {
        XxxE xxxE = new XxxE();
        xxxE.setName(cmd.getName());
        xxxE.setRemark(cmd.getRemark());
        xxxGateway.add(xxxE);
    }
}

查询执行器 XxxQueryExe.java

package com.zcloud.xinyigate.command.query.module;

import com.zcloud.xinyigate.domain.gateway.module.XxxGateway;
import com.zcloud.xinyigate.domain.model.module.XxxE;
import com.zcloud.xinyigate.dto.clientobject.module.XxxCO;
import com.zcloud.xinyigate.dto.module.XxxPageQry;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class XxxQueryExe {

    private final XxxGateway xxxGateway;

    public XxxCO getById(Long id) {
        XxxE xxxE = xxxGateway.getById(id);
        // E → CO 转换
        XxxCO co = new XxxCO();
        co.setId(xxxE.getId());
        co.setName(xxxE.getName());
        co.setRemark(xxxE.getRemark());
        return co;
    }

    public Object queryPage(XxxPageQry qry) {
        // 调用Gateway分页查询转换返回
        return null;
    }
}

5.4 web-infrastructure — 数据库对接

数据对象 XxxDO.java

package com.zcloud.xinyigate.persistence.dataobject.module;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("t_xxx")
public class XxxDO {

    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private String remark;
}

Mapper接口 XxxMapper.java

package com.zcloud.xinyigate.persistence.mapper.module;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zcloud.xinyigate.persistence.dataobject.module.XxxDO;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface XxxMapper extends BaseMapper<XxxDO> {
}

Mapper XML XxxMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zcloud.xinyigate.persistence.mapper.module.XxxMapper">

</mapper>

网关实现 XxxGatewayImpl.java

package com.zcloud.xinyigate.gatewayimpl.module;

import com.zcloud.xinyigate.domain.gateway.module.XxxGateway;
import com.zcloud.xinyigate.domain.model.module.XxxE;
import com.zcloud.xinyigate.persistence.dataobject.module.XxxDO;
import com.zcloud.xinyigate.persistence.mapper.module.XxxMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class XxxGatewayImpl implements XxxGateway {

    private final XxxMapper xxxMapper;

    @Override
    public void add(XxxE xxxE) {
        XxxDO xxxDO = new XxxDO();
        xxxDO.setName(xxxE.getName());
        xxxDO.setRemark(xxxE.getRemark());
        xxxMapper.insert(xxxDO);
    }

    @Override
    public void edit(XxxE xxxE) {
        XxxDO xxxDO = new XxxDO();
        xxxDO.setId(xxxE.getId());
        xxxDO.setName(xxxE.getName());
        xxxDO.setRemark(xxxE.getRemark());
        xxxMapper.updateById(xxxDO);
    }

    @Override
    public void remove(Long id) {
        xxxMapper.deleteById(id);
    }

    @Override
    public XxxE getById(Long id) {
        XxxDO xxxDO = xxxMapper.selectById(id);
        if (xxxDO == null) return null;
        XxxE xxxE = new XxxE();
        xxxE.setId(xxxDO.getId());
        xxxE.setName(xxxDO.getName());
        xxxE.setRemark(xxxDO.getRemark());
        return xxxE;
    }
}

5.5 web-adapter — Controller

REST接口 XxxController.java

package com.zcloud.xinyigate.web.module;

import com.jjb.saas.framework.client.ResponseData;
import com.zcloud.xinyigate.api.module.XxxServiceI;
import com.zcloud.xinyigate.dto.module.XxxAddCmd;
import com.zcloud.xinyigate.dto.module.XxxEditCmd;
import com.zcloud.xinyigate.dto.module.XxxPageQry;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@RestController
@RequestMapping("/xxx")
@Api(tags = "Xxx管理")
@RequiredArgsConstructor
public class XxxController {

    private final XxxServiceI xxxService;

    @PostMapping("/add")
    @ApiOperation("新增")
    public ResponseData add(@Valid @RequestBody XxxAddCmd cmd) {
        return xxxService.addXxx(cmd);
    }

    @PostMapping("/edit")
    @ApiOperation("编辑")
    public ResponseData edit(@Valid @RequestBody XxxEditCmd cmd) {
        return xxxService.editXxx(cmd);
    }

    @PostMapping("/remove/{id}")
    @ApiOperation("删除")
    public ResponseData remove(@PathVariable Long id) {
        return xxxService.removeXxx(id);
    }

    @GetMapping("/get/{id}")
    @ApiOperation("详情")
    public ResponseData get(@PathVariable Long id) {
        return xxxService.getXxx(id);
    }

    @PostMapping("/page")
    @ApiOperation("分页查询")
    public ResponseData page(@RequestBody XxxPageQry qry) {
        return xxxService.queryXxxPage(qry);
    }
}

5.6 定时任务web-adapter

XxxJob.java

package com.zcloud.xinyigate.job;

import com.jjb.saas.framework.job.Job;
import com.jjb.saas.framework.job.annotation.JobRegister;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
@Slf4j
public class XxxJob implements Job {

    private final XxxServiceI xxxService;

    @Override
    @JobRegister(cron = "0 0 0 * * ?", jobDesc = "Xxx定时任务", triggerStatus = 1)
    @XxlJob("com.zcloud.xinyigate.job.XxxJob")
    public ReturnT<String> execute(String param) {
        log.info("【Xxx定时任务】开始执行");
        try {
            // xxxService.doSomething();
            log.info("【Xxx定时任务】执行完成");
        } catch (Exception e) {
            log.error("【Xxx定时任务】执行异常", e);
            return new ReturnT<>(ReturnT.FAIL_CODE, e.getMessage());
        }
        return ReturnT.SUCCESS;
    }
}

六、开发步骤清单

实现一个新接口时,按以下顺序创建文件:

步骤 模块 文件 说明
1 web-client dto/module/XxxAddCmd.java 定义入参
2 web-client dto/module/XxxPageQry.java 定义查询参数
3 web-client dto/clientobject/module/XxxCO.java 定义出参
4 web-client api/module/XxxServiceI.java 定义服务接口
5 web-domain domain/model/module/XxxE.java 定义领域实体
6 web-domain domain/gateway/module/XxxGateway.java 定义网关接口
7 web-infrastructure persistence/dataobject/module/XxxDO.java 定义数据对象
8 web-infrastructure persistence/mapper/module/XxxMapper.java 定义Mapper接口
9 web-infrastructure resources/mapper/module/XxxMapper.xml 编写SQL
10 web-infrastructure gatewayimpl/module/XxxGatewayImpl.java 实现网关
11 web-app command/module/XxxAddExe.java 实现新增逻辑
12 web-app command/query/module/XxxQueryExe.java 实现查询逻辑
13 web-app service/module/XxxServiceImpl.java 实现Service
14 web-adapter web/module/XxxController.java 暴露REST接口

七、命名规范

类型 命名 示例
Controller {业务}Controller GateRecordController
Service接口 {业务}ServiceI GateRecordServiceI
Service实现 {业务}ServiceImpl GateRecordServiceImpl
新增执行器 {业务}AddExe GateRecordAddExe
编辑执行器 {业务}EditExe GateRecordEditExe
删除执行器 {业务}RemoveExe GateRecordRemoveExe
查询执行器 {业务}QueryExe GateRecordQueryExe
领域实体 {业务}E GateRecordE
网关接口 {业务}Gateway GateRecordGateway
网关实现 {业务}GatewayImpl GateRecordGatewayImpl
数据对象 {业务}DO GateRecordDO
Mapper接口 {业务}Mapper GateRecordMapper
新增命令 {业务}AddCmd GateRecordAddCmd
编辑命令 {业务}EditCmd GateRecordEditCmd
分页查询 {业务}PageQry GateRecordPageQry
返回对象 {业务}CO GateRecordCO
定时任务 {业务}Job GateRecordJob

八、注意事项

  1. 包名统一为 com.zcloud.xinyigateJava目录对应 com/zcloud/xinyigate/
  2. Application.java 中的 mapperPackages 已配置为 com.zcloud.xinyigate.persistence.mapper新Mapper会自动扫描
  3. 分页参数统一使用 pageIndex(页码)和 pageSize(每页条数),参考 Query.java 工具类
  4. 定时任务必须实现 Job 接口,同时加 @JobRegister@XxlJob 注解
  5. 对象转换Cmd → E在Exe中DO → E在GatewayImpl中E → CO在QueryExe中
  6. Flyway 已集成,数据库变更脚本放在 start/src/main/resources/db/migration/