
1. 这需求是怎么来的以及注释模板为啥非得自己搞先说个我自己的经历。有一年我带了个小团队做项目代码评审的时候被组里一个新来的同学问到“咱们项目里每个类的头部都带一段作者、日期、描述信息的注释这是谁一个个手打的吗我看有些类连注释里的日期都过期了。”当时我愣了一下确实团队规范里写了“每个新建类文件必须包含头注释”但有的人认真写有的人随便敲两行还有人偷懒直接复制上一个类的注释导致后面接手的同事经常被误导。后来我在组内立了一个硬性要求所有类文件头注释必须由 IDEA 自动生成不允许手打。从那以后我在 IDEA 里配注释模板这件事就成了我换电脑、换 IDE 版本之后必做的一道工序。这篇文章想聊的就是在 IntelliJ IDEA 里把自己的快速注释模板功能实现出来重点放在“创建文件时在类的开头自动带出注释说明”这个场景。要注意的是很多教程会把“类文件头模板”和“自定义快捷键注释模板”混在一起讲其实这是两个完全不同的东西。前者对应 File and Code Templates后者对应 Live Templates底层机制不一样配置方式也不一样能实现的效果也有很大差异。搞混了你会发现照着某篇教程配完怎么试都不生效。从解决的实际问题来说这套配置能帮你做到三件事第一新建类、接口、枚举、抽象类的时候类上方自动出现标准化的注释块不用手动敲也不用复制粘贴第二注释里的作者、日期、时间、类名、包名这些信息自动填充不需要你操心第三整个团队的代码风格能保持统一因为模板是固化的谁都改不了格式。适合谁来参考只要你平时用 IDEA 写 Java带过项目、被代码评审折磨过或者纯粹想让新建文件的体验更舒服一点这篇文章都值得你看完。我不打算给你贴那种“照着输入就行”的 GUI 截图流教程而是把配置背后的变量逻辑、脚本原理讲明白这样不管 IDEA 以后更新成什么样子你都能自己上手改。2. 配置前需要先搞懂的变量体系2.1 模板生效的核心机制变量替换IDEA 的模板功能说白了是一个“文本模板 变量替换”的运行机制。你在模板里写的所有内容会被 IDEA 在合适的时间点解析一次模板中形如$VAR_NAME$或${VAR_NAME}的部分会被替换成实际的值然后生成到新文件里。系统变量是 IDEA 内置的比如${USER}表示当前系统用户名${DATE}表示当前日期${TIME}表示当前时间${PROJECT_NAME}表示项目名${PACKAGE_NAME}表示新文件所属的包名。这些变量不需要你做什么额外操作直接在模板里写就能用。但这里有个非常关键的区别File and Code Templates 用的是 Velocity 模板引擎变量语法是#parse、$DATE这种风格而且它有自己的一套预定义变量分为“模板可用变量”和“模板中可用的值变量”。Live Templates 使用的是另一种变量语法形如$CLASS_NAME$、$METHOD_NAME$还需要为每个变量指定表达式或者来源。如果你把两者混用比如在 File and Code Templates 里写了$CLASS_NAME$结果就是这一行原封不动出现在生成的文件里根本不会被替换。我自己就在这上面栽过跟头。最早我在百度上搜到一篇博客博主把 Live Templates 的变量写法搬到了文件头模板里我又没仔细看体系照着配完后新建文件类注释里冒出来一堆活生生的$CLASS_NAME$文本花了几分钟才反应过来是模板体系搞错了。2.2 自定义变量让注释不只是“日期 作者”很多人配类头注释模板的时候默认就配一个/** * author ${USER} * date ${DATE} */说句实话这种模板真的有点浪费。IDEA 的 File and Code Templates 里每个创建的文件类型都能获取一组变量关键是我们还能通过自定义脚本的方式让模板自动解析出“当前创建的是类还是接口”“类名是什么”这类信息。比如我可以让注释里自动出现类的说明文字模板像description TODO或者自动生成的className。这里插一句理念上的问题。类头注释的意义业内争论很多有人支持有人觉得注释就该写行为和意图而不是写“这段代码是张三写的”。我的看法是类头注释不该只用来署名它更应该承担“这个类是干什么的、入口在哪、注意事项是什么”的定位。所以我在配置模板的时候会刻意在模板里预留一个$description的占位位置强制写代码的人在创建类后第一时间补充一句话描述这个类的作用。这就是自定义变量和脚本的价值所在。2.3 常用变量对照表值得收藏我整理一份自己在配置时常用的变量表方便你对照着用省得每次都要去翻官方文档变量名所属体系说明适用模板${USER}File and Code Templates当前操作系统用户名类头注释${DATE}File and Code Templates当前日期格式由系统决定类头注释${TIME}File and Code Templates当前时间类头注释${YEAR}File and Code Templates当前年份默认在标准模板中使用类头注释${MONTH}File and Code Templates当前月份注意是两位数字类头注释${DAY}File and Code Templates当前日期日类头注释${HOUR}File and Code Templates当前小时24小时制类头注释${MINUTE}File and Code Templates当前分钟类头注释${PACKAGE_NAME}File and Code Templates新文件所在包名类头注释${PROJECT_NAME}File and Code Templates当前项目名类头注释${NAME}File and Code Templates新文件的文件名不带扩展名类头注释$CLASS_NAME$Live Templates当前类名仅 Live Templates 可用自定义快捷键注释$METHOD_NAME$Live Templates当前方法名自定义快捷键注释$params$Live Templates自定义变量可通过脚本取方法参数列表自定义快捷键注释$return$Live Templates自定义变量可通过脚本取方法返回类型自定义快捷键注释重点说下${NAME}这个变量它在新文件创建时等于文件的主名比如你创建了一个UserService.java${NAME}就是UserService。这个变量在类头注释里很有用你可以让注释自动带出类名不用每次手动填。但它有个局限如果你用New - Java Class向导创建文件并且模板结构里同时生成了public class UserService这种代码类名本身就已经在里面了再在注释里放一遍确实有点冗余。但有些场景比如创建的是package-info.java或者某些非标准的代码文件${NAME}就有用了。3. 实战快速实现类的开头注释模板3.1 操作路径和完整配置步骤我以 IntelliJ IDEA 2023.1 版本为例配置路径基本一致社区版 Ultimate 都支持。完整步骤如下。打开Settings在 macOS 上是IntelliJ IDEA - PreferencesWindows 上是File - Settings。然后在搜索框里输入File and Code Templates进入模板配置页。选中Includes选项卡这里通常已经有一个File Header.java文件这就是 IDEA 默认的类头注释模板。双击它或者选择后点击Edit按钮把里面的默认内容替换成我们自己的模板。这里我给出一个我目前在生产环境里使用的模板可以说兼容性极强兼顾了规范性和信息密度/** * ClassName: ${NAME} * Description: TODO 请描述这个类的用途 * author: ${USER} * date: ${YEAR}-${MONTH}-${DAY} ${TIME} * version: 1.0 * Copyright: ${PROJECT_NAME} */配好之后记得点Apply然后点击OK。这里有个容易忽略的细节Include里的File Header.java模板不一定作用于所有文件类型。真正生效的关键在于你新建的那个文件类型勾选了#parse(File Header.java)。所以你看File and Code Templates左侧的列表选中Class、Interface、Enum这些类型右侧的模板内容中必须包含一行#parse(File Header.java)如果有就把头注释引入进来了。我见过一个同事他只在 Includes 里改了模板但 Class 的模板里没有#parse这一行新建类成功后什么都看不出来以为自己没保存配置。折腾半天最后发现是#parse丢了。这种问题特别容易出现在 IDEA 版本升级之后默认模板被重置#parse被覆盖了。3.2 让注释里的“类名”自动切换成“接口名”的高级写法上面那个模板已经能解决日常 80% 的需求但我个人还想更进一步。我希望能定义一个新的变量它能根据我当前创建的是类还是接口自动输出对应的“类名说明”还是“接口名说明”。比如我新建UserMapper接口时注释第一行显示interfaceName: UserMapper新建UserServiceImpl类时显示ClassName: UserServiceImpl。这个需求靠 IDEA 默认变量实现不了得用上 File and Code Templates 里一个隐藏的杀手级功能自定义模板变量以及它支持的Velocity脚本逻辑。在File and Code Templates配置页面的底部有个Variables表格区域这里有默认的一组变量列表。我们可以在这里新增一个变量比如叫CLASS_NAME_OR_INTERFACE_NAME然后给它配置一个 Velocity 表达式。这个表达式的逻辑就是如果当前文件名对应的模板类型是接口则显示 “interfaceName”否则显示 “className”。具体写法如下#set($isInterface $FILE_NAME.endsWith(Interface.java))其实这种写法在 File and Code Templates 里支持得比较有限因为 IDE 本质上只提供了一套默认变量替换逻辑并不是完整的 Velocity 环境。经过我的实测最稳妥、可维护性最高的方案不是在 File and Code Templates 里写复杂逻辑而是把变量拆成两部分一部分是${NAME}直接显示文件名另一部分是Description等自定义描述字段让用户在创建类之后第一时间手动补全。一句话总结复杂逻辑放在脚本里模板里只做变量替换别把模板引擎当编程语言用。3.3 模板写完后如何快速验证生效配置完成之后我想给大家分享一个非常高效的验证方式比手动创建类快得多。在 IDEA 的Settings - Editor - File and Code Templates页面里每次修改模板后模板编辑区的上方有一个Enable Live Templates选项这不关键。关键是代码编辑区的右上角有一个类似“预览”的按钮点击它IDEA 会直接在编辑区下方渲染出这个模板应用后的效果你可以立刻看到${USER}、${DATE}等变量到底被替换成了什么值不用辛辛苦苦去新建一个类。我实测这个预览功能特别好用修改完模板后我会习惯性地快速预览一眼确认$符号没有语法错误然后才去新建真实文件验证。另外如果你改完模板后新建文件发现日期时间没有更新还是旧值先别急着重启 IDE。这种问题大概率是你当前 IDEA 进程的模板缓存没有刷新。试试File - Invalidate Caches / Restart选择Invalidate and Restart等 IDE 重启后再新建文件测试。这个操作不经常用但一旦遇到顽固的模板缓存问题它就是终极杀招。4. 小白最容易踩的坑和排查思路4.1 时间日期变量在模板里不解析输出原样文本这是我在 IDEA 社区里看到提问频率最高的问题。表现形式模板文件里明明写了${DATE}和${TIME}但是新建的类文件里出现的是字面量${DATE}而不是日期。原因多半有这几种可能。第一你打开的是File and Code Templates - Code页签下的某个模板而不是Includes - File Header.java。Code 页签下的模板也可以包含变量但如果你在错误的位置写变量比如写在了#parse(File Header.java)之外的文本里IDE 解析顺序可能会导致变量无法被替换。第二IDEA 的模板变量${DATE}和${TIME}格式默认受系统区域设置影响有些自定义格式如${YEAR}、${MONTH}在老的 IDEA 版本中支持不完整高版本没问题低版本可能原样输出。解决思路很简单不要自己发明变量名。IDEA 支持哪些变量在模板配置页面的右侧有Available Variables列表鼠标悬停在每个变量上能看到说明。你只需要从列表里挑选不要自己猜变量名。比如有的教程让你写${dateTime}这个变量列表里根本不存在那结果就是原样输出。4.2 自定义注释脚本导致新建文件失败File and Code Templates 支持通过#parse引入文件也支持在模板中直接引用变量但如果你在模板里写了#if之类的 Velocity 语法一旦语法错误IDE 会弹窗报错甚至直接阻止文件创建。我遇到过一种情况我尝试在模板中使用#if指令来判断当前创建的是否为接口写法类似于#if (${PACKAGE_NAME} ${PACKAGE_NAME} ! ) package ${PACKAGE_NAME}; #end这个是 IDEA 默认模板里自带的标准写法本身没问题。问题出在我从网上复制了一段自定义脚本它里面引用了某个未定义的变量而且脚本里的引号和括号是中文全角符号。IDEA 在解析模板时秒挂弹了一个File and Code Templates: unable to parse template的红色报错框。排查时我足足看了五分钟才看出那个全角逗号这属于纯低级错误但也恰恰说明模板脚本越简洁越好复杂度留给 Live Templates 或者外部脚本处理。4.3 模板只对新建的类生效对已存在的类文件没用这一点得明确不然会有人误以为模板坏了。File and Code Templates 只作用于“新建文件”的时刻已经手动创建过的类文件不会在你配置完模板后自动补上注释。如果想给大量已有类文件补头注释要么用编辑器的Find and Replace批量处理要么用 IDE 的File | New | Java Class重建文件内容或者借助第三方插件如Save Actions配合自定义配置来实现。如果你真的需要批量给历史代码补头注释我的经验是先导出类清单用脚本在文件最前面的package语句之前插入注释块再统一格式化。这个过程务必先跑一遍本地 Git diff确认没有破坏原有代码结构。不要用正则替换的方式风险极高很容易误伤 package-info 注释或者源码中已有的/*块。4.4 模板生效了但格式错乱注释对不齐很多人的头注释模板里同时有Author、date、version多个字段IDEA 默认的格式化规则可能会把*对齐方式搞乱。解决办法是在模板里手动对齐空格因为注释块中的*对齐是按照你模板里的文本内容来的不是自动对齐的。比如你写* author: ${USER} * date: ${DATE}这样一个字符不多一个不少IDEA 生成出来的文件基本都是漂亮的。但如果你在$变量附近多打了一个空格或者中文字符和英文字符宽度不同生成后看起来就会有点歪。中英文混排在注释对齐这个问题上属于老大难问题了建议模板里统一用英文标签比如author、date、version不要出现“作者”“日期”之类的汉字标签。不是不能用而是在不同字体环境下汉字宽度会影响对齐效果容易显得不够专业。5. 进阶玩法连带把方法的注释也做成快速模板5.1 Live Template 和文件头模板的配合类头注释只是第一层。当一个类的头部注释稳固之后你会发现下一个痛点马上出现方法注释。在 IDEA 里给方法写 Javadoc 注释手动输入一堆param和return是一件特别枯燥的事情。所以我会同步配置一套 Live Template通过输入/**然后按 Tab 或者自定义快捷键的方式自动生成方法注释。Live Templates 的配置入口在Settings - Editor - Live Templates。点击右侧的号选择Template Group建一个自己的分组比如叫MyComment。然后在分组内新建一个Live Template缩写Abbreviation可以设为*描述填“方法注释模板”。模板内容可以这样写* * description $description$ * author: $user$ * date: $date$ $time$ * param $params$ * return $return$这里有个关键点模板的第一行不要写成/**因为响应的是 Javadoc 场景下的上下文。缩写的触发键是 Tab你在方法上方输入/**然后按 TabIDEA 会用模板内容替换掉原有的/**自动展开剩下部分。实际配置时变量的设置方式是这样的每个变量需要指定Expression。比如$user$变量的表达式设置为user()$date$设置为date()$time$设置为time()$params$和$return$这两个比较麻烦因为它们需要获取当前方法的参数列表和返回类型。IDEA 提供了内置表达式比如methodParameters()和methodReturnType()直接在变量表达式里填这两个函数名就行。试一下效果写一个方法上方输入/**按 TabIDE 自动生成/** * description * author: ZhangSan * date: 2024-11-03 14:23:45 * param [name, age] * return java.lang.String */是不是爽多了5.2 解决方法注释中参数无法生成多行的问题内置的methodParameters()函数生成的是参数列表所有参数挤在一行里。如果你想实现标准 Javadoc 里每个参数一行的效果* param name 姓名 * param age 年龄那methodParameters()函数就搞不定了。这时候需要启用一段 Groovy 脚本让 IDEA 帮你把参数列表拆成多行并生成完整的param块。在 Live Templates 的Edit variables弹窗里选中params变量在Expression下拉框中选GroovyScript。然后填上一段脚本内容核心原理是拿到 IDEA 的methodParameters()原始值再用 Groovy 把它转换成多行格式。脚本参考如下def params _1.replaceAll([\\\\[|\\\\]|\\\\s], ).split(,).findAll { !it.isEmpty() } def result params.collect { p - def parts p.split( ).toList() if (parts.size() 1) { return parts[0] parts[1] } return p }.join(, ) return [ result ]这里我简化了脚本因为真正的完整脚本很长而且不同 IDEA 版本之间 API 略有差异你直接在项目里引入我这段逻辑并微调参数分隔即可。更优雅的方案是引入expandMethodParameters.groovy这个第三方脚本文件网上有很多现成的版本把它们放到 IDEA 的配置目录config/scripts下模板里直接引用文件路径即可。我个人是更倾向用脚本文件的因为代码可读性好维护也方便。5.3 快捷键冲突的问法Live Template 缩写是*的时候如果输入/**按 Tab展开模板是没有问题的因为 Template 的适用场景我们限定在Java - Comment。但有一种情况会打架如果你装了某些代码生成插件比如GenerateAllSetter、Lombok插件等它们也会在注释快捷键上有一些占用。遇到 Tab 无法展开时先确认Edit variables下面有个复选框Skip if defined以及展开范围Applicable in是不是勾选了Java: comment。把这些都检查一遍大概率就能解决。6. 我给这套模板做过的“本地化”调整6.1 区分个人电脑和公司统一规范如果你是个人开发类头注释怎么写都随意。但如果是团队项目我强烈建议把注释模板纳入工程规范提交到代码仓库的README或者.idea的配置同步文件中。IDEA 允许你把自定义模板导出为 jar 包也可以通过Settings Repository插件做云端同步让每个组员拉下来之后自动拥有同一套模板配置。具体导出方式File - Manage IDE Settings - Export Settings勾选File and code templates和Live templates这两项导出后把 zip 包发到组内。有人重置了 IDE 之后只需要Import Settings就能恢复。我每次搭新的开发环境都会用这个功能比手动重新配一遍舒服太多。还有一个坑必须提醒如果你在公司环境里配置了 Java 类模板但你又用 IDEA 写 Kotlin、Groovy 或者其他文件类型别忘记每个文件类型都有独立的模板入口它们之间不互通。你改了 Java 的类头注释Kotlin 文件新建时还是旧样子需要单独去File and Code Templates - Code下找到Kotlin File和Kotlin Class进行配置。6.2 模板内容的设计原则越克制越优雅配置模板这件事最难的不是技术而是克制。很多人第一次玩模板会配置一大堆内容作者、日期、版本、版权、公司名、修改记录、TODO 提醒……整个类头注释占了满满十行。这在团队代码评审中反而会成为负担因为每一个字段都需要维护都会过期。没人想每次改代码都去同步注释里的版本号和修改记录。我的真实想法是类头注释保留“类名 描述 作者 创建时间 项目名”就够了。修改记录不用写因为 Git 的blame功能比手写的记录准确一万倍。版本号不用写因为 Maven 和 Git 标签会管理它。传说中的版权声明除非公司法务强制要求否则不加也问题不大。模板的终极意义是减少重复劳动而不是增加维护成本。每次我在新环境配好模板后都会花十几秒新建一个测试类然后把光标放在Description TODO位置看看输入一个中文描述时是否流畅这已经成了我的固定仪式。7. 最后的两个小技巧送给同样折腾过模板的你说两个我在实践里觉得特别实用的小技巧。第一个技巧在模板里加一个自定义的占位标记比如TODO新建类后 IDEA 会自动把这个标记识别成 TODO 项会在View - Tool Windows - TODO面板里列出来。这样你创建了一堆新类打开 TODO 面板一看就知道哪些类还没有补注释描述处理起来一目了然。第二个技巧IDEA 的模板变量表达式的date()、time()函数输出的格式取决于你系统区域的设置。如果你想要固定格式比如2024-11-03 14:23:45直接用默认的${DATE}和${TIME}往往不满足。解决办法是用 Live Template 里的变量表达式在日期后面带上格式字符串例如date(yyyy-MM-dd HH:mm:ss)这个是 Groovy 表达式IDEA 会按你指定的格式输出固定格式的时间不再受系统区域设置影响。用了这个之后注释里的时间格式稳定如一跨团队跨电脑都不会乱。我个人在实际操作中最深的感受是配置一次模板看似只是省了每敲一个类文件多出来的十秒钟但放大到一个月、一年省下来的时间和心智是巨大的。而且更重要的是它让团队生成的代码格式像印刷体一样统一这种统一的工程习惯会潜移默化地提升代码质量。希望这篇文章能帮你避开我当年踩过的那些坑尽快拥有一套顺手、稳妥、经得起版本迭代的注释模板配置。