leniu-customization-location

当在 leniu-tengyun-wuhanxieheyiyuan (或其他定制仓库)中开发定制功能时,遵循以下规范确定代码位置和修改方式。

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-customization-location" with this command: npx skills add xu-cell/ai-engineering-init/xu-cell-ai-engineering-init-leniu-customization-location

leniu 定制项目代码位置规范

适用场景

当在 leniu-tengyun-wuhanxieheyiyuan (或其他定制仓库)中开发定制功能时,遵循以下规范确定代码位置和修改方式。

一、定制项目特征识别

特征 说明

仓库名 leniu-tengyun-wuhanxieheyiyuan

主模块 leniu-yunshitang

包名根路径 net.xnzn.yunshitang.* (新写类)/ net.xnzn.core.* (迁移类)

类名前缀 Dz (如 DzReportSummaryService 、DzOrderOpenApi )

表名前缀 dz_ (如 dz_subsidy_batch 、dz_report_sum_canteen_wallet_mealtime )

注释标记 // 定制开始 / // 定制结束

二、新写代码的位置

2.1 新写类的存放路径

所有新写的定制类放在:

leniu-yunshitang/src/main/java/net/xnzn/yunshitang/

文件名前缀必须用 Dz ,示例:

  • DzMealOnlineService.java

  • DzReportSummaryController.java

  • DzMealDetailVO.java

  • DzSubsidyBatch.java (Entity)

  • DzCustInfoMapper.java (Mapper)

2.2 标准包结构

net.xnzn.yunshitang/ ├── account/ # 账户/补贴模块 │ ├── controller/ │ ├── service/ │ ├── mapper/ │ ├── model/ # Entity:DzSubsidyBatch、DzSubsidyDetail │ ├── dto/ │ ├── vo/ │ └── enums/ ├── customer/ # 人员模块 │ ├── mapper/ # DzCustInfoMapper(继承 CustInfoMapper) │ └── service/ ├── notice/ # 通知模块 │ ├── business/ # DzNoticeBurialPointBusiness │ └── config/ ├── order/ │ └── open/ # DzOrderOpenApi ├── pay/ │ └── custom/ # PayCustomBusinessImpl └── report/ └── statistics/ └── order/ ├── basic/ # 基础报表(直接查 report_order_info) │ ├── controller/ │ ├── service/ │ ├── mapper/ # DzXxxMapper.java + DzXxxMapper.xml(同目录) │ ├── param/ │ └── vo/ ├── analysis/ # 分析报表 └── summary/ # 汇总报表

2.3 注释规范

在修改/新增的代码块上下方加注释:

// 定制开始:计算线下订单销售额占比 if (CollUtil.isNotEmpty(list) && total != null) { list.forEach(item -> { BigDecimal proportion = item.getSalesAmount() .divide(total.getSalesAmount(), 4, RoundingMode.HALF_UP) .setScale(2, RoundingMode.HALF_UP); item.setSalesAmountProportion(proportion); }); } // 定制结束

何时使用注释:

  • 新写 Dz 前缀的类:类文件整体被认为是定制,注释可选

  • 迁移改造的 net.xnzn.core.* 类:每个改动处必须加注释

  • 在父类方法中插入逻辑时必须加注释

2.4 Mapper XML 存放位置

MyBatis XML 不能放在 resources/mapper/ 目录,必须与 Mapper 接口同目录:

net/xnzn/yunshitang/.../mapper/DzXxxMapper.java net/xnzn/yunshitang/.../mapper/DzXxxMapper.xml ← 同目录!

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>

2.5 新建表名前缀

定制业务新建的数据库表,表名必须以 dz_ 开头:

CREATE TABLE dz_subsidy_batch ( id BIGINT NOT NULL COMMENT '主键(雪花ID)', batch_num VARCHAR(255) NOT NULL COMMENT '批次号', subsidy_date DATE DEFAULT NULL COMMENT '补贴日期', total_count INT DEFAULT 0 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) ) COMMENT = '定制-补贴批次主表'; -- ⚠️ 无需 tenant_id(双库物理隔离)

三、修改 core 文件的三种方式

方式选择决策树

