velocity模板引擎

news2025/4/20 22:57:18

文章目录

  • 学习链接
  • 一. velocity简介
    • 1. velocity简介
    • 2. 应用场景
    • 3. velocity 组成结构
  • 二. 快速入门
    • 1. 需求分析
    • 2. 步骤分析
    • 3. 代码实现
      • 3.1 创建工程
      • 3.2 引入坐标
      • 3.3 编写模板
      • 3.4 输出结果
      • 示例1
        • 编写模板
        • 测试
      • 示例2
    • 4. 运行原理
  • 三. 基础语法
    • 3.1 VTL介绍
    • 3.2 VTL注释
      • 3.2.1 语法
      • 3.2.1 示例
    • 3.3 非解析内容
      • 3.3.1 语法
      • 3.3.2 示例
    • 3.4 引用
      • **3.4.1 变量引用**
        • 语法
        • 示例
      • 3.4.2 属性引用
        • 语法
        • 示例
      • 3.4.3 方法引用
        • 语法
        • 示例
    • 3.5 指令
      • 3.5.1 流程控制
        • #set
        • #if/#elseif/#else
        • #foreach
      • 3.5.2 引入资源
        • #include
        • #parse
        • #define
        • #evaluate
      • 3.5.3 宏指令
  • 四. 综合案例
    • 4.1 需求分析
    • 4.2 步骤分析
    • 4.3 代码实现
      • 4.3.1 创建项目
      • 4.3.2 导入依赖
      • 4.3.3 编写模板
        • Controller.java.vm
        • Service.java.vm
        • ServiceImpl.java.vm
        • Dao.java.vm
      • 4.3.4 生成代码
      • 4.3.5 运行测试

学习链接

velocity模板引擎
freemarker模板引擎
thymleaf模板引擎

Apache Velocity Project 官网

Velocity Engine基础

Velocity 模板引擎使用介绍

黑马程序员Java进阶VelocityTools全套教程

一. velocity简介

1. velocity简介

Velocity是一个基于Java的模板引擎,可以通过特定的语法获取在java对象的数据 , 填充到模板中,从而实现界面和java代码的分离 !

在这里插入图片描述

2. 应用场景

  • Web应用程序 : 作为为应用程序的视图, 展示数据。
  • 源代码生成 : Velocity可用于基于模板生成Java源代码
  • 自动电子邮件 : 网站注册 , 认证等的电子邮件模板
  • 网页静态化 : 基于velocity模板 , 生成静态网页

3. velocity 组成结构

在这里插入图片描述

Velocity主要分为app、context、runtime和一些辅助util几个部分。

  • app模块 : 主要封装了一些接口 , 暴露给使用者使用。主要有两个类,分别是Velocity(单例)和VelocityEngine。

  • Context模块 : 主要封装了模板渲染需要的变量

  • Runtime模块 : 整个Velocity的核心模块,Runtime模块会将加载的模板解析成语法树,Velocity调用mergeTemplate方法时会渲染整棵树,并输出最终的渲染结果。

  • RuntimeInstance类为整个Velocity渲染提供了一个单例模式,拿到了这个实例就可以完成渲染过程了。

二. 快速入门

1. 需求分析

使用velocity定义html模板 , 将动态数据填充到模板中 , 形成一个完整的html页面

2. 步骤分析

  1. 创建项目(maven)
  2. 引入依赖
  3. 定义模板
  4. 输出html

3. 代码实现

3.1 创建工程

在这里插入图片描述

3.2 引入坐标

<dependencies>
    <dependency>
        <groupId>org.apache.velocity</groupId>
        <artifactId>velocity-engine-core</artifactId>
        <version>2.2</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>

3.3 编写模板

在项目resources目录下创建模板文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

hello , ${name} !

</body>
</html>

3.4 输出结果

@Test
public void test1() throws IOException {
    //设置velocity资源加载器
    Properties prop = new Properties();
    prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
    Velocity.init(prop);

    //创建Velocity容器
    VelocityContext context = new VelocityContext();
    context.put("name", "zhangsan");
    //加载模板
    Template tpl = Velocity.getTemplate("vms/demo1.vm", "UTF-8");

    FileWriter fw  = new FileWriter("D:\\work\\workspace\\velocity\\velocity_01\\src\\main\\resources\\html\\demo1.html");
    //合并数据到模板
    tpl.merge(context, fw);

    //释放资源
    fw.close();
}

