fix: bound dashboard monitoring queries
This commit is contained in:
@@ -19,7 +19,6 @@ import org.springframework.web.bind.annotation.GetMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -55,8 +54,8 @@ public class IndexController extends BaseController {
|
|||||||
@Anonymous
|
@Anonymous
|
||||||
@GetMapping("/bill/status")
|
@GetMapping("/bill/status")
|
||||||
public AjaxResult getBillStatusCount() {
|
public AjaxResult getBillStatusCount() {
|
||||||
// Temporarily bypass the three unbounded bill queries while diagnosing dashboard latency.
|
List<BillStatusCount> list = billStatusCountService.selectAllBillStatusCount(new BaseEntity());
|
||||||
return success(Collections.emptyList());
|
return success(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -10,23 +10,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public interface BillStatusCountMapper {
|
public interface BillStatusCountMapper {
|
||||||
/**
|
/**
|
||||||
* 查询入库单据状态统计
|
* 查询最近的入库、出库和盘点单据。
|
||||||
*
|
|
||||||
* @return 入库单据状态统计列表
|
|
||||||
*/
|
*/
|
||||||
public List<BillStatusCount> selectStockinStatusCount(BaseEntity baseEntity);
|
List<BillStatusCount> selectRecentBillStatus(BaseEntity baseEntity);
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询出库单据状态统计
|
|
||||||
*
|
|
||||||
* @return 出库单据状态统计列表
|
|
||||||
*/
|
|
||||||
public List<BillStatusCount> selectStockoutStatusCount(BaseEntity baseEntity);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询盘点单据状态统计
|
|
||||||
*
|
|
||||||
* @return 盘点单据状态统计列表
|
|
||||||
*/
|
|
||||||
public List<BillStatusCount> selectStockcheckStatusCount(BaseEntity baseEntity);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import com.ruoyi.index.service.IBillStatusCountService;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,29 +27,6 @@ public class BillStatusCountServiceImpl implements IBillStatusCountService {
|
|||||||
@DataScope
|
@DataScope
|
||||||
// @DataScope(warehouseAlias = "")
|
// @DataScope(warehouseAlias = "")
|
||||||
public List<BillStatusCount> selectAllBillStatusCount(BaseEntity baseEntity) {
|
public List<BillStatusCount> selectAllBillStatusCount(BaseEntity baseEntity) {
|
||||||
List<BillStatusCount> resultList = new ArrayList<>();
|
return billStatusCountMapper.selectRecentBillStatus(baseEntity);
|
||||||
|
|
||||||
// 查询入库单据状态统计
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ public class RequestLogController extends BaseController
|
|||||||
public AjaxResult getMethod()
|
public AjaxResult getMethod()
|
||||||
{
|
{
|
||||||
List<String> strings=requestLogService.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()
|
public AjaxResult getSource()
|
||||||
{
|
{
|
||||||
List<String> strings=requestLogService.getSource();
|
List<String> strings=requestLogService.getSource();
|
||||||
return AjaxResult.success(requestLogService.getSource());
|
return AjaxResult.success(strings);
|
||||||
}
|
}
|
||||||
// 获取目标系统
|
// 获取目标系统
|
||||||
@GetMapping("/getTarget")
|
@GetMapping("/getTarget")
|
||||||
public AjaxResult getTarget()
|
public AjaxResult getTarget()
|
||||||
{
|
{
|
||||||
List<String> strings=requestLogService.getTarget();
|
List<String> strings=requestLogService.getTarget();
|
||||||
return AjaxResult.success(requestLogService.getTarget());
|
return AjaxResult.success(strings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,25 +10,37 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="type" column="type"/>
|
<result property="type" column="type"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<select id="selectStockinStatusCount" resultMap="BillStatusCountResult">
|
<select id="selectRecentBillStatus" parameterType="BaseEntity" resultMap="BillStatusCountResult">
|
||||||
select stockin_id as id, status, '1' as type
|
select top (30) id, status, type
|
||||||
from in_stockin
|
from (
|
||||||
where status in ('1', '2', '3')
|
select id, status, type, create_date
|
||||||
${params.warehouseDataScope}
|
from (
|
||||||
</select>
|
select top (30) stockin_id as id, status, '1' as type, create_date
|
||||||
|
from in_stockin
|
||||||
<select id="selectStockoutStatusCount" resultMap="BillStatusCountResult">
|
where status in ('1', '2', '3')
|
||||||
select stockout_id as id, status, '2' as type
|
${params.warehouseDataScope}
|
||||||
from out_stockout
|
order by create_date desc, stockin_id desc
|
||||||
where status in ('1', '2', '3')
|
) recent_stockin
|
||||||
${params.warehouseDataScope}
|
union all
|
||||||
</select>
|
select id, status, type, create_date
|
||||||
|
from (
|
||||||
<select id="selectStockcheckStatusCount" resultMap="BillStatusCountResult">
|
select top (30) stockout_id as id, status, '2' as type, create_date
|
||||||
select stock_check_id as id, status, '3' as type
|
from out_stockout
|
||||||
from check_stockin
|
where status in ('1', '2', '3')
|
||||||
where status in ('1', '2', '3')
|
${params.warehouseDataScope}
|
||||||
${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>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -27,7 +27,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="selectRequestLogList" parameterType="RequestLog" resultMap="RequestLogResult">
|
<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>
|
<where>
|
||||||
<if test="requestTime != null and requestTime != ''"> and request_time like concat('%', #{requestTime}, '%')</if>
|
<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>
|
<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="duration != null and duration != ''"> and duration like concat('%', #{duration}, '%')</if>
|
||||||
<if test="isSuccessful != null and isSuccessful != ''"> and Is_successful like concat('%', #{isSuccessful}, '%')</if>
|
<if test="isSuccessful != null and isSuccessful != ''"> and Is_successful like concat('%', #{isSuccessful}, '%')</if>
|
||||||
</where>
|
</where>
|
||||||
|
order by request_id desc
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectRequestLogByRequestId" parameterType="Long" resultMap="RequestLogResult">
|
<select id="selectRequestLogByRequestId" parameterType="Long" resultMap="RequestLogResult">
|
||||||
@@ -113,14 +123,35 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
<select id="getMethod" resultType="string">
|
<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>
|
||||||
|
|
||||||
<select id="getSource" resultType="string">
|
<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>
|
||||||
<select id="getTarget" resultType="string">
|
<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>
|
</select>
|
||||||
|
|
||||||
<delete id="deleteRequestLogByRequestIds" parameterType="String">
|
<delete id="deleteRequestLogByRequestIds" parameterType="String">
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user