velocity快速入门

1.velocity简介

  velocity是一个基于Java的模板引擎,可以通过特定的语法获取在Java对象的数据,填充到模板中,从而实现界面和Java代码的分离。这意味着可以使用velocity替代jsp的开发模式了,这使得前端开发人员可以和 Java 程序开发人员同步开发一个遵循 MVC 架构的 web 站点,在实际应用中,velocity还可以应用于很多其他的场景。

2.应用场景

web应用程序:作为应用程序的视图,展示数据。

源代码生成:velocity可用于基于模板生成Java源代码。

自动电子邮件:网站注册,认证等的电子邮件模板。

网页静态化:基于velocity模板,生成静态网页。

3.velocity组成结构

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

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

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

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

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

4.快速入门

4.1 需求分析

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

4.2 步骤分析

(1)创建项目

(2)引入依赖

(3)定义模板

(4)输出html

4.3 velocity入门程序

创建maven项目,然后引入如下依赖

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

 在templates目录下新建一个模板文件 demo1.vm,内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
hello,${name}!
</body>
</html>

编写测试类,使用velocity生成html文件

    @Test
    public void test1() throws IOException {
        // 1.设置velocity的资源加载器
        Properties properties=new Properties();
        properties.put("file.resource.loader.class","org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        // 2.初始化velocity引擎
        Velocity.init(properties);
        // 3.创建velocity容器
        VelocityContext context=new VelocityContext();
        context.put("name","张三");
        // 4.加载模板文件
        Template template = Velocity.getTemplate("templates\demo1.vm", "utf-8");
        // 5.合并数据到模板
        FileWriter fw=new FileWriter("D:\idea_code\cat-movie-main\cat-movie-main\movie-server\src\main\resources\static\demo1.html");
        template.merge(context,fw);
        // 6.释放资源
        fw.close();
    }

执行单元测试,就可以看到static目录下生成了demo1.html,并且数据显示

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

5.基础语法

5.1 VTL介绍

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

VTL语法分为四大类:注释、非解析内容、引用和指令

5.2 注释

注释的内容不会被输出

1.单行注释

## 行注释内容

2.多行注释

#*
*多行注释1
*多行注释2
*#

3.文档注释

#**
*文档注释
*
*#

5.3 非解析内容

非解析内容会原样输出

#[[
非解析内容${name}
]]#

5.4 引用

5.4.1 变量引入

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

$变量名,若上下文中没有对应的变量,则输出字符串$变量名

${变量名},若上下文中没有对应的变量,则输出字符串${变量名}

$!变量名,若上下文中没有对应的变量,则输出空字符串""

$!{变量名},若上下文中没有对应的变量,则输出空字符串""

5.4.2 属性引用

$变量名.属性,若上下文中没有对应的变量,则输出字符串$变量名.属性

${变量名.属性},若上下文中没有对应的变量,则输出字符串${变量名.属性}

$!变量名.属性,若上下文中没有对应的变量,则输出空字符串""

$!{变量名.属性},若上下文中没有对应的变量,则输出空字符串""

5.4.3 方法引用

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

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

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

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

5.5 指令

#set

作用:在页面中声明变量

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

#set($number=10)
#set($str="hello world $number")

${str}

#if/#elseif/#else

作用:进行逻辑判断

语法:

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

具体实例

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

#foreach($item in items)

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

#foreach($item in $items)
     ……
    [break]
#end

$items:需要遍历的对象或者集合,如果items的类型为map集合,那么遍历的是map的value

$item:变量名称,代表遍历的每一项

#break:退出循环

内置属性:$foreach.index:获取遍历的索引,从0开始,$foreach.count:获取遍历的次数,从1开始

#foreach($item in $hobbies)
     $item
     #break
#end

#evaluate

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

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

可以将服务端的代码直接解析

#include

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

语法:#include(resources)

resources可以为单引号或者双引号的字符串,也可以为$变量,内容为外部资源路径

注意:路径如果为相对路径,则以引擎配置的文件加载器加载路径作为参考

#parse

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

语法:#parse(resources)

