# Java 后端接口实现进度(第 2 批) > 对照基准:线上 PHP 站点 `https://shop.qinys.cn`(同一套库、同一份数据) > 校验方式:逐个接口抓 PHP 黄金样本 → Java 同参数请求 → 递归逐字段 diff(`tools/compare_batch.py`) > 最近一次运行:**28 个接口全部 PASS,0 差异** ## 一、本次修复:`/store/store/info` 报 500 **根因**:该路由此前没有实现。Spring 找不到处理器时抛 `NoResourceFoundException`,被全局异常兜底成 `{"status":500,"message":"服务器内部错误"}`,前端只看到 500,无法判断是"没实现"还是"真报错"。 **修复**: 1. 新增 `StoreController`(`/store/store/info`、`/store/store/update`),出参与 PHP `Store::info` 一致: `{"storeInfo":{...,"logoImage":null}}`。 2. `GlobalExceptionHandler` 增加 `NoResourceFoundException` 专门处理,未实现的路由现在返回 `{"status":500,"message":"接口未实现:/store/xxx/yyy"}`,一眼能定位。 > 注意路由规则:PHP 的 URL 是「模块 + 控制器 + 方法」,所以前端 `api/store/store/info` > 对应 Java 的 `/store/store/info`(第一个 `store` 是模块,第二个是控制器 `Store.php`); > 多级控制器写成点号,如 `/store/goods.service/list`、`/store/store.menu/list`。 ## 二、本次新实现并通过 0 差异校验的接口 | 接口 | 说明 | |---|---| | `GET /store/store/info` | 商城信息(含 logoImage) | | `POST /store/store/update` | 更新商城信息 | | `GET /store/store.menu/list` | 后台菜单树(含 menuApi / apiIds,过滤空操作菜单) | | `GET /store/store.role/list` | 角色树(含 roleMenu / menuIds) | | `GET /store/store.user/list` | 管理员列表(含 role / roleIds) | | `GET /store/category/list` | 商品分类树(含 image / children) | | `POST /store/category/add\|edit\|delete` | 分类增删改(含"上级不能设为自己子级""被商品引用不能删"校验) | | `GET /store/goods.service/list\|all` | 商品服务(保障服务) | | `POST /store/goods.service/add\|edit\|delete` | 商品服务增删改(软删除) | | `GET /store/files/list` | 文件库列表(类型/分组/来源/回收站筛选,15 条分页) | | `GET /store/files.group/list` | 文件分组树 | | `POST /store/files.group/add\|edit\|delete` | 分组增删改(删组时文件归还"未分组") | | `POST /store/files/edit\|delete\|moveGroup` | 文件改名/批量删除(≤15)/移动分组 | | `GET /store/region/all` | 全部地区(约 240KB,key 为地区 ID) | | `GET /store/region/tree` | 地区树(省→city→region) | | `GET /store/user/list` | 会员列表(昵称/手机号/性别/等级/注册时间筛选) | | `GET /store/user.grade/all\|list` | 会员等级(upgrade / equity 由 JSON 串转对象) | | `GET /store/order/list?dataType=` | 订单列表(paginate(10),7 种 dataType,6 种关键词检索) | | `GET /store/order/detail` | 订单详情(goods / user / address / trade) | | `GET /store/setting/detail` | 设置项(无该项时 `values: []`) | | `POST /store/setting/update` | 更新设置项 | | `GET /store/setting.cache/items` | 缓存清理项 | | `GET /store/setting.delivery/all\|list` | 配送模板 | | `GET /store/setting.express/all\|list` | 物流公司 | | `GET /store/setting.printer/all\|list` | 打印机 | | `GET /store/store.address/all\|list` | 商城地址(cascader / region / full_address) | | `GET /store/page/list` | 页面列表(不含 page_data 长文本) | | `GET /store/content.article/list` | 文章列表(不含 content,含 image / category) | | `GET /store/content.article.category/list` | 文章分类 | | `GET /store/content.help/list` | 帮助列表 | | `GET /store/market.coupon/list` | 优惠券列表 | | `GET /store/market.points/log` | 积分明细(含会员) | | `GET /store/market.recharge.plan/list` | 充值套餐 | | `GET /store/user.balance/log` | 余额明细(含会员) | ## 三、本批踩到的"出参差异坑"(已在代码里注释) | 现象 | 处理 | |---|---| | PHP 关联字段名是 camelCase(`logoImage`、`menuApi`、`roleMenu`、`menuIds`、`roleIds`、`apiIds`) | Jackson 全局 SNAKE_CASE 会把它们变成 `logo_image`,逐个加 `@JsonProperty("xxxYyy")` | | 菜单无 api 绑定时 PHP 输出 `"apiIds": []`、`"menuApi": []` | 关联设为空 List,不用 null | | 订单 `update_price` 是对象 `{symbol,value}` | 用 `getUpdatePriceVo()` 组对象 | | 订单 `pay_time/delivery_time/receipt_time` 为 0 时输出 `""` | `TimeUtil.formatOrBlank()`(对齐 PHP `format_time()`) | | 订单 `order_source_data` 库内是 json 串,出参是数组 | 出参时 JSON 解析,空串返回 `[]` | | 订单/流水里的 `user` 只 with 了 avatar,没有 `grade` 键 | `UserLiteSerializer` 序列化后剔除 `grade` | | 订单商品 `content` 列表不返回 | 查询排除 + `@JsonInclude(NON_NULL)` | | `yoshop_store_setting` 主键是字符串 `key` | `@TableId(value="`key`", IdType.INPUT)`,更新走条件更新 | ## 四、尚未实现的接口(下一批) 按页面优先级排序: 1. **商品新增/编辑**:`goods/add`、`goods/edit`、`goods/delete`、`goods/state`、`goods/basic`、`goods/list_by_ids` 2. **订单操作**:`order.event/*`(确认取消、改价、改地址、备注、打印)、`order.refund/*`、`order.delivery/*` 3. **文件上传**:`upload/image`、`upload/video`(需要落盘 + 写 `yoshop_upload_file`) 4. **设置-支付**:`setting.payment/options`、`setting.payment.template/*` 5. **统计**:`statistics.data/survey`、`statistics.data/initialize` 6. **CRUD 补齐**:文章/帮助/优惠券/充值套餐/页面/配送模板/物流公司/打印机/角色/管理员的 add|edit|delete 7. **API 级权限**:PHP 的 `checkPrivilege()`(按角色校验 `store_api`),当前只校验登录态 ## 五、怎么跑 ```bash # 后端 cd F:\shop\java-rewrite\yoshop-java mvn spring-boot:run -Dspring-boot.run.arguments="--server.port=18080 --yoshop.auth.mode=file --yoshop.auth.runtime-cache-path=F:/shop/java-rewrite/runtime/cache" # 前端 cd F:\shop\yoshop2.0-store NODE_OPTIONS=--openssl-legacy-provider ./node_modules/.bin/vue-cli-service serve # 8120 # 回归对比(需本地 Java 服务 + golden 样本) cd F:\shop\java-rewrite\tools python compare_batch.py ``` > 本机有系统代理(`HTTP_PROXY=127.0.0.1:xxx`),会让 `127.0.0.1` 也走代理并返回 502, > 联调脚本里已用 `trust_env = False`;手工 curl 记得加 `--noproxy '*'`。