新闻详情

新闻详情

首页 / 资讯中心 / 详情

Java后端代码生成器实战:从CRUD四件套到自动化骨架搭建

发布时间:2026/9/9 19:54:50来源:尧图网络
Java后端代码生成器实战:从CRUD四件套到自动化骨架搭建
不会吧还有人每天在重复敲 Controller、Service、Mapper、Entity 这套四件套我入行第八年的时候终于忍不住了花了一个周末写了这个 Java 后端代码骨架生成器。今天把这套东西的完整思路、核心实现和踩过的坑一次性倒出来希望能让同样被重复劳动折磨的兄弟们少走点弯路。先说清楚它能干什么基于给定的实体信息表名、字段名、类型一键生成完整的一套 Controller、Service、Mapper、Entity 代码文件包含基础的 CRUD 接口、通用返回结构、分页参数、异常处理甚至连带 MyBatis 的 XML 文件骨架。生成完的代码拿过来就能直接跑起来不用再手动补那些繁琐的注解和积累重复的模板代码。这背后其实是一个很小的设计问题代码骨架生成的本质是把业务无关的样板代码和业务相关的核心逻辑分开处理。我用的方案是模板引擎 元数据解析——模板里固定的是结构变化的是数据。听起来简单但真正落地的时候细节都在那些看起来不复杂的地方。这篇文章适合几类人看被日常 CRUD 淹没的 Java 后端开发、团队里想搞开发效率脚手架的人、对代码生成器原理好奇但一直没动手实践的读者。我尽量把每一步的为什么这么做讲清楚不光是给结论。1. 为什么我不直接用一个现成的代码生成器很多人的第一反应是这东西不是早就有人做了吗MyBatis Generator、MyBatis-Plus Generator还有各种在线生成器为什么还要自己写一个说几个我实际体验下来的痛点。第一个痛点是通用生成器生成的代码太过标准。标准到每个 Service 都给你生成一个完整的 ServiceImpl 接口实现每个 Controller 都有一堆根本不用的方法。线上项目经过两轮迭代之后这些代码迟早要被删掉大半而删除模板生成的多余代码比手写还费劲。我见过不止一个同学用 MyBatis Generator 生成代码之后又花了一个下午清理那些这辈子都用不到的 selectByExample。第二个痛点是团队内部的编码规范没法通过生成器统一。比如某些团队要求 Controller 层必须通过一个统一的结果类包装返回某些团队要求所有新增接口都带操作人和时间戳的参数某些团队禁用魔法数字某些团队要求在 Service 层做参数校验而不是在 Controller 层。开源生成器很难在配置里覆盖所有这种琐碎的规范差异结果就是生成器生成了代码代码审查时照样被一顿批。第三个痛点是数据字典与管理后台的对接问题。大部分在线生成器只管生成三个类但实际项目中每一个新加的表可能要同时处理前端展示名、表格列配置、导出字段、下拉选项的数据来源这些信息往往都存在数据字典里。这个环节开源生成器基本不覆盖得自己补。所以当我决定给团队做一套脚手架的时候我清楚地知道我不需要一个万能的生成器我需要一个能完全贴合我们团队开发习惯和规范约定的生成器。自己写一套看似重复造轮子实际是用一个周末的时间省下未来每个迭代里十几个小时的重复劳动。这个决定放到今天回头看依然是对的。2. 四层代码骨架的职责边界先想清楚再写模板生成器核心的逻辑就一句话**输入表结构元数据输出四类 Java 文件。**但数据从哪来、输出哪些内容每种文件的长相必须在动手写模板之前定清楚。2.1 Entity承载字段元数据的数据源Entity 层是整个生成过程的起点因为后面的 Mapper、Service、Controller 都依赖它的字段信息。这一层的生成逻辑不算复杂本质上就是把数据库字段类型映射为 Java 类型再补上 MyBatis-Plus 的注解和 Lombok 注解。我定义的映射规则大概长这样数据库类型Java 类型说明bigintLong主键和关联字段常用int/integerInteger一般状态字段tinyintInteger有些表用来表示逻辑删除varchar/charString常规文本date/datetime/timestampLocalDate/LocalDateTime不再建议用java.util.Datedecimal/numericBigDecimal金额、比例等精确数字text/longtextString内容类字段字段名从下划线转驼峰user_name-userName表名转模块名sys_user-SysUser这些是约定俗成的规矩但要注意一个细节**不是所有字段都适合映射到 Entity 里。**有些项目会在表里设计冗余统计字段比如order_count这种字段一般不允许直接修改只有当查询返回给前端时才需要展示。如果盲目生成会诱导后续开发同学把order_count当成普通字段来更新很容易出问题。我的处理方式是生成器只生成与表中真正的业务字段对应的属性统计类字段靠开发同学按需补充或者在模板里用注释标出来。注释里写清楚字段的业务含义这比生成一百个属性还重要。文档能力是所有程序员最容易忽略但是最关键的能力。2.2 Mapper能跑通 CRUD 就算合格在骨架生成器这个场景里Mapper 层的核心价值不是帮你把 SQL 写出来而是帮你把最容易出错的注解和映射关系先定好。Controller、Service 层面的代码写错了还能编译通过后暴露问题Mapper 层的 XML 映射文件写错了是直接启动报错而且报错信息往往不友好。所以生成器在 Mapper 层的策略是接口定义规范 XML 文件裸奔。接口部分生成标准的BaseMapperTMyBatis-Plus 接口加上项目里自定义的基础 Mapper 接口比如带逻辑删除、多租户处理的基础类。这一层不生成自定义查询方法因为每个模块的自定义 SQL 差异太大生成器硬套一个模板只会让人觉得不好用。XML 文件生成基础的ResultMap、公共字段的sql片段和几个通用查询的 SQL 骨架。为什么连 SQL 都要生成因为很多 MyBatis 项目的ResultMap的 column 映射错误是启动时才会暴露的提前生成好能省掉一次启动排错的过程。2.3 Service定制化程度最高的一层Service 层是四层里最需要因团队而异设计的一层。MyBatis-Plus 的IServiceServiceImpl方案用得很普遍但我遇到不少团队不习惯这个方案他们更常用Service 接口 ServiceImpl 实现的纯手写模式因为更可控。我的模板里同时保留了两套 Service 骨架通过配置文件切换方案 A继承 MyBatis-Plus 的 IService/ServiceImpl生成器只补充分页查询方法和批量插入方法。方案 B独立 Service 接口 实现类生成器把 CRUD 方法逐个列出每个方法体里补上基础实现不依赖 MyBatis-Plus 的通用方法。两种方案我都用过。小团队、快速迭代的项目用方案 A 效率高不过注意 MyBatis-Plus 的saveBatch默认不是真正的批量插入性能有问题时还是要换成手写 SQL。老项目、对 SQL 执行路径要求严格审计的团队用方案 B 更多一些生成的代码虽然多一点但每一条 SQL 链路都清晰可控。方案 B 的 ServiceImpl 生成的代码长这样Override public SysUser getById(Long id) { SysUser sysUser sysUserMapper.selectById(id); if (sysUser null) { throw new BusinessException(ErrorCode.USER_NOT_FOUND); } return sysUser; }看到那个throw new BusinessException了没有这一行是我在生成器里刻意加进去的。如果模板里只生成return sysUserMapper.selectById(id);生成出来的代码到手之后大部分人会直接丢进代码评审流程发现查不到数据时直接返回 null让上层 NPE这是我最不想在团队代码里看到的处理方式。生成器主动加上查不到就抛异常的骨架是在帮团队建立异常处理的统一习惯。2.4 Controller最容易被低估的一层Controller 层的生成模板在业务代码里是最容易被低估的。很多生成器的 Controller 模板就是生成一个RestController空壳加一个list方法这样的代码交到业务手上最后大概率是Controller 里塞业务判断返工重写。我生成的 Controller 层要求做三件事统一前缀、统一返回、统一分页参数。统一前缀是通过配置确定每个模块的 URL 前缀比如/api/sys/user而不是让每个人手动拼字符串拼错了路径排查半天。统一返回指的是所有接口方法的返回值都必须落在RT这个统一结果对象里不允许直接裸返回 Entity。统一分页参数是指分页查询用固定的PageQuery对象做入参而不是让不同开发者在不同的接口里各写各的分页参数名。生成出来的 Controller 方法签名示例PostMapping(/page) public RPageResultSysUserVO page(RequestBody SysUserQuery query) { PageResultSysUserVO pageResult sysUserService.page(query); return R.ok(pageResult); } GetMapping(/{id}) public RSysUserVO detail(PathVariable Long id) { SysUserVO sysUserVO sysUserService.detail(id); return R.ok(sysUserVO); }方法名统一用detail而不是get、query、find满天飞接口返回的对象统一是VO。这些决策都不是随意定的而是从代码评审的抱怨里总结出来的——规范一致的时候评审速度可以快很多。3. 生成器的核心实现元数据、模板引擎与文件输出骨架生成器说到底是一个元数据 模板的转换工具。元数据描述这个表长什么样模板描述这个类的代码长什么样中间用代码把模板套上元数据生成最终的 .java 文件。3.1 元数据从哪里来解析 DDL 还是连接数据库这是生成器设计时首先要做的一个决定。我见过有人直接把表结构手工维护成 JSON 文件也见过直接用 JDBC 连数据库读取表结构元数据还有人选择解析CREATE TABLE的 DDL 语句。三种方式各有适用场景。直接连接数据库是最省事的用 JDBC 的DatabaseMetaData接口就能拿到表名、字段名、字段类型、是否主键、字段注释代码量不大。但是有个明显的短板不是所有开发者都愿意给生成器开一个数据库连接权限特别是生产环境的表结构连库读表在很多公司要走审批流程。解析 DDL 的方式则在数据库迁移和跨环境生成代码时特别好用因为 DDL 文件本来就在代码库里。我的生成器最终采用的是配置文件 DDL 解析兜底的双通道方案。默认情况下开发者在生成器配置文件里用一段简短的 DSL 描述表结构生成器解析这段 DSL 后生成代码。如果需要也可以传入create table语句生成。DSL 描述示例table: name: sys_user comment: 系统用户表 fields: - name: id type: bigint comment: 主键ID primaryKey: true - name: username type: varchar(64) comment: 登录账号 - name: password type: varchar(128) comment: 密码加密存储 - name: status type: tinyint comment: 状态1正常0禁用 - name: create_time type: datetime comment: 创建时间DSL 的好处是任何人都能看得懂并快速修改不会像直接调数据库接口那样依赖环境。然后字段信息被转换成一个TableMeta对象这个对象就是后面所有模板要用的数据源。3.2 模板引擎选型我为什么用 Freemarker 而不是手写字符串拼接生成器内部最核心的代码就是模板渲染这一步我直接选了 Freemarker 而没有手写拼接字符串。原因很简单后期的可维护性差一个量级。手写拼接字符串的生成器长这样StringBuilder sb new StringBuilder(); sb.append(package ).append(packageName).append(;\n\n); sb.append(import ...\n); for (FieldMeta field : fields) { sb.append(private ).append(field.getJavaType()).append( ).append(field.getFieldName()).append(;\n); }看起来好像也不复杂但一旦要加条件判断比如加了逻辑删除字段就要加TableLogic注解字符串拼接会膨胀到没法看。而且 Java 代码里嵌 Java 代码模板特征完全被冲掉了后续改一版代码换两个人基本就没人敢动了。用 Freemarker模板独立在.ftl文件里代码的结构、缩进、注释都能做到跟手写代码完全一致。举个例子Entity 模板的核心片段#list table.fields as field #if field.comment?? field.comment! /** * ${field.comment} */ /#if #if field.primaryKey TableId(value ${field.columnName}, type IdType.AUTO) #elseif field.logicDelete TableLogic #else TableField(${field.columnName}) /#if private ${field.javaType} ${field.javaName}; /#list这样的模板拿到团队里任何做过 Web 开发的同事都能看得懂需要加字段时直接在模板里加一段#if判断就行。这就是我用模板引擎最核心的理由——降低后续维护成本。不过我也要提醒一句Freemarker 的#if指令写多了之后模板本身会变得很难维护。所以我在设计模板文件时坚持了一个原则**每个层级的模板只保留该层级的独特部分公共部分放到宏macro里复用。**比如所有类文件都要有的包名、import 头定义成一个宏Controller、Service、Entity 的模板调用同一个宏避免每个模板里都复制一遍 import 处理逻辑改起来也不至于漏掉其中一个文件。3.3 文件输出如何保证生成代码的结构化与覆盖安全生成器的输出不能只是把字符串写到一个文件里那么简单还要处理几个工程化问题。第一个问题是包路径结构。生成的代码文件必须按模块分包存放通常放在同一个模块下的controller、service、mapper、entity包中。我的配置里用一个basePackage加一个moduleName拼接出完整包路径这样生成到不同模块时只要改配置就行。第二个问题是文件覆盖策略。一个生成器如果每次重新生成都把原来的文件整体覆盖掉那它肯定没法在真实项目里落地——因为生成完之后开发者一定会在文件上做手工修改二次生成要是覆盖了手工代码谁都不敢再用。我的策略是**首次生成采用跳过已存在文件模式二次生成只生成缺失的方法和新增加字段对应的代码已有的方法体一律不覆盖。**为实现这个逻辑生成器在解析目标文件时先读取方法签名列表如果方法签名已存在模板渲染时就把该方法标记为跳过。我在设计上更进一步凡是存在同名方法就直接跳过该方法的整个方法体生成并把新代码生成到附加方法区用// 新增方法开始 分隔这样开发者能一眼看出哪些是重新生成时补上的。第三个问题是编译验证。生成完代码之后很多生成器就结束了但是一个健壮的工具应该顺手做一次编译检查。我在这套工具里集成了 Java Compiler API生成完代码后自动尝试编译这些文件如果有语法错误直接给出提示而不是等到项目启动才报错。这个功能初次调试的时候救了我好几次因为模板里的变量名一旦拼错页面上看不出来编译一跑全暴露了。4. 实操演示从建表到四层骨架一次到位理论说了一大堆不如实际跑一遍。我把一次完整的生成流程拆开带大家看看每一步发生了什么、生成了什么。4.1 准备阶段定义配置在项目目录下创建一个generator-config.yml内容除了上一节里提到的那段表结构 DSL 之外还需要做几项配置project: basePackage: com.example.demo moduleName: system author: devexample.com templateDir: templates outputDir: output database: type: mysql prefix: sys_ mappingFile: type-mapping.properties这里最关键的坑就是prefix。我要求所有表名都带sys_、biz_这类模块前缀生成器在生成类名时自动去掉前缀sys_user-User但生成 Entity 的TableName注解时保留完整表名。这样设计是为了避免类名里出现两个连续的模块名后缀很多人第一次写生成器就容易忘掉这一步。4.2 执行生成器并查看产物执行一个Main.main()方法这里我直接用命令行启动没有包装成插件因为要保持足够简单控制台输出如下[INFO] 加载表结构元数据: sys_user [INFO] 生成 Entity 类完成: SysUser.java [INFO] 生成 Mapper 接口完成: SysUserMapper.java [INFO] 生成 Mapper XML 完成: SysUserMapper.xml [INFO] 生成 Service 接口完成: SysUserService.java [INFO] 生成 Service 实现类完成: SysUserServiceImpl.java [INFO] 生成 Controller 类完成: SysUserController.java [INFO] 构建项目结构完成共 6 个文件生成的SysUserController.java核心内容完整展示package com.example.demo.system.controller; import com.example.demo.common.R; import com.example.demo.common.PageQuery; import com.example.demo.common.PageResult; import com.example.demo.system.entity.SysUser; import com.example.demo.system.service.SysUserService; import com.example.demo.system.vo.SysUserVO; import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import jakarta.validation.Valid; Validated RestController RequestMapping(/api/system/sysUser) RequiredArgsConstructor public class SysUserController { private final SysUserService sysUserService; PostMapping(/page) public RPageResultSysUserVO page(RequestBody Valid PageQuerySysUser query) { return R.ok(sysUserService.page(query)); } GetMapping(/detail/{id}) public RSysUserVO detail(PathVariable Long id) { return R.ok(sysUserService.detail(id)); } PostMapping(/create) public RVoid create(RequestBody Valid SysUser entity) { sysUserService.create(entity); return R.ok(); } PutMapping(/update) public RVoid update(RequestBody Valid SysUser entity) { sysUserService.update(entity); return R.ok(); } DeleteMapping(/delete/{id}) public RVoid delete(PathVariable Long id) { sysUserService.delete(id); return R.ok(); } }有人可能会问为什么page方法的入参用的是PageQuerySysUser而不是直接传SysUser这是我特意留给业务团队扩展查询条件的坑位因为实际的表结构会有很多非实体的查询参数比如时间范围、状态列表用泛型占位符生成器可以不改模板就兼容后续扩展生成完代码后开发者只要把SysUser换成SysUserQuery即可。4.3 运行验证生成器工具本身我已经在内部跑了一轮完整的验证生成的代码能通过 Spring Boot 项目的编译。这一步验证最值得注意的一点是**生成器生成的代码必须能编译通过这是它的底线。**如果一个生成器生成的代码打开就是红的那还不如不生成。所以在生成器设计里编译验证环节不能省。5. 生成器实现里的关键细节与常见坑骨架生成器看起来简单实际踩坑的地方一点都不少。我把开发过程中遇到的几个高频问题列出来每一个都是从报错到解决的完整链路。5.1 Java 关键字与字段名冲突第一个坑是数据库字段名和 Java 关键字撞车的问题比如用户表里有一个字段叫mode在 Java 里没问题但如果有字段叫default_value转成驼峰之后变成defaultValue这也没问题但如果字段直接叫class、package、record甚至有些表里会设计一个叫type的字段这个不算关键字但和某些框架的保留字撞车生成出来的 Java 类就是编译错误。我在生成器里维护了一张关键字黑名单表一旦检测到字段转换后的名字落在黑名单里自动在末尾加上一个Field后缀class-classField同时生成注释标记原始字段名。还有一个更隐蔽的坑数据库字段是is_deleted生成的属性名应该是deleted还是isDeleted不同 MyBatis 版本对 Boolean 字段的别名解析行为不同容易导致状态值读取异常。我的建议是数据库字段名尽量不要用 is_ 前缀如果已经存在生成器默认转化为deleted而不是isDeleted从源头规避 MyBatis 的映射歧义问题。5.2 类型映射的边界tinyint(1) 是个特殊的存在日常开发里tinyint(1)这个数据库类型特别容易引发争议。有些人写布尔字段会用tinyint(1)联表查询时它的驱动映射到 Java 端非常不可控在新版 MySQL 驱动里默认映射成Boolean旧驱动映射成Integer。我这边最终定下的映射规则是tinyint(1)映射为Integer由应用层自己决定怎么解释这个数字。为什么不用Boolean因为tinyint(1)在很多表里除了表示是否删除之外还可能表示状态枚举的多个取值0/1/2。如果把tinyint(1)统一映射为 Boolean遇到取值 2 时就丢失了语义而且数据库加枚举值之后反而要改 Java 类型很被动。宁可让类型宽一点也不要把数据读出来就截断。5.3 Mapper XML 的可维护性问题生成器生成的 Mapper XML 数量一多之后会变成项目里最没人想动的文件。因为ResultMap动一下对应的所有查询都要核对一遍字段。我的做法是在生成 XML 文件时把所有公共字段定义成一个sql片段同时把主表的字段列表放进一个BASE_COLUMN_LIST而不是每个 select 里复制一遍字段列表。sql idBase_Column_List id, username, password, status, create_time /sql select idselectPageList resultMapBaseResultMap select include refidBase_Column_List/ from sys_user where if testquery.username ! null and query.username ! and username like concat(%, #{query.username}, %) /if if testquery.status ! null and status #{query.status} /if /where order by id desc /select这种结构一旦面对后续新增字段只需要改两处一个是 ResultMap一个是sql片段比逐个修改所有 select 语句里的字段列表要安全得多。5.4 逻辑删除与多租户字段很多业务系统的表都带逻辑删除标志deleted和多租户标识tenant_id。如果生成器不处理这几个字段生成的代码里就会到处出现where deleted 0的手写判断漏一处就在数据层面出一次事故。我的生成器把这些字段识别之后在生成 XML 时自动在所有查询 SQL 末尾加上and deleted 0或and tenant_id #{query.tenantId}生成 Entity 时对deleted字段加TableLogic注解让 MyBatis-Plus 自动处理这块逻辑。这套规则能够显著减少开发过程中的低级数据安全失误比靠人工记忆靠谱得多。5.5 二次生成时如何分辨手动改进的代码我前面提到过文件的覆盖策略这里再展开说一个细节二次生成时怎么判断已有文件是不是被开发者改过最简单的办法是算文件的哈希值把首次生成的哈希快照保存下来后续重新生成时对比——如果文件哈希完全一致说明没人改过可以整体覆盖如果文件哈希变了说明有人动过不能覆盖转为增量补丁模式。但哈希方案有个问题开发者改了代码之后文件哈希就变了但如果是模板本身升级了生成器想给这个文件增加一个新方法此时无法自动判断这个文件的哪些部分是可重写的。我的最终方案是引入生成标记注释// generated by CodeGenerator v1.0.0 -- 本文件的部分内容由生成器维护请勿移除本注释。如果文件头部存在这个标记生成器会尝试解析方法级边界通过方法名匹配决定是否覆盖。如果开发者删掉了这个标记生成器就默认整个文件为手写文件不再自动覆盖只做区分提示。这个设计说实话不是最完美的但它保证了一个最重要的特性**生成器永远不会静默覆盖掉开发者手写的代码。**宁可不更新也绝不能丢代码。任何做代码生成工具的人都应该把这条当成底线。6. 生成器后续可以扩展的进阶方向我这个工具目前还是一个命令行小工具但它已经有几条非常清晰的演进路径如果有团队想在此基础上继续做可以考虑下面几个方向。6.1 从类骨架到接口文档的延伸生成的 Controller 代码里已经包含了RequestMapping、PostMapping等注解这些信息完全足够用来同步生成 OpenAPISwagger的接口文档。把生成的接口元数据暴露出去可以让前端的 mock 服务和后端的接口定义保持同步更新减少前端等的接口还没建好的协作摩擦。更进一步可以从 Controller 方法签名直接推导出请求参数对象和响应对象的定义继而生成 typescript 的 interface 类型定义文件方便前端也一起使用同一份骨架。这个联动一旦做完骨架生成器就不再只是后端工具而是整个前后端协作流程的基础设施了。6.2 从命令行工具到 Maven 插件 / IDEA 插件的封装命令行工具适合单个开发者自己用但要让全团队都用起来更好的解法是封装成 Maven 插件或 IDE 插件。Maven 插件可以让代码生成绑定到generate-sources生命周期里每次编译自动执行IDEA 插件则可以给开发者在图形界面里选表、选模板、点按钮生成大幅降低使用门槛。我目前在准备把这个工具封装成 IDEA 插件版本理由是后端开发者开发时几乎都开着 IDEA与其切到命令行敲命令不如直接在 IDE 里完成操作。但封装成插件有个额外的坑要处理——模板修改后的热加载机制。IDEA 插件跑在独立的 JVM 里模板改了不能每次都重启 IDE这块需要单独设计模板文件的监听刷新机制。6.3 结合数据库结构变更做增量生成生成器的长期演进方向应当是结合数据库版本管理工具如 Flyway、Liquibase做增量生成。每次数据库迁移脚本执行完之后自动比对一个上次生成记录和当前表结构的差异把新增字段对应生成的代码补充到 Entity 和 Mapper XML 里实现表结构变更自动同步到代码的效果。这条路走通之后团队的日常开发流程就变成了需求评审 → 提 SQL 变更 → 执行迁移 → 代码骨架自动同步。重复劳动进一步下降人就可以把精力放到真正需要思考的业务逻辑上。7. 这套生成器在团队落地时的实际体会最后说一点切身的落地经验。我在团队里推行这套工具的时候遇到的最大阻力不是技术问题而是生成的代码风格和项目里老代码不一样的适应问题。老项目的写法本身就五花八门有的 Controller 返回 String 模板名有的直接返回实体有的用 Lombok 有的不用而生成器强行统一了一套规范一开始被不少人吐槽生成的代码太死板。我的处理办法是**把生成器定位成新模块的起点而不是所有代码的标准答案。**新模块从生成器创建骨架老模块维持原样类比的场景是装修——你先画好一套水电图再走线肯定比在老房子里这里加一个插座那里加一个开关要规整得多。另一点体会是**生成器的模板一定要让团队的核心成员参与维护。**如果只有我一个人维护模板团队其他人只负责用那生成器很快就变成了别人家的工具——出了问题没人管改了规则没人懂。后来我专门安排每个小组轮值维护模板谁发现问题谁直接改改完大家评审这才让工具真正沉淀成了团队的共同资产。工具的意义从来不是替你写代码而是把团队形成共识的规范用最不费脑子的方式执行下去。代码生成器只是替你把那些已经想清楚但重复了一百遍的事情一次性做完而已。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

