fix: bound dashboard monitoring queries

This commit is contained in:
zgw
2026-09-04 13:30:45 +08:00
parent 731c140d24
commit 58c7fff4a9
7 changed files with 146 additions and 73 deletions

View File

@@ -19,7 +19,6 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -55,8 +54,8 @@ public class IndexController extends BaseController {
@Anonymous
@GetMapping("/bill/status")
public AjaxResult getBillStatusCount() {
// Temporarily bypass the three unbounded bill queries while diagnosing dashboard latency.
return success(Collections.emptyList());
List<BillStatusCount> list = billStatusCountService.selectAllBillStatusCount(new BaseEntity());
return success(list);
}
/**

View File

@@ -10,23 +10,7 @@ import java.util.List;
*/
public interface BillStatusCountMapper {
/**
* 查询入库单据状态统计
*
* @return 入库单据状态统计列表
* 查询最近的入库、出库和盘点单据。
*/
public List<BillStatusCount> selectStockinStatusCount(BaseEntity baseEntity);
/**
* 查询出库单据状态统计
*
* @return 出库单据状态统计列表
*/
public List<BillStatusCount> selectStockoutStatusCount(BaseEntity baseEntity);
/**
* 查询盘点单据状态统计
*
* @return 盘点单据状态统计列表
*/
public List<BillStatusCount> selectStockcheckStatusCount(BaseEntity baseEntity);
List<BillStatusCount> selectRecentBillStatus(BaseEntity baseEntity);
}

View File

@@ -8,7 +8,6 @@ import com.ruoyi.index.service.IBillStatusCountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
@@ -28,29 +27,6 @@ public class BillStatusCountServiceImpl implements IBillStatusCountService {
@DataScope
// @DataScope(warehouseAlias = "")
public List<BillStatusCount> selectAllBillStatusCount(BaseEntity baseEntity) {
List<BillStatusCount> resultList = new ArrayList<>();
// 查询入库单据状态统计
List<BillStatusCount> stockinList = billStatusCountMapper.selectStockinStatusCount(baseEntity);
if (stockinList != null) {
resultList.addAll(stockinList);
}
// 查询出库单据状态统计
List<BillStatusCount> stockoutList = billStatusCountMapper.selectStockoutStatusCount(baseEntity);
if (stockoutList != null) {
resultList.addAll(stockoutList);
}
// 查询盘点单据状态统计
List<BillStatusCount> stockcheckList = billStatusCountMapper.selectStockcheckStatusCount(baseEntity);
if (stockcheckList != null) {
resultList.addAll(stockcheckList);
}
// 按照status降序排序(3、2、1)
resultList.sort((a, b) -> b.getStatus().compareTo(a.getStatus()));
return resultList;
return billStatusCountMapper.selectRecentBillStatus(baseEntity);
}
}

View File

@@ -93,7 +93,7 @@ public class RequestLogController extends BaseController
public AjaxResult getMethod()
{
List<String> strings=requestLogService.getMethod();
return AjaxResult.success(requestLogService.getMethod());
return AjaxResult.success(strings);
}
// 获取原系统
@@ -101,14 +101,14 @@ public class RequestLogController extends BaseController
public AjaxResult getSource()
{
List<String> strings=requestLogService.getSource();
return AjaxResult.success(requestLogService.getSource());
return AjaxResult.success(strings);
}
// 获取目标系统
@GetMapping("/getTarget")
public AjaxResult getTarget()
{
List<String> strings=requestLogService.getTarget();
return AjaxResult.success(requestLogService.getTarget());
return AjaxResult.success(strings);
}

View File

@@ -10,25 +10,37 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="type" column="type"/>
</resultMap>
<select id="selectStockinStatusCount" resultMap="BillStatusCountResult">
select stockin_id as id, status, '1' as type
from in_stockin
where status in ('1', '2', '3')
${params.warehouseDataScope}
<select id="selectRecentBillStatus" parameterType="BaseEntity" resultMap="BillStatusCountResult">
select top (30) id, status, type
from (
select id, status, type, create_date
from (
select top (30) stockin_id as id, status, '1' as type, create_date
from in_stockin
where status in ('1', '2', '3')
${params.warehouseDataScope}
order by create_date desc, stockin_id desc
) recent_stockin
union all
select id, status, type, create_date
from (
select top (30) stockout_id as id, status, '2' as type, create_date
from out_stockout
where status in ('1', '2', '3')
${params.warehouseDataScope}
order by create_date desc, stockout_id desc
) recent_stockout
union all
select id, status, type, create_date
from (
select top (30) stock_check_id as id, status, '3' as type, create_date
from check_stockin
where status in ('1', '2', '3')
${params.warehouseDataScope}
order by create_date desc, stock_check_id desc
) recent_stockcheck
) recent_bill
order by create_date desc, id desc
</select>
<select id="selectStockoutStatusCount" resultMap="BillStatusCountResult">
select stockout_id as id, status, '2' as type
from out_stockout
where status in ('1', '2', '3')
${params.warehouseDataScope}
</select>
<select id="selectStockcheckStatusCount" resultMap="BillStatusCountResult">
select stock_check_id as id, status, '3' as type
from check_stockin
where status in ('1', '2', '3')
${params.warehouseDataScope}
</select>
</mapper>
</mapper>

View File

@@ -27,7 +27,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</sql>
<select id="selectRequestLogList" parameterType="RequestLog" resultMap="RequestLogResult">
<include refid="selectRequestLogVo"/>
select log.request_id, log.request_time, log.source_system, log.target_system, log.endpoint,
log.request_url, log.request_method, log.request_headers, log.request_body,
log.response_time, log.response_body, log.response_status, log.error_details,
log.duration, log.Is_successful
from (
select top (10000) request_id as recent_request_id
from request_log
order by request_id desc
) recent_log
inner join request_log log on log.request_id = recent_log.recent_request_id
<where>
<if test="requestTime != null and requestTime != ''"> and request_time like concat('%', #{requestTime}, '%')</if>
<if test="sourceSystem != null and sourceSystem != ''"> and source_system like concat('%', #{sourceSystem}, '%')</if>
@@ -44,6 +53,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="duration != null and duration != ''"> and duration like concat('%', #{duration}, '%')</if>
<if test="isSuccessful != null and isSuccessful != ''"> and Is_successful like concat('%', #{isSuccessful}, '%')</if>
</where>
order by request_id desc
</select>
<select id="selectRequestLogByRequestId" parameterType="Long" resultMap="RequestLogResult">
@@ -113,14 +123,35 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</delete>
<select id="getMethod" resultType="string">
select endpoint from request_log group by endpoint
select distinct endpoint
from (
select top (10000) request_id, endpoint
from request_log
order by request_id desc
) recent_log
where endpoint is not null
order by endpoint
</select>
<select id="getSource" resultType="string">
select source_system from request_log group by source_system
select distinct source_system
from (
select top (10000) request_id, source_system
from request_log
order by request_id desc
) recent_log
where source_system is not null
order by source_system
</select>
<select id="getTarget" resultType="string">
select target_system from request_log group by target_system
select distinct target_system
from (
select top (10000) request_id, target_system
from request_log
order by request_id desc
) recent_log
where target_system is not null
order by target_system
</select>
<delete id="deleteRequestLogByRequestIds" parameterType="String">

View File

@@ -0,0 +1,71 @@
package com.ruoyi.index;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Locale;
import static org.assertj.core.api.Assertions.assertThat;
class BoundedDashboardQueryTest {
private final Path root = projectRoot();
@Test
void dashboardBillEndpointUsesBoundedServiceQuery() throws IOException {
String controller = text("ruoyi-admin/src/main/java/com/ruoyi/index/controller/IndexController.java");
String mapper = normalized("ruoyi-admin/src/main/resources/mapper/index/BillStatusCountMapper.xml");
assertThat(controller).contains(
"billStatusCountService.selectAllBillStatusCount(new BaseEntity())",
"return success(list);");
assertThat(controller).doesNotContain("Collections.emptyList()");
assertThat(occurrences(mapper, "top (30)")).isEqualTo(4);
assertThat(mapper).contains("union all", "order by create_date desc, id desc");
assertThat(occurrences(mapper, "${params.warehousedatascope}")).isEqualTo(3);
}
@Test
void requestLogPageAndOptionsAreBoundedToRecentRows() throws IOException {
String mapper = normalized("ruoyi-admin/src/main/resources/mapper/requestInterface/RequestLogMapper.xml");
String controller = text("ruoyi-admin/src/main/java/com/ruoyi/log/controller/RequestLogController.java");
assertThat(occurrences(mapper, "top (10000)")).isEqualTo(4);
assertThat(mapper).contains("order by request_id desc");
assertThat(mapper).contains(
"inner join request_log log on log.request_id = recent_log.recent_request_id",
"select top (10000) request_id as recent_request_id");
assertThat(mapper).contains(
"select distinct endpoint",
"select distinct source_system",
"select distinct target_system");
assertThat(occurrences(controller, "requestLogService.getMethod()")).isEqualTo(1);
assertThat(occurrences(controller, "requestLogService.getSource()")).isEqualTo(1);
assertThat(occurrences(controller, "requestLogService.getTarget()")).isEqualTo(1);
}
private String text(String relativePath) throws IOException {
return Files.readString(root.resolve(relativePath), StandardCharsets.UTF_8);
}
private String normalized(String relativePath) throws IOException {
return text(relativePath).replaceAll("\\s+", " ").toLowerCase(Locale.ROOT);
}
private int occurrences(String value, String token) {
return (value.length() - value.replace(token, "").length()) / token.length();
}
private Path projectRoot() {
Path current = Path.of("").toAbsolutePath().normalize();
while (current != null && !Files.exists(current.resolve("ruoyi-admin/pom.xml"))) {
current = current.getParent();
}
if (current == null) {
throw new IllegalStateException("Could not locate project root");
}
return current;
}
}