From bf23b3dd580bd138cfbc62741834ca4377838f8b Mon Sep 17 00:00:00 2001 From: lml <1297555865@qq.com> Date: Thu, 29 Oct 2026 15:43:40 +0800 Subject: [PATCH] =?UTF-8?q?feat(tenant-online):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=A7=9F=E6=88=B7=E7=AB=AF=E8=A1=A8=E5=8D=95/=E6=8A=A5?= =?UTF-8?q?=E8=A1=A8=E5=85=83=E6=95=B0=E6=8D=AE=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TenantOnlFormHeadController:开放查询、保存、删除、tableInfo、 selectOnlFrom;syncDB/generate/download/defaultData/checkTableName/ getDir/onlFormSync 统一 404 - TenantOnlCgreportHeadController:开放查询、保存、删除、getData; parseSql 等管理端能力 404 --- .../TenantOnlCgreportHeadController.java | 188 +++++++++++++++++ .../controller/TenantOnlFormHeadController.java | 223 +++++++++++++++++++++ 2 files changed, 411 insertions(+) create mode 100644 common/common-tenant-online/src/main/java/apelet/common/tenant/online/controller/TenantOnlCgreportHeadController.java create mode 100644 common/common-tenant-online/src/main/java/apelet/common/tenant/online/controller/TenantOnlFormHeadController.java diff --git a/common/common-tenant-online/src/main/java/apelet/common/tenant/online/controller/TenantOnlCgreportHeadController.java b/common/common-tenant-online/src/main/java/apelet/common/tenant/online/controller/TenantOnlCgreportHeadController.java new file mode 100644 index 0000000..b3efb71 --- /dev/null +++ b/common/common-tenant-online/src/main/java/apelet/common/tenant/online/controller/TenantOnlCgreportHeadController.java @@ -0,0 +1,188 @@ +package apelet.common.tenant.online.controller; + +import apelet.common.core.annotation.MyRequestBody; +import apelet.common.core.exception.DataNotFoundException; +import apelet.common.core.object.MyOrderParam; +import apelet.common.core.object.MyPageParam; +import apelet.common.core.object.ResponseResult; +import apelet.common.generator.controller.OnlCgreportHeadController; +import apelet.common.generator.dto.OnlCgreportHeadDto; +import apelet.common.tenant.annotation.SwitchTenantCommonDatasource; +import com.alibaba.fastjson.JSONObject; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * 租户端在线报表元数据接口。 + * + *
只开放报表配置的日常维护(查询、保存、删除、取数),绝对不开放 {@code parseSql}: + * 该接口会用 {@code jdbcTemplate} 直接执行调用方传入的任意 SQL,黑名单可被 union、子查询、 + * information_schema 等绕过,租户用户可借此读取同库任意表(含用户密码哈希、其他租户数据)。
+ * + *注意:Spring MVC 会把父类带 {@code @RequestMapping} 的方法一并注册到子类路径下, + * 仅“不覆写”并不能屏蔽接口。因此这里除了覆写白名单方法外,还显式覆写了所有 + * 黑名单方法并统一抛出 {@link DataNotFoundException},由全局异常处理器返回 404。
+ * + * @author apelet + */ +@SwitchTenantCommonDatasource +@Tag(name = "租户在线报表元数据接口") +@Slf4j +@RestController +@RequestMapping("${common-online.urlPrefix}/tenantOnlCgreportHead") +public class TenantOnlCgreportHeadController extends OnlCgreportHeadController { + + /** + * 租户端未开放的接口统一按 404 返回,避免通过状态码区分“不存在”和“无权限”。 + * + * @return 404 业务异常。 + */ + private DataNotFoundException notOpen() { + return new DataNotFoundException("租户端不开放该接口"); + } + + /** + * 分页列表查询。租户维度由父类按当前登录租户过滤(PRD FR-4.15)。 + * + * @param onlCgreportHeadDto 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象。 + */ + @PostMapping("/page") + @Schema(description = "分页列表查询") + @Override + public ResponseResult> page(@MyRequestBody OnlCgreportHeadDto onlCgreportHeadDto, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + return super.page(onlCgreportHeadDto, orderParam, pageParam); + } + + /** + * 单条查询。 + * + * @param id 报表主键Id。 + * @return 应答结果对象。 + */ + @GetMapping("/getById") + @Schema(description = "单条查询") + @Override + public ResponseResult> getById(@RequestParam("id") String id) { + return super.getById(id); + } + + /** + * 查询对应 sql 的字段。 + * + * @param id 报表主键Id。 + * @return 应答结果对象。 + */ + @GetMapping("/getFieldsById") + @Schema(description = "查询对应sql的字段") + @Override + public ResponseResult> getFieldsById(@RequestParam("id") String id) { + return super.getFieldsById(id); + } + + /** + * 查询对应 sql 的参数。 + * + * @param id 报表主键Id。 + * @return 应答结果对象。 + */ + @GetMapping("/getParamsById") + @Schema(description = "查询对应sql的参数") + @Override + public ResponseResult> getParamsById(@RequestParam("id") String id) { + return super.getParamsById(id); + } + + /** + * 保存报表配置+字段+参数。 + * + * @param onlCgreportHeadDto 新增对象。 + * @return 应答结果对象。 + */ + @PostMapping("/addAll") + @Schema(description = "保存报表配置+字段+参数") + @Override + public ResponseResult> addAll(@RequestBody OnlCgreportHeadDto onlCgreportHeadDto) { + return super.addAll(onlCgreportHeadDto); + } + + /** + * 编辑报表配置+字段+参数。 + * + * @param onlCgreportHeadDto 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/editAll") + @Schema(description = "编辑报表配置+字段+参数") + @Override + public ResponseResult> editAll(@RequestBody OnlCgreportHeadDto onlCgreportHeadDto) { + return super.editAll(onlCgreportHeadDto); + } + + /** + * 删除报表配置+字段+参数。 + * + * @param id 报表主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/removeAllById") + @Schema(description = "删除报表配置+字段+参数") + @Override + public ResponseResult> removeAllById(@MyRequestBody Long id) { + return super.removeAllById(id); + } + + /** + * 根据 code 查询所需的字段信息和搜索字段。 + * + * @param code 报表编码。 + * @return 应答结果对象。 + */ + @GetMapping("/getRpColumns/{code}") + @Schema(description = "根据code查询所需的字段信息和搜索字段-基础版本") + @Override + public ResponseResult> getRpColumns(@PathVariable String code) { + return super.getRpColumns(code); + } + + /** + * 根据 id 查询具体数据。 + * + * @param dto 查询条件。 + * @param id 报表主键Id。 + * @param pageParam 分页参数。 + * @return 应答结果对象。 + */ + @PostMapping("/getData") + @Schema(description = "根据id查询具体数据接口-基础版本") + @Override + public ResponseResult> getData(@MyRequestBody JSONObject dto, + @MyRequestBody String id, + @MyRequestBody MyPageParam pageParam) { + return super.getData(dto, id, pageParam); + } + + /** + * 租户端绝对不开放:会直接用 jdbcTemplate 执行调用方传入的任意 SQL, + * 且 dbKey=easSql 时还会把 SQL 转发到外部 EAS 系统执行(任务清单 #8)。 + */ + @GetMapping("/parseSql") + @Schema(description = "租户端不开放") + @Override + public ResponseResult> parseSql(@RequestParam(name = "sql") String sql, + @RequestParam(name = "dbKey", required = false) String dbKey) { + throw notOpen(); + } +} diff --git a/common/common-tenant-online/src/main/java/apelet/common/tenant/online/controller/TenantOnlFormHeadController.java b/common/common-tenant-online/src/main/java/apelet/common/tenant/online/controller/TenantOnlFormHeadController.java new file mode 100644 index 0000000..a31d01b --- /dev/null +++ b/common/common-tenant-online/src/main/java/apelet/common/tenant/online/controller/TenantOnlFormHeadController.java @@ -0,0 +1,223 @@ +package apelet.common.tenant.online.controller; + +import apelet.common.core.annotation.MyRequestBody; +import apelet.common.core.exception.DataNotFoundException; +import apelet.common.core.object.MyOrderParam; +import apelet.common.core.object.MyPageParam; +import apelet.common.core.object.ResponseResult; +import apelet.common.generator.controller.OnlFormHeadController; +import apelet.common.generator.dto.OnlFormCodeDto; +import apelet.common.generator.dto.OnlFormHeadDto; +import apelet.common.tenant.annotation.SwitchTenantCommonDatasource; +import com.alibaba.fastjson.JSONObject; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletResponse; + +/** + * 租户端表单元数据接口。 + * + *只开放表单元数据的日常维护(查询、保存、删除、代码生成弹窗、元数据选择), + * 不开放会执行 DDL、生成源码、读取服务器目录、同步外部 EAS 等管理端能力。
+ * + *注意:Spring MVC 会把父类带 {@code @RequestMapping} 的方法一并注册到子类路径下, + * 仅“不覆写”并不能屏蔽接口。因此这里除了覆写白名单方法外,还显式覆写了所有 + * 黑名单方法并统一抛出 {@link DataNotFoundException},由全局异常处理器返回 404。
+ * + * @author apelet + */ +@SwitchTenantCommonDatasource +@Tag(name = "租户表单元数据接口") +@Slf4j +@RestController +@RequestMapping("${common-online.urlPrefix}/tenantOnlFormHead") +public class TenantOnlFormHeadController extends OnlFormHeadController { + + /** + * 租户端未开放的接口统一按 404 返回,避免通过状态码区分“不存在”和“无权限”。 + * + * @return 404 业务异常。 + */ + private DataNotFoundException notOpen() { + return new DataNotFoundException("租户端不开放该接口"); + } + + /** + * 分页查询。租户维度由父类按当前登录租户过滤(PRD FR-4.15)。 + * + * @param dto 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象。 + */ + @Schema(description = "分页查询") + @PostMapping("/page") + @Override + public ResponseResult> page(@MyRequestBody OnlFormHeadDto dto, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + return super.page(dto, orderParam, pageParam); + } + + /** + * 查询主数据和分录数据。 + * + * @param id 主数据主键Id。 + * @return 应答结果对象。 + */ + @Schema(description = "查询主数据和分录数据") + @GetMapping("/listByHeadId") + @Override + public ResponseResult> listByHeadId(@RequestParam Long id) { + return super.listByHeadId(id); + } + + /** + * 添加主数据和分录数据。 + * + * @param dto 新增对象。 + * @return 应答结果对象。 + */ + @Schema(description = "添加主数据和分录数据") + @PostMapping("/addAll") + @Override + public ResponseResult> addAll(@MyRequestBody OnlFormHeadDto dto) { + return super.addAll(dto); + } + + /** + * 编辑主数据和分录数据。 + * + * @param dto 更新对象。 + * @return 应答结果对象。 + */ + @Schema(description = "编辑主数据和分录数据") + @PostMapping("/editAll") + @Override + public ResponseResult> editAll(@MyRequestBody OnlFormHeadDto dto) { + return super.editAll(dto); + } + + /** + * 删除主数据和分录数据。 + * + * @param id 主数据主键Id。 + * @return 应答结果对象。 + */ + @Schema(description = "删除") + @PostMapping("/removeAllById") + @Override + public ResponseResult> removeAllById(@MyRequestBody Long id) { + return super.removeAllById(id); + } + + /** + * 代码生成按钮弹出信息。 + * + * @param id 主数据主键Id。 + * @return 应答结果对象。 + */ + @Schema(description = "代码生成按钮弹出信息") + @GetMapping("/tableInfo") + @Override + public ResponseResult> tableInfo(@RequestParam Long id) { + return super.tableInfo(id); + } + + /** + * 查询对象的所有元数据。 + * + * @param name 查询对象name。 + * @param type 是否查询字段关联的元数据 1:是 0:否。 + * @param isChild 是否查询子表 1:是 0:否。 + * @return 应答结果对象。 + */ + @Schema(description = "查询对象的所有元数据") + @GetMapping("/selectOnlFrom") + @Override + public ResponseResult> selectOnlFrom(@RequestParam String name, @RequestParam String type, + @RequestParam(required = false) Integer isChild) { + return super.selectOnlFrom(name, type, isChild); + } + + /** + * 租户端不开放:会执行 DDL。 + */ + @Schema(description = "租户端不开放") + @GetMapping("/syncDB") + @Override + public ResponseResult> syncDB(@RequestParam("id") Long id, @RequestParam("type") Long type) { + throw notOpen(); + } + + /** + * 租户端不开放:会生成源码。 + */ + @Schema(description = "租户端不开放") + @PostMapping("/generate") + @Override + public ResponseResult> generate(@RequestBody OnlFormCodeDto onlFormCodeDto) { + throw notOpen(); + } + + /** + * 租户端不开放:会读取服务器上的生成文件。 + */ + @Schema(description = "租户端不开放") + @PostMapping("/download") + @Override + public void download(@RequestBody JSONObject jsonObject, HttpServletResponse response) { + throw notOpen(); + } + + /** + * 租户端不开放:返回管理端固定字段定义。 + */ + @Schema(description = "租户端不开放") + @GetMapping("/defaultData") + @Override + public ResponseResult> defaultData(@RequestParam(required = false) String type, + @RequestParam(required = false) String treeType, + @RequestParam(required = false) String metaType, + @RequestParam(required = false) String metaTable) { + throw notOpen(); + } + + /** + * 租户端不开放:管理端表名判重。 + */ + @Schema(description = "租户端不开放") + @GetMapping("/checkTableName") + @Override + public ResponseResult> checkTableName(@RequestParam String tableName) { + throw notOpen(); + } + + /** + * 租户端不开放:会读取服务器目录。 + */ + @Schema(description = "租户端不开放") + @GetMapping("/getDir") + @Override + public ResponseResult> getDir(@RequestParam(required = false) String dir) { + throw notOpen(); + } + + /** + * 租户端不开放:会同步外部 EAS 元数据。 + */ + @Schema(description = "租户端不开放") + @GetMapping("/onlFormSync") + @Override + public ResponseResult> onlFormSync(@RequestParam("billType") String billType, @RequestParam("id") Long id) { + throw notOpen(); + } +}