import json, subprocess, tempfile, os from urllib.parse import quote # 中文查询参数必须预先百分号编码:Windows 下 curl 会把 argv 里的中文按 GBK 转码, # 直接写中文进 URL 会变成乱码查不到数据(与请求体同样的坑,请求体走 --data-binary @文件)。 def q(text): return quote(text, encoding='utf-8') def kw(value): # 方括号必须百分号编码(参数名前端的 tansParams 就是 encodeURIComponent(键)), # 原样写 params[keyword]= 会被 Tomcat 以 400 Bad Request 拒掉 return 'params%5Bkeyword%5D=' + q(value) def api(method, url, body=None): cmd = ['sh', '.tmp_api.sh', method, url] tmp = None if body is not None: fd, tmp = tempfile.mkstemp(suffix='.json') with os.fdopen(fd, 'w', encoding='utf-8') as f: json.dump(body, f, ensure_ascii=False) cmd.append(tmp) out = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8').stdout.strip() if tmp: os.remove(tmp) try: return json.loads(out) except Exception: return {'raw': out} def show(tag, res, keys=None): if 'code' in res: msg = res.get('msg') extra = '' if keys: extra = ' | ' + str({k: res.get('data', {}) and (res['data'][k] if isinstance(res['data'], dict) else None) for k in keys}) print(f'{tag}: code={res["code"]} msg={msg}{extra}') else: print(f'{tag}: {str(res)[:200]}') print('=== A. 城市列表与筛选 ===') r = api('GET', '/account/user/city/list?pageNum=1&pageSize=50') print('A1 全部(未删除)total =', r['total'], '(期望 28 = 27正常 + 1禁用)') r = api('GET', '/account/user/city/list?' + kw('杭州')) print('A2 keyword=杭州 total =', r.get('total', r), '首行 =', [(x['province'], x['cityName']) for x in r.get('rows', [])]) r = api('GET', '/account/user/city/list?' + kw('广东')) print('A3 keyword=广东 total =', r.get('total', r), '(按省份模糊匹配)') r = api('GET', '/account/user/city/list?status=1') print('A4 status=1 total =', r['total'], [(x['cityName'], x['status']) for x in r['rows']]) r = api('GET', '/account/user/city/list?pageNum=1&pageSize=5') print('A5 分页 pageSize=5 -> rows =', len(r['rows']), 'total =', r['total']) print() print('=== B. 新增校验 ===') show('B1 同名', api('POST', '/account/user/city', {'province': '浙江省', 'cityName': '杭州'})) show('B2 缺省', api('POST', '/account/user/city', {'cityName': '测试市'})) show('B3 缺市名', api('POST', '/account/user/city', {'province': '测试省'})) r = api('POST', '/account/user/city', {'province': '广东省', 'cityName': '珠海', 'sortNo': 999}) show('B4 新增珠海', r) print() print('=== C. 修改 / 状态 / 删除(自建数据,用完清理) ===') r = api('GET', '/account/user/city/list?' + kw('珠海')) cid = r['rows'][0]['id'] if r.get('rows') else None print('C0 新增后的 id =', cid) show('C1 改名成珠海市(同名查重排除自身)', api('PUT', '/account/user/city', {'id': cid, 'province': '广东省', 'cityName': '珠海'})) show('C2 改成已存在的城市名', api('PUT', '/account/user/city', {'id': cid, 'province': '广东省', 'cityName': '杭州'})) show('C3 不存在的 id', api('PUT', '/account/user/city', {'id': 999999, 'province': '广东省', 'cityName': '珠海'})) show('C4 非法状态', api('PUT', '/account/user/city/changeStatus', {'id': cid, 'status': '9'})) show('C5 禁用', api('PUT', '/account/user/city/changeStatus', {'id': cid, 'status': '1'})) opts = api('GET', '/account/user/city/options')['data'] print('C6 禁用后是否还在 options 里 =', any(x['id'] == cid for x in opts)) show('C7 启用', api('PUT', '/account/user/city/changeStatus', {'id': cid, 'status': '0'})) print('C8 删除被档案引用的城市(杭州 id=113):', end=' ') show('', api('DELETE', '/account/user/city/113')) print('C9 删除无引用的城市(珠海 id=%s):' % cid, end=' ') show('', api('DELETE', '/account/user/city/%s' % cid)) r = api('GET', '/account/user/city/list?pageNum=1&pageSize=50') print('C10 清理后 total =', r['total'], '(期望回到 28)') r = api('GET', '/account/user/city/list?' + kw('珠海')) print('C11 已删除的珠海是否还在列表 =', r.get('total', 0) > 0, '(期望 False)')