示例1

编写模板

模板文件:resources/vms/template.vm

## 用户信息模板
#set($title = "用户详情")

<!DOCTYPE html>
<html>
<head>
    <title>$title</title>
</head>
<body>
<h1>$!{user.name} 的信息</h1>

    ## 条件判断:是否显示年龄
    #if($user.age && $user.age > 0)
    <p>年龄:$user.age 岁</p>
    #else
    <p>年龄:未公开</p>
    #end

    ## 循环输出朋友列表
<h2>好友列表(共 ${friends.size()} 人)</h2>
<ul>
    #foreach($friend in $friends)
        <li>
            ${foreach.count}. $friend.name
            #if($friend.role == "admin")
                (管理员)
            #end
        </li>
    #end
</ul>

    ## 使用宏简化代码
    #macro(showRole $role)
        #if($role == "admin")
        <span style="color: red;">管理员</span>
        #else
        <span style="color: blue;">普通用户</span>
        #end
    #end

<p>角色:#showRole($user.role)</p>
</body>
</html>
测试
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import java.io.StringWriter;
import java.util.List;
import java.util.Properties;

public class VelocityDemo {
    public static void main(String[] args) {
        // 1. 初始化引擎
        VelocityEngine velocityEngine = new VelocityEngine();
        Properties props = new Properties();
        props.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        velocityEngine.init(props);

        // 2. 创建上下文并填充数据
        VelocityContext context = new VelocityContext();
        context.put("user", new User("张三", 25, "admin"));
        context.put("friends", List.of(new User("ls", 25, "user"), new User("ww", 27, "user")));

        // 3. 加载模板(假设模板在 classpath 的 templates 目录)
        Template template = velocityEngine.getTemplate("vms/template.vm");

        // 4. 渲染结果
        StringWriter writer = new StringWriter();
        template.merge(context, writer);
        System.out.println(writer.toString());
    }
}

示例2

import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;

import java.io.StringWriter;
import java.util.List;

public class InlineVelocityDemo {
    public static void main(String[] args) {
    
        // 1. 初始化 Velocity 引擎(无需配置文件)
        VelocityEngine velocityEngine = new VelocityEngine();
        velocityEngine.init();  // 使用默认配置

        // 2. 定义模板字符串(直接写在代码中)
        String templateString = """
            ## 用户信息模板
            <h1>$!{user.name} 的信息 - $user.name - $!user.name</h1>
            
            #if($user.age > 0)
                <p>年龄:${user.age} 岁</p>
            #else
                <p>年龄:未公开</p>
            #end
            
            ## 循环输出订单
            <h2>近期订单:</h2>
            <ul>
            #foreach($order in $orders)
                <li>
                    $foreach.count. $order.id 
                    $order.amount
                </li>
            #end
            </ul>
            """;

        // 3. 准备模板变量(模拟数据)
        VelocityContext context = new VelocityContext();
        context.put("user", new User("李雷", 30));  // 自定义对象
        context.put("orders", List.of(
            new Order("O2023001", 199.99),
            new Order("O2023002", 599.50)
        ));

        // 4. 渲染模板
        try (StringWriter writer = new StringWriter()) {
        
            // 关键方法:直接解析字符串模板
            velocityEngine.evaluate(context, writer, "inline", templateString);
            
            // 5. 输出结果
            System.out.println(writer.toString());
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

4. 运行原理

Velocity解决了如何在后台程序和网页之间传递数据的问题,后台代码和视图之间相互独立,一方的修改不影响另一方 .

他们之间是通过环境变量(Context)来实现的,网页制作一方和后台程序一方相互约定好对所传递变量的命名约定,比如上个程序例子中的site, name变量,它们在网页上就是 n a m e , name , name,site 。

只要双方约定好了变量名字,那么双方就可以独立工作了。无论页面如何变化,只要变量名不变,那么后台程序就无需改动,前台网页也可以任意由网页制作人员修改。这就是Velocity的工作原理。

在这里插入图片描述

三. 基础语法

3.1 VTL介绍

Velocity Template Language (VTL) , 是Velocity 中提供的一种模版语言 , 旨在提供最简单和最干净的方法来将动态内容合并到网页中。简单来说VTL可以将程序中的动态数展示到网页中

VTL的语句分为4大类:注释 , 非解析内容 ** , 引用指令**。

3.2 VTL注释

3.2.1 语法

1. 行注释

## 行注释内容

2. 块注释

#*
块注释内容1
块注释内容2
*#

3. 文档注释

#**
文档注释内容1
文档注释内容2
*#

3.2.1 示例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
## 我是行注释

#*
* 我是块注释
* 呵呵呵
* *#

#**
* 我是文档注释
*
* *#
hello , ${name} !

</body>
</html>

3.3 非解析内容

所谓非解析内容也就是不会被引擎解析的内容。

3.3.1 语法

#[[
非解析内容1
非解析内容2 
]]#

3.3.2 示例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

hello , ${name} !
    
<h1>非解析内容</h1>
#[[
直接输出的内容1
直接输出的内容2
${name}
]]#
</body>
</html>

