|
@@ -0,0 +1,186 @@
|
|
|
|
|
+"""把 api 模块控制器里的 @RequestMapping(value=..., method={GET,POST}) 改成 @GetMapping / @PostMapping。
|
|
|
|
|
+
|
|
|
|
|
+HTTP 方法依据 uniapp 前端 api/*.js 的实际调用(request.get / request.post)逐条确定,
|
|
|
|
|
+admin / store 模块不动。
|
|
|
|
|
+"""
|
|
|
|
|
+import re
|
|
|
|
|
+import sys
|
|
|
|
|
+from pathlib import Path
|
|
|
|
|
+
|
|
|
|
|
+sys.path.insert(0, str(Path(__file__).parent))
|
|
|
|
|
+from _root import ROOT # noqa: E402
|
|
|
|
|
+
|
|
|
|
|
+CTRL_DIR = ROOT / "yoshop-java" / "src/main/java/cn/yoshop/api/controller"
|
|
|
|
|
+
|
|
|
|
|
+# (完整路径 -> 方法),路径已含控制器类上的前缀
|
|
|
|
|
+METHODS = {
|
|
|
|
|
+ # 收货地址
|
|
|
|
|
+ "/api/address/list": "Get",
|
|
|
|
|
+ "/api/address/defaultId": "Get",
|
|
|
|
|
+ "/api/address/detail": "Get",
|
|
|
|
|
+ "/api/address/add": "Post",
|
|
|
|
|
+ "/api/address/edit": "Post",
|
|
|
|
|
+ "/api/address/setDefault": "Post",
|
|
|
|
|
+ "/api/address/remove": "Post",
|
|
|
|
|
+ # 图形 / 短信验证码
|
|
|
|
|
+ "/api/captcha/image": "Get",
|
|
|
|
|
+ "/api/captcha/sendSmsCaptcha": "Post",
|
|
|
|
|
+ # 购物车
|
|
|
|
|
+ "/api/cart/list": "Get",
|
|
|
|
|
+ "/api/cart/total": "Get",
|
|
|
|
|
+ "/api/cart/add": "Post",
|
|
|
|
|
+ "/api/cart/update": "Post",
|
|
|
|
|
+ "/api/cart/clear": "Post",
|
|
|
|
|
+ # 收银台
|
|
|
|
|
+ "/api/cashier/orderInfo": "Get",
|
|
|
|
|
+ "/api/cashier/orderPay": "Post",
|
|
|
|
|
+ "/api/cashier/tradeQuery": "Get",
|
|
|
|
|
+ # 结算台
|
|
|
|
|
+ "/api/checkout/order": "Get",
|
|
|
|
|
+ "/api/checkout/submit": "Post",
|
|
|
|
|
+ # 内容
|
|
|
|
|
+ "/api/category/list": "Get",
|
|
|
|
|
+ "/api/article/list": "Get",
|
|
|
|
|
+ "/api/article/detail": "Get",
|
|
|
|
|
+ "/api/article.category/list": "Get",
|
|
|
|
|
+ "/api/help/list": "Get",
|
|
|
|
|
+ "/api/page/detail": "Get",
|
|
|
|
|
+ # 商品
|
|
|
|
|
+ "/api/goods/list": "Get",
|
|
|
|
|
+ "/api/goods/detail": "Get",
|
|
|
|
|
+ "/api/goods/basic": "Get",
|
|
|
|
|
+ "/api/goods/specData": "Get",
|
|
|
|
|
+ "/api/goods/skuInfo": "Get",
|
|
|
|
|
+ "/api/goods.service/list": "Get",
|
|
|
|
|
+ # 站点入口(纯文本兜底)
|
|
|
|
|
+ "/api/index/index": "Get",
|
|
|
|
|
+ # 营销
|
|
|
|
|
+ "/api/comment/list": "Get",
|
|
|
|
|
+ "/api/comment/total": "Get",
|
|
|
|
|
+ "/api/comment/listRows": "Get",
|
|
|
|
|
+ "/api/coupon/list": "Get",
|
|
|
|
|
+ "/api/myCoupon/list": "Get",
|
|
|
|
|
+ "/api/myCoupon/receive": "Post",
|
|
|
|
|
+ "/api/express/list": "Get",
|
|
|
|
|
+ # 订单
|
|
|
|
|
+ "/api/order/list": "Get",
|
|
|
|
|
+ "/api/order/detail": "Get",
|
|
|
|
|
+ "/api/order/express": "Get",
|
|
|
|
|
+ "/api/order/cancel": "Post",
|
|
|
|
|
+ "/api/order/receipt": "Post",
|
|
|
|
|
+ "/api/order/todoCounts": "Get",
|
|
|
|
|
+ "/api/order.comment/list": "Get",
|
|
|
|
|
+ "/api/order.comment/submit": "Post",
|
|
|
|
|
+ # 登录
|
|
|
|
|
+ "/api/passport/login": "Post",
|
|
|
|
|
+ "/api/passport/loginMpWx": "Post",
|
|
|
|
|
+ "/api/passport/loginMpWxMobile": "Post",
|
|
|
|
|
+ "/api/passport/isPersonalMpweixin": "Post",
|
|
|
|
|
+ # 充值
|
|
|
|
|
+ "/api/recharge/center": "Get",
|
|
|
|
|
+ "/api/recharge/submit": "Post",
|
|
|
|
|
+ "/api/recharge/tradeQuery": "Get",
|
|
|
|
|
+ "/api/recharge.order/list": "Get",
|
|
|
|
|
+ # 售后
|
|
|
|
|
+ "/api/refund/list": "Get",
|
|
|
|
|
+ "/api/refund/goods": "Get",
|
|
|
|
|
+ "/api/refund/apply": "Post",
|
|
|
|
|
+ "/api/refund/detail": "Get",
|
|
|
|
|
+ "/api/refund/delivery": "Post",
|
|
|
|
|
+ # 地区
|
|
|
|
|
+ "/api/region/all": "Get",
|
|
|
|
|
+ "/api/region/tree": "Get",
|
|
|
|
|
+ # 商城 / 设置
|
|
|
|
|
+ "/api/store/data": "Get",
|
|
|
|
|
+ "/api/setting/data": "Get",
|
|
|
|
|
+ # 上传
|
|
|
|
|
+ "/api/upload/image": "Post",
|
|
|
|
|
+ # 用户
|
|
|
|
|
+ "/api/user/info": "Get",
|
|
|
|
|
+ "/api/user/assets": "Get",
|
|
|
|
|
+ "/api/user/bindMobile": "Post",
|
|
|
|
|
+ "/api/user/personal": "Post",
|
|
|
|
|
+ "/api/balance.log/list": "Get",
|
|
|
|
|
+ "/api/points.log/list": "Get",
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+ANN_RE = re.compile(r"@RequestMapping\((.*?)\)", re.S)
|
|
|
|
|
+VALUE_RE = re.compile(r'value\s*=\s*(\{[^}]*\}|"[^"]*")')
|
|
|
|
|
+PRODUCES_RE = re.compile(r'produces\s*=\s*("[^"]*"|[A-Za-z0-9_.]+)')
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def paths_of(value_expr):
|
|
|
|
|
+ return re.findall(r'"([^"]*)"', value_expr)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def norm_path(p):
|
|
|
|
|
+ """把下划线写法归一成驼峰写法,用于查表。"""
|
|
|
|
|
+ if "_" in p:
|
|
|
|
|
+ head, *rest = p.split("_")
|
|
|
|
|
+ # spec_data / sku_info / list_rows / todo_counts / set_default / default_id
|
|
|
|
|
+ return head + "".join(w[:1].upper() + w[1:] for w in rest)
|
|
|
|
|
+ return p
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def process(path: Path):
|
|
|
|
|
+ src = path.read_text(encoding="utf-8")
|
|
|
|
|
+ cls = re.search(r'^@RequestMapping\("([^"]+)"\)', src, re.M)
|
|
|
|
|
+ prefix = cls.group(1) if cls else ""
|
|
|
|
|
+ changed = 0
|
|
|
|
|
+
|
|
|
|
|
+ def repl(m):
|
|
|
|
|
+ nonlocal changed
|
|
|
|
|
+ body = m.group(1)
|
|
|
|
|
+ vm = VALUE_RE.search(body)
|
|
|
|
|
+ if not vm:
|
|
|
|
|
+ return m.group(0)
|
|
|
|
|
+ value_expr = vm.group(1)
|
|
|
|
|
+ paths = paths_of(value_expr)
|
|
|
|
|
+ full = prefix + paths[0]
|
|
|
|
|
+ key = norm_path(full)
|
|
|
|
|
+ if key not in METHODS:
|
|
|
|
|
+ raise SystemExit(f"未定义 HTTP 方法: {path.name} -> {full}")
|
|
|
|
|
+ ann = METHODS[key]
|
|
|
|
|
+ pm = PRODUCES_RE.search(body)
|
|
|
|
|
+ parts = [f"value = {value_expr}"]
|
|
|
|
|
+ if pm:
|
|
|
|
|
+ parts.append(f"produces = {pm.group(1)}")
|
|
|
|
|
+ changed += 1
|
|
|
|
|
+ return f"@{ann}Mapping({', '.join(parts)})"
|
|
|
|
|
+
|
|
|
|
|
+ new_src = ANN_RE.sub(repl, src)
|
|
|
|
|
+ if not changed:
|
|
|
|
|
+ return 0
|
|
|
|
|
+
|
|
|
|
|
+ # 清理 / 补齐 import
|
|
|
|
|
+ if "RequestMethod." not in new_src:
|
|
|
|
|
+ new_src = new_src.replace(
|
|
|
|
|
+ "import org.springframework.web.bind.annotation.RequestMethod;\n", "")
|
|
|
|
|
+ for name in ("GetMapping", "PostMapping"):
|
|
|
|
|
+ if f"@{name}(" in new_src and f"import org.springframework.web.bind.annotation.{name};" not in new_src:
|
|
|
|
|
+ new_src = new_src.replace(
|
|
|
|
|
+ "import org.springframework.web.bind.annotation.RequestMapping;",
|
|
|
|
|
+ f"import org.springframework.web.bind.annotation.{name};\n"
|
|
|
|
|
+ "import org.springframework.web.bind.annotation.RequestMapping;", 1)
|
|
|
|
|
+ # import 块按字母排序
|
|
|
|
|
+ lines = new_src.split("\n")
|
|
|
|
|
+ idx = [i for i, ln in enumerate(lines) if ln.startswith("import ")]
|
|
|
|
|
+ if idx:
|
|
|
|
|
+ start, end = idx[0], idx[-1]
|
|
|
|
|
+ block = lines[start:end + 1]
|
|
|
|
|
+ if all(ln.startswith("import ") for ln in block):
|
|
|
|
|
+ lines[start:end + 1] = sorted(set(block))
|
|
|
|
|
+ new_src = "\n".join(lines)
|
|
|
|
|
+ path.write_text(new_src, encoding="utf-8")
|
|
|
|
|
+ return changed
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+total = 0
|
|
|
|
|
+for f in sorted(CTRL_DIR.glob("*.java")):
|
|
|
|
|
+ if f.name == "ApiNotifyController.java":
|
|
|
|
|
+ continue
|
|
|
|
|
+ n = process(f)
|
|
|
|
|
+ if n:
|
|
|
|
|
+ print(f"{f.name}: {n}")
|
|
|
|
|
+ total += n
|
|
|
|
|
+print("合计:", total)
|