refactor: 适配校验改为站点汇总+适配器页面批量校验模式

This commit is contained in:
mediabot-pt
2026-06-30 23:01:49 +08:00
parent 0568923ce9
commit bf9ad010a1
10 changed files with 499 additions and 203 deletions

View File

@@ -0,0 +1,18 @@
package com.par.core.dto;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 单个页面的访问结果汇总
*/
@Data
public class AccessPageSummaryDTO {
private String url;
private int count;
private int validCount;
private int invalidCount;
private LocalDateTime lastSubmitted;
}

View File

@@ -0,0 +1,21 @@
package com.par.core.dto;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
/**
* 站点访问结果汇总(按页面分组)
*/
@Data
public class SiteAccessSummaryDTO {
private String siteId;
private int totalResults;
private int validCount;
private int invalidCount;
private int uncheckedCount;
private LocalDateTime lastSubmitted;
private List<AccessPageSummaryDTO> pages;
}

View File

@@ -5,8 +5,10 @@ import com.par.core.entity.AccessResult;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
import java.util.Map;
/**
* 站点访问结果 Mapper
@@ -19,4 +21,21 @@ public interface AccessResultMapper extends BaseMapper<AccessResult> {
@Select("SELECT * FROM access_results ORDER BY created_at DESC")
List<AccessResult> selectAll();
/**
* 按站点+页面聚合统计访问结果
*/
@Select("SELECT site_id, url, " +
"COUNT(*) AS cnt, " +
"SUM(CASE WHEN is_valid = 1 THEN 1 ELSE 0 END) AS valid_cnt, " +
"SUM(CASE WHEN is_valid = 0 THEN 1 ELSE 0 END) AS invalid_cnt, " +
"MAX(created_at) AS last_at " +
"FROM access_results GROUP BY site_id, url ORDER BY site_id, cnt DESC")
List<Map<String, Object>> selectPageSummary();
/**
* 批量标记站点某个URL的所有结果为有效/无效
*/
@Update("UPDATE access_results SET is_valid = #{isValid} WHERE site_id = #{siteId} AND url = #{url} AND is_valid IS NULL")
int batchValidateUrl(@Param("siteId") String siteId, @Param("url") String url, @Param("isValid") Boolean isValid);
}

View File

@@ -1,6 +1,7 @@
package com.par.core.service;
import com.par.core.dto.AccessResultDTO;
import com.par.core.dto.SiteAccessSummaryDTO;
import com.par.core.entity.AccessResult;
import java.util.List;
@@ -37,6 +38,16 @@ public interface AccessResultService {
*/
AccessResult validate(Long id, Boolean isValid, String note);
/**
* 获取所有站点的访问结果汇总(按URL分组统计)
*/
List<SiteAccessSummaryDTO> listSiteSummaries();
/**
* 批量标记站点某个URL的所有未验证结果为有效/无效
*/
int batchValidateUrl(String siteId, String url, Boolean isValid);
/**
* 实体转 DTO(不含内容)
*/

View File

@@ -1,6 +1,8 @@
package com.par.core.service.impl;
import com.par.core.dto.AccessPageSummaryDTO;
import com.par.core.dto.AccessResultDTO;
import com.par.core.dto.SiteAccessSummaryDTO;
import com.par.core.entity.AccessResult;
import com.par.core.mapper.AccessResultMapper;
import com.par.core.service.AccessResultService;
@@ -9,8 +11,9 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.UUID;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@@ -103,4 +106,73 @@ public class AccessResultServiceImpl implements AccessResultService {
dto.setCreatedAt(entity.getCreatedAt());
return dto;
}
// ==================== 站点汇总 ====================
@Override
public List<SiteAccessSummaryDTO> listSiteSummaries() {
List<Map<String, Object>> rows = mapper.selectPageSummary();
// 按 siteId 分组聚合
Map<String, SiteAccessSummaryDTO> siteMap = new LinkedHashMap<>();
for (Map<String, Object> row : rows) {
String siteId = (String) row.get("site_id");
String url = (String) row.get("url");
int cnt = toInt(row.get("cnt"));
int validCnt = toInt(row.get("valid_cnt"));
int invalidCnt = toInt(row.get("invalid_cnt"));
LocalDateTime lastAt = toLocalDateTime(row.get("last_at"));
SiteAccessSummaryDTO site = siteMap.computeIfAbsent(siteId, k -> {
SiteAccessSummaryDTO s = new SiteAccessSummaryDTO();
s.setSiteId(k);
s.setPages(new ArrayList<>());
s.setTotalResults(0);
s.setValidCount(0);
s.setInvalidCount(0);
s.setUncheckedCount(0);
return s;
});
site.setTotalResults(site.getTotalResults() + cnt);
site.setValidCount(site.getValidCount() + validCnt);
site.setInvalidCount(site.getInvalidCount() + invalidCnt);
if (site.getLastSubmitted() == null || (lastAt != null && lastAt.isAfter(site.getLastSubmitted()))) {
site.setLastSubmitted(lastAt);
}
AccessPageSummaryDTO page = new AccessPageSummaryDTO();
page.setUrl(url);
page.setCount(cnt);
page.setValidCount(validCnt);
page.setInvalidCount(invalidCnt);
page.setLastSubmitted(lastAt);
site.getPages().add(page);
}
// 计算未验证数量
for (SiteAccessSummaryDTO site : siteMap.values()) {
site.setUncheckedCount(site.getTotalResults() - site.getValidCount() - site.getInvalidCount());
}
return new ArrayList<>(siteMap.values());
}
@Override
public int batchValidateUrl(String siteId, String url, Boolean isValid) {
int affected = mapper.batchValidateUrl(siteId, url, isValid);
log.info("Batch validated: siteId={}, url={}, isValid={}, affected={}", siteId, url, isValid, affected);
return affected;
}
private int toInt(Object val) {
if (val instanceof Number n) return n.intValue();
if (val instanceof String s) return Integer.parseInt(s);
return 0;
}
private LocalDateTime toLocalDateTime(Object val) {
if (val instanceof LocalDateTime ldt) return ldt;
if (val instanceof Timestamp ts) return ts.toLocalDateTime();
return null;
}
}