leniu-architecture-design

leniu-tengyun-core 架构设计指南

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "leniu-architecture-design" with this command: npx skills add xu-cell/ai-engineering-init/xu-cell-ai-engineering-init-leniu-architecture-design

leniu-tengyun-core 架构设计指南

双库架构

物理分离双库,Entity 无 tenant_id 字段:

库类型 数据范围 访问方式

系统库 租户信息、商户配置、系统字典 Executors.doInSystem()

商户库 订单、菜品、用户、设备等 默认(请求头 MERCHANT-ID )

多租户上下文切换

// 获取当前租户 Long tenantId = TenantContextHolder.getTenantId();

// 在指定商户库执行 Executors.doInTenant(tenantId, () -> { /* 商户库 */ });

// 在系统库执行 Executors.doInSystem(() -> { /* 系统库 */ });

// 遍历所有租户执行(定时任务场景) Executors.doInAllTenant(tenantId -> { /* 每个租户 */ });

双库路由场景

// 场景1:商户业务(默认,前端请求头携带 MERCHANT-ID) @PostMapping("/order/add") public void addOrder(@RequestBody LeRequest<OrderDTO> request) { orderService.add(request.getContent()); // 自动路由商户库 }

// 场景2:系统配置操作 @PostMapping("/merchant/config") public void updateConfig(@RequestBody LeRequest<ConfigDTO> request) { Executors.doInSystem(() -> configService.update(request.getContent())); }

// 场景3:定时任务遍历所有租户 public void execute() { Executors.doInAllTenant(tenantId -> reportService.generate(tenantId)); }

// 场景4:MQ 消费指定租户 @RabbitListener(queues = "order.queue") public void consumeOrder(Message message) { Long tenantId = getTenantFromMessage(message); Executors.doInTenant(tenantId, () -> orderService.process(message)); }

四层架构

Controller → Business → Service → Mapper

层 职责 命名

Controller 接收请求、参数校验、路由分端 XxxWebController

Business 业务编排、跨 Service 协调 XxxWebBusiness

Service 单表 CRUD、事务 XxxServiceImpl

Mapper ORM 映射(XML 同目录) XxxMapper

Business 层是本项目核心特色,复杂逻辑在此编排,简单 CRUD 可跳过直接 Controller→Service。

Controller 示例

package net.xnzn.core.xxx.controller;

import com.pig4cloud.pigx.common.core.util.LeRequest; import net.xnzn.framework.secure.filter.annotation.RequiresAuthentication;

@RestController @RequiresAuthentication @RequestMapping("/api/v2/web/xxx") public class XxxWebController {

@Autowired
private XxxWebBusiness xxxBusiness;

@PostMapping("/add")
public void add(@Validated @RequestBody LeRequest&#x3C;XxxDTO> request) {
    xxxBusiness.add(request.getContent());
}

@PostMapping("/query")
public Page&#x3C;XxxVO> query(@Validated @RequestBody LeRequest&#x3C;PageDTO> request) {
    return xxxBusiness.query(request.getContent());
}

}

Business 示例

package net.xnzn.core.xxx.business.impl;

@Component public class XxxWebBusiness {

@Autowired
private XxxServiceImpl xxxService;
@Autowired
private YyyServiceImpl yyyService;

public void add(XxxDTO dto) {
    // 编排多个 Service
    xxxService.add(dto);
    yyyService.bindRelation(dto.getId());
}

public Page&#x3C;XxxVO> query(PageDTO dto) {
    return xxxService.query(dto);
}

}

Service 示例

package net.xnzn.core.xxx.service.impl;

@Service public class XxxServiceImpl { @Autowired private XxxMapper xxxMapper;

public void add(XxxDTO dto) {
    long id = Id.next();
    XxxEntity entity = new XxxEntity();
    BeanUtil.copyProperties(dto, entity);
    entity.setId(id);
    xxxMapper.insert(entity);
}

public Page&#x3C;XxxVO> query(PageDTO dto) {
    return xxxMapper.page(dto.getMpPage(), dto.getKeyword());
}

}

Mapper 示例

package net.xnzn.core.xxx.mapper;

@Mapper public interface XxxMapper extends BaseMapper<XxxEntity> { Page<XxxVO> page(Page<Object> page, @Param("keyword") String keyword); }

Mapper XML(与 Java 同目录)

src/main/java/net/xnzn/core/xxx/mapper/ ├── XxxMapper.java └── XxxMapper.xml ← 同目录,非 resources/mapper/