注意:路径如果为相对路径,则以引擎配置的文件加载器加载路径作为参考

#define

作用:定义重用模块

语法:

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

使用的时候直接  $模块名称

宏指令

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

语法:

定义语法:

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

调用语法:

#宏名([$arg]?)

实例:

#macro(table $hobbies)
    #foreach($item in $hobbies)
         $item
    #end
#end

#table($hobbies)

6.生成代码

6.1 定义模板

创建controller模板 Controller.java.vm

package ${package}.controller;

import ${package}.entity.${className};
import ${package}.entity.ResultData;
import ${package}.service.${className}Service;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;


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

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

    /**
     * 查询列表
     *
     * @param name
     * @param addr
     * @return
     */
    @GetMapping("/list")
    public ResultData getList(String name, String addr, Integer page, Integer limit, HttpServletRequest r ) {
        return ${classname}Service.getList(name, addr, page, limit);
    }

    /**
     * 根据电影名称查询影院信息
     *
     * @param name
     * @return
     */
    @GetMapping("/index")
    public ResultData getIndexList(String name) {
        List<${className}> list = ${classname}Service.getIndexList(name);
        return new ResultData(true, "查询成功", list);
    }

    /**
     * 修改信息
     *
     * @param ${classname}
     * @return
     */
    @PostMapping("/edit")
    public ResultData updateInfo(@RequestBody ${className} ${classname}) {
        int count = ${classname}Service.updateInfo(${classname});
        if (count == 0) {
            return new ResultData(false, "操作失败");
        } else {
            return new ResultData(true, "操作成功");
        }
    }

    /**
     * 添加信息
     *
     * @param pojo
     * @return
     */
    @PostMapping("/add")
    public ResultData addInfo(@RequestBody ${className} ${classname}) {
        int count = ${classname}Service.addInfo(${classname});
        if (count == 0) {
            return new ResultData(false, "操作失败");
        } else {
            return new ResultData(true, "操作成功");
        }
    }

    /**
     * 根据id删除信息
     *
     * @param ids
     * @return
     */
    @PostMapping("/del")
    public ResultData deleteById(@RequestParam("ids") List<Integer> ids) {
        ${classname}Service.deleteById(ids);
        return new ResultData(true, "操作成功");
    }

}
View Code

创建service模板 Service.java.vm

package ${package}.service;

import ${package}.entity.${className};
import ${package}.entity.ResultData;

import java.util.List;

public interface ${className}Service {
    ResultData getList(String name, String addr, Integer page, Integer limit);

    int updateInfo(${className} ${classname});

    int addInfo(${className} ${classname});

    void deleteById(List<Integer> ids);

    List<${className}> getIndexList(String name);
}
View Code

创建serviceImpl模板 ServiceImpl.java.vm

package ${package}.service.impl;

import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import ${package}.dao.${className}Dao;
import ${package}.entity.${className};
import ${package}.entity.ResultData;
import ${package}.service.${className}Service;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.List;

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

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

    @Override
    public ResultData getList(String name, String addr, Integer page, Integer limit) {
        if (page != null && limit != null) {
            PageHelper.startPage(page, limit);
        }
        Example example = new Example(${className}.class);
        Example.Criteria criteria = example.createCriteria();
        if (StrUtil.isNotBlank(name)) {
            criteria.andLike("name", "%" + name + "%");
        }
        if (StrUtil.isNotBlank(addr)) {
            criteria.andLike("addr", "%" + addr + "%");
        }
        List<${className}> list = ${classname}Dao.selectByExample(example);
        // 是否分页查询
        if (page != null && limit != null) {
            PageInfo<${className}> pageInfo = new PageInfo(list);
            return new ResultData(true, "查询成功", pageInfo.getList(), pageInfo.getTotal());
        } else {
            return new ResultData(true, "查询成功", list);
        }
    }

    @Override
    public int updateInfo(${className} ${classname}) {
        return ${classname}Dao.updateByPrimaryKeySelective(${classname});
    }

    @Override
    public int addInfo(${className} ${classname}) {
        return ${classname}Dao.insertSelective(${classname});
    }

    @Override
    public void deleteById(List<Integer> ids) {
        if (ids != null && ids.size() > 0) {
            ids.stream().forEach(item -> ${classname}Dao.deleteByPrimaryKey(item));
        }
    }

    @Override
    public List<${className}> getIndexList(String name) {
        return ${classname}Dao.getIndexList(name);
    }
}
View Code

