[CMLR-030] 控制器签名 Map->DTO 等价替换
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
package vvpkassistant.controller;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import vvpkassistant.Data.ResponseData;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
class ControllerMapToDtoContractTests {
|
||||
|
||||
@Test
|
||||
void shouldKeepAllFormerMapEndpointsAndReturnTypes() {
|
||||
Map<String, Class<?>> expected = new LinkedHashMap<>();
|
||||
expected.put("user/inputUserInfo", ResponseData.class);
|
||||
expected.put("user/loginWithPhoneNumber", ResponseData.class);
|
||||
expected.put("user/queryMyAllPkData", ResponseData.class);
|
||||
expected.put("user/handlePkInfo", ResponseData.class);
|
||||
expected.put("user/pkRecordDetail", ResponseData.class);
|
||||
expected.put("user/pinToTop", ResponseData.class);
|
||||
expected.put("user/cancelPin", ResponseData.class);
|
||||
expected.put("user/pointsDetail", ResponseData.class);
|
||||
expected.put("pk/pkList", ResponseData.class);
|
||||
expected.put("pk/queryMyCanUsePkData", ResponseData.class);
|
||||
expected.put("pk/pkInfoDetail", ResponseData.class);
|
||||
expected.put("pk/deletePkDataWithId", ResponseData.class);
|
||||
expected.put("pk/fetchDetailPkDataWithId", ResponseData.class);
|
||||
expected.put("pk/listUninvitedPublishedAnchorsByUserId", ResponseData.class);
|
||||
expected.put("anchor/list", ResponseData.class);
|
||||
expected.put("anchor/deleteMyAnchor", ResponseData.class);
|
||||
expected.put("systemMessage/list", ResponseData.class);
|
||||
expected.put("chat/receiveImMessage", Map.class);
|
||||
|
||||
Map<String, Class<?>> actual = new HashMap<>();
|
||||
Class<?>[] controllers = new Class<?>[]{
|
||||
UserController.class,
|
||||
PkController.class,
|
||||
AnchorsController.class,
|
||||
SystemMessageController.class,
|
||||
ChatController.class
|
||||
};
|
||||
for (Class<?> controllerClass : controllers) {
|
||||
RequestMapping requestMapping = controllerClass.getAnnotation(RequestMapping.class);
|
||||
String basePath = requestMapping == null ? "" : firstPath(requestMapping.value(), requestMapping.path());
|
||||
for (Method method : controllerClass.getDeclaredMethods()) {
|
||||
PostMapping postMapping = method.getAnnotation(PostMapping.class);
|
||||
if (postMapping == null) {
|
||||
continue;
|
||||
}
|
||||
String subPath = firstPath(postMapping.value(), postMapping.path());
|
||||
String fullPath = joinPath(basePath, subPath);
|
||||
if (expected.containsKey(fullPath)) {
|
||||
actual.put(fullPath, method.getReturnType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Assertions.assertEquals(18, actual.size(), "目标端点数量不匹配");
|
||||
expected.forEach((path, returnType) ->
|
||||
Assertions.assertEquals(returnType, actual.get(path), "端点返回类型不一致: " + path)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotUseRequestBodyMapInTargetControllers() {
|
||||
Class<?>[] controllers = new Class<?>[]{
|
||||
UserController.class,
|
||||
PkController.class,
|
||||
AnchorsController.class,
|
||||
SystemMessageController.class,
|
||||
ChatController.class
|
||||
};
|
||||
for (Class<?> controllerClass : controllers) {
|
||||
for (Method method : controllerClass.getDeclaredMethods()) {
|
||||
for (Parameter parameter : method.getParameters()) {
|
||||
if (!hasRequestBody(parameter.getAnnotations())) {
|
||||
continue;
|
||||
}
|
||||
Assertions.assertFalse(Map.class.isAssignableFrom(parameter.getType()),
|
||||
"存在 @RequestBody Map 参数: " + controllerClass.getSimpleName() + "." + method.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasRequestBody(Annotation[] annotations) {
|
||||
return Arrays.stream(annotations).anyMatch(annotation -> annotation.annotationType() == RequestBody.class);
|
||||
}
|
||||
|
||||
private static String firstPath(String[] values, String[] paths) {
|
||||
if (values != null && values.length > 0 && values[0] != null && !values[0].isEmpty()) {
|
||||
return values[0];
|
||||
}
|
||||
if (paths != null && paths.length > 0 && paths[0] != null && !paths[0].isEmpty()) {
|
||||
return paths[0];
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String joinPath(String basePath, String subPath) {
|
||||
String base = basePath.startsWith("/") ? basePath.substring(1) : basePath;
|
||||
String sub = subPath.startsWith("/") ? subPath.substring(1) : subPath;
|
||||
if (base.isEmpty()) {
|
||||
return sub;
|
||||
}
|
||||
if (sub.isEmpty()) {
|
||||
return base;
|
||||
}
|
||||
return base + "/" + sub;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user