3.4 引用

3.4.1 变量引用

引用语句就是对引擎上下文对象中的属性进行操作。语法方面分为常规语法($属性)和正规语法(${属性})。

语法
$变量名, 若上下文中没有对应的变量,则输出字符串"$变量名"
${变量名},若上下文中没有对应的变量,则输出字符串"${变量名}" 
$!变量名, 若上下文中没有对应的变量,则输出空字符串"" 
$!{变量名}, 若上下文中没有对应的变量,则输出空字符串""
示例
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>引用变量</h1>
常规语法 : $name
正规语法 : ${name}

## 如果获取的变量不存在, 表达式会原样展示 , 如果不想展示 , 可以使用 $!变量名
## 以下写法的含义代表么如果有变量, 那么获取变量值展示, 没有变量展示""
常规语法 : $!name
正规语法 : $!{name}

</body>
</html>

3.4.2 属性引用

语法
$变量名.属性, 	若上下文中没有对应的变量,则输出字符串"$变量名.属性"
${变量名.属性}	若上下文中没有对应的变量,则输出字符串"${变量名.属性}"
$!变量名.属性	若上下文中没有对应的变量,则输出字符串""
$!{变量名.属性}	若上下文中没有对应的变量,则输出字符串""
示例
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>引用属性</h1>
常规语法 : $user.username --- $user.password
正规语法 : ${user.username} --- ${user.password}

正规语法 : ${user.email} --- ${user.email}
正规语法 : $!{user.email} --- $!{user.email}

</body>
</html>

3.4.3 方法引用

方法引用实际就是指方法调用操作,关注点返回值参数 , 方法的返回值将输出到最终结果中

语法
$变量名.方法([入参1[, 入参2]*]?), 常规写法
${变量名.方法([入参1[, 入参2]*]?)}, 正规写法

$!变量名.方法([入参1[, 入参2]*]?), 常规写法
$!{变量名.方法([入参1[, 入参2]*]?)}, 正规写法
示例
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>引用属性</h1>
$str.split(" ")
${str.split(" ")}
$time.getTime()
${time.getTime()}

</body>
</html>

3.5 指令

指令主要用于定义重用模块、引入外部资源、流程控制。指令以 # 作为起始字符。

3.5.1 流程控制

#set

作用 : 在页面中声明定义变量

语法: #set($变量 = 值)

示例 :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>set指令</h1>
#set($str = "hello world")
#set($int = 1)
#set($arr = [1,2])
#set($boolean = true)
#set($map = {"key1":"value1", "key2":"value2"})

## 在字符串中也可以引用之前定义过的变量
#set($str2 = "$str , how are you !")
#set($str3 = '$str , how are you !')
    

<h1>获取set指令定义的变量</h1>
${str}
${int}
${arr}
${boolean}
${map.key1}--${map.key2}
${str2}
${str3}


</body>
</html>
#if/#elseif/#else