ToolJet 接入 Google BigQuery 数据源全指南:服务账号认证、连接配置与九大数据操作实战 2026/9/9 20:30:55

ToolJet 接入 Google BigQuery 数据源全指南:服务账号认证、连接配置与九大数据操作实战

ToolJet 接入 Google BigQuery 数据源全指南:服务账号认证、连接配置与九大数据操作实战 【免费下载链接】ToolJet Open-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workf…

阅读更多 →
SpringAI-Advisor实战:自定义Advisor机制与DeepSeek content为空排查 2026/9/9 20:30:55

SpringAI-Advisor实战:自定义Advisor机制与DeepSeek content为空排查

说实话,第一次看到“SpringAI-Advisor”这个项目名,我第一反应是:又是一个把Spring AI包了一层、塞了几个工具类的示例工程。但真正把源码拉下来、跑通链路之后,我发现自己低估了它——Advisor在Spring AI里扮演的角色&#xff0c…

阅读更多 →
服务端状态与数据获取库技术选型对比:React Query vs SWR vs Apollo Client vs RTK Query vs React Router 2026/9/9 20:30:55

服务端状态与数据获取库技术选型对比:React Query vs SWR vs Apollo Client vs RTK Query vs React Router

服务端状态与数据获取库技术选型对比:React Query vs SWR vs Apollo Client vs RTK Query vs React Router 【免费下载链接】query 🤖 Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Qu…

