fix: 优化到数统计接口逻辑

This commit is contained in:
tangwei 2026-05-13 15:54:04 +08:00
parent 3d48fb05b4
commit 85434d4d33
7 changed files with 177 additions and 155 deletions

View File

@ -1,44 +0,0 @@
package com.yfd.platform.config;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 将以 /prod-api/ 开头的请求转发到去掉前缀的真实后端接口路径
* 例如/prod-api/user/code -> /user/code
* 这样可以兼容前端生产环境仍使用 /prod-api 作为网关前缀的情况
*/
@WebFilter(urlPatterns = "/prod-api/*", filterName = "prodApiPrefixFilter")
public class ProdApiPrefixFilter implements Filter {
private static final String PREFIX = "/prod-api";
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
if (!(req instanceof HttpServletRequest) || !(res instanceof HttpServletResponse)) {
chain.doFilter(req, res);
return;
}
HttpServletRequest request = (HttpServletRequest) req;
String uri = request.getRequestURI();
// 仅拦截 /prod-api/* 的接口请求并进行内部 forward
if (uri.startsWith(PREFIX + "/")) {
String forwardUri = uri.substring(PREFIX.length());
RequestDispatcher dispatcher = request.getRequestDispatcher(forwardUri);
dispatcher.forward(req, res);
return;
}
chain.doFilter(req, res);
}
}

View File