需要修改 core 类? ├── 是否是报表 Service(实现 ReportOrderConsumeService/含 consume/fix 方法)? │ ├── 是 → 【方式三:迁移】将文件迁移到定制仓库的 net.xnzn.core.* 路径 │ └── 否 → 【方式一:继承 + @Primary】新建 Dz 前缀子类覆盖 │ ├── 是否是新增扩展点实现(实现新接口)? │ └── 是 → 【方式二:实现接口 + @Primary】 │ └── 是否是 Mapper 接口? └── 是 → 【方式四:继承 Mapper + @Primary】

方式一:继承 Service/Business/API + @Primary(推荐)

适用于:普通 Service、Business、Open API 等单实现场景。

// 定制开始 @Primary @Service @Slf4j public class DzOrderOpenApi extends OrderOpenApi {

@Lazy
@Autowired
private OrderRefundMapper orderRefundMapper;

@Override
public PageVO&#x3C;QueryRefundTradeOpenVO> queryConsumeOrderRefundFlow(OrderOpenRefundFlowQueryDTO queryDTO) {
    // 先调用父类逻辑
    PageVO&#x3C;QueryRefundTradeOpenVO> pageVO = super.queryConsumeOrderRefundFlow(queryDTO);

    if (CollUtil.isEmpty(pageVO.getRecords())) {
        return pageVO;
    }

    // 定制开始:补充退款申请时间和审核时间
    List&#x3C;Long> refundIds = pageVO.getRecords().stream()
        .map(QueryRefundTradeOpenVO::getRefundOrdId).toList();

    Map&#x3C;Long, OrderRefund> orderRefundMap = orderRefundMapper
        .selectList(Wrappers.lambdaQuery(OrderRefund.class)
            .select(OrderRefund::getOrderRefundId, OrderRefund::getApplyTime, OrderRefund::getCheckTime)
            .in(OrderRefund::getOrderRefundId, refundIds))
        .stream()
        .collect(Collectors.toMap(OrderRefund::getOrderRefundId, Function.identity()));

    for (QueryRefundTradeOpenVO record : pageVO.getRecords()) {
        OrderRefund orderRefund = orderRefundMap.get(record.getRefundOrdId());
        if (orderRefund != null) {
            record.setApplyTime(orderRefund.getApplyTime());
            record.setCheckTime(orderRefund.getCheckTime());
        }
    }
    // 定制结束

    return pageVO;
}

} // 定制结束

Business 层继承示例(覆盖通知渠道):

@Service @Slf4j @Primary public class DzNoticeBurialPointBusiness extends NoticeBurialPointBusiness {

@Resource
private NoticeSendWebServiceSMSBusiness noticeSendWebServiceSMSBusiness;

@Override
public NoticeSendBusiness getSpecialNoticeSendBusiness(Integer templateType) {
    if (NoticeTemplateTypeEnum.isSms(templateType)) {
        // 定制开始:使用医院本地短信服务
        return noticeSendWebServiceSMSBusiness;
        // 定制结束
    }
    return null;
}

@Override
public boolean isXnSmsPlatform() {
    return false; // 定制:不使用讯牛短信,改用本地 WebService 短信
}

}

关键规则:

  • @Primary 确保 Spring 优先注入定制类

  • @Lazy 防止循环依赖(注入新 Bean 时使用)

  • 调用 super.xxx() 复用父类逻辑,再追加定制逻辑

方式二:实现新接口 + @Primary

适用于:framework 提供了扩展点接口,需要提供实现。

// 定制开始 @Primary @Service public class PayCustomBusinessImpl implements PayCustomBusiness {

@Override
public AutoQuerySupportVO didSupportAutoQuery(UnifyPayDTO unifyPayDTO,
                                              UnifyPayVO unifyPayVO,
                                              AutoQuerySupportVO supportVO) {
    // 定制开始:微信JSAPI支付通过招商银行通道时启用自动查询
    if (PayTypeEnum.isWechatJsapiPay(unifyPayDTO.getPayType())
            &#x26;&#x26; PayChannelEnum.CMB_PAY.getKey().equals(unifyPayDTO.getPayChannel())) {
        supportVO.setNeedAutoQuery(true);
        supportVO.setExpireSeconds(180L);
        supportVO.setAutoDelaySeconds(5L);
    }
    // 定制结束
    return supportVO;
}

} // 定制结束

方式三:迁移报表 Service(含 consume/fix 方法)

⚠️ 不能用 @Primary 继承 — 会导致 MQ 消费双重注册(两个 Bean 都收到消息)。