pom.xml 必须配置资源过滤:

<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/resources</directory> </resource> </resources> </build>

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="net.xnzn.core.xxx.mapper.XxxMapper"> <select id="page" resultType="net.xnzn.core.xxx.vo.XxxVO"> SELECT id, name, status, crtime, uptime FROM xxx_table WHERE del_flag = 2 <if test="keyword != null and keyword != ''"> AND name LIKE CONCAT('%', #{keyword}, '%') </if> </select> </mapper>

多端 Controller 路由

端 路由前缀 Controller 命名

Web 管理端 /api/v2/web/{module}

XxxWebController

移动端 /api/v2/mobile/{module}

XxxMobileController

设备端 /api/v2/android/{module}

XxxAndroidController

开放接口 /api/v2/open/{module}

XxxOpenController

Entity 设计

package net.xnzn.core.xxx.model;

@Data @TableName("xxx_table") public class XxxEntity {

@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;  // 雪花ID:Id.next()

private String name;
private Integer status;

// 审计字段
@TableField(fill = FieldFill.INSERT)
private String crby;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime crtime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private String upby;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime uptime;

// 逻辑删除:1=删除,2=正常
private Integer delFlag;

}

DelFlagEnum

public enum DelFlagEnum { DEL_TRUE(1, "删除"), DEL_FALSE(2, "正常");

private final Integer key;
private final String val;

}

对应建表 SQL

CREATE TABLE xxx_table ( id BIGINT NOT NULL COMMENT '主键(雪花ID)', name VARCHAR(100) COMMENT '名称', status INT COMMENT '状态', crby VARCHAR(64) COMMENT '创建人', crtime DATETIME COMMENT '创建时间', upby VARCHAR(64) COMMENT '更新人', uptime DATETIME COMMENT '更新时间', del_flag INT DEFAULT 2 COMMENT '删除标识(1-删除,2-正常)', PRIMARY KEY (id) ); -- 无需 tenant_id(双库物理隔离)

请求响应封装

// 请求体:LeRequest<T> 包装 @PostMapping("/add") public void add(@Validated @RequestBody LeRequest<XxxDTO> request) { XxxDTO dto = request.getContent(); }

// 分页请求 @PostMapping("/query") public Page<XxxVO> query(@Validated @RequestBody LeRequest<PageDTO> request) { return xxxService.query(request.getContent()); }

PageDTO

@Data public class PageDTO { @NotNull @Min(1) private Integer pageNum; @NotNull @Min(1) private Integer pageSize; private String keyword;

public Page&#x3C;Object> getMpPage() {
    return new Page&#x3C;>(pageNum, pageSize);
}

}

异常与国际化

// 业务异常 throw new LeException("业务错误信息");

// 带国际化 throw new LeException(I18n.getMessage("error.key"));

项目模块结构

leniu-tengyun-core/ ├── core-base/ # 公共基础模块 ├── sys-common/ # 公共业务(支付、通知、对接) ├── sys-canteen/ # 食堂业务 ├── sys-kitchen/ # 后场厨房 ├── sys-drp/ # 供应链 ├── sys-logistics/ # 物流 └── sys-open/ # 开放接口

标准包结构

net.xnzn.core.[module]/ ├── controller/ # 按端分:web/mobile/android ├── business/impl/ # 业务编排 ├── service/impl/ # 服务层 ├── mapper/ # Mapper + XML(同目录) ├── model/ # Entity ├── vo/ # 响应对象 ├── dto/ # 请求参数 ├── constants/ # 枚举和常量 ├── mq/ # 消息队列 └── task/ # 定时任务

参考代码位置

类型 路径

订单 Controller sys-canteen/.../order/web/controller/OrderInfoWebController.java

订单 Business sys-canteen/.../order/web/business/impl/OrderWebBusiness.java

订单 Service sys-canteen/.../order/common/service/impl/OrderInfoService.java

排班 Controller sys-kitchen/.../attendance/scheduling/controller/BackAttendanceWorkShiftController.java

Bootstrap 配置 core-base/src/main/resources/bootstrap.yml

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

scheduled-jobs

No summary provided by upstream source.

Repository SourceNeeds Review
General

loki-log-query

No summary provided by upstream source.

Repository SourceNeeds Review
General

brainstorm

No summary provided by upstream source.

Repository SourceNeeds Review
General

openspec-ff-change

No summary provided by upstream source.

Repository SourceNeeds Review