From 100aaa62c3541940f6f8dda9a42fec1c7084d6ec Mon Sep 17 00:00:00 2001 From: zhaogd Date: Tue, 28 Jul 2026 11:15:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AA=92=E8=B5=84=E5=85=A8?= =?UTF-8?q?=E9=87=8F=E8=81=9A=E5=90=88=E6=8E=A5=E5=8F=A3=E5=B9=B6=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=A4=9A=E6=A0=8F=E7=9B=AE=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 /openapi/partner/media/list-all 接口,按一级栏目(如471电影)聚合其下所有二级栏目内容一次返回,解决第三方逐个栏目频繁调用后端的问题 - /list 接口支持 catalogid 逗号分隔传多个,单栏目走橘视厅原生分页,多栏目聚合后本地分页 - JetsenMediaClient 抽取 fetchByCatalogIds 方法,fetchAllByParentCatalog 复用,pagesize=5000 一次拉取减少请求数 --- .../media/client/JetsenMediaClient.java | 46 ++++++++ .../controller/OpenApiMediaController.java | 106 +++++++++++++++--- 2 files changed, 137 insertions(+), 15 deletions(-) diff --git a/src/main/java/io/as/modules/media/client/JetsenMediaClient.java b/src/main/java/io/as/modules/media/client/JetsenMediaClient.java index beba651..b56ad19 100644 --- a/src/main/java/io/as/modules/media/client/JetsenMediaClient.java +++ b/src/main/java/io/as/modules/media/client/JetsenMediaClient.java @@ -150,6 +150,52 @@ public class JetsenMediaClient { return tree; } + /** + * 按多个栏目id聚合拉取内容(各栏目全量拉取后合并,不去重) + * @param catalogids 栏目id列表 + * @return 合并后的全部内容列表 + */ + public List fetchByCatalogIds(List catalogids) { + List all = new ArrayList<>(); + for (String catalogid : catalogids) { + int page = 1; + int fetched = 0; + while (true) { + JSONObject resp = getContentList(catalogid, page, 5000); + List items = extractList(resp); + all.addAll(items); + fetched += items.size(); + Integer totalPage = resp.getInteger("pagetotal"); + if (totalPage == null || page >= totalPage || items.isEmpty()) { + break; + } + page++; + } + logger.info("栏目[{}]拉取完成, 本栏目{}条, 累计{}条", catalogid, fetched, all.size()); + } + return all; + } + + /** + * 按一级栏目全量拉取内容 + *

遍历一级栏目下所有二级子栏目,分页拉取全部内容并合并返回(不去重,第三方自行处理)。

+ *

用于第三方一次性获取某一级栏目(如471电影)下的全部内容,避免逐个子栏目多次请求。

+ * + * @param parentCatalogid 一级栏目id(如 "471"=电影) + * @return 全部内容列表(各二级栏目合并,可能存在跨栏目重复) + */ + public List fetchAllByParentCatalog(String parentCatalogid) { + List subs = extractList(getTagsList(parentCatalogid)); + logger.info("全量拉取一级栏目[{}]下{}个二级栏目", parentCatalogid, subs.size()); + List subIds = new ArrayList<>(); + for (JSONObject sub : subs) { + subIds.add(String.valueOf(sub.get("id"))); + } + List all = fetchByCatalogIds(subIds); + logger.info("一级栏目[{}]全量拉取完成, 共{}条", parentCatalogid, all.size()); + return all; + } + /** 从橘视厅响应 result 字段提取为 List */ private List extractList(JSONObject resp) { List list = new ArrayList<>(); diff --git a/src/main/java/io/as/modules/openapi/controller/OpenApiMediaController.java b/src/main/java/io/as/modules/openapi/controller/OpenApiMediaController.java index 4d3201e..50c52eb 100644 --- a/src/main/java/io/as/modules/openapi/controller/OpenApiMediaController.java +++ b/src/main/java/io/as/modules/openapi/controller/OpenApiMediaController.java @@ -190,26 +190,39 @@ public class OpenApiMediaController { data.put("list", from < total ? all.subList(from, to) : new ArrayList<>()); data.put("totalCount", total); data.put("totalPage", (total + pagesize - 1) / pagesize); - } else if (catalogIds != null) { - // CATALOG级别:校验catalogid在授权范围内 - if (StringUtils.isBlank(catalogid) || !catalogIds.contains(catalogid)) { - logCall(req, "/list", "GET", 400, start); - return R.error("catalogid不在授权范围内,可用栏目: " + pkg.getCatalogIds()); - } - JSONObject resp = jetsenMediaClient.getContentList(catalogid, pageindex, pagesize); - data.put("list", extractList(resp)); - data.put("totalCount", resp.getIntValue("sizetotal")); - data.put("totalPage", resp.getIntValue("pagetotal")); } else { - // FULL级别:直接查 + // CATALOG / FULL 级别 if (StringUtils.isBlank(catalogid)) { logCall(req, "/list", "GET", 400, start); return R.error("catalogid不能为空"); } - JSONObject resp = jetsenMediaClient.getContentList(catalogid, pageindex, pagesize); - data.put("list", extractList(resp)); - data.put("totalCount", resp.getIntValue("sizetotal")); - data.put("totalPage", resp.getIntValue("pagetotal")); + // 解析 catalogid(支持逗号分隔多个) + List ids = parseCatalogIdList(catalogid); + // CATALOG级别:校验每个 catalogid 都在授权范围内 + if (catalogIds != null) { + for (String id : ids) { + if (!catalogIds.contains(id)) { + logCall(req, "/list", "GET", 400, start); + return R.error("catalogid[" + id + "]不在授权范围内,可用栏目: " + pkg.getCatalogIds()); + } + } + } + if (ids.size() == 1) { + // 单栏目:橘视厅分页 + JSONObject resp = jetsenMediaClient.getContentList(ids.get(0), pageindex, pagesize); + data.put("list", extractList(resp)); + data.put("totalCount", resp.getIntValue("sizetotal")); + data.put("totalPage", resp.getIntValue("pagetotal")); + } else { + // 多栏目:聚合全量 + 本地分页 + List all = jetsenMediaClient.fetchByCatalogIds(ids); + int total = all.size(); + int from = Math.max(0, (pageindex - 1) * pagesize); + int to = Math.min(from + pagesize, total); + data.put("list", from < total ? all.subList(from, to) : new ArrayList<>()); + data.put("totalCount", total); + data.put("totalPage", (total + pagesize - 1) / pagesize); + } } data.put("currPage", pageindex); data.put("pageSize", pagesize); @@ -217,6 +230,69 @@ public class OpenApiMediaController { return R.dataSuccess(data); } + /** + * 全量内容列表(按一级栏目聚合) + *

一次请求返回某一级栏目(如471电影)下所有二级栏目去重后的全部内容。

+ *

第三方低频调用(建议按天),避免逐个 catalogid 多次请求后端。

+ *

三级授权:CONTENT(按contentcode过滤) > CATALOG(按授权栏目过滤) > FULL(全量)

+ */ + @ApiOperation("全量内容列表(按一级栏目聚合)") + @GetMapping("/list-all") + public R listAll(@RequestParam(defaultValue = "471") String parentCatalogid, + HttpServletRequest req) { + long start = System.currentTimeMillis(); + String partnerId = partnerIdFrom(req); + ContentPackageEntity pkg = contentPackageService.getByPartnerId(partnerId); + Set contentCodes = parseContentCodes(pkg); + Set catalogIds = parseCatalogIds(pkg); + + List all = jetsenMediaClient.fetchAllByParentCatalog(parentCatalogid); + + if (contentCodes != null) { + // CONTENT级别:只保留授权contentcode + all = new ArrayList<>(all); + all.removeIf(item -> !contentCodes.contains(item.getString("contentcode"))); + } else if (catalogIds != null) { + // CATALOG级别:只保留属于授权二级栏目的内容(item的catalogid为逗号分隔多栏目串) + all = new ArrayList<>(all); + all.removeIf(item -> !catalogMatch(item, catalogIds)); + } + // FULL: 返回全量 + + Map data = new HashMap<>(); + data.put("list", all); + data.put("totalCount", all.size()); + data.put("parentCatalogid", parentCatalogid); + logCall(req, "/list-all", "GET", 0, start); + return R.dataSuccess(data); + } + + /** 判断内容的 catalogid 逗号串是否命中任一授权栏目 */ + private boolean catalogMatch(JSONObject item, Set catalogIds) { + String cats = item.getString("catalogid"); + if (cats == null) { + return false; + } + for (String c : cats.split(",")) { + if (catalogIds.contains(c.trim())) { + return true; + } + } + return false; + } + + /** 解析 catalogid 参数(支持逗号分隔多个) */ + private List parseCatalogIdList(String catalogid) { + List ids = new ArrayList<>(); + for (String s : catalogid.split(",")) { + String t = s.trim(); + if (!t.isEmpty()) { + ids.add(t); + } + } + return ids; + } + /** 搜索(按授权过滤) */ @ApiOperation("搜索") @GetMapping("/search")