# 第 3 批接口移植报告(权限管理 / 商城地址 / 页面装修 / 内容管理) 更新时间:2026-10-17 工程:`java-rewrite/yoshop-java`(Spring Boot 3.2.5 + MyBatis-Plus) ## 一、本批新增接口(21 个) | 模块 | 接口 | 说明 | |---|---|---| | 权限-角色 | `/store/store.role/add` `/edit` `/delete` | 角色树增删改,菜单权限差集同步 `yoshop_store_role_menu` | | 权限-管理员 | `/store/store.user/add` `/edit` `/delete` `/renew` | 账号增删改、当前登录人改资料(同步刷新登录态缓存) | | 商城地址 | `/store/store.address/add` `/edit` `/delete` | 省市区 `cascader` 拆成 province/city/region 三列落库 | | 页面装修 | `/store/page/defaultData` `/detail` `/add` `/edit` `/delete` `/setHome` | 默认组件库、默认值合并、富文本解码、首页唯一性 | | 帮助中心 | `/store/content.help/add` `/edit` `/delete` | | | 文章分类 | `/store/content.article.category/add` `/edit` `/delete` | 删除前校验分类下文章数 | | 文章管理 | `/store/content.article/detail` `/add` `/edit` `/delete` | 详情返回 `content`(实体解码)、`image` 对象、`image_url`、`show_views` | 顺带修正的既有行为:`/store/store.address/all`、`/list` 之前忽略 `type`(10 发货 / 20 退货)与 `search`(收货人 / 电话)筛选参数,已按 PHP `Address::getFilter` 补齐。 ## 二、关键实现点 ### 1. 统一响应体:成功提示语要放 `message` PHP `renderSuccess('添加成功')` 会把字符串参数**当成提示语**: ```json {"status":200,"message":"添加成功","data":[]} ``` Java 之前写成 `R.ok("添加成功")`,结果提示语跑进了 `data`,`message` 仍是 `success`——前端 `message.success(res.message)` 就会弹出 "success"。已新增 `R.okMsg(String)` 并替换全部写接口,同时把方法返回类型由 `R` 改为 `R`。 ### 2. 页面装修的默认值合并(resetOptions) `page_data` 在库里是 JSON 字符串,出参却是「默认值 + 实际值」合并后的对象。PHP 的 `resetOptions()` 语义有三处容易踩: - 键顺序以**默认值**为准,实际值多出来的键追加在尾部; - 两边都是数组时:默认值是**关联数组**则递归合并,是**索引数组**(如 `data`、`items`)则整体用实际值覆盖; - 取值为 `null` 时回退到默认值(`??` 语义)。 已抽到 `common/util/PhpArray.reset()` 复用。默认组件库(20 种组件)以 PHP `getDefaultItems()` 的实际输出落成 `resources/page/default-data.json`,图片地址用 `{{BASE}}` 占位、运行时替换 `yoshop.base-url`,避免换域名后图片 404。 ### 3. 口令哈希与 PHP 互认 PHP `encryption_hash()` = `password_hash($pwd, PASSWORD_DEFAULT)` → bcrypt cost 10、前缀 `$2y$`。Java 用 `BCrypt.hashpw(..., gensalt(10))` 生成 `$2a$`,算法一致但与库内历史数据不同构,统一转成 `$2y$`(`common/util/PasswordUtil`)。 **实测**:Java 新增的管理员账号可以直接用 PHP 端 `password_verify()` 校验通过(反向也成立),因此迁移期两套后端共存不会出现"改了密码另一边登不上"。 ### 4. 关联表的差集同步 管理员-角色、角色-菜单的编辑都走「差集删除 + 差集新增」,而不是先清空再插入——保证关联行 `id` 稳定,与 PHP `UserRole::updates()` / `RoleMenu::updates()` 行为一致。 ### 5. 软删除要显式写 `update_time` `yoshop_store_user` / `yoshop_store_address` / `yoshop_page` / `yoshop_help` / `yoshop_article` 的 `is_delete` 是 0/1(不是商品的 10/30)。删除统一用 `lambdaUpdate().set(is_delete, 1).set(update_time, now)`,避免 MyBatis-Plus 的 `@TableLogic` 在 `updateById` 时把逻辑删除列一起塞进 SET 造成歧义。 ## 三、校验结果 ### 读接口逐字段对比(30 个,全部 PASS) - 第 1、2 批 28 个接口:`tools/compare_batch.py` → **28/28 PASS,差异 0** - 本批新增:`tools/compare_batch3.py` - `/store/page/defaultData` → 0.7 万字符默认组件库,与 PHP 逐字段一致 - `/store/page/detail?pageId=10001` → 合并后的 `page_data` 逐字段一致(合并算法正确性由此验证) ### 写接口端到端自测(62 项断言,全部通过) `tools/test_batch3_writes.py`(38 项)+ `tools/test_content_writes.py`(24 项),覆盖:新增 → 落库校验 → 编辑生效 → 删除 → 删除后不可见,以及 8 类异常文案: | 场景 | 期望提示 | |---|---| | 角色未选菜单 | 菜单权限不能为空,请重新选择 | | 用户名重复 | 用户名已存在 | | 两次密码不一致 | 确认密码不正确 | | 管理员未选角色 | 请选择所属角色 | | 删除默认首页 | 默认首页不可以删除 | | 文章缺封面图 | 请上传封面图 | | 文章缺内容 | 请输入文章内容 | | 删除被引用的文章分类 | 该分类下存在 N 个文章,不允许删除 | 另外校验了:`user_name` 自动转小写、`cascader → province/city/region_id` 拆分、地址 `full_address` 组装、`type`/`search` 过滤、页面 `page_data` 合并、文章详情 `content` 的 HTML 实体解码、`show_views = virtual + actual`。 **所有测试数据均在脚本末尾清理并复核**,库内未残留(备份见 `java-rewrite/backup/*.json`)。 ## 四、整体进度 按 `API清单.csv`(store 模块 151 个接口): - 已实现 **81** 个(含 `default_data`/`set_home`/`move_group` 等 ThinkPHP 下划线写法的等价路由) - 待实现 **约 70** 个,集中在: | 优先级 | 模块 | 接口 | |---|---|---| | 高 | 商品 | add / edit / state / delete / basic / list_by_ids、goods.spec/list、goods.comment/\* | | 高 | 订单 | order.event/\*(改价、备注、改地址、取消、删除、打印)、order.delivery/\*、order.refund/\*、order.export/\* | | 高 | 上传 | upload/image、upload/video | | 中 | 设置 | setting.payment/options+update、payment.template/\*、delivery 增删改查、express 增删改、printer 增删改 | | 中 | 营销 | market.coupon add/edit/detail/delete/receive、market.recharge.plan add/edit/delete | | 中 | 会员 | user.delete、user.grade(改等级)、user.recharge/\*、user.grade add/edit/delete | | 低 | 统计 | statistics.data/initialize+data+survey | | 低 | 客户端 | client.h5.setting/\*、client.wxapp.setting/\* | 另外 **`checkPrivilege`(API 级权限拦截)仍未实现**,上线前必须补:目前只校验登录态,低权限角色会比 PHP 端多访问到接口。 ## 五、复跑方式 ```bash cd java-rewrite/tools python compare_batch.py # 28 个读接口逐字段对比 python compare_batch3.py # 页面装修对比 python test_batch3_writes.py # 权限/地址/页面 写接口自测(自动清理) python test_content_writes.py # 内容模块写接口自测(自动清理) python check_progress.py # 接口实现进度盘点 ```