创建dao模板 Dao.java.vm

package ${package}.dao;


import ${package}.entity.${className};
import tk.mybatis.mapper.common.Mapper;

import java.util.List;

public interface ${className}Dao extends Mapper<${className}> {
    List<${className}> getIndexList(String name);
}
View Code

6.2 编写工具类

编写生成Java文件工具类

package com.zxh.movieserver.util;

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.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @Author Eric
 * @Date 5/26/2021 5:12 PM
 */
public class GenUtils {
    /**
     * 生成Java代码
     * @param data 生成到模板中的数据
     * @param templates 模板名称
     * @param
     */
    public static void generatorCode(Map<String,Object> data, List<String> templates, File file){
        // 1.设置velocity的资源加载器
        Properties properties=new Properties();
        properties.put("file.resource.loader.class","org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        // 2.初始化velocity引擎
        Velocity.init(properties);
        // 3.创建velocity容器
        VelocityContext context=new VelocityContext(data);
        // 4.加载模板文件
        //遍历模板列表,获取每一个模板
        for (String template : templates) {
            Template tpl = Velocity.getTemplate(template, "utf-8");
//            StringWriter sw=new StringWriter();
//            // 5.合并数据到模板
//            tpl.merge(context,sw);

            String fileName = genFileName(template, data.get("className").toString(), data.get("package").toString());
            try {

                FileWriter fileWriter=new FileWriter(file+File.separator+fileName);
                tpl.merge(context,fileWriter);
                fileWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

//            try {
//                zip.putNextEntry(new ZipEntry(fileName));
//                IOUtils.write(sw.toString(),zip,"UTF-8");
//                IOUtils.closeQuietly(sw);
//                zip.flush();
//                zip.closeEntry();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
        }
    }
    /**
     * 根据模板名称,类名称,包名称拼接一个完整的文件路径和名称
     * @param template 模板名称
     * @param className 类名称
     * @param packageName 包名称
     * @return
     */
    public static String genFileName(String template,String className,String packageName){
        String packagePath="main"+ File.separator+"java"+File.separator;
        if(StringUtils.isNotEmpty(packageName)){
            packagePath+=packageName.replace(".",File.separator)+File.separator;
        }
        if(template.contains("Controller.java.vm")){
            return packagePath+"controller"+File.separator+className+"Controller.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("Dao.java.vm")){
            return packagePath+"dao"+File.separator+className+"Dao.java";
        }
        return null;
    }

}
View Code

6.3 单元测试

运行测试类就可以生成相关代码

package com.zxh.movieserver;

import com.zxh.movieserver.util.GenUtils;
import org.junit.jupiter.api.Test;

import java.awt.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipOutputStream;

/**
 * @Author Eric
 * @Date 5/26/2021 5:52 PM
 */
public class Test4 {

    @Test
    public void test1() throws FileNotFoundException {
        Map<String,Object> map=new HashMap<>();
        map.put("package","com.zxh.movieserver");
        map.put("className","Account");
        map.put("classname","account");
        //构建模板列表
        List<String> list=new ArrayList<>();
        list.add("templates/Controller.java.vm");
        list.add("templates/Service.java.vm");
        list.add("templates/ServiceImpl.java.vm");
        list.add("templates/Dao.java.vm");

        File file=new File("D:\idea_code\cat-movie-main\cat-movie-main\movie-server\src\");
//        FileOutputStream fileOutputStream=new FileOutputStream(file);
//        ZipOutputStream zipOutputStream=new ZipOutputStream(fileOutputStream);
        GenUtils.generatorCode(map,list,file);
    }
}
View Code

一点点学习,一丝丝进步。不懈怠,才不会被时代所淘汰!

原文地址:https://www.cnblogs.com/fqh2020/p/14812817.html