作用 : 进行逻辑判断

语法 :

#if(判断条件)
  .........
#elseif(判断条件)
  .........
#else
  .........
#end 

示例 :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>if/elseif/else指令</h1>
#set($language="PHP")

#if($language.equals("JAVA"))
    java开发工程师
#elseif($language.equals("PHP"))
    php开发工程师
#else
    开发工程师
#end

</body>
</html>
#foreach

作用 : 遍历循环数组或者集合

格式:

#foreach($item in $items)
    ..........
    [#break]
#end
  • $items : 需要遍历的对象或者集合
    • 如果items的类型为map集合, 那么遍历的是map的value
  • $item : 变量名称, 代表遍历的每一项
  • break : 退出循环
  • 内置属性 :
    • $foreach.index : 获取遍历的索引 , 从0开始
    • $foreach.count : 获取遍历的次数 , 从1开始

示例 :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>遍历数组</h1>
#foreach($hobby in $hobbies)
    $foreach.index -- $foreach.count -- $hobby  <br>
    ${foreach.index} -- ${foreach.count} -- ${hobby}  <br>
#end

<h1>变量对象集合</h1>
<table border="1px" align="center">
    <tr>
        <td>编号</td>
        <td>用户名</td>
        <td>密码</td>
        <td>邮箱</td>
        <td>年龄</td>
        <td>操作</td>
    </tr>
    #foreach($user in $users)
        <tr>
            <td>${foreach.index}</td>
            <td>${user.username}</td>
            <td>${user.password}</td>
            <td>$user.email</td>
            <td>$user.age</td>
            <td>
                <a href="">编辑</a>
                <a href="">删除</a>
            </td>
        </tr>
    #end
</table>

<h1>遍历map集合</h1>
<h2>遍历值</h2>
 #foreach($value in $map)
     $value
 #end

<h2>遍历键值对</h2>
#foreach($entry in $map.entrySet())
    $entry.key -- $entry.value
#end


</body>
</html>

3.5.2 引入资源

#include

作用 : 引入外部资源 , 引入的资源不会被引擎所解析

语法 : #include(resource)

  • resource可以为单引号或双引号的字符串,也可以为**$变量**,内容为外部资源路径。
  • 注意 : 路径如果为相对路径,则以引擎配置文件加载器加载路径作为参考

示例 :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!-- 1、将hello.vm的内容全部引入, 
     2、如果引入的内容中有模板表达式的话,不会对内部的内容进行模板解析 -->
#include("vms/hello.vm")

</body>
</html>
#parse

作用 : 引入外部资源 , 引入的资源将被引擎所解析

语法 : #parse(resource)

  • resource可以为单引号或双引号的字符串,也可以为**$变量**,内容为外部资源路径。
  • 注意 : 路径如果为相对路径,则以引擎配置的文件加载器加载路径作为参考系

示例 :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!-- 1、将hello.vm的内容全部引入, 
     2、如果引入的内容中有模板表达式的话,会对内部的内容进行模板解析 -->
#include("vms/hello.vm")

</body>
</html>
#define

作用 : 定义重用模块(不带参数)

语法 :

#define($模块名称)
	模块内容
#end

示例 :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>定义模块</h1>
    <!-- define定义的内容中,可以使用模板表达式 -->
    #define($table)
    <table border="1px" align="center">
        <tr>
            <td>编号</td>
            <td>用户名</td>
            <td>密码</td>
            <td>邮箱</td>
            <td>年龄</td>
            <td>操作</td>
        </tr>
        #foreach($user in $users)
        <tr>
            <td>${foreach.index}</td>
            <td>${user.username}</td>
            <td>${user.password}</td>
            <td>$user.email</td>
            <td>$user.age</td>
            <td>
                <a href="">编辑</a>
                <a href="">删除</a>
            </td>
        </tr>
        #end
    </table>
    #end

<h1>使用模块</h1>
    $table
    $table
    $table

</body>
</html>
#evaluate

作用 : 动态计算 , 动态计算可以让我们在字符串中使用变量

语法 : #evalute("计算语句")

示例 :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>动态计算</h1>
    #set($name = "over")

    #if($name=='over')
        over
    #else
        not over
    #end

    ## 直接使用
    #evaluate("#if($name=='over') over  #else  not over #end")

    ## code是context中设置的变量, 它是字符串类型, 内容是: #if($name=='over') over  #else  not over #end
    ## 这里也可以解析出来
    #evaluate($code)

</body>
</html>

3.5.3 宏指令

作用 : 定义重用模块(可带参数)

语法 :

定义语法

#macro(宏名 [$arg]?)
   .....
#end

调用语法

#宏名([$arg]?)

**示例 : **

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        
        <h1>定义宏</h1>

        #macro(table $list)
        <table border="1px">
            <tr>
                <td>编号</td>
                <td>用户名</td>
                <td>密码</td>
                <td>邮箱</td>
                <td>年龄</td>
                <td>操作</td>
            </tr>
            #foreach($item in $list)
            <tr>
                <td>${foreach.count}</td>
                <td>${item.username}</td>
                <td>${item.password}</td>
                <td>${item.email}</td>
                <td>${item.age}</td>
                <td>
                    <a href="">编辑</a>
                    <a href="">删除</a>
                </td>
            </tr>
            #end
        </table>
        #end

        <h1>调用宏</h1>
        #table($users)

    </body>
</html>

四. 综合案例

4.1 需求分析

在实际项目开发过程中, 编写基础的CRUD操作代码, 往往会花费我们大量的时间 , 而且这些CRUD代码的基础结构基本上是固定的 , 如果能有一个代码生成器 , 能够帮助我们把这些代码生成出来 , 我们就可以节省出大量的时间关注核心业务代码的开发, 大大提高了我们的开发效率 !

需求 : 使用velocity实现一个简单的代码生成器 , 生成项目开发过程中的基础CRUD代码

4.2 步骤分析

  1. 创建项目
  2. 导入依赖
  3. 编写模板
  4. 生成代码

4.3 代码实现

4.3.1 创建项目

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.3.2 导入依赖

<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.2</version>
</dependency>

4.3.3 编写模板

一般我们的项目开发将项目分为三层 , 我们的代码生成器就基于传统的三层架构生成代码 , 所以我们需要为每一层的每一个类创建模板 , 所以需要有如下模板 :

  • Controller.java.vm : 控制层模板
  • Service.java.vm : 业务层接口模板
  • ServiceImpl.java.vm : 业务层实现模板
  • Dao.java.vm : 数据服务层模板(数据访问层基于通用Mpper实现)
Controller.java.vm
package ${package}.controller;

import ${package}.pojo.${className};
import ${package}.service.${className}Service;
import ${package}.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/${classname}")
public class ${className}Controller {

    @Autowired
    private ${className}Service ${classname}Service ;


    /**
     * 查询列表
     * @return
     */
    @RequestMapping("/list")
    public Result list(){
        List<${className}>  ${classname}s = null;
        try {
                ${classname}s = ${classname}Service.list();
            return Result.ok(${classname}s);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("查询数据异常");
        }
    }

    /**
     * 保存
     * @param ${classname}
     * @return
     */
    @RequestMapping("/save")
    public Result save(@RequestBody ${className} ${classname}){
        try {
                ${classname}Service.save(${classname});
            return Result.ok("新增数据成功");
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("新增数据异常");
        }
    }

    /**
     * 更新
     * @param ${classname}
     * @return
     */
    @RequestMapping("/update")
    public Result update(@RequestBody ${className} ${classname}){
        try {
                ${classname}Service.update(${classname});
            return Result.ok("修改数据成功");
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("修改数据异常");
        }
    }

    /**
     * 删除
     * @param ids
     * @return
     */
    @RequestMapping("/delete")
    public Result delete(@RequestBody Integer[] ids){
        try {
                ${classname}Service.delete(ids);
            return Result.ok("删除数据成功");
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("删除数据异常");
        }
    }
}

Service.java.vm
package ${package}.service;

import com.itheima.pojo.${className};

import java.util.List;
import java.util.Map;

public interface ${className}Service {

    /**
     * 查询数据列表
     * @return
     */
    List<${className}> list();

    /**
     * 保存数据
     * @param ${classname}
     */
    void save(${className} ${classname});

    /**
     * 更新数据
     * @param ${classname}
     */
    void update(${className} ${classname});

    /**
     * 删除数据
     * @param ids
     */
    void delete(Integer[] ids);
}

ServiceImpl.java.vm
package ${package}.service.impl;

import ${package}.dao.${className}Dao;
import ${package}.pojo.${className};
import ${package}.service.${className}Service;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class ${className}ServiceImpl  implements ${className}Service {

    @Autowired
    private ${className}Dao ${classname}Dao ;

    public List<${className}> list() {
        return ${classname}Dao.selectAll();
    }

    public void save(${className} ${classname}) {
            ${classname}Dao.insert(${classname});
    }

    public void update(${className} ${classname}) {
            ${classname}Dao.updateByPrimaryKey(${classname});
    }

    public void delete(Integer[] ids) {
        Stream.of(ids).forEach(${classname}Dao::deleteByPrimaryKey);
    }
}

Dao.java.vm
package ${package}.dao;

import com.itheima.pojo.${className};
import tk.mybatis.mapper.common.Mapper;

public interface ${className}Dao extends Mapper<${className}> {
}

4.3.4 生成代码

我们可以封装一个生成代码的工具类 , 后期生成代码运行工具类即可

package com.itheima.utils;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 代码生成器   工具类
 */
public class GenUtils {

    private static String currentTableName;

    public static List<String> getTemplates() {
        List<String> templates = new ArrayList<String>();
        templates.add("vms/Controller.java.vm");
        templates.add("vms/Service.java.vm");
        templates.add("vms/ServiceImpl.java.vm");
        templates.add("vms/Dao.java.vm");

        return templates;
    }


    /**
     * 生成代码
     */
    public static void generatorCode(Map<String, Object> data, 
                                     List<String> templates, 
                                     ZipOutputStream zip) {

        //设置velocity资源加载器
        Properties prop = new Properties();
        prop.put("file.resource.loader.class", 
                 "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        Velocity.init(prop);

        //封装模板数据
        VelocityContext context = new VelocityContext(data);

        //获取模板列表
        for (String template : templates) {
            //渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, "UTF-8");
            tpl.merge(context, sw);

            try {
                //添加到zip
                zip.putNextEntry(
                    new ZipEntry(getFileName(template, 
                                             data.get("className").toString(),
                                             data.get("package").toString()
                                            )
                    )
                );
                IOUtils.write(sw.toString(), zip, "UTF-8");
                IOUtils.closeQuietly(sw);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }



    /**
     * 获取文件名 , 每个文件所在包都不一样, 在磁盘上的文件名几路径也各不相同
     */
    public static String getFileName(String template, 
                                     String className,
                                     String packageName) {
        String packagePath = "main" + File.separator + "java" + File.separator;
        if (StringUtils.isNotBlank(packageName)) {
            packagePath += packageName.replace(".", File.separator) + File.separator;
        }

        if (template.contains("Dao.java.vm")) {
            return packagePath + "dao" + File.separator + className + "Dao.java";
        }

        if (template.contains("Service.java.vm")) {
            return packagePath + "service" + File.separator + className + "Service.java";
        }

        if (template.contains("ServiceImpl.java.vm")) {
            return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
        }

        if (template.contains("Controller.java.vm")) {
            return packagePath + "controller" + File.separator + className + "Controller.java";
        }

        return null;
    }
}

4.3.5 运行测试

public class GeneratorCodeTest {

    public static void main(String[] args) throws IOException {
        Map<String,Object> data = new HashMap<String,Object>();
        data.put("className","Product");
        data.put("classname","product");
        data.put("package","com.itheima");

        File file = new File("D:\\Users\\Desktop\\code.zip");
        FileOutputStream outputStream = new FileOutputStream(file);
        ZipOutputStream zip = new ZipOutputStream(outputStream);

        GenUtils.generatorCode(data, GenUtils.getTemplates(), zip);

        zip.close();
    }
}

运行完毕之后, 可以看到输出路径下回自动生成一个压缩文件 , 解压之后将里面的代码copy到我们的项目之中即可 !

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2339048.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

13.第二阶段x64游戏实战-分析人物等级和升级经验

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 上一个内容&#xff1a;12.第二阶段x64游戏实战-远程调试 效果图&#xff1a; 如下图红框&#xff0c;…

六边形棋盘格(Hexagonal Grids)的坐标

1. 二位坐标转六边形棋盘的方式 1-1这是“波动式”的 这种就是把【方格子坐标】“左右各错开半个格子”做到的 具体来说有如下几种情况 具体到庙算平台上&#xff0c;是很巧妙的用一个4位整数&#xff0c;前两位为x、后两位为y来进行表示 附上计算距离的代码 def get_hex_di…

SICAR 标准 安全门锁操作箱 按钮和指示灯说明

1、安全门锁操作箱 2、按钮和指示灯说明 一、指示灯说明 红灯&#xff1a; 常亮&#xff1a;表示安全门已解锁&#xff1b;闪烁&#xff1a;表示安全门未复位&#xff1b;熄灭&#xff1a;表示安全门已复位。 黄灯&#xff1a; 常亮&#xff1a;表示处于维修模式。 绿灯&…

Day10【基于encoder- decoder架构实现新闻文本摘要的提取】

实现新闻文本摘要的提取 1. 概述与背景2.参数配置3.数据准备4.数据加载5.主程序6.预测评估7.生成效果8.总结 1. 概述与背景 新闻摘要生成是自然语言处理&#xff08;NLP&#xff09;中的一个重要任务&#xff0c;其目标是自动从长篇的新闻文章中提取出简洁、准确的摘要。近年来…

【blender小技巧】使用blender的Cats Blender Plugin插件将3D人物模型快速绑定或者修复为标准的人形骨骼

文章目录 前言绑定或者修复人形骨骼1、下载模型2、导入模型到blender中3、删除无用的相机和灯光3、导出模型并在unity中使用 专栏推荐完结 前言 有时候我们下载的3D人物模型&#xff0c;可能不带骨骼信息&#xff0c;或者带一些错乱的骨骼信息。这时候我们就可以使用blender将…

Linux——firewalld防火墙(笔记)

目录 一&#xff1a;Firewalld防火墙的概述 &#xff08;1&#xff09;firewalld简介 &#xff08;2&#xff09;firewalld&iptables的关系 &#xff08;3&#xff09;firewalld与iptables service的区别 1. ‌规则管理方式‌ 2. ‌默认策略与设计逻辑‌ 3. ‌配置文…

YOLO拓展-锚框(anchor box)详解

一.锚框&#xff08;anchor box&#xff09;概述 1.1什么是锚框 锚框就是一种进行预测的像素框&#xff0c;通过遍历输入图像上所有可能的像素框&#xff0c;然后选出正确的目标框&#xff0c;并对位置和大小进行调整就可以完成目标检测任务。 对于yolo锚框的建设须基于实际…

kubernetes》》k8s》》Service

Kubernetes 中的 Service 是用于暴露应用服务的核心抽象&#xff0c;为 Pod 提供稳定的访问入口、负载均衡和服务发现机制。Service在Kubernetes中代表了一组Pod的逻辑集合&#xff0c;通过创建一个Service&#xff0c;可以为一组具有相同功能的容器应用提供一个统一的入口地址…

已注册商标如何防止被不使用撤销!

近年来已注册商标被撤销越来越多&#xff0c;不乏著名企业或机构&#xff0c;普推知产商标老杨看到前一阵看到央视和百度等申请的商标也被申请撤销&#xff0c;连续三年不使用撤销也是正常的商标流程。 已注册商标被撤销普推老杨看到案例主要是集中在一些早期申请注册的好记的商…

管理与维护samba服务器

允许 Linux、Unix 系统与 Windows 系统之间进行文件和打印机共享&#xff0c;使得不同操作系统的用户能够方便地访问和共享资源&#xff0c;就像在同一局域网中的 Windows 计算机之间共享资源一样。 server01安装Samba服务器 [rootserver ~]# rpm -qa | grep samba [rootserver…

EAGLE代码研读+模型复现

要对代码下手了&#xff0c;加油(ง •_•)ง 作者在他们自己的设备上展现了推理的评估结果&#xff0c;受第三方评估认证&#xff0c;EAGLE为目前最快的投机方法&#xff08;虽然加速度是评估投机解码方法的主要指标&#xff0c;但其他点也值得关注。比如PLD和Lookahead无需额…

2024期刊综述论文 Knowledge Graphs and Semantic Web Tools in Cyber Threat Intelligence

发表在期刊Journal of Cybersecurity and Privacy上&#xff0c;专门讲知识图谱技术和语义Web工具在网络威胁情报领域的作用&#xff0c;还把本体和知识图谱放在相同的地位上讨论。 此处可以明确一点&#xff1a;本体和知识图谱都可以用于网络威胁情报的应用&#xff0c;当然也…

linux socket编程之udp(实现客户端和服务端消息的发送和接收)

目录 一.创建socket套接字(服务器端) 二.bind将prot与端口号进行绑定(服务器端) 2.1填充sockaddr_in结构 2.2bind绑定端口 三.直接通信(服务器端) 3.1接收客户端发送的消息 3.2给客户端发送消息 四.客户端通信 4.1创建socket套接字 4.2客户端bind问题 4.3直接通信即可…

计算机网络 实验四 静态路由的配置与应用

一、实验目的 掌握路由器基础工作原理及静态路由协议机制熟练使用华为ENSP网络模拟器进行拓扑设计与设备配置建立系统化的网络故障排除思维通过实践验证静态路由在中小型网络中的部署优势 二、实验环境 硬件配置&#xff1a;标准PC终端软件工具&#xff1a;华为企业网络模拟…

[每周一更]-(第140期):sync.Pool 使用详解:性能优化的利器

文章目录 一、什么是 sync.Pool&#xff1f;二、sync.Pool 的基本作用三、sync.Pool 的主要方法四、sync.Pool 的内部工作原理五、sync.Pool 适用场景六、使用示例示例 1&#xff1a;基本使用输出示例&#xff1a;示例 2&#xff1a;并发使用 七、一个基于 sync.Pool 的 **Benc…

3.QT-信号和槽|自定义槽函数|自定义信号}自定义的语法}带参数的信号和槽(C++)

信号和槽 Linux信号 Signal 系统内部的通知机制. 进程间通信的方式. 信号源&#xff1a;谁发的信号.信号的类型&#xff1a;哪种类别的信号信号的处理方式&#xff1a;注册信号处理函数&#xff0c;在信号被触发的时候自动调用执行. Qt中的信号和Linux中的信号&#xff0c;虽…

健康养生之道

在快节奏的现代生活中&#xff0c;健康养生不再是中老年人的专属话题&#xff0c;越来越多的人开始意识到&#xff0c;合理的养生方式是保持良好身体状态和生活质量的关键。​ 饮食养生是健康的基石。遵循 “食物多样、谷类为主” 的原则&#xff0c;保证每天摄入足够的蔬菜、…

Spark-SQL核心编程3

数据加载与保存 通用方式&#xff1a; SparkSQL 提供了通用的保存数据和数据加载的方式。这里的通用指的是使用相同的API&#xff0c;根据不同的参数读取和保存不同格式的数据&#xff0c;SparkSQL 默认读取和保存的文件格式为parquet 数据加载方法&#xff1a; spark.read.lo…

TVM计算图分割--Collage

1 背景 为满足高效部署的需要&#xff0c;整合大量优化的tensor代数库和运行时做为后端成为必要之举。现在的深度学习后端可以分为两类&#xff1a;1&#xff09;算子库(operator kernel libraries)&#xff0c;为每个DL算子单独提供高效地低阶kernel实现。这些库一般也支持算…

MCGS昆仑通太屏笔记

4.3寸&#xff1a;4013ef/e1 7寸&#xff1a;7032kw 特点&#xff1a; 如果是使用组态屏进行调试使用&#xff0c;选择com1如果是实际项目使用&#xff0c;选择com2 操作步骤&#xff1a; 先创建设备窗口&#xff0c;再创建用户界面 在设备窗口界面&#xff0c;依次设置如下…