feat(filter): 添加事件列表接口到认证白名单

- 在 AuthGlobalFilter 中添加 /event/list/transient/page 接口到白名单
- 在 AuthGlobalFilter 中添加 /event/list/transient/page/debug 接口到白名单
- 新增 DATA_FLICKER.sql 数据库脚本文件,包含电能质量相关数据表结构
This commit is contained in:
2026-05-14 09:12:16 +08:00
parent b56116264c
commit a8a57e882f
11 changed files with 2708 additions and 17 deletions

View File

@@ -0,0 +1,26 @@
package com.njcn.gather.event.eventlist.config;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* 暂态事件时间字段按秒输出,避免接口响应携带毫秒。
*/
public class EventSecondTimeSerializer extends JsonSerializer<LocalDateTime> {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (value == null) {
gen.writeNull();
return;
}
gen.writeString(FORMATTER.format(value));
}
}

View File

@@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.njcn.gather.event.eventlist.config.EventSecondTimeSerializer;
import lombok.Data; import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
@@ -38,7 +39,7 @@ public class EventListVO implements Serializable {
@Excel(name = "发生时刻", width = 25, exportFormat = "yyyy-MM-dd HH:mm:ss") @Excel(name = "发生时刻", width = 25, exportFormat = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonDeserialize(using = LocalDateTimeDeserializer.class) @JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class) @JsonSerialize(using = EventSecondTimeSerializer.class)
private LocalDateTime startTime; private LocalDateTime startTime;
@Excel(name = "监测点名称", width = 25) @Excel(name = "监测点名称", width = 25)

View File

@@ -13,7 +13,7 @@
- 独立任务持久化表 - 独立任务持久化表
- 前端页面代码 - 前端页面代码
目录中保留历史 SQL 脚本 `DATA_FLICKER.sql`,并同步复制到 `src/main/resources/sql/add-data` 供运行时解析表字段元数据。 SQL 元数据脚本位于 `src/main/resources/sql/add-data/DATA_FLICKER.sql`供运行时解析表字段元数据。
## 当前结构 ## 当前结构
@@ -21,7 +21,6 @@
add-data/ add-data/
├── pom.xml ├── pom.xml
├── README.md ├── README.md
├── DATA_FLICKER.sql
└── src/main/java/com/njcn/gather/tool/adddata/ └── src/main/java/com/njcn/gather/tool/adddata/
├── component/ ├── component/
├── config/ ├── config/

File diff suppressed because it is too large Load Diff

View File

@@ -105,6 +105,7 @@ wave-tool/
- `1`: 普通展示 - `1`: 普通展示
- `2`: App 抽点 - `2`: App 抽点
- `3`: 原始波形 - `3`: 原始波形
- `4`: 简化显示,保留 x 轴时间,对暂降底部中间段幅值置空
- `ptType` - `ptType`
- PT 接线方式 - PT 接线方式
- `0`: 星形 - `0`: 星形

View File

@@ -12,7 +12,7 @@ import lombok.Data;
public class WaveComtradeParseParam { public class WaveComtradeParseParam {
/** 解析类型。 */ /** 解析类型。 */
@ApiModelProperty(value = "解析类型0 高级算法采样率 32-1281 普通展示2 App 抽点3 原始波形", example = "1") @ApiModelProperty(value = "解析类型0 高级算法采样率 32-1281 普通展示2 App 抽点3 原始波形4 简化显示", example = "1")
private Integer parseType = 1; private Integer parseType = 1;
/** PT 接线方式。 */ /** PT 接线方式。 */

View File

@@ -47,6 +47,12 @@ public class WaveServiceImpl implements WaveService {
private static final int DEFAULT_PARSE_TYPE = 1; private static final int DEFAULT_PARSE_TYPE = 1;
/** 向量计算固定使用原始波形解析类型。 */ /** 向量计算固定使用原始波形解析类型。 */
private static final int RAW_WAVE_PARSE_TYPE = 3; private static final int RAW_WAVE_PARSE_TYPE = 3;
/** COMTRADE 简化显示解析类型。 */
private static final int SIMPLIFIED_DISPLAY_PARSE_TYPE = 4;
/** 暂降判定默认阈值。 */
private static final float DEFAULT_SAG_THRESHOLD_RATE = 0.9F;
/** 暂降底部平台默认浮动带。 */
private static final float DEFAULT_BOTTOM_THRESHOLD_RATE = 0.02F;
/** PT/CT 默认变比。 */ /** PT/CT 默认变比。 */
private static final double DEFAULT_RATIO = 1D; private static final double DEFAULT_RATIO = 1D;
/** PT 默认接线方式0 表示星形。 */ /** PT 默认接线方式0 表示星形。 */
@@ -114,16 +120,21 @@ public class WaveServiceImpl implements WaveService {
WaveComtradeParseParam resolvedParam = param == null ? new WaveComtradeParseParam() : param; WaveComtradeParseParam resolvedParam = param == null ? new WaveComtradeParseParam() : param;
try (InputStream cfgInputStream = cfgStream; InputStream datInputStream = datStream) { try (InputStream cfgInputStream = cfgStream; InputStream datInputStream = datStream) {
WaveDataDTO waveDataDTO = waveFileComponent.getComtrade(cfgInputStream, datInputStream, sanitizeParseType(resolvedParam.getParseType())); int parseType = sanitizeParseType(resolvedParam.getParseType());
boolean simplifiedDisplay = parseType == SIMPLIFIED_DISPLAY_PARSE_TYPE;
WaveDataDTO waveDataDTO = waveFileComponent.getComtrade(cfgInputStream, datInputStream, parseType);
applyWaveMetadata(waveDataDTO, resolvedParam); applyWaveMetadata(waveDataDTO, resolvedParam);
boolean needRms = shouldCalculateRms(resolvedParam); boolean needRms = shouldCalculateRms(resolvedParam) || simplifiedDisplay;
boolean buildDetails = shouldBuildDetails(resolvedParam); boolean buildDetails = shouldBuildDetails(resolvedParam);
boolean calculateEigenvalue = Boolean.TRUE.equals(resolvedParam.getCalculateEigenvalue()); boolean calculateEigenvalue = Boolean.TRUE.equals(resolvedParam.getCalculateEigenvalue());
if (needRms || buildDetails || calculateEigenvalue) { if (needRms || buildDetails || calculateEigenvalue) {
waveDataDTO = waveFileComponent.getValidData(waveDataDTO); waveDataDTO = waveFileComponent.getValidData(waveDataDTO);
} }
if (simplifiedDisplay) {
applySimplifiedDisplay(waveDataDTO);
}
WaveComtradeResultVO result = new WaveComtradeResultVO(); WaveComtradeResultVO result = new WaveComtradeResultVO();
fillComtradeSummary(result, waveDataDTO); fillComtradeSummary(result, waveDataDTO);
@@ -284,8 +295,169 @@ public class WaveServiceImpl implements WaveService {
return param.getBuildDetails() == null || param.getBuildDetails(); return param.getBuildDetails() == null || param.getBuildDetails();
} }
private void applySimplifiedDisplay(WaveDataDTO waveDataDTO) {
if (waveDataDTO == null || waveDataDTO.getListWaveData() == null || waveDataDTO.getListRmsData() == null) {
return;
}
SimplifiedRange range = resolveSimplifiedRange(waveDataDTO);
if (range == null) {
return;
}
maskBottomMiddle(waveDataDTO.getListWaveData(), range);
maskBottomMiddle(waveDataDTO.getListRmsData(), range);
}
private SimplifiedRange resolveSimplifiedRange(WaveDataDTO waveDataDTO) {
List<List<Float>> rmsData = waveDataDTO.getListRmsData();
if (rmsData == null || rmsData.isEmpty()) {
return null;
}
int valueColumnCount = resolveValueColumnCount(rmsData);
if (valueColumnCount <= 0) {
return null;
}
int baseIndex = resolveBaseIndex(waveDataDTO, rmsData);
if (baseIndex < 0 || baseIndex >= rmsData.size()) {
return null;
}
float[] baseValues = resolveBaseValues(rmsData.get(baseIndex), valueColumnCount);
if (baseValues == null) {
return null;
}
int startIndex = -1;
int recoverIndex = -1;
float bottomValue = Float.MAX_VALUE;
for (int i = baseIndex; i < rmsData.size(); i++) {
Float minValue = minValue(rmsData.get(i), valueColumnCount);
if (minValue == null) {
continue;
}
boolean sag = isSag(rmsData.get(i), baseValues, valueColumnCount);
if (startIndex < 0 && sag) {
startIndex = i;
}
if (startIndex >= 0 && recoverIndex < 0 && minValue < bottomValue) {
bottomValue = minValue;
}
if (startIndex >= 0 && !sag) {
recoverIndex = i;
break;
}
}
if (startIndex < 0 || recoverIndex < 0 || startIndex >= recoverIndex || bottomValue == Float.MAX_VALUE) {
return null;
}
float bottomThreshold = bottomValue + resolveBottomBand(baseValues);
int bottomStartIndex = -1;
int bottomEndIndex = -1;
for (int i = startIndex; i <= recoverIndex; i++) {
Float minValue = minValue(rmsData.get(i), valueColumnCount);
if (minValue == null || minValue > bottomThreshold) {
continue;
}
if (bottomStartIndex < 0) {
bottomStartIndex = i;
}
bottomEndIndex = i;
}
if (bottomStartIndex < 0 || bottomEndIndex < 0 || bottomStartIndex >= bottomEndIndex) {
return null;
}
return new SimplifiedRange(bottomStartIndex, bottomEndIndex);
}
private int resolveValueColumnCount(List<List<Float>> rows) {
int count = 0;
for (List<Float> row : rows) {
if (row != null && row.size() > 1) {
count = Math.max(count, row.size() - 1);
}
}
return count;
}
private int resolveBaseIndex(WaveDataDTO waveDataDTO, List<List<Float>> rmsData) {
Integer sampleRate = waveDataDTO.getComtradeCfgDTO() == null ? null : waveDataDTO.getComtradeCfgDTO().getFinalSampleRate();
int preferred = sampleRate == null ? 0 : sampleRate + 2;
return preferred < rmsData.size() ? preferred : 0;
}
private float[] resolveBaseValues(List<Float> row, int valueColumnCount) {
if (row == null || row.size() <= valueColumnCount) {
return null;
}
float[] baseValues = new float[valueColumnCount];
for (int i = 0; i < valueColumnCount; i++) {
Float value = row.get(i + 1);
if (value == null || value <= 0) {
return null;
}
baseValues[i] = value;
}
return baseValues;
}
private boolean isSag(List<Float> row, float[] baseValues, int valueColumnCount) {
if (row == null || row.size() <= valueColumnCount) {
return false;
}
for (int i = 0; i < valueColumnCount; i++) {
Float value = row.get(i + 1);
if (value != null && value < baseValues[i] * DEFAULT_SAG_THRESHOLD_RATE) {
return true;
}
}
return false;
}
private Float minValue(List<Float> row, int valueColumnCount) {
if (row == null || row.size() <= valueColumnCount) {
return null;
}
Float minValue = null;
for (int i = 0; i < valueColumnCount; i++) {
Float value = row.get(i + 1);
if (value == null) {
continue;
}
minValue = minValue == null ? value : Math.min(minValue, value);
}
return minValue;
}
private float resolveBottomBand(float[] baseValues) {
float minBaseValue = Float.MAX_VALUE;
for (float baseValue : baseValues) {
minBaseValue = Math.min(minBaseValue, baseValue);
}
if (minBaseValue == Float.MAX_VALUE) {
return 0F;
}
return minBaseValue * DEFAULT_BOTTOM_THRESHOLD_RATE;
}
private void maskBottomMiddle(List<List<Float>> rows, SimplifiedRange range) {
if (rows == null || range == null) {
return;
}
for (int i = 0; i < rows.size(); i++) {
if (i <= range.bottomStartIndex || i >= range.bottomEndIndex) {
continue;
}
List<Float> row = rows.get(i);
if (row == null || row.size() <= 1) {
continue;
}
for (int j = 1; j < row.size(); j++) {
row.set(j, null);
}
}
}
private int sanitizeParseType(Integer parseType) { private int sanitizeParseType(Integer parseType) {
if (parseType == null || parseType < 0 || parseType > 3) { if (parseType == null || parseType < 0 || parseType > SIMPLIFIED_DISPLAY_PARSE_TYPE) {
return DEFAULT_PARSE_TYPE; return DEFAULT_PARSE_TYPE;
} }
return parseType; return parseType;
@@ -434,4 +606,17 @@ public class WaveServiceImpl implements WaveService {
} }
return samplingInterval; return samplingInterval;
} }
private static final class SimplifiedRange {
/** 暂降底部平台起始下标。 */
private final int bottomStartIndex;
/** 暂降底部平台结束下标。 */
private final int bottomEndIndex;
private SimplifiedRange(int bottomStartIndex, int bottomEndIndex) {
this.bottomStartIndex = bottomStartIndex;
this.bottomEndIndex = bottomEndIndex;
}
}
} }

View File

@@ -114,7 +114,10 @@ public final class WaveUtil {
if (row == null || row.isEmpty()) { if (row == null || row.isEmpty()) {
continue; continue;
} }
float x = row.get(0); Float x = row.get(0);
if (x == null) {
continue;
}
float valueA = 0f; float valueA = 0f;
float valueB = 0f; float valueB = 0f;
float valueC = 0f; float valueC = 0f;
@@ -124,18 +127,29 @@ public final class WaveUtil {
for (int m = 0; m < phaseCount; m++) { for (int m = 0; m < phaseCount; m++) {
String currentTitle = waveTitle.get(phaseCount * index + m + 1).substring(1); String currentTitle = waveTitle.get(phaseCount * index + m + 1).substring(1);
float value = row.get(phaseCount * index + m + 1) * ratio; int valueIndex = phaseCount * index + m + 1;
if (row.size() <= valueIndex) {
continue;
}
Float sourceValue = row.get(valueIndex);
Float value = sourceValue == null ? null : sourceValue * ratio;
if (currentTitle.contains("A")) { if (currentTitle.contains("A")) {
valueA = value; if (value != null) {
existsA = true; valueA = value;
existsA = true;
}
aValues.add(buildPoint(x, value)); aValues.add(buildPoint(x, value));
} else if (currentTitle.contains("B")) { } else if (currentTitle.contains("B")) {
valueB = value; if (value != null) {
existsB = true; valueB = value;
existsB = true;
}
bValues.add(buildPoint(x, value)); bValues.add(buildPoint(x, value));
} else if (currentTitle.contains("C")) { } else if (currentTitle.contains("C")) {
valueC = value; if (value != null) {
existsC = true; valueC = value;
existsC = true;
}
cValues.add(buildPoint(x, value)); cValues.add(buildPoint(x, value));
} }
} }
@@ -168,7 +182,7 @@ public final class WaveUtil {
/** /**
* 构建单个点位。 * 构建单个点位。
*/ */
private static List<Float> buildPoint(float x, float y) { private static List<Float> buildPoint(Float x, Float y) {
List<Float> point = new ArrayList<>(2); List<Float> point = new ArrayList<>(2);
point.add(x); point.add(x);
point.add(y); point.add(y);

View File

@@ -0,0 +1,22 @@
package com.njcn.gather.tool.wave.component;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**
* 波形文件解析组件测试。
*/
class WaveFileComponentTest {
@Test
void shouldRoundWaveTimeToThreeDecimals() {
Assertions.assertEquals(1.235F, WaveFileComponent.roundWaveTime(1.2345F));
Assertions.assertEquals(-99.988F, WaveFileComponent.roundWaveTime(-99.9876F));
}
@Test
void shouldRoundWaveAmplitudeToThreeDecimals() {
Assertions.assertEquals(220.123F, WaveFileComponent.roundWaveAmplitude(220.1234F));
Assertions.assertEquals(-12.988F, WaveFileComponent.roundWaveAmplitude(-12.9876F));
}
}

View File

@@ -0,0 +1,162 @@
package com.njcn.gather.tool.wave.service.impl;
import com.njcn.gather.tool.wave.component.WaveFileComponent;
import com.njcn.gather.tool.wave.component.WaveVectorComponent;
import com.njcn.gather.tool.wave.pojo.dto.AnalogDTO;
import com.njcn.gather.tool.wave.pojo.dto.ComtradeCfgDTO;
import com.njcn.gather.tool.wave.pojo.dto.WaveDataDTO;
import com.njcn.gather.tool.wave.pojo.param.WaveComtradeParseParam;
import com.njcn.gather.tool.wave.pojo.vo.WaveComtradeResultVO;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 波形服务测试。
*/
class WaveServiceImplTest {
@Test
void shouldUseCfgRatioWhenCfgContainsValidPtAndCt() throws Exception {
WaveServiceImpl service = new WaveServiceImpl(new WaveFileComponent(), new WaveVectorComponent());
WaveDataDTO waveDataDTO = new WaveDataDTO();
ComtradeCfgDTO cfgDTO = new ComtradeCfgDTO();
cfgDTO.setLstAnalogDTO(Arrays.asList(
buildAnalog("V", 10000F, 100F),
buildAnalog("A", 200F, 1F)
));
waveDataDTO.setComtradeCfgDTO(cfgDTO);
WaveComtradeParseParam param = new WaveComtradeParseParam();
param.setPt(1D);
param.setCt(1D);
Method method = WaveServiceImpl.class.getDeclaredMethod("applyWaveMetadata", WaveDataDTO.class, WaveComtradeParseParam.class);
method.setAccessible(true);
method.invoke(service, waveDataDTO, param);
Assertions.assertEquals(100D, waveDataDTO.getPt());
Assertions.assertEquals(200D, waveDataDTO.getCt());
}
@Test
void shouldFillComtradeSummaryFields() throws Exception {
WaveServiceImpl service = new WaveServiceImpl(new WaveFileComponent(), new WaveVectorComponent());
WaveDataDTO waveDataDTO = new WaveDataDTO();
ComtradeCfgDTO cfgDTO = new ComtradeCfgDTO();
cfgDTO.setNChannelNum(8);
cfgDTO.setNPhasic(3);
cfgDTO.setLstAnalogDTO(Arrays.asList(
buildAnalog("V", 10000F, 100F),
buildAnalog("A", 200F, 1F)
));
waveDataDTO.setComtradeCfgDTO(cfgDTO);
waveDataDTO.setIPhasic(3);
WaveComtradeResultVO result = new WaveComtradeResultVO();
Method method = WaveServiceImpl.class.getDeclaredMethod("fillComtradeSummary", WaveComtradeResultVO.class, WaveDataDTO.class);
method.setAccessible(true);
method.invoke(service, result, waveDataDTO);
Assertions.assertEquals(8, result.getTotalChannels());
Assertions.assertEquals(3, result.getPhaseCount());
Assertions.assertEquals("kV/A", result.getUnit());
}
@Test
void shouldMaskValuesInsideBottomPlatformMiddle() throws Exception {
WaveServiceImpl service = new WaveServiceImpl(new WaveFileComponent(), new WaveVectorComponent());
WaveDataDTO waveDataDTO = new WaveDataDTO();
ComtradeCfgDTO cfgDTO = new ComtradeCfgDTO();
cfgDTO.setFinalSampleRate(1);
waveDataDTO.setComtradeCfgDTO(cfgDTO);
waveDataDTO.setListWaveData(buildRows(new float[][]{
{0F, 100F, 100F, 100F},
{1F, 100F, 100F, 100F},
{2F, 100F, 100F, 100F},
{3F, 100F, 100F, 100F},
{4F, 80F, 100F, 100F},
{5F, 60F, 100F, 100F},
{6F, 60F, 100F, 100F},
{7F, 60F, 100F, 100F},
{8F, 95F, 100F, 100F},
{9F, 100F, 100F, 100F}
}));
waveDataDTO.setListRmsData(buildRows(new float[][]{
{0F, 100F, 100F, 100F},
{1F, 100F, 100F, 100F},
{2F, 100F, 100F, 100F},
{3F, 100F, 100F, 100F},
{4F, 80F, 100F, 100F},
{5F, 60F, 100F, 100F},
{6F, 60F, 100F, 100F},
{7F, 60F, 100F, 100F},
{8F, 95F, 100F, 100F},
{9F, 100F, 100F, 100F}
}));
Method method = WaveServiceImpl.class.getDeclaredMethod("applySimplifiedDisplay", WaveDataDTO.class);
method.setAccessible(true);
method.invoke(service, waveDataDTO);
Assertions.assertEquals(0F, waveDataDTO.getListWaveData().get(0).get(0));
Assertions.assertEquals(100F, waveDataDTO.getListWaveData().get(0).get(1));
Assertions.assertEquals(100F, waveDataDTO.getListWaveData().get(2).get(1));
Assertions.assertEquals(80F, waveDataDTO.getListWaveData().get(4).get(1));
Assertions.assertEquals(60F, waveDataDTO.getListWaveData().get(5).get(1));
Assertions.assertNull(waveDataDTO.getListWaveData().get(6).get(1));
Assertions.assertEquals(60F, waveDataDTO.getListWaveData().get(7).get(1));
Assertions.assertEquals(95F, waveDataDTO.getListWaveData().get(8).get(1));
Assertions.assertEquals(100F, waveDataDTO.getListWaveData().get(9).get(1));
}
@Test
void shouldKeepDataWhenSimplifiedRangeCannotBeDetected() throws Exception {
WaveServiceImpl service = new WaveServiceImpl(new WaveFileComponent(), new WaveVectorComponent());
WaveDataDTO waveDataDTO = new WaveDataDTO();
ComtradeCfgDTO cfgDTO = new ComtradeCfgDTO();
cfgDTO.setFinalSampleRate(1);
waveDataDTO.setComtradeCfgDTO(cfgDTO);
waveDataDTO.setListWaveData(buildRows(new float[][]{
{0F, 100F, 100F, 100F},
{1F, 99F, 100F, 100F},
{2F, 98F, 100F, 100F}
}));
waveDataDTO.setListRmsData(buildRows(new float[][]{
{0F, 100F, 100F, 100F},
{1F, 99F, 100F, 100F},
{2F, 98F, 100F, 100F}
}));
Method method = WaveServiceImpl.class.getDeclaredMethod("applySimplifiedDisplay", WaveDataDTO.class);
method.setAccessible(true);
method.invoke(service, waveDataDTO);
Assertions.assertEquals(99F, waveDataDTO.getListWaveData().get(1).get(1));
Assertions.assertEquals(98F, waveDataDTO.getListRmsData().get(2).get(1));
}
private AnalogDTO buildAnalog(String unit, Float primary, Float secondary) {
AnalogDTO analogDTO = new AnalogDTO();
analogDTO.setSzUnitName(unit);
analogDTO.setFPrimary(primary);
analogDTO.setFSecondary(secondary);
return analogDTO;
}
private List<List<Float>> buildRows(float[][] values) {
List<List<Float>> rows = new ArrayList<>();
for (float[] value : values) {
List<Float> row = new ArrayList<>();
for (float item : value) {
row.add(item);
}
rows.add(row);
}
return rows;
}
}

View File

@@ -34,7 +34,9 @@ public class AuthGlobalFilter implements Filter, Ordered {
"/doc.html", "/doc.html",
"/v3/api-docs", "/v3/api-docs",
"/admin/login", "/admin/login",
"/admin/getPublicKey" "/admin/getPublicKey",
"/event/list/transient/page",
"/event/list/transient/page/debug"
); );
@Resource @Resource