This is an automated email from the ASF dual-hosted git repository.
Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new 2f99c24ece fix(admin): paginate API listings and batch tag lookups
(#7235)
2f99c24ece is described below
commit 2f99c24ece8cb737ee58dfd1d469a93e15acd282
Author: Liming Deng <[email protected]>
AuthorDate: Wed Sep 30 11:46:11 2026 +0800
fix(admin): paginate API listings and batch tag lookups (#7235)
---
.../shenyu/admin/mapper/TagRelationMapper.java | 8 +++++
.../shenyu/admin/service/impl/ApiServiceImpl.java | 30 ++++++++++-------
.../src/main/resources/mappers/api-sqlmap.xml | 3 +-
.../main/resources/mappers/tag-relation-sqlmap.xml | 14 ++++++++
.../apache/shenyu/admin/mapper/ApiMapperTest.java | 38 ++++++++++++++++++++++
.../shenyu/admin/mapper/TagRelationMapperTest.java | 14 ++++++++
.../shenyu/admin/service/ApiServiceTest.java | 24 ++++++++++++++
7 files changed, 118 insertions(+), 13 deletions(-)
diff --git
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/TagRelationMapper.java
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/TagRelationMapper.java
index 67622e601e..d453173b6e 100644
---
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/TagRelationMapper.java
+++
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/TagRelationMapper.java
@@ -96,6 +96,14 @@ public interface TagRelationMapper extends ExistProvider {
*/
List<TagRelationDO> selectByQuery(TagRelationQuery tagRelationQuery);
+ /**
+ * Select tag relations for one API page.
+ *
+ * @param apiIds API identifiers
+ * @return matching relations
+ */
+ List<TagRelationDO> selectByApiIds(@Param("apiIds") List<String> apiIds);
+
/**
* update record.
*
diff --git
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ApiServiceImpl.java
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ApiServiceImpl.java
index 8ac6ae4f74..43e02883c5 100644
---
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ApiServiceImpl.java
+++
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ApiServiceImpl.java
@@ -23,6 +23,7 @@ import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.Objects;
import
org.apache.shenyu.admin.disruptor.RegisterClientServerDisruptorPublisher;
+import org.apache.shenyu.admin.aspect.annotation.Pageable;
import org.apache.shenyu.admin.mapper.ApiMapper;
import org.apache.shenyu.admin.mapper.TagMapper;
import org.apache.shenyu.admin.mapper.TagRelationMapper;
@@ -59,6 +60,8 @@ import
org.springframework.transaction.annotation.Transactional;
import java.sql.Timestamp;
import java.util.List;
+import java.util.Map;
+import java.util.Collections;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -265,18 +268,23 @@ public class ApiServiceImpl implements ApiService {
}
@Override
+ @Pageable
public CommonPager<ApiVO> listByPage(final ApiQuery apiQuery) {
- return PageResultUtils.result(apiQuery.getPageParameter(), () ->
apiMapper.selectByQuery(apiQuery)
- .stream().map(item -> {
- List<TagRelationDO> tagRelations =
tagRelationMapper.selectByQuery(TagRelationQuery.builder().apiId(item.getId()).build());
- List<String> tagIds =
tagRelations.stream().map(TagRelationDO::getTagId).collect(Collectors.toList());
- List<TagVO> tagVOS = Lists.newArrayList();
- if (CollectionUtils.isNotEmpty(tagIds)) {
- List<TagDO> tagDOS = tagMapper.selectByIds(tagIds);
- tagVOS =
tagDOS.stream().map(TagVO::buildTagVO).collect(Collectors.toList());
- }
- return ApiVO.buildApiVO(item, tagVOS);
- }).collect(Collectors.toList()));
+ List<ApiDO> apis = apiMapper.selectByQuery(apiQuery);
+ if (apis.isEmpty()) {
+ return PageResultUtils.result(apiQuery.getPageParameter(),
Collections::emptyList);
+ }
+ List<String> apiIds =
apis.stream().map(ApiDO::getId).collect(Collectors.toList());
+ List<TagRelationDO> relations =
tagRelationMapper.selectByApiIds(apiIds);
+ List<String> tagIds =
relations.stream().map(TagRelationDO::getTagId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
+ Map<String, TagVO> tags = tagIds.isEmpty() ? Collections.emptyMap() :
tagMapper.selectByIds(tagIds).stream()
+ .collect(Collectors.toMap(TagDO::getId, TagVO::buildTagVO));
+ Map<String, List<TagRelationDO>> relationsByApi =
relations.stream().collect(Collectors.groupingBy(TagRelationDO::getApiId));
+ return PageResultUtils.result(apiQuery.getPageParameter(), () ->
apis.stream().map(api -> {
+ List<TagVO> apiTags = relationsByApi.getOrDefault(api.getId(),
Collections.emptyList()).stream()
+
.map(TagRelationDO::getTagId).distinct().map(tags::get).filter(Objects::nonNull).collect(Collectors.toList());
+ return ApiVO.buildApiVO(api, apiTags);
+ }).collect(Collectors.toList()));
}
@Override
diff --git a/shenyu-admin/src/main/resources/mappers/api-sqlmap.xml
b/shenyu-admin/src/main/resources/mappers/api-sqlmap.xml
index 2192ffefe1..f011b0c9b9 100644
--- a/shenyu-admin/src/main/resources/mappers/api-sqlmap.xml
+++ b/shenyu-admin/src/main/resources/mappers/api-sqlmap.xml
@@ -280,7 +280,6 @@
api.api_owner,
api.api_desc,
api.api_source,
- api.document,
api.document_md5,
api.date_created,
api.date_updated
@@ -297,7 +296,7 @@
and state = #{state, jdbcType=TINYINT}
</if>
</where>
- order by api.date_created desc
+ order by api.date_created desc, api.id desc
</select>
<select id="selectByIds" parameterType="java.util.List"
resultMap="BaseResultMap">
diff --git a/shenyu-admin/src/main/resources/mappers/tag-relation-sqlmap.xml
b/shenyu-admin/src/main/resources/mappers/tag-relation-sqlmap.xml
index 7dc16797ef..5e63b730ac 100644
--- a/shenyu-admin/src/main/resources/mappers/tag-relation-sqlmap.xml
+++ b/shenyu-admin/src/main/resources/mappers/tag-relation-sqlmap.xml
@@ -193,4 +193,18 @@
#{id, jdbcType=VARCHAR}
</foreach>
</delete>
+ <select id="selectByApiIds" resultMap="BaseResultMap">
+ SELECT <include refid="Base_Column_List"/>
+ FROM tag_relation
+ WHERE
+ <choose>
+ <when test="apiIds != null and apiIds.size() > 0">
+ api_id IN
+ <foreach collection="apiIds" item="apiId" open="("
separator="," close=")">
+ #{apiId, jdbcType=VARCHAR}
+ </foreach>
+ </when>
+ <otherwise>1 = 0</otherwise>
+ </choose>
+ </select>
</mapper>
diff --git
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/ApiMapperTest.java
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/ApiMapperTest.java
index 232ef66eaa..cd5a1dda76 100644
---
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/ApiMapperTest.java
+++
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/ApiMapperTest.java
@@ -21,6 +21,9 @@ import org.apache.shenyu.admin.AbstractSpringIntegrationTest;
import org.apache.shenyu.admin.model.entity.ApiDO;
import org.apache.shenyu.admin.model.page.PageParameter;
import org.apache.shenyu.admin.model.query.ApiQuery;
+import org.apache.shenyu.admin.model.page.CommonPager;
+import org.apache.shenyu.admin.model.vo.ApiVO;
+import org.apache.shenyu.admin.service.ApiService;
import org.apache.shenyu.common.utils.UUIDUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -34,6 +37,8 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.greaterThan;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
/**
* Test cases for ApiMapper.
@@ -43,6 +48,9 @@ public final class ApiMapperTest extends
AbstractSpringIntegrationTest {
@Resource
private ApiMapper apiMapper;
+ @Resource
+ private ApiService apiService;
+
private final ApiDO apiDO = buildApiDO();
@BeforeEach
@@ -51,6 +59,36 @@ public final class ApiMapperTest extends
AbstractSpringIntegrationTest {
assertEquals(1, count);
}
+ @Test
+ public void testApiListPaginationExcludesDocument() {
+ ApiDO first = buildApiDO();
+ String path = "/pagination/" + first.getId();
+ first.setApiPath(path);
+ first.setDocument("large document");
+ ApiDO second = buildApiDO();
+ second.setApiPath(path);
+ apiMapper.insert(first);
+ apiMapper.insert(second);
+ try {
+ ApiQuery query = new ApiQuery();
+ query.setApiPath(path);
+ query.setPageParameter(new PageParameter(1, 1));
+ CommonPager<ApiVO> pageOne = apiService.listByPage(query);
+ query.setPageParameter(new PageParameter(2, 1));
+ CommonPager<ApiVO> pageTwo = apiService.listByPage(query);
+ assertEquals(2, pageOne.getPage().getTotalCount());
+ assertEquals(1, pageOne.getDataList().size());
+ assertEquals(1, pageTwo.getDataList().size());
+ assertNotEquals(pageOne.getDataList().get(0).getId(),
pageTwo.getDataList().get(0).getId());
+ assertNull(pageOne.getDataList().get(0).getDocument());
+ assertNull(pageTwo.getDataList().get(0).getDocument());
+ assertEquals("large document",
apiMapper.selectByPrimaryKey(first.getId()).getDocument());
+ } finally {
+ apiMapper.deleteByPrimaryKey(first.getId());
+ apiMapper.deleteByPrimaryKey(second.getId());
+ }
+ }
+
@Test
public void testInsert() {
ApiDO newApiDO = buildApiDO();
diff --git
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/TagRelationMapperTest.java
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/TagRelationMapperTest.java
index 33a203137d..7b8f9895ce 100644
---
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/TagRelationMapperTest.java
+++
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/TagRelationMapperTest.java
@@ -20,6 +20,7 @@ package org.apache.shenyu.admin.mapper;
import com.google.common.collect.Lists;
import java.sql.Timestamp;
import java.util.List;
+import java.util.Collections;
import java.util.Objects;
import jakarta.annotation.Resource;
import org.apache.shenyu.admin.AbstractSpringIntegrationTest;
@@ -38,6 +39,19 @@ public class TagRelationMapperTest extends
AbstractSpringIntegrationTest {
@Resource
private TagRelationMapper tagRelationMapper;
+ @Test
+ public void testSelectByApiIds() {
+ TagRelationDO record = buildTagRelationDO();
+ record.setApiId(UUIDUtils.getInstance().generateShortUuid());
+ tagRelationMapper.insert(record);
+ try {
+ assertEquals(record.getId(),
tagRelationMapper.selectByApiIds(Collections.singletonList(record.getApiId())).get(0).getId());
+ assertEquals(0,
tagRelationMapper.selectByApiIds(Collections.emptyList()).size());
+ } finally {
+ tagRelationMapper.deleteByPrimaryKey(record.getId());
+ }
+ }
+
@Test
public void testInsert() {
TagRelationDO record = buildTagRelationDO();
diff --git
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ApiServiceTest.java
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ApiServiceTest.java
index 0b69cbf3a1..1a6cc3c3b1 100644
---
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ApiServiceTest.java
+++
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ApiServiceTest.java
@@ -25,6 +25,8 @@ import org.apache.shenyu.admin.model.dto.ApiDTO;
import org.apache.shenyu.admin.model.entity.ApiDO;
import org.apache.shenyu.admin.model.entity.MetaDataDO;
import org.apache.shenyu.admin.model.entity.SelectorDO;
+import org.apache.shenyu.admin.model.entity.TagDO;
+import org.apache.shenyu.admin.model.entity.TagRelationDO;
import org.apache.shenyu.admin.model.page.CommonPager;
import org.apache.shenyu.admin.model.page.PageParameter;
import org.apache.shenyu.admin.model.query.ApiQuery;
@@ -45,6 +47,7 @@ import org.mockito.quality.Strictness;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Collections;
+import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@@ -236,6 +239,27 @@ public final class ApiServiceTest {
given(this.apiMapper.selectByQuery(apiQuery)).willReturn(apiDOList);
final CommonPager<ApiVO> apiDOCommonPager =
this.apiService.listByPage(apiQuery);
assertEquals(apiDOCommonPager.getDataList().size(), apiDOList.size());
+
verify(tagRelationMapper).selectByApiIds(apiDOList.stream().map(ApiDO::getId).collect(Collectors.toList()));
+ verify(tagRelationMapper, never()).selectByQuery(any());
+ verify(tagMapper, never()).selectByIds(any());
+ }
+
+ @Test
+ public void testListByPageBatchesTags() {
+ ApiQuery query = new ApiQuery(null, 0, "", new PageParameter());
+
given(apiMapper.selectByQuery(query)).willReturn(Arrays.asList(buildApiDO("first"),
buildApiDO("second")));
+ given(tagRelationMapper.selectByApiIds(Arrays.asList("first",
"second"))).willReturn(Arrays.asList(
+ TagRelationDO.builder().apiId("first").tagId("tag").build(),
TagRelationDO.builder().apiId("second").tagId("tag").build()));
+ TagDO tag = new TagDO();
+ tag.setId("tag");
+ tag.setDateCreated(new Timestamp(0));
+ tag.setDateUpdated(new Timestamp(0));
+
given(tagMapper.selectByIds(Collections.singletonList("tag"))).willReturn(Collections.singletonList(tag));
+ List<ApiVO> result = apiService.listByPage(query).getDataList();
+ assertEquals("tag", result.get(0).getTags().get(0).getId());
+ assertEquals("tag", result.get(1).getTags().get(0).getId());
+ verify(tagMapper).selectByIds(Collections.singletonList("tag"));
+ verify(tagRelationMapper, never()).selectByQuery(any());
}
private ApiDO buildApiDO(final String id) {