IntelliJ IDEA给Controller、Service、Mapper不同文件设置不同的文件头注释模板、Velocity模板引擎
通过在 IntelliJ IDEA 中的 “Includes” 部分添加多个文件头模板,并在 “Files” 模板中利用这些包含来实现不同类型文件的注释。以下是为 Controller、Service、Mapper 文件设置不同文件头的完整示例:
1. 设置 Includes 文件头模板
File > Settings (在 macOS 上是 Preferences)> Editor > File and Code Templates > includes
在 “Includes” 选项卡中,创建以下三个文件头模板:
ControllerHeader
/*** 控制层:* Controller Class: ${NAME}* @Author: ${USER}* @Date: ${DATE} ${TIME}* @Version: ${VERSION}* @Description: ${DESCRIPTION}*/
ServiceHeader
/*** 服务层:* Service Class: ${NAME}* @Author: ${USER}* @Date: ${DATE} ${TIME}* @Version: ${VERSION}* @Description: ${DESCRIPTION}*/
MapperHeader
/*** 数据层:* Mapper Class: ${NAME}* @Author: ${USER}* @Date: ${DATE} ${TIME}* @Version: ${VERSION}* @Description: ${DESCRIPTION}*/
2. 设置 Files 模板
2.1 设置路径
File > Settings (在 macOS 上是 Preferences)> Editor > File and Code Templates > includes
2.2 在 “Files” 选项卡中,找到或创建 Java 类模板,并使用条件判断来选择合适的文件头:
2.2.1 根据文件名区分
${NAME.endsWith("Controller")}
这种写法专业名词叫Velocity 模板引擎
,关于该引擎在后续有详细介绍
#if (${NAME.endsWith("Controller")})#parse("ControllerHeader.java")
#elseif (${NAME.endsWith("Service")})#parse("ServiceHeader.java")
#elseif (${NAME.endsWith("Mapper")})#parse("MapperHeader.java")
#else
/*** Class: ${NAME}* Author: ${USER}* Date: ${DATE}* Description: ${DESCRIPTION}*/
#end
使用更严谨的File template
#if (${NAME.matches(".*Controller$")})#parse("ControllerHeader.java")
#elseif ($NAME.matches(".*Service$") || $NAME.matches(".*ServiceImpl$"))#parse("ServiceHeader.java")
#elseif (${NAME.matches(".*(Mapper|Dao|Repo)$")})#parse("DataLayerHeader.java")
#else
/*** Class: ${NAME}* Author: ${USER}* Date: ${DATE}* Description: ${DESCRIPTION}*/
#end
2.2.2根据包名区分
#if (${PACKAGE_NAME}.contains("controller"))
/*** Controller层 - ${NAME}* 包路径:${PACKAGE_NAME}*/
#elseif (${PACKAGE_NAME}.contains("service"))
/*** Service层 - ${NAME}*/
#elseif (${PACKAGE_NAME}.contains("mapper"))
/*** Mapper接口 - ${NAME}*/
#end
- 更严谨的判断
#set($isMapperPackage = ${PACKAGE_NAME.contains(".mapper")} || ${PACKAGE_NAME.contains(".dao")})
#set($isServiceImplPackage = ${PACKAGE_NAME.contains(".service.impl")})#if ($isMapperPackage && ($isMapper || ${NAME.endsWith("Repository")}))#parse("mapperHeader.java")
#elseif ($isServiceImplPackage)#parse("serviceImplHeader.java")
#end
3. 应用模板
- 当你创建一个新文件时,例如
UserController.java
、UserService.java
或UserMapper.java
,IDEA 将根据文件名后缀自动应用相应的文件头注释。 - 确保新文件的命名遵循
*Controller
、*Service
、*Mapper
的模式,以便条件判断能够正确匹配。
4. 为不同文件类型创建完全独立模板
4.1 实图讲解
- 新增Controller模板—效果图:
New
->Java Class
->Controller
就会出现新添加的模板
4.2 自定义Files模板详细设置
在 IntelliJ IDEA 中创建需要的文件模板,比如 Controller、Service、Mapper,可以通过以下步骤来实现:
-
打开文件模板设置:
- 在 IntelliJ IDEA 的菜单栏中,点击
File
->Settings
(在 macOS 上是IntelliJ IDEA
->Preferences
)。 - 在左侧栏中,选择
Editor
->File and Code Templates
。
- 在 IntelliJ IDEA 的菜单栏中,点击
-
创建新的文件模板:
- 在
Files
标签页中,点击右上角的+
按钮,创建一个新的文件模板(如Controller)。 - 为你的模板命名,比如
Controller
、Service
、Mapper
, - 设置文件名:如
Controller
等,扩展名:java
。
- 在
-
定义文件模板内容:
-
在模板的编辑器中输入你希望的文件内容。你可以使用变量来动态生成代码,如
${NAME}
、${PACKAGE_NAME}
等。 -
例如,对于一个
Controller
模板,你可以这样定义:package ${PACKAGE_NAME};import org.springframework.web.bind.annotation.*;#parse("ControllerHeader.java") @RestController @RequestMapping("/${NAME}") public class ${NAME}Controller {// Add your endpoints here }
-
对于
Service
模板,可以这样定义:package ${PACKAGE_NAME};import org.springframework.stereotype.Service;#parse("ServiceHeader.java") @Service public class ${NAME}Service {// Add your service methods here }
-
对于
Mapper
模板,可以这样定义:package ${PACKAGE_NAME};import org.apache.ibatis.annotations.Mapper;#parse("MapperHeader.java") @Mapper public interface ${NAME}Mapper {// Add your mapper methods here }
-
-
使用模板:
- 当你创建新文件时,右键点击项目结构树中的目标包或目录,选择
New
->Java Class
。 - 在弹出的对话框中,选择你创建的模板(如
Controller
、Service
、Mapper
)。 - 输入文件名,IDEA 会根据模板自动生成文件内容,包括你预定义的文件头注释。
- 当你创建新文件时,右键点击项目结构树中的目标包或目录,选择
通过这些步骤,你可以为常用的文件类型创建模板,提升开发效率和代码的一致性。
5. Velocity 模板引擎
如**#set
** 是 Velocity 模板引擎的核心指令之一。以下为您完整解析 Velocity 的语法体系和学习路径:
5.0 相关指令
以下是 Velocity 模板引擎核心指令的详细解析:
一、变量操作指令
1. #set
- 变量赋值
#set($var = "value") ## 字符串
#set($num = 10 + 5) ## 数值计算
#set($list = [1, 2, 3]) ## 列表
#set($map = {"key":"value"}) ## 键值对
特性:
- 右值可以是表达式、方法调用或嵌套指令
- 变量类型动态推断(无需声明类型)
- 变量作用域为整个模板(类似全局变量)
特殊场景:
## 多变量赋值
#set($a = $b = 10)## 空值处理
#set($result = $optionalValue ?: "default")
二、流程控制指令
2. #if / #elseif / #else
- 条件分支
#if($user.role == "admin")ADMIN MODE
#elseif($user.age >= 18)ADULT USER
#elseGUEST MODE
#end
判断规则:
条件表达式 | 判定为 false 的情况 |
---|---|
$var | null、空字符串、空集合、false |
$var == 5 | 值不相等或类型不同 |
$list && $list.size() > 0 | 组合逻辑判断 |
3. #foreach
- 循环迭代
#foreach($item in $items)Item $foreach.index: $item.name#if($foreach.count == 5)#break ## 退出循环#end
#end
循环变量:
属性 | 说明 |
---|---|
$foreach.index | 当前索引(从 0 开始) |
$foreach.count | 当前计数(从 1 开始) |
$foreach.first | 是否是第一次迭代(布尔值) |
$foreach.last | 是否是最后一次迭代(布尔值) |
三、模板组织指令
4. #include
- 静态引入
#include("header.html")
特点:
- 引入的文件内容不解析 Velocity 语法
- 适合引入静态 HTML/CSS/JS 片段
- 可一次引入多个文件:
#include("head.html", "footer.html")
5. #parse
- 动态解析
#parse("user_card.vm")
与 #include 对比:
特性 | #parse | #include |
---|---|---|
语法解析 | ✅ 会解析 VTL 指令 | ❌ 原样输出 |
变量共享 | ✅ 共享当前上下文变量 | ❌ 无变量传递 |
性能 | 较低(需解析) | 较高(直接读取) |
6. #stop
- 引擎停止
#if($error)#stop ## 立即终止模板渲染
#end
使用场景:
- 遇到致命错误时中断渲染
- 调试时快速定位问题
四、逻辑控制指令
7. #break
- 退出当前指令
#foreach($item in $list)#if($item == "stop") #break ## 退出当前 #foreach 循环#end
#end
作用范围:
- 仅对当前所在指令有效(如
#foreach
、#macro
)
8. #evaluate
- 动态执行
#set($template = "Hello $name")
#evaluate($template) ## 输出:Hello John
危险操作:
## 可能引发代码注入(慎用!)
#evaluate($userInput)
五、代码复用指令
9. #define
- 定义代码块
#define($block)<div class="alert">This is a reusable block</div>
#end## 调用
$block
特点:
- 类似变量赋值,但可包含复杂 HTML/VTL
- 每次调用输出相同内容
10. #macro
- 定义可传参宏
#macro(renderUser $user $isAdmin)<div class="#if($isAdmin)admin#end">$user.name</div>
#end## 调用
#renderUser($currentUser true)
高级特性:
功能 | 示例 |
---|---|
默认参数 | #macro(show $msg="Hello") |
可变参数 | #macro(sum $nums...) |
嵌套调用 | 宏内可调用其他宏 |
六、指令对比矩阵
指令 | 是否解析内容 | 是否共享变量 | 典型应用场景 |
---|---|---|---|
#include | ❌ | ❌ | 引入静态资源文件 |
#parse | ✅ | ✅ | 模块化动态模板 |
#define | ✅ | ✅ | 定义重复使用的静态内容块 |
#macro | ✅ | ✅ | 创建带参数的复用组件 |
七、安全实践建议
-
避免
#evaluate
用户输入## 危险! #evaluate($request.getParameter("tpl"))
-
防御性模板设计
## 安全变量引用 $!{userInput} ## 自动处理 null## 集合判空 #if($!{list} && $list.size() > 0)
-
性能优化
## 复杂计算预编译 #set($regex = "^\\d{4}-\\d{2}-\\d{2}$") #if($dateStr.matches($regex))
八、完整示例模板
## 用户列表模板 (user_list.vm)
#define($header)<!DOCTYPE html><html><head><title>User List</title>#include("styles.css")</head>
#end#macro(userCard $user)<div class="card">#parse("user_avatar.vm")<h3>$!{user.name}</h3>#if($user.isAdmin)<span class="badge">ADMIN</span>#end</div>
#end$header
<body>#foreach($user in $users)#if($user.name == "root")#stop ## 禁止显示 root 用户#end#userCard($user)#if($foreach.count >= 100)#break ## 最多显示 100 条#end#end#parse("footer.vm")
</body>
</html>
以上内容可作为 Velocity 开发的权威参考,建议结合官方文档实践验证。每个指令的详细行为可能因 Velocity 版本略有差异(本文基于 2.x 版本)。
5.1、#set
指令详解
5.1.1. 基础作用
#set($variable = "value")
- 变量定义:创建或修改变量(类似编程中的赋值)
- 动态计算:可赋值为字符串、数字、布尔值,或通过表达式计算的结果
- 作用域:在整个模板中有效(类似全局变量)
5.1.2. 典型用法
## 字符串赋值
#set($className = "UserController")## 数值计算
#set($total = 10 + 5 * 3) ## $total = 25## 布尔逻辑
#set($isValid = $name && $name.length() > 5)## 对象方法调用
#set($firstChar = $className.substring(0,1))
5.2、Velocity 的语法规则
Velocity 的语法规则来源于以下渠道:
5.2.1. 官方文档
Apache Velocity 官网 (velocity.apache.org) 提供完整的 VTL (Velocity Template Language) 规范。
5.2.2. IDE 集成
- IntelliJ IDEA 等 IDE 的 Velocity 模板编辑界面会提供语法提示
- 输入
#
时会自动弹出指令列表(如#if
,#foreach
,#macro
)
5.2.3. 开源项目实践
- 许多 Java 项目(如 Spring Boot 的代码生成器)使用 Velocity 模板
- 通过阅读开源代码学习实际应用技巧
5.3、系统学习 Velocity 语法的路径
5.3.1. 基础语法
指令/语法 | 用途 | 示例 |
---|---|---|
变量引用 | 输出变量值 | $variable 或 ${variable} |
注释 | 添加模板注释 | ## 单行注释 或 #* 多行注释 *# |
#set | 变量赋值 | #set($price = 99.9) |
#if/#else/#elseif | 条件分支 | 见下方示例 |
#foreach | 循环遍历集合 | 见下方示例 |
条件判断示例:
#if($user.role == "admin")<p>管理员权限</p>
#elseif($user.age > 18)<p>成年用户</p>
#else<p>未成年用户</p>
#end
循环示例:
<ul>
#foreach($item in $items)<li>${foreach.index} - ${item.name}</li>
#end
</ul>
5.3.2. 高级功能
功能 | 说明 | 示例 |
---|---|---|
宏 (Macro) | 定义可复用的代码片段 | #macro(showError $msg)<div class="error">$msg</div>#end |
引入其他模板 | 模块化模板设计 | #parse("header.vm") |
内置工具对象 | 提供字符串/数学等工具方法 | $math.add(1,2) 或 $date.format('yyyy-MM-dd') |
转义输出 | 防止 XSS 攻击 | $!{userInput} 或 #escape($htmlContent) |
宏定义与调用:
## 定义宏
#macro(renderButton $text $color)<button style="color:${color}">$text</button>
#end## 调用宏
#renderButton("提交", "blue")
5.3.3. 调试技巧
- 输出原始文本:使用
#[[ 不解析的内容 ]]#
#[[这里的 $variable 不会被解析 → 直接输出 $variable ]]#
- 查看变量类型:
$variable.class.name ## 输出变量类型(如 java.lang.String)
5.4、快速查询手册
在模板开发中常用以下语法:
需求场景 | 对应语法 |
---|---|
避免变量为 null 时报错 | $!{variable} |
字符串拼接 | #set($fullName = "$firstName $lastName") |
集合是否为空判断 | #if($list.isEmpty()) 或 `#if(!$list |
数值格式化 | $number.format("#,###", $price) |
日期格式化 | $date.format('yyyy-MM-dd', $today) |
5.5、学习资源推荐
5.5.1. 官方文档(必读)
- VTL 语法参考
- 用户指南
5.5.2. 实战教程
- Baeldung 的 Velocity 指南
- TutorialsPoint 的 Velocity 教程
5.5.3. IDE 辅助
- 在 IntelliJ IDEA 中创建
.vm
文件,IDE 会提供:- 语法高亮
- 指令自动补全(输入
#
触发) - 错误检查
5.6、示例:完整模板文件
## 模板:user_profile.vm
#set($user = $data.getUser())
#set($birthday = $date.format('yyyy-MM-dd', $user.birthDate))<html>
<head><title>$!{user.name} 的资料</title>
</head>
<body>#if($user.isAdmin())<div class="admin-banner">管理员用户</div>#end<h1>用户信息</h1><ul><li>姓名:$!{user.name}</li><li>年龄:$math.sub($date.getYear(), $user.birthYear)</li><li>生日:$birthday</li></ul>#macro(renderSection $title $content)<div class="section"><h2>$title</h2><p>$content</p></div>#end#renderSection("联系方式", $user.contactInfo)
</body>
</html>
通过系统学习上述内容,您将能:
- 熟练使用 Velocity 生成动态内容
- 理解模板引擎的运行机制
- 快速定位和解决模板渲染问题
建议边学边实践,在 IntelliJ 中创建 .vm
文件体验实时语法反馈。
5.7 Velocity引擎与Freemarker等热门引擎对比以及应用场景
Velocity 确实不如 Freemarker、Thymeleaf 这类模板引擎知名度高,但它是一个历史悠久且特定场景下非常高效的模板引擎。以下是它的核心应用场景和特点解析,帮助您理解为什么某些场景(比如 IDEA 的注释模板)会选择它:
一、Velocity 的典型应用场景
1. 代码生成(核心优势场景)
- Java 注释模板(如 IDEA 内置)
- MyBatis 逆向工程(生成 DAO/Mapper 文件)
- Spring Boot 项目脚手架(如 JHipster 早期版本)
- API 文档生成(结合 Swagger 模板)
优势:
✅ 语法简单,适合非前端开发者使用
✅ 无复杂依赖,可嵌入任何 Java 环境
✅ 生成纯文本(代码/配置文件)时性能极高
2. 传统 Web 页面渲染(逐渐被替代)
- 早期的 Java Web 项目(如 Struts 1.x 时代)
- 企业级 CMS 内容模板(如 Alfresco)
现状:
⚠️ 新项目更推荐 Thymeleaf/FreeMarker(对现代前端更友好)
⚠️ 不支持响应式设计等现代特性
3. 邮件模板
- 企业级邮件内容动态生成(如订单通知)
- 相比 HTML 页面,邮件模板更简单,Velocity 足够轻量
4. 配置文件动态化
#set($dbHost = "192.168.1.100")
jdbc.url=jdbc:mysql://${dbHost}:3306/db
二、为什么 IDEA 选择 Velocity 做注释模板?
-
轻量级
无需引入额外依赖,IDEA 内置的模板引擎需要极低的开销。 -
逻辑简单
注释模板通常只需要变量替换和简单条件判断,例如:/*** @author ${USER}* @date ${DATE}#if(${DESCRIPTION})* @description ${DESCRIPTION}#end*/
-
无副作用
不会像 FreeMarker 那样产生意外换行或空格(对代码格式敏感)。
三、与现代模板引擎对比
特性 | Velocity | FreeMarker | Thymeleaf |
---|---|---|---|
学习曲线 | ⭐(最简单) | ⭐⭐ | ⭐⭐⭐(需懂 HTML) |
性能 | ⭐⭐⭐(最快) | ⭐⭐ | ⭐ |
前端友好度 | ❌(纯后端) | ✅ | ✅⭐⭐⭐(原生 HTML) |
动态代码生成 | ✅⭐⭐⭐ | ✅⭐ | ❌ |
社区活跃度 | ⭐(维护模式) | ⭐⭐⭐ | ⭐⭐⭐⭐ |
四、经典代码生成示例
MyBatis 生成器模板(mapper.xml.vm
)
<!-- 生成于 ${date} -->
<mapper namespace="${package.Mapper}.${table.mapperName}">#foreach($field in ${table.fields})#if(${field.keyFlag})<id column="${field.name}" property="${field.propertyName}" />#else<result column="${field.name}" property="${field.propertyName}" />#end#end<select id="selectById" resultMap="BaseResultMap">SELECT * FROM ${table.name} WHERE id = #{id}</select>
</mapper>
Spring Controller 模板(Controller.java.vm
)
#set($entity = ${table.entityName.toLowerCase()})
@RestController
@RequestMapping("/api/${entity}")
public class ${table.controllerName} {@Autowiredprivate ${table.serviceName} ${entity}Service;@GetMapping("/{id}")public Result<${table.entityName}> getById(@PathVariable ${table.primaryKeyType} id) {return Result.success(${entity}Service.getById(id));}
}
五、什么时候应该选择 Velocity?
-
需要生成代码/配置文件
(如自动生成 CRUD 代码、批量创建相似文件) -
嵌入式模板需求
(如插件系统需要允许用户自定义模板) -
历史项目维护
(老系统升级时保留原有模板)
六、为什么不推荐新项目用 Velocity 做页面渲染?
-
功能局限
缺少模板继承、片段复用等现代特性,复杂页面难以维护。 -
前后端协作困难
设计师无法直接修改 HTML(模板语法混合在标签中)。 -
安全风险
默认不开启 HTML 转义,容易导致 XSS 攻击(需手动处理)。
七、快速识别 Velocity 模板
- 文件扩展名:
.vm
- 语法特征:
<!-- 变量使用 $ 前缀 --> <h1>$title</h1><!-- 指令以 # 开头 --> #foreach($item in $list)<li>$item</li> #end
如果您只需要一个轻量级文本生成工具(如代码注释、配置文件生成),Velocity 仍然是优秀选择。但对于 Web 页面开发,建议转向 FreeMarker/Thymeleaf 等现代引擎。