字段说明测试
All checks were successful
API接口参数变更检测 / api-param-check (push) Successful in 16s

This commit is contained in:
2026-06-05 15:20:01 +08:00
parent 1d05aec86c
commit dbcc1a3490
2 changed files with 59 additions and 10 deletions

View File

@@ -254,6 +254,42 @@ def _param_description(param: FormalParameter) -> Optional[str]:
return None
def _parse_javadoc_params(source_code: str) -> Dict[str, Dict[str, str]]:
"""
使用正则从 Java 源代码中提取方法上的 Javadoc @param 描述。
返回结构:
{ method_name: { param_name: description } }
"""
javadoc_map: Dict[str, Dict[str, str]] = {}
# 匹配 Javadoc 块 + 其后的方法声明
# 简单启发式Javadoc 后面第一个标识符 + ( 视为方法名
pattern = re.compile(
r'/\*\*(?P<javadoc>.*?)\*/\s*(?:public|private|protected|static|\s)*'
r'[\w<>\[\],\.\s]+\s+(?P<method>\w+)\s*\(',
re.DOTALL | re.MULTILINE
)
for match in pattern.finditer(source_code):
javadoc_block = match.group('javadoc')
method_name = match.group('method')
param_descs: Dict[str, str] = {}
# 提取 @param 行
param_pattern = re.compile(r'@param\s+(\w+)\s+([^\n@]+)', re.IGNORECASE)
for p_match in param_pattern.finditer(javadoc_block):
p_name = p_match.group(1)
p_desc = p_match.group(2).strip()
if p_desc:
param_descs[p_name] = p_desc
if param_descs:
javadoc_map[method_name] = param_descs
return javadoc_map
class ControllerAstParser:
"""
基于 javalang 的 Controller 解析器。
@@ -268,6 +304,7 @@ class ControllerAstParser:
self.repo_root = repo_root
self.source_dir = source_dir
self._dto_cache: Dict[str, List[ApiParameter]] = {}
self._javadoc_map: Dict[str, Dict[str, str]] = {} # method_name -> param_name -> description
def parse_file_content(self, source: str, repo_relative_path: str) -> List[ApiEndpoint]:
"""
@@ -284,6 +321,9 @@ class ControllerAstParser:
print(f"[警告] 解析失败 {repo_relative_path}: {exc}")
return endpoints
# 解析当前文件的 Javadoc @param用于参数描述回退
self._javadoc_map = _parse_javadoc_params(source)
for type_decl in tree.types or []:
if not isinstance(type_decl, ClassDeclaration):
continue
@@ -323,7 +363,7 @@ class ControllerAstParser:
method_path = _ann_string(ann, "value", "path")
params = []
for p in method.parameters or []:
params.extend(self._extract_param(p))
params.extend(self._extract_param(p, method_name=method.name))
return ApiEndpoint(
http_method=_http_method(ann_name, ann),
@@ -335,7 +375,7 @@ class ControllerAstParser:
)
return None
def _extract_param(self, param: FormalParameter) -> List[ApiParameter]:
def _extract_param(self, param: FormalParameter, method_name: Optional[str] = None) -> List[ApiParameter]:
"""提取方法参数,@RequestBody 展开 DTO 字段;忽略框架注入参数。"""
type_name = _type_to_str(param.type)
name = _param_name(param)
@@ -347,6 +387,11 @@ class ControllerAstParser:
return self._expand_dto(type_name, "body")
desc = _param_description(param)
# Javadoc @param 回退(如果注解中没有描述)
if not desc and method_name and method_name in self._javadoc_map:
desc = self._javadoc_map[method_name].get(name)
return [
ApiParameter(
name=name,

View File

@@ -42,8 +42,9 @@ public class CultureClockInController {
/**
* 打卡分享 - 获取随机图片
*
* @param lastCombo 上次组合
* @param response HttpServletResponse
* @param response HttpServletResponse
*/
@PostMapping(value = "/random-preview1")
public void getRandomPicPreview(@RequestParam(value = "lastCombo1", required = false) String lastCombo1, HttpServletRequest request, HttpServletResponse response) throws Exception {
@@ -66,8 +67,9 @@ public class CultureClockInController {
/**
* 打卡分享 - 获取随机图片[base64]
*
* @param lastCombo 上次组合
* @param response HttpServletResponse
* @param response HttpServletResponse
*/
// @GetMapping(value = "/random-preview/base641")
@PutMapping(value = "/random-preview/base64")
@@ -89,8 +91,9 @@ public class CultureClockInController {
/**
* 打卡分享 - 获取随机图片[base64]
*
* @param lastCombo 上次组合
* @param response HttpServletResponse
* @param response HttpServletResponse
*/
@DeleteMapping(value = "/random-preview/delete")
public ActionResult<Base64ImageVo> getRandomPicPreviewBase64(@RequestParam(value = "lastCombo", required = false) String lastCombo, HttpServletRequest request, HttpServletResponse response) throws Exception {
@@ -112,6 +115,7 @@ public class CultureClockInController {
/**
* 打卡分享 - 打卡
*
* @param currentCombo 当前组合
* @return jnpf.base.ActionResult<jnpf.model.culture.vo.CultureClockInVo>
*/
@@ -127,15 +131,14 @@ public class CultureClockInController {
/**
* 打卡动态 - 打卡记录列表
*
* @param cursorDate 游标日期(yyyy-MM-dd)[首次不传]
* @param limitNum 返回有数据的天数
* @param limitNum 返回有数据的天数
* @return jnpf.base.ActionResult<jnpf.model.culture.vo.RecordListVo>
*/
@GetMapping(value = "/dynamic1")
// public ActionResult<RecordListVo> getRecordList(@RequestParam(value = "cursorDate", required = false) String cursorDate,
// @RequestParam(value = "limitNum", required = false, defaultValue = "10") Integer limitNum) {
public ActionResult<RecordListVo> getRecordList(@ApiParam(value = "游标日期(yyyy-MM-dd),首次请求不传", required = false) @RequestParam(value = "cursorDate1", required = false) String cursorDate,
@ApiParam(value = "返回有数据的天数", required = false) @RequestParam(value = "limitNum", required = false, defaultValue = "10") Integer limitNum) {
public ActionResult<RecordListVo> getRecordList(@RequestParam(value = "cursorDate1", required = false) String cursorDate,
@RequestParam(value = "limitNum", required = false, defaultValue = "10") Integer limitNum) {
limitNum = Math.max(10, Math.min(limitNum, 30));
RecordListVo recordList = cultureClockInService.getRecordList(cursorDate, limitNum);
@@ -144,6 +147,7 @@ public class CultureClockInController {
/**
* 打卡日历
*
* @param year 年
* @return jnpf.base.ActionResult<jnpf.model.culture.vo.YearDataVo>
*/