@ -22,6 +22,10 @@ public class FishStatisticsVO implements Serializable {
private String stationNames; private String stationNames;
private String basinCode;
private String stationCode;
private String reportMonth; private String reportMonth;
private Date minStrdt; private Date minStrdt;

View File

@ -7,11 +7,11 @@ import java.util.List;
public interface FishStatisticsMapper { public interface FishStatisticsMapper {
List<FishStatisticsVO> queryStatistics(@Param("basinNames") List<String> basinNames, List<FishStatisticsVO> queryStatistics(@Param("basinCode") String basinCode,
@Param("stationNames") List<String> stationNames, @Param("stationCode") String stationCode,
@Param("startRow") int startRow, @Param("startRow") int startRow,
@Param("endRow") int endRow); @Param("endRow") int endRow);
int countStatistics(@Param("basinNames") List<String> basinNames, int countStatistics(@Param("basinCode") String basinCode,
@Param("stationNames") List<String> stationNames); @Param("stationCode") String stationCode);
} }

View File

@ -28,11 +28,11 @@ public class FishStatisticsServiceImpl implements IFishStatisticsService {
public Page<FishStatisticsVO> queryPage(DataSourceRequest dataSourceRequest) { public Page<FishStatisticsVO> queryPage(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest.toDevRequest(); DataSourceLoadOptionsBase loadOptions = dataSourceRequest.toDevRequest();
String basinNamesStr = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "basinNames"); String basinNamesStr = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "basinCode");
String stationNamesStr = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "stationNames"); String stationNamesStr = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "stationCode");
List<String> basinNames = parseFilterList(basinNamesStr); // List<String> basinNames = parseFilterList(basinNamesStr);
List<String> stationNames = parseFilterList(stationNamesStr); // List<String> stationNames = parseFilterList(stationNamesStr);
int take = dataSourceRequest.getTake(); int take = dataSourceRequest.getTake();
int skip = dataSourceRequest.getSkip(); int skip = dataSourceRequest.getSkip();
@ -44,9 +44,9 @@ public class FishStatisticsServiceImpl implements IFishStatisticsService {
int endRow = skip + take; int endRow = skip + take;
List<FishStatisticsVO> records = fishStatisticsMapper.queryStatistics( List<FishStatisticsVO> records = fishStatisticsMapper.queryStatistics(
basinNames, stationNames, startRow, endRow); basinNamesStr, stationNamesStr, startRow, endRow);
int total = fishStatisticsMapper.countStatistics(basinNames, stationNames); int total = fishStatisticsMapper.countStatistics(basinNamesStr, basinNamesStr);
Page<FishStatisticsVO> page = new Page<>(); Page<FishStatisticsVO> page = new Page<>();
page.setRecords(records); page.setRecords(records);

View File

@ -1,5 +1,8 @@
server: server:
port: 8093 port: 8093
tomcat:
connection-timeout: 300000
max-swallow-size: 500MB
spring: spring:
#应用名称 #应用名称
@ -112,6 +115,9 @@ spring:
multipart: multipart:
max-file-size: 300MB max-file-size: 300MB
max-request-size: 500MB max-request-size: 500MB
file-size-threshold: 1KB
location: /tmp/upload
resolve-lazily: true
logging: logging:
file: file:

View File

@ -1,8 +1,8 @@
server: server:
port: 8093 port: 8093
tomcat: tomcat:
max-http-form-post-size: 500MB # Tomcat 表单体大小限制 connection-timeout: 300000
connection-timeout: 120000 # 连接超时(毫秒),大文件上传需要更长 max-swallow-size: 500MB
spring: spring:
#应用名称 #应用名称
application: application:

View File

@ -10,6 +10,8 @@
<result column="CONTACT" property="contact"/> <result column="CONTACT" property="contact"/>
<result column="BASIN_NAMES" property="basinNames"/> <result column="BASIN_NAMES" property="basinNames"/>
<result column="STATION_NAMES" property="stationNames"/> <result column="STATION_NAMES" property="stationNames"/>
<result column="BASIN_CODE" property="basinCode"/>
<result column="STATION_CODE" property="stationCode"/>
<result column="REPORT_MONTH" property="reportMonth"/> <result column="REPORT_MONTH" property="reportMonth"/>
<result column="MIN_STRDT" property="minStrdt"/> <result column="MIN_STRDT" property="minStrdt"/>
<result column="MAX_ENDDT" property="maxEnddt"/> <result column="MAX_ENDDT" property="maxEnddt"/>
@ -17,117 +19,171 @@
</resultMap> </resultMap>
<sql id="statisticsQuery"> <sql id="statisticsQuery">
WITH user_scope_detail AS ( WITH
SELECT DISTINCT user_scope_detail AS (
su.ID AS USER_ID, SELECT DISTINCT
h.HBRVNM AS BASIN_NAME, su.ID AS USER_ID,
e.ENNM AS STATION_NAME e.STCD AS STATION_CODE,
FROM QGC_REFA.SYS_USER su h.HBRVCD AS BASIN_CODE,
JOIN QGC_REFA.SYS_USER_DATA_SCOPE sud h.HBRVNM AS BASIN_NAME,
ON su.ID = sud.USER_ID e.ENNM AS STATION_NAME
AND sud.STATUS = 1 FROM QGC_REFA.SYS_USER su
AND sud.ORG_TYPE = 'HBRVCD' JOIN QGC_REFA.SYS_USER_DATA_SCOPE sud
JOIN QGC_REFA.SD_HBRV_DIC h ON su.ID = sud.USER_ID
ON sud.ORG_ID = h.HBRVCD AND sud.STATUS = 1
AND h.ENABLED = 1 AND sud.ORG_TYPE = 'HBRVCD'
AND h.IS_DELETED = 0 JOIN QGC_REFA.SD_HBRV_DIC h
JOIN QGC_REFA.SD_ENGINFO_B_H e ON sud.ORG_ID = h.HBRVCD
ON e.HBRVCD = h.HBRVCD AND h.ENABLED = 1
AND e.USFL = 1 AND h.IS_DELETED = 0
WHERE su.STATUS = 1 JOIN QGC_REFA.SD_ENGINFO_B_H e
AND su.REG_STATUS IN ('PENDING', 'APPROVED', 'REJECTED') ON e.HBRVCD = h.HBRVCD
AND e.USFL = 1
WHERE su.STATUS = 1
AND su.REG_STATUS IN ('PENDING', 'APPROVED', 'REJECTED')
UNION UNION
SELECT DISTINCT SELECT DISTINCT
su.ID AS USER_ID, su.ID AS USER_ID,
h.HBRVNM AS BASIN_NAME, e.STCD AS STATION_CODE,
e.ENNM AS STATION_NAME h.HBRVCD AS BASIN_CODE,
FROM QGC_REFA.SYS_USER su h.HBRVNM AS BASIN_NAME,
JOIN QGC_REFA.SYS_USER_DATA_SCOPE sud e.ENNM AS STATION_NAME
ON su.ID = sud.USER_ID FROM QGC_REFA.SYS_USER su
AND sud.STATUS = 1 JOIN QGC_REFA.SYS_USER_DATA_SCOPE sud
AND sud.ORG_TYPE = 'STATION' ON su.ID = sud.USER_ID
JOIN QGC_REFA.SD_ENGINFO_B_H e AND sud.STATUS = 1
ON sud.ORG_ID = e.STCD AND sud.ORG_TYPE = 'STATION'
AND e.USFL = 1 JOIN QGC_REFA.SD_ENGINFO_B_H e
JOIN QGC_REFA.SD_HBRV_DIC h ON sud.ORG_ID = e.STCD
ON e.HBRVCD = h.HBRVCD AND e.USFL = 1
AND h.ENABLED = 1 JOIN QGC_REFA.SD_HBRV_DIC h
AND h.IS_DELETED = 0 ON e.HBRVCD = h.HBRVCD
WHERE su.STATUS = 1 AND h.ENABLED = 1
AND su.REG_STATUS IN ('PENDING', 'APPROVED', 'REJECTED') AND h.IS_DELETED = 0
WHERE su.STATUS = 1
AND su.REG_STATUS IN ('PENDING', 'APPROVED', 'REJECTED')
), ),
user_scope AS (
SELECT filtered_users AS (
USER_ID, SELECT DISTINCT USER_ID
RTRIM( FROM user_scope_detail
XMLAGG(XMLELEMENT(E, BASIN_NAME || ',') ORDER BY BASIN_NAME) <where>
.EXTRACT('//text()').GETCLOBVAL(), <if test="basinCode != null and basinCode != ''">
',' AND BASIN_CODE = #{basinCode}
) AS BASIN_NAMES, </if>
RTRIM( <if test="stationCode != null and stationCode != ''">
XMLAGG(XMLELEMENT(E, STATION_NAME || ',') ORDER BY STATION_NAME) AND STATION_CODE = #{stationCode}
.EXTRACT('//text()').GETCLOBVAL(), </if>
',' </where>
) AS STATION_NAMES
FROM user_scope_detail
GROUP BY USER_ID
), ),
fish_monthly AS (
SELECT distinct_basins AS (
CREATED_BY, SELECT DISTINCT USER_ID,BASIN_CODE, BASIN_NAME
TO_CHAR(STRDT, 'YYYY-MM') AS REPORT_MONTH, FROM user_scope_detail
MIN(STRDT) AS MIN_STRDT, WHERE USER_ID IN (SELECT USER_ID FROM filtered_users)
MAX(STRDT) AS MAX_ENDDT, ),
SUM(FCNT) AS TOTAL_FCNT
FROM QGC_REFA.FISH_DRAFT_DATA distinct_stations AS (
WHERE DELETED_FLAG = 0 AND STATUS IN ('PENDING','APPROVED') SELECT DISTINCT USER_ID, STATION_CODE, STATION_NAME
GROUP BY CREATED_BY, TO_CHAR(STRDT, 'YYYY-MM') FROM user_scope_detail
) WHERE USER_ID IN (SELECT USER_ID FROM filtered_users)
),
basin_agg AS (
SELECT SELECT
us.USER_ID, USER_ID,
su.REAL_NAME, RTRIM(
su.PHONE, XMLAGG(XMLELEMENT(E, BASIN_NAME || ',') ORDER BY BASIN_NAME)
su.NICKNAME || '/' || su.PHONE AS CONTACT, .EXTRACT('//text()').GETCLOBVAL(),
us.BASIN_NAMES, ','
us.STATION_NAMES, ) AS BASIN_NAMES,
fm.REPORT_MONTH, MIN(BASIN_CODE) AS MIN_BASIN_CODE -- 辅助排序字段VARCHAR2
fm.MIN_STRDT, FROM distinct_basins
fm.MAX_ENDDT, GROUP BY USER_ID
fm.TOTAL_FCNT ),
FROM user_scope us
station_agg AS (
SELECT
USER_ID,
RTRIM(
XMLAGG(XMLELEMENT(E, STATION_NAME || ',') ORDER BY STATION_NAME)
.EXTRACT('//text()').GETCLOBVAL(),
','
) AS STATION_NAMES,
MIN(STATION_CODE) AS MIN_STATION_CODE -- 辅助排序字段VARCHAR2
FROM distinct_stations
GROUP BY USER_ID
),
fish_monthly AS (
SELECT
CREATED_BY,
TO_CHAR(STRDT, 'YYYY-MM') AS REPORT_MONTH,
MIN(STRDT) AS MIN_STRDT,
MAX(STRDT) AS MAX_ENDDT,
SUM(FCNT) AS TOTAL_FCNT
FROM QGC_REFA.FISH_DRAFT_DATA
WHERE DELETED_FLAG = 0
AND STATUS IN ('PENDING','APPROVED')
GROUP BY CREATED_BY, TO_CHAR(STRDT, 'YYYY-MM')
),
all_users AS (
SELECT USER_ID FROM filtered_users
)
SELECT
u.USER_ID,
su.REAL_NAME,
su.PHONE,
su.NICKNAME || '/' || su.PHONE AS CONTACT,
ba.MIN_BASIN_CODE,
sa.MIN_STATION_CODE,
ba.BASIN_NAMES,
sa.STATION_NAMES,
fm.REPORT_MONTH,
fm.MIN_STRDT,
fm.MAX_ENDDT,
fm.TOTAL_FCNT
FROM all_users u
JOIN QGC_REFA.SYS_USER su JOIN QGC_REFA.SYS_USER su
ON us.USER_ID = su.ID ON u.USER_ID = su.ID
LEFT JOIN basin_agg ba
ON u.USER_ID = ba.USER_ID
LEFT JOIN station_agg sa
ON u.USER_ID = sa.USER_ID
LEFT JOIN fish_monthly fm LEFT JOIN fish_monthly fm
ON us.USER_ID = fm.CREATED_BY ON u.USER_ID = fm.CREATED_BY
WHERE 1 = 1
<if test="basinNames != null and basinNames.size() > 0"> <!-- 可选排序 -->
AND ( <!-- <if test="basinNames != null and basinNames.size() > 0">-->
<foreach collection="basinNames" item="name" separator=" OR "> <!-- AND (-->
INSTR(us.BASIN_NAMES, #{name}) > 0 <!-- <foreach collection="basinNames" item="name" separator=" OR ">-->
</foreach> <!-- INSTR(ba.BASIN_NAMES, #{name}) > 0-->
) <!-- </foreach>-->
</if> <!-- )-->
<if test="stationNames != null and stationNames.size() > 0"> <!-- </if>-->
AND ( <!-- <if test="stationNames != null and stationNames.size() > 0">-->
<foreach collection="stationNames" item="name" separator=" OR "> <!-- AND (-->
INSTR(us.STATION_NAMES, #{name}) > 0 <!-- <foreach collection="stationNames" item="name" separator=" OR ">-->
</foreach> <!-- INSTR(sa.STATION_NAMES, #{name}) > 0-->
) <!-- </foreach>-->
</if> <!-- )-->
ORDER BY fm.REPORT_MONTH, us.USER_ID <!-- </if>-->
</sql> </sql>
<select id="queryStatistics" resultMap="StatisticsResultMap"> <select id="queryStatistics" resultMap="StatisticsResultMap">
SELECT * FROM ( SELECT * FROM (
SELECT t.*, ROWNUM rn FROM ( SELECT
<include refid="statisticsQuery"/> t.*,
) t ROW_NUMBER() OVER (ORDER BY t.REPORT_MONTH, t.USER_ID) AS rn
WHERE ROWNUM &lt;= #{endRow} FROM (
) WHERE rn &gt; #{startRow} <include refid="statisticsQuery"/>
) t ORDER BY t.MIN_BASIN_CODE,t.MIN_STATION_CODE,t.REPORT_MONTH,t.MIN_STRDT
) WHERE rn BETWEEN #{startRow}+1 AND #{endRow}
</select> </select>
<select id="countStatistics" resultType="int"> <select id="countStatistics" resultType="int">
SELECT COUNT(*) FROM ( SELECT COUNT(*) FROM (
<include refid="statisticsQuery"/> <include refid="statisticsQuery"/>