正确做法:

  • 将原文件从 leniu-tengyun-core 复制到定制仓库

  • 保持包名不变(仍是 net.xnzn.core.* ),但存放在定制仓库目录

  • 在修改处加 // 定制开始 / // 定制结束

原位置(core 仓库)

leniu-tengyun-core/sys-canteen/src/.../service/ReportSumDishesService.java

迁移后(定制仓库,包名不变!)

leniu-yunshitang/src/main/java/net/xnzn/core/report/statistics/order/summary/service/ReportSumDishesService.java

迁移文件中的定制部分:

@Override public ReportBaseTotalVO<ReportSumDishesVO> pageDishesSalesSummary(ReportDishesParam param) { // ... 原有逻辑 ...

// 定制开始:自助餐类型使用特殊 Mapper 方法
if (param.getOrderTypeList().stream().allMatch(s -> s == 12)) {
    list = reportSumDishesMapper.listBuffetOrderDishesSum(param, authPO, dataPermission);
    total = reportSumDishesMapper.getBuffetSummaryTotal(param, authPO, dataPermission);
}
// 定制结束

// ... 原有逻辑 ...

}

方式四:继承 Mapper 接口 + @Primary

适用于:需要扩展原 Mapper 的查询方法,或添加定制 SQL。

@Mapper @Primary public interface DzCustInfoMapper extends CustInfoMapper { // 继承原有所有方法 // 可新增定制查询方法 List<CustInfoVO> selectByPayrollNo(@Param("payrollNo") String payrollNo); }

四、核心包路径对照

内容 核心路径(core 仓库) 定制路径(wuhanxiehe 仓库)

新写定制类 — net.xnzn.yunshitang.*

迁移改造的 core 类 net.xnzn.core.*

net.xnzn.core.* (同包名,放在定制仓库)

定制 Mapper XML — 与 Java 文件同目录(不放 resources)

定制数据库表 — 表名前缀 dz_

定制配置 — bootstrap-ext.yml (定制仓库 resources 下)

五、配置文件规范

定制项目特有配置放在 bootstrap-ext.yml :

定制项目报表配置

yunshitang: report: exclude-canteen-name: ${EXCLUDE_CANTEEN_NAME:本院营养食堂} headquarter: area: name: 本部食堂

定制第三方服务(如医院短信平台)

wuhanxiehe: sms: service-url: ${PROJECT_WUHANXIEHE_SMS_SERVICE_URL:http://...} username: ${PROJECT_WUHANXIEHE_SMS_USERNAME:xxx} timeout: ${PROJECT_WUHANXIEHE_SMS_TIMEOUT:30000}

六、完整定制报表功能实现步骤

新建一个完整的定制报表功能的标准步骤:

  • 创建定制查询参数 → DzXxxParam.java (继承 ReportBaseParam 或 PageDTO )

  • 创建定制返回 VO → DzXxxVO.java (金额字段 BigDecimal,以分为单位)

  • 创建定制 Mapper → DzXxxMapper.java (接口,3 参数:param + authPO + dataPermission)

  • 创建定制 Mapper XML → DzXxxMapper.xml (同目录,baseWhere 引入权限片段)

  • 创建定制 Service → DzXxxService.java (注入权限 Bean,pageWithTotal/getTotal/export 三个方法)

  • 注册到 Controller → 在 DzReportSummaryController 中注入 Service,新增接口

七、检查清单

  • 新写类文件名有 Dz 前缀

  • 新写类放在 net.xnzn.yunshitang.* 包下

  • 修改代码处有 // 定制开始 / // 定制结束 注释

  • Mapper XML 与 Java 文件同目录(非 resources)

  • pom.xml 已配置 src/main/java 下 xml 资源过滤

  • 新建表以 dz_ 开头,审计字段用 crby/crtime/upby/uptime/del_flag

  • 覆盖普通 Service/Business/API 时使用 @Primary 继承

  • 报表 MQ Service(有 consume/fix 方法)必须迁移,不能用 @Primary

  • 不直接修改 leniu-tengyun-core 仓库的文件

  • 报表查询方法注入 MgrAuthV2Api

  • ReportDataPermissionService ,所有 Mapper 调用传权限参数
  • 继承类中调用父类逻辑时用 super.xxx() ,只重写需要变更的部分

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

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
General

utils-toolkit

No summary provided by upstream source.

Repository SourceNeeds Review