阅读更多 →
中小企业低成本SEO实操指南:从关键词到内容优化的完整打法 2026/9/9 20:30:55

中小企业低成本SEO实操指南:从关键词到内容优化的完整打法

做SEO这行十年,被中小企业老板问得最多的一句话是:“我预算不多,能不能不花大价钱也能把网站做上来?”我的回答通常是:能,但前提是你得把力气用在刀刃上。大公司烧钱买词、堆资源、养团队,那是他…

阅读更多 →
从 Changelog 读懂 expo-app-integrity:Expo 应用完整性校验模块的版本演进与实现剖析 2026/9/9 20:30:55

从 Changelog 读懂 expo-app-integrity:Expo 应用完整性校验模块的版本演进与实现剖析

从 Changelog 读懂 expo-app-integrity:Expo 应用完整性校验模块的版本演进与实现剖析 【免费下载链接】expo An open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web. 项目地址: https://gitcode.com/G…

阅读更多 →
Istio 示例镜像构建指南:读懂 samples/builder 的 docker buildx bake 流水线 2026/9/9 20:27:55

Istio 示例镜像构建指南:读懂 samples/builder 的 docker buildx bake 流水线

Istio 示例镜像构建指南:读懂 samples/builder 的 docker buildx bake 流水线 【免费下载链接】istio Connect, secure, control, and observe services. 项目地址: https://gitcode.com/GitHub_Trending/is/istio Istio 仓库的许多示例(bookinfo…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