TinyPro v1.4.0 发布有段时间了,我自己在几个内部项目和外包项目里已经跑了一轮,今天把升级体验和踩坑记录整理出来。如果你正在做中后台管理系统、Admin 类项目,或者刚好在纠结"前端脚手架怎么和后端工程打通""移动端适配到底要做到什么程度",这篇应该能帮你少走不少弯路。
先交代一下背景。TinyPro 本身是一套中后台前端解决方案,核心思路是"通用模板 + 页面级代码生成",你选好页面类型,它自动生成对应的 React/Vue 代码、路由配置、权限配置和 API 封装。v1.4.0 这次升级,亮点是三条:正式支持 Spring Boot 后端工程联动、移动端适配、新增卡片列表和高级表单两套页面模板。实际用下来,这三条正好卡在很多团队的痛点上——前端模板不缺,缺的是和 Java 后端那套东西的衔接方案;PC 端页面不缺,缺的是手机浏览器上真正能用的后台页面;表格页不缺,缺的是展示密度更高、对用户更友好的卡片式布局。
接下来我会从整体设计思路讲起,然后分别拆解 Spring Boot 支持、移动端适配、新增页面这三块的核心实现,最后集中整理我实际测试中遇到的问题和排查过程。全程基于 v1.4.0 的真机实操,不写空话。
1. 整体设计与版本思路拆解
1.1 TinyPro 到底解决了什么问题
很多团队做中后台项目,流程是固定的:先搭前端脚手架,再手写列表页、表单页、详情页,然后联调后端接口,最后调整样式适配不同屏幕。这套流程本身不复杂,但重复度极高。同一个后台管理系统,换个项目换个甲方,80% 的页面长得差不多,逻辑也差不多——列表要分页、要有筛选、要有操作列;表单要有校验、要有提交、要有成功提示。
TinyPro 解决的就是这 80% 的重复工作。它把你需要的常见页面类型模板化,通过配置和生成的方式产出可用代码,而不是让你从零开始写。v1.4.0 之前,它主要覆盖列表页、表单页、详情页、嵌套页这些基础场景;这次升级新增的卡片列表和高级表单,是把"展示密度"和"交互复杂度"这两块短板补上了。
但光有前端不够。中小团队最常见的尴尬是:前端模板选好了,后端却还在用 Spring Boot + MyBatis 的老一套,两边数据结构对不上,前端生成的代码根本跑不起来。v1.4.0 的"支持 Spring Boot"不是简单加一个后端依赖,而是把前后端联动作为一等公民来处理,从工程生成、接口定义到数据模拟,全部打通。
1.2 为什么 Spring Boot 是绕不开的选项
国内中后台项目里,Java 后端的占比不用多说。Spring Boot + MyBatis 的组合,在相当长一段时间里是中小型系统和外包项目的标配。虽然现在有 Spring Cloud、微服务、Go、Node 这些新的选择,但存量项目、人力储备、招人难度这些现实因素摆在那里,大多数团队的默认技术栈依然是 Spring Boot。
TinyPro 选择在 v1.4.0 明确支持 Spring Boot,本质上是在回应这个现实。我在实际项目里体会最深的一点是,它不是在"支持某一种后端语言",而是在"支持一套完整的工程协作方式"——前端生成的 API 调用代码,能直接对应到后端 Controller 方法;后端生成的代码,自带规范的分层结构和数据库访问层。以前两头各写各的,现在中间那层"接口契约"被工具固定下来了,联调成本直线下降。
1.3 v1.4.0 版本规划的三个维度
这次版本更新,可以沿着三条线去看:
第一是工程链路线。从"前端模板代码"扩展为"前后端一体工程生成",新增 Spring Boot 后端代码生成器,并且让前端 API 模块自动关联 Mock 数据和真实后端接口,切换零成本。
第二是终端适配线。从"只保证 PC 浏览器正常显示"升级为"响应式布局 + 触控交互适配",在平板和手机浏览器上也能正常完成查询、录入、审批这类操作。
第三是页面场景线。在原有标准列表页和基础表单页之外,新增卡片列表和高级表单,分别应对"图片/富文本内容展示"和"复杂业务录入"这两类高频场景。
这三条线是并行推进的,也因为这样,v1.4.0 实际发版后涉及的改动面比之前几个版本大不少。下面我逐个章节展开讲讲每条线背后的设计逻辑和实施要点。
2. Spring Boot 支持:前端工程与 Java 后端如何真正打通
2.1 代码生成器的分层设计思路
v1.4.0 在创建项目时增加了一个关键选项:是否生成配套的 Spring Boot 后端工程。我实测时选择生成完整前后端结构,得到的结果是比较标准的 Maven 多模块工程:
backend-parent ├── backend-common // 通用工具、异常、返回结构 ├── backend-system // 系统管理:用户、角色、菜单 ├── backend-business // 业务模块,按需生成 └── backend-admin // Web 入口,Spring Boot 启动类每个模块内部按 Controller -> Service -> Mapper 分层,Mapper 层基于 MyBatis,支持 XML 和注解两种方式。前端工程则保持独立,通过 API 模块和后端对接。这种前后端分离但工程可联动的结构,是我比较认可的一种方式——前端可以独立部署到 Nginx,后端独立打包成 Jar,两边互不阻塞。
官方在生成器中内置了业界常见的实现思路:用 Velocity 模板渲染 Java 文件,根据数据库表结构反推实体字段类型,并自动生成增删改查接口。这一点值得展开说下,因为"工具能生成代码"并不稀奇,真正有价值的是它生成的代码长什么样、规范不规范。
2.2 数据库表到接口的通关流程
我在测试环境里准备了一张用户表,包含 id、username、email、status、create_time 等字段,走了一遍完整流程:
第一步,在生成器界面选择"Spring Boot + MyBatis"后端模板,填写数据库连接信息,选择要生成的表。
第二步,生成器读取表结构,自动完成字段类型映射。这里有个细节我特意核对了:数据库的 datetime 类型映射为 Java 的 LocalDateTime,而不是早期的 Date;tinyint 映射为 Integer,而不是 Boolean。这个映射策略对 MyBatis 使用者来说更实用,因为很多业务字段用 tinyint 存储多位状态值,硬映射为 Boolean 反而要改代码。
第三步,生成标准接口。最终得到的接口风格是 RESTful 的:
@RestController @RequestMapping("/api/user") public class UserController { @Resource private UserService userService; @GetMapping("/page") public Result<PageResult<UserVO>> page(UserQuery query) { return Result.success(userService.page(query)); } @PostMapping public Result<Void> create(@Validated @RequestBody UserDTO dto) { userService.create(dto); return Result.success(); } @PutMapping("/{id}") public Result<Void> update(@PathVariable Long id, @Validated @RequestBody UserDTO dto) { userService.update(id, dto); return Result.success(); } @DeleteMapping("/{id}") public Result<Void> delete(@PathVariable Long id) { userService.delete(id); return Result.success(); } }这里我注意到一个细节,生成的分页查询返回结构统一为 PageResult 对象,包含 total 和 records 两个字段。这和前端列表页的分页组件默认数据结构完全对齐,意味着前端拿到数据直接塞进表格/列表组件即可,不需要再写一层适配转换。
第四步,前端 API 模块自动生成对应的方法:
export function pageUser(params: UserQuery) { return request.get<PageResult<UserVO>>('/api/user/page', { params }); } export function createUser(data: UserDTO) { return request.post('/api/user', data); }前端方法的函数名、参数类型、返回类型,都是根据后端接口定义自动生成的,两边对应关系一目了然。我在多个项目里的体会是,这一步省掉的不仅是手写 API 文件的时间,更重要的是省掉了"前后端字段名不一致"这种低级联调问题。
2.3 Mock 数据与真实后端切换的无缝方案
实际开发中,前后端不可能同时完成。v1.4.0 延续了 Mock 优先的策略,并且在这次版本中做了一层更细致的处理:前端生成的 API 模块,默认指向 Mock;后端工程就绪后,只需修改一个配置文件就能切到真实接口。
这个配置我贴一下:
// .env 文件 // 开发环境默认走 Mock VITE_USE_MOCK = true // 切到真实后端时改为 false VITE_USE_MOCK = false VITE_API_BASE_URL = '/api'同时开发服务器配置了代理,将/api前缀的请求转发到localhost:8080,也就是 Spring Boot 服务的地址。整条链路从浏览器到前端 dev server,再到后端接口,中间没有跨域问题。
我在切换过程中没遇到什么坑,因为这背后是一套约定:前端所有请求方法统一从request实例发出,而request内部根据VITE_USE_MOCK决定走本地 Mock 模块还是真实 HTTP 请求。这样业务代码从头到尾不需要改,切换只是环境变量的事。这点对于团队协作特别重要,前端开发不会被后端阻塞,后端开发也不会被前端催促。
2.4 登录鉴权与 Spring Security/Interceptor 的选择
新版本的后端工程里,登录鉴权默认实现是基于拦截器 + JWT 的轻量方案,而不是直接引入 Spring Security。我在内部评审时有人问过为什么不用 Spring Security,这里说下我的理解和实际考量。
Spring Security 功能强大,但学习成本和配置复杂度都很高,对中小型后台系统来说,很多特性是用不上的。轻量方案用拦截器校验 Token,配合自定义注解做权限控制,代码量小、逻辑直观、调试方便,对团队里经验不一的开发者也更友好。
具体实现思路如下:登录接口验证用户名密码成功后,签发 JWT,后续请求在 Header 中携带Authorization: Bearer <token>,拦截器解析并校验,将用户信息放入 ThreadLocal 供业务层使用。
这里我分享一个我在测试中发现的注意点。拦截器默认对/api/**路径生效,但如果你的业务里有文件上传下载、定时任务回调这类不需要鉴权的接口,一定要在排除名单里显式配置。我在测试文件下载功能时,因为忘记在排除名单里加白名单,导致下载链接返回 401,排查了好一会儿。这类细节在文档里往往不会强调,实际跑到就会遇到。
2.5 集成 MyBatis 时容易忽略的三个细节
后端工程基于 MyBatis,这里我补充三个我在测试中实际碰到的问题,都是常规文档不会写但很容易出错的地方。
第一个是下划线转驼峰。很多表字段都是 create_time、update_time 这种命名,如果 MyBatis 没开启驼峰映射,查询结果直接映射到实体类时,createTime 会是 null。检查配置:
mybatis: configuration: map-underscore-to-camel-case: true第二个是主键回填。生成的 Mapper 里插入语句默认使用useGeneratedKeys="true"和keyProperty="id",这样插入后实体的 id 字段会被自动填上。我自己写代码时偶尔会忘,生成器直接生成好这一点很省心。
第三个是逻辑删除。新版生成器在数据库表中有 deleted 字段时,会自动在查询语句里拼接WHERE deleted = 0条件,并在删除方法上改为UPDATE语句。这个功能默认开启,但注意它同时要求你的表确实存在 deleted 字段,否则生成报错。如果你不想用逻辑删除,需要在生成前手动关闭。
这三个细节看起来不起眼,但对联调和数据正确性影响很大。建议第一次使用 Spring Boot 后端生成的团队,先把这三条确认好再开始写业务。
3. 移动端适配:从"能看"到"能用"
3.1 断点策略与栅格重构
中后台系统做移动端适配,难点往往不在技术,而在产品定位——你是要完整支持手机端操作,还是只保证"紧急场景下能看看数据、批个流程"。TinyPro v1.4.0 的做法是两者兼顾:小屏下布局自动切换,常用操作保留,但隐藏一些重度功能入口。
栅格系统是这套适配的地基。新版本将页面容器重构为标准 24 列栅格,并定义了四个断点:
| 断点 | 屏幕宽度 | 典型设备 | 页面布局策略 |
|---|---|---|---|
| xs | < 576px | 手机竖屏 | 单列布局,表格转为卡片,抽屉全屏 |
| sm | >= 576px | 大屏手机/小平板 | 单列为主,局部两列 |
| md | >= 768px | 平板竖屏 | 两列布局,保留侧边栏 |
| lg | >= 992px | 平板横屏/小笔记本 | 三列到四列,接近桌面端 |
实际开发中,我强烈建议把断点值做成常量统一管理,而不是散落在各个样式文件里。v1.4.0 是把断点定义放在主题配置中,页面组件统一引用,这样调整断点时只需要改一处。
页面的侧边栏处理也值得说。桌面端最常见的后台布局是"左侧菜单 + 右侧内容",但到了手机端,左侧菜单占用的空间不可接受。新版本在 xs 断点下自动将侧边栏收起,变为抽屉式导航,由顶部汉堡按钮触发。这个交互是移动端后台的标准做法,好处是内容区域完整保留,操作路径清晰。
3.2 表格组件在手机端的交互改造
列表页在桌面端的主力组件是表格,但表格天然不适合小屏。v1.4.0 在移动端对表格做了两层处理,这也反应了这套适配的细致程度。
第一层:列裁剪。默认只渲染关键列,其余列收纳到"更多"操作里。比如用户列表,桌面端显示用户名、邮箱、手机号、状态、创建时间、操作六列;手机端只显示用户名、状态和操作,邮箱手机号这些信息点击"详情"查看。这个策略不是简单用 CSS 隐藏列,而是在渲染层面根据断点动态判断,减少 DOM 节点数量和渲染压力。
第二层:切换为卡片展示。这在 v1.4.0 里默认绑定在 xs 断点下,表格自动变成纵向信息流,每条记录渲染为一张小卡片,关键字段以标签形式并排。实测体验比横向滚动表格好得多,起码拇指能够到,不用左右滑。
这里有个值得注意的取舍:TinyPro 没有做"把表格横过来"的方案,也就是保持表格原样加横向滚动。这种方案在技术实现上最简单,但移动端体验极差,用户在手机上左右滑动查看字段很容易失去焦点。我见过不少项目选择这条路,然后被业务方反复吐槽。v1.4.0 直接做了卡片化切换,是真正从使用场景出发的决策。
3.3 弹窗、抽屉与表单输入适配
移动端页面里,弹窗的尺寸策略也需要专门处理。桌面端一个 Modal 通常居中出现,宽度 520px 左右;到了手机端,如果还保持这种样式,弹窗四周留白,视觉上又小又难受。v1.4.0 的处理是:小屏下 Modal 自动改为底部弹出面板,类似移动端原生动作面板,宽度占满屏幕,圆角顶部。实测交互手感接近原生 App,比居中弹窗舒服太多。
抽屉组件的逻辑类似。桌面端抽屉通常从右侧滑出,宽度 300px 左右;移动端改为全屏抽屉,几乎等同于新开一页。这样设计的好处是,复杂筛选表单在抽屉里有足够的空间展示,用户的操作路径不会被打断。
表单输入的适配重点在键盘。数字输入框会自动设置inputmode,手机端呼出数字键盘;日期选择用组件库自带的移动端滚动选择器替代桌面端弹层。我在测试时发现一个细节,小屏下表单的按钮区固定在底部,而不是跟随内容滚动,这样用户填完表单不用翻到页面底部去点提交。这个细节看起来简单,但对长表单的体验提升非常明显。
3.4 移动端性能优化与实测数据
移动端性能是这个版本另一个下功夫的点。中后台页面通常数据量不小,图片、表格、图表并存,手机浏览器性能弱于桌面浏览器,不做优化很容易卡顿。
我在测试环境用低端安卓机(骁龙 680 级别)跑了几个核心页面,和旧版本对比如下:
| 页面类型 | v1.3.0 首屏耗时 | v1.4.0 首屏耗时 | 主要优化手段 |
|---|---|---|---|
| 标准列表页 | 3.2s | 1.8s | 按需加载、减少首屏请求数 |
| 卡片列表页 | 无 | 2.1s | 图片懒加载、虚拟滚动 |
| 数据分析页 | 4.5s | 2.6s | 图表按需引入、数据分片渲染 |
| 高级表单页 | 无 | 1.5s | 步骤表单分步加载 |
其中最有价值的是虚拟滚动。卡片列表在切换到移动端后,如果一次性渲染上百张卡片,DOM 数量太多,滚动掉帧明显。引入虚拟滚动后,屏幕外元素被回收,实际渲染节点维持在 20 到 30 个左右,滚动流畅度提升了一个量级。这个方案在桌面端也同样受益,本质上是大列表渲染的通用解法。
代码分割方面,新版本默认按路由懒加载,首屏只加载当前页面的代码,其他页面按需加载。图表库单独拆包,避免把整个 echarts 打进主包里。这些手段听起来基础,但很多中后台模板并没有默认做好,需要使用者自己优化,TinyPro 这次直接内置了。
4. 新增页面一:卡片列表的应用场景与实现
4.1 什么样的业务适合卡片列表
卡片列表并不是所有场景都适用。我在项目里最常见的误用场景是:把纯文本、字段密集的数据也强行做成卡片,结果信息密度极低,一屏只能看两三条,用户反而要找更多次。
卡片列表真正擅长的是"以内容展示为主"的业务。典型场景包括:商品管理(需要展示图片、价格、库存)、内容管理(文章缩略图、标题、摘要)、任务中心(任务封面、状态、操作按钮)、团队成员(头像、姓名、角色标签)。这些业务的共同点是,每条数据都有一个可视化主体,用户的第一反应是"看"而不是"找"。
反过来说,用户列表、订单列表这种字段固定、以批量密集查看为目标的场景,标准表格更合适。v1.4.0 同时保留标准列表页和新增卡片列表页,并不是用卡片取代表格,而是根据业务形态提供不同的展示解法。选型的时候搞清楚业务本质,才不会做无效设计。
4.2 卡片布局的核心实现思路
卡片列表页在代码层面是一个独立模板,核心结构分为三块:筛选区、卡片容器、加载状态。
筛选区在桌面端展示在页面顶部,移动端自动收纳为抽屉。筛选条件和标准列表页的区别在于,卡片页的筛选条件通常更少、更宽松,一般只有关键词搜索和两三个状态选择。因为卡片列表本身信息密度低,用户不太可能通过大量筛选条件精确定位,他们更多是"看到哪张是哪张"。
卡片容器的核心是栅格自适应。桌面端一行显示 4 张卡片,平板显示 2 到 3 张,手机端显示 1 张。这里不是简单 CSS 百分比,而是结合断点动态计算卡片的最小宽度:
.card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; }minmax(280px, 1fr)的意思是每张卡片最小宽度 280px,如果容器够宽,自动多放几列;不够宽就换行。这样不需要写多个媒体查询,栅格自动适配。
加载状态方面,卡片列表用的是滚动加载而不是分页。原因是卡片的高度固定,滚动加载的用户体验更接近信息流,不需要点击分页按钮。当然这也要求后端接口支持游标或者页码参数,我在对接后端时直接用了生成器提供的page接口,配合滚动到底部自动加载下一页,整个过程没有额外开发。
4.3 卡片交互里的关键细节
卡片列表的交互细节比表格多,下面几个是我在实际使用中认为最关键的。
卡片悬浮操作与常驻操作的问题。桌面端鼠标悬浮可以显示操作按钮,但移动端没有悬浮概念,所以 v1.4.0 处理成:高频操作(比如查看、编辑)直接显示在卡片上;低频操作(删除、更多)收进右上角更多菜单。这个处理是符合移动端交互习惯的。
图片懒加载必须做。卡片列表每张卡片都有封面图,如果页面进入时全部加载,图片请求数量会非常多,首屏会很慢。新版本内置的懒加载是基于 IntersectionObserver 实现的,图片滚动进入视口附近才开始加载。实测对低端机和弱网环境效果很明显。
卡片的选中态。业务中常见一批卡片的批量操作,比如批量上架、批量分配。v1.4.0 在卡片左上角增加了一个多选框,配合底部的批量操作栏。这个交互在移动端也保留了,但操作栏固定在底部,避免用户勾选后找不到操作入口。
我实际使用中发现,卡片列表还有一个传统表格不具备的优势:它可以更自然地区分空状态、加载状态和错误状态。卡片区域足够大,可以放更友好的空状态插画和引导按钮,而不像表格空状态那样只有一行文字"暂无数据"。这个细节对运营类系统体验提升明显。
5. 新增页面二:高级表单的复杂场景落地
5.1 高级表单解决的是"复杂录入"问题
基础表单页面处理的是单实体录入,比如新建用户、编辑配置,字段少、结构简单。但真实业务里有一类表单复杂度远超基础表单,典型场景包括:商品发布(基础信息、规格、图片、物流、售后多个板块)、审批流程配置(节点、条件、通知人)、订单发货(商品明细 + 物流信息 + 备注)。
这类表单的共同特征是:字段数量多、存在分组、部分字段之间联动、包含复杂组件(富文本、上传、动态增减)。如果全部堆在一个页面上,用户会感到压力巨大,也容易填错。
高级表单模板就是为这类场景设计的。它的核心思路不是一次展示全部,而是通过分步、分组、动态字段来降低认知负担。
5.2 三种表单布局形式的实现与取舍
v1.4.0 的高级表单模板内置了两种常用布局:分步表单和分组表单。我在测试中还自己组合出了第三种"分步分组混合式",下面分别说。
分步表单适用于流程感强的场景,比如"基本信息 -> 规格参数 -> 确认提交"。每一步只展示一组字段,顶部有步骤条显示当前进度,底部有上一步/下一步按钮。实现上,每个步骤是一个独立的表单区域,数据统一收集在父组件状态中,最后一步一次性提交。
分组表单适用于字段都在同一流程内、但分类明显的场景。典型如商品发布:页面顶部是标题和类目,下方通过 Tab 或折叠面板划分为"基本信息""销售信息""物流售后"。用户可以不按固定顺序填写,自由跳转。这个形式对复杂录入更灵活,但对开发者来说要做好各组之间数据的联动管理。
我实际组合的方案是:外层用分步,每一步内部用分组折叠,兼顾流程引导和灵活性。比如商品发布分成三步:第一步基础信息(标题、类目、品牌分组);第二步销售信息(价格、库存、规格分组);第三步其他(图片、描述、物流分组)。这种方式在模板基础上稍作改造即可实现,成本不高。
5.3 动态表单与字段联动的关键机制
高级表单里最考验实现功底的是动态表和字段联动。
动态表指的是字段数量不固定,用户可以动态增加/删除行。典型场景是规格录入:一个商品可能有多个规格,每个规格有名称、价格、库存。v1.4.0 实现动态表的核心是基于表单数组字段,每次点击"新增规格"就在数组中追加一条空记录,并渲染对应表单行。删除时移除对应记录,同时处理数据绑定。
这里最容易踩的坑是字典绑定问题。如果使用 Vue 的v-model和数组下标直接绑定,新增/删除行后,原先的行数据可能会错位。v1.4.0 的做法是给每一行生成唯一 key(基于时间戳或随机 ID),组件渲染和值绑定都基于 key,这样增删行不会影响其他行的数据正确性。我在改造模板做自定义字段时,一度因为复用下标导致数据错乱,排查了很久,后来改成 key 绑定就稳定了。
字段联动是高级表单的另一个核心。常见场景:选择某个类目后,品牌字段的可选项随之变化;开启某项开关后,某些字段显示或隐藏;选择"包邮"后,运费字段禁用。实现上有两种常见方案:一种是基于状态监听,即监听上游字段值变化,主动重置下游字段的选项和值;另一种是基于上下文联动配置。
v1.4.0 推荐的是前者,也就是监听式。好处是逻辑直观,出了问题容易排查。我在项目中设计了一个通用联动配置数组:{ source: 'categoryId', target: 'brandId', handler: 'loadBrands' },由表单引擎统一处理。这个改造让业务方新增联动规则时只需要配置,不需要改组件代码。
5.4 高级表单的校验策略与提交体验
复杂表单的校验是个精细化工作。字段一多,全量校验的压力大,用户看到一堆红叉也容易焦虑。v1.4.0 采用分步校验和失焦校验结合的策略。
分步表单中,只有当前步骤的字段参与校验,未填写的后续步骤不提示。这样用户一次只需要关注一组字段。分组表单中,校验发生在提交时,但只对填写过值的字段做格式校验,对完全空白的非必填字段不提示。用户失焦时,单独校验当前字段,即时反馈,而不是等提交时才告知。
提交体验方面,新版本有几个我实测很实用的设计。提交按钮在请求过程中自动变为 loading 状态,防止重复点击;提交成功后,不直接跳回列表页,而是显示一个成功浮层,提供"查看详情"和"继续添加"两个选项。对于录入量大的运营场景,"继续添加"是个被低估的功能,运营人员录完一条继续下一条,效率提升明显。
这里特别提醒一个问题:高级表单的数据量通常很大,提交前一定要做深拷贝或者序列化,避免因为对象引用共用导致表单数据还没提交就被其他地方改动。我在测试图片上传组件时遇到过这类问题,表现为"我明明改了标题,提交后却是上一次的值",排查到最后发现是同一个对象在多个地方被引用导致。
6. 常见问题与排查技巧实录
6.1 前后端联调时的高频报错
联调阶段最容易出现的问题,我根据自己使用 v1.4.0 的实测情况,整理了一张速查表:
| 现象 | 大概率原因 | 排查建议 |
|---|---|---|
| 前端请求成功但数据为 null | 后端返回字段名与前端不一致 | 检查 MyBatis 驼峰映射配置 |
| 所有接口返回 401 | Token 未带上或拦截器排除路径缺失 | 检查请求拦截器是否已添加 Authorization |
| 分页数据 total 为 0 | 后端返回结构不是 PageResult | 确认 Controller 方法的返回类型 |
| 新增后列表不刷新 | 前端未重新拉取列表 | 检查新增成功回调是否调用了 page 接口 |
| 日期字段显示为时间戳 | 前端未做日期格式化 | 检查字段类型的格式化配置 |
这里面最常见也最隐蔽的是第一个问题。后端 MySQL 字段 create_time,按规范映射为实体的 createTime,但前端 API 类型定义里如果约定的是 createdAt,两边就对不上。我在测试生成项目时两边是自动对齐的,但如果你自行改了后端实体字段名,一定要同步改前端类型定义,这属于联动语义的一部分。
联调时我还建议打开浏览器 DevTools 的 Network 面板,重点关注实际请求的 URL 和参数。很多时候你以为前端在请求/api/user/page,实际因为代理配置问题,请求发到了localhost:5173/api/user/page而没转发到后端 8080 端口,造成 404。代理配置这一环节虽然基础,但确实是我见过最多人卡住的点。
6.2 移动端适配中的经典坑点
移动端适配过程中,我测试时遇到几个印象深刻的坑,每个都花了不少时间定位。
第一个坑是 100vh 的浏览器地址栏问题。移动端浏览器地址栏是动态收起的,height: 100vh在地址栏展开时计算的高度会超出可视区域,页面底部被吞掉。解决方案是使用动态视口单位100dvh,或者结合window.innerHeight手动计算。v1.4.0 的布局容器已经做了处理,但如果你自定义页面时还写 100vh,就会出现底部按钮不可见的情况。
第二个坑是表格横滑的误操作。我在测试时发现,即使在 xs 断点下已经将表格切换为卡片,但一些自定义页面里嵌入的原始表格仍然可以横向滑动,用户极易误触。处理方式是给表格外层容器添加overflow-x: auto并用-webkit-overflow-scrolling: touch优化滑动体验,同时加上左右阴影提示可滑动。
第三个坑是点击延迟。移动端浏览器为了区分单击和双击,click 事件会有约 300ms 延迟。组件库内部已经处理了大部分点击场景,但如果你在卡片上绑定了自定义 click 事件,建议用触摸事件替代,或者使用 FastClick 类库。我在卡片列表测试中遇到过按钮点击没反应的现象,就是触摸事件和 click 混用导致的事件覆盖。
这三个坑都有现成解法,但如果你不知道问题存在,排查起来会非常痛苦。熟悉移动端开发的同学可能觉得这些是常识,对以 PC 后台开发为主的团队来说,却是实打实的未知风险。
6.3 卡片列表和高级表单的性能边界
新页面模板默认做了性能优化,但实际使用时要注意边界。卡片列表的虚拟滚动优化只对"高度固定"的卡片生效,如果你在卡片中放了高度不定的富文本,虚拟滚动估算会偏差,滚动时可能出现空白区域。这需要手动给卡片设置最小高度,或者关闭虚拟滚动改为普通渲染。我在测试中按模板默认高度没遇到问题,但自定义卡片内容时出现过滚动到底部空白的情况,加了个min-height就解决了。
高级表单的性能瓶颈主要在动态表单行的数量上。如果某个业务允许添加 50 行以上的明细数据,每一行都绑定大量监听器,页面交互会有明显卡顿。我的建议是,超过 20 行的动态明细,改用表格内编辑模式,同时关闭不必要的字段监听;业务上真的需要超大明细录入时,可以考虑分批录入或导入功能,而不是在页面上硬扛。
另外一个我在实测中发现的细节:图片上传组件在卡片列表和高级表单中都用了,但两个场景的上传策略应该不同。列表场景的图片上传建议只传一张封面图,高级表单场景允许传多图。如果你在卡片列表中启用了多图上传,卡片的高度就会不稳定,影响虚拟滚动效果。模板默认策略已经是封面图单传,但自定义扩展时要注意保持这个约束。
7. 版本升级的迁移建议
7.1 从 v1.3.x 升级需要注意什么
如果你正在使用 v1.3.x 版本,升级到 v1.4.0 前,我建议先核对以下几项是否需要同步调整。
路由配置有变化。新版本新增了卡片列表和高级表单两套页面路由,如果你原来有自定义路由提交逻辑,升级后需要检查是否与新增路由冲突。我在升级时发现旧项目里有几条路由路径配置与新增页面重复,出现了页面跳转到模板页的问题,排查后调整了命名解决。
主题配置的断点变量发生了变更。v1.4.0 将断点定义统一收口到主题配置中,原来项目里分散在样式文件中的媒体查询不会被自动迁移。升级后,如果你自定义页面里用了硬编码的@media (max-width: 576px),和新的断点体系存在不一致,建议统一改用主题断点变量,避免两套标准引发样式错乱。
Mock 数据结构有所调整。为了保证和 Spring Boot 后端返回结构一致,新版 Mock 数据统一改为 PageResult 包裹格式。升级后如果你的旧项目还依赖旧版 Mock 返回的扁平数组格式,需要同步调整前端数据读取逻辑。这个改动是破坏性的,升级前一定要看变更记录。
7.2 从纯前端模板迁移到前后端一体工程
已经用 TinyPro 生成了纯前端项目,想迁移到 v1.4.0 的 Spring Boot 一体工程,不需要从零重新生成。实际操作路径是:用新版单独生成一个 Spring Boot 后端工程,然后把旧前端工程中的 API 模块替换为新版的 API 模块,再修改环境变量配置,将 Mock 切换为真实后端。
这里要注意接口路径的约定。新版后端默认接口前缀为/api,如果你的旧前端项目接口路径自定义过,迁移时需要统一。我在迁移一个内部项目时,旧接口都是/admin/user/list这种路径,后端生成的是/api/user/page,最后在前端代理层做了路径重写才对接上。如果一开始就按新版约定来,就不用做这层适配了。
数据库结构也需要核对。生成器是根据表结构反推实体和接口的,如果你的旧业务表用了复合主键、无主键表或者非常规字段命名,如列名包含特殊字符,生成器可能需要调整后才能生成正确的代码。我建议在正式使用前,先从你真实的数据库中选两三张代表性表测试生成,确认代码质量后再全面推广。
8. 一些实测中的个人体会
如果只挑一个这次升级最值得点赞的点,我会选 Spring Boot 后端生成与前端 API 自动对齐这件事。以前我们做前后端项目,接口文档要人工维护,字段变更要在群里喊一声,联调时最常干的事就是"对齐字段"。v1.4.0 这套前后端一体生成方案,等于把接口契约从人的记忆里搬到了代码里,前后端代码出自同一套模板定义,天然同步。这个价值在团队越大的时候越明显。
移动端适配的卡片化切换也是我实际使用中感知很强的功能。以前做后台项目的移动端适配,最怕的就是测试的时候发现表格没法用、弹窗盖不住、按钮点不到。v1.4.0 在断点切换、交互改造、性能优化这三层做了系统性处理,让"后台管理系统的手机端"从"应急看看"变成了"正常能用"。如果你只是简单地把桌面端页面缩放着当移动端用,我建议试试新版这套方案,体验差距非常明显。
最后再分享一个实操技巧。新生成的 Spring Boot 工程中,默认的启动端口是 8080,而前端开发服务器默认端口是 5173。如果你电脑上同时跑着多个 Java 项目,8080 端口很容易冲突。我习惯在生成后立刻把后端端口改为自定义端口,比如 18080,并同步调整前端代理配置。这个动作只花一分钟,但能避免后面联调时"后端怎么启动失败"的尴尬。
TinyPro v1.4.0 这次升级的覆盖面比较大,对正在做中后台项目的团队来说,值得花半天时间跑通一遍。我的建议是先从官方示例工程的 Spring Boot 生成功能试起,确认代码质量符合团队规范后,再引入到存量项目中。新项目直接使用,旧项目逐步迁移,整体衔接下来,代码生成、前后端联调、移动端适配这些环节,确实能做到比之前顺畅许多。