NVelocity中怎么实现代码生成功能

发布时间:2021-08-03 15:22:37 作者:Leah
来源:亿速云 阅读:103
# NVelocity中怎么实现代码生成功能

## 一、NVelocity简介

### 1.1 什么是NVelocity
NVelocity是Apache Velocity模板引擎的.NET移植版本,它是一个基于Java的模板引擎的C#实现。作为一款强大的模板引擎,NVelocity允许开发者将业务逻辑与展示层分离,通过简单的模板语法实现动态内容生成。

### 1.2 NVelocity的核心特性
- **模板与代码分离**:保持业务逻辑与显示逻辑的独立性
- **简单语法**:类似HTML的模板语法,学习成本低
- **高性能**:模板编译后执行效率高
- **可扩展性**:支持自定义指令和扩展点
- **多领域应用**:适用于网页生成、代码生成、邮件模板等场景

### 1.3 代码生成的应用场景
- 数据库实体类自动生成
- 重复性高的CRUD代码生成
- 项目脚手架创建
- 协议代码生成(如gRPC、Thrift)
- 自动化测试用例生成

## 二、环境准备与基础配置

### 2.1 安装NVelocity
通过NuGet包管理器安装最新版本:
```bash
Install-Package NVelocity

或使用.NET CLI:

dotnet add package NVelocity

2.2 基础配置示例

using Commons.Collections;
using NVelocity.App;
using NVelocity.Runtime;

// 初始化引擎
var props = new ExtendedProperties();
props.AddProperty(RuntimeConstants.RESOURCE_LOADER, "file");
props.AddProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, 
    Path.Combine(Directory.GetCurrentDirectory(), "Templates"));

var velocityEngine = new VelocityEngine();
velocityEngine.Init(props);

2.3 目录结构建议

ProjectRoot/
├── Templates/          # 模板存放目录
│   ├── Entities/       # 实体类模板
│   ├── Repositories/   # 仓储接口模板
│   └── Services/       # 服务类模板
├── Generated/          # 生成代码输出目录
└── CodeGenerator.cs    # 生成器主程序

三、模板语法详解

3.1 基本模板语法结构

## 单行注释
#* 
  多行注释
*#

#set($name = "value")  ## 变量定义

${variable}  ## 变量输出

3.2 变量与表达式

#set($userName = "John Doe")
#set($age = 30)
#set($isAdmin = true)

用户信息:${userName},年龄:$age
#if($isAdmin)
  (管理员权限)
#end

3.3 流程控制语句

条件判断

#if($condition)
  ...
#elseif($otherCondition)
  ...
#else
  ...
#end

循环遍历

#foreach($item in $items)
  当前项:$item
  #if($foreach.hasNext),#end
#end

3.4 宏定义与使用

#macro(renderUser $user)
<div class="user">
  <span>$!user.Name</span>
  <span>$!user.Age</span>
</div>
#end

## 使用宏
#renderUser($currentUser)

四、代码生成实战

4.1 数据库实体生成示例

模板文件(Entities/EntityTemplate.vm)

using System;

namespace ${nameSpace}.Entities
{
    /// <summary>
    /// ${tableComment}
    /// </summary>
    public class ${entityName}
    {
#foreach($column in $columns)
        /// <summary>
        /// ${column.Comment}
        /// </summary>
        public ${column.Type} ${column.Name} { get; set; }
        
#end
    }
}

生成器代码

var context = new VelocityContext();
context.Put("nameSpace", "MyProject");
context.Put("entityName", "User");
context.Put("tableComment", "用户信息表");

var columns = new List<object> {
    new { Name = "Id", Type = "int", Comment = "主键ID" },
    new { Name = "UserName", Type = "string", Comment = "用户名" },
    // 其他字段...
};
context.Put("columns", columns);

var writer = new StringWriter();
velocityEngine.MergeTemplate("Entities/EntityTemplate.vm", Encoding.UTF8.HeaderName, context, writer);

File.WriteAllText("Generated/User.cs", writer.ToString());

4.2 动态生成Repository接口

模板文件(Repositories/RepositoryTemplate.vm)

using System.Collections.Generic;

namespace ${nameSpace}.Repositories
{
    public interface I${entityName}Repository
    {
        ${entityName} GetById(int id);
        
        IEnumerable<${entityName}> GetAll();
        
        void Add(${entityName} entity);
        
        void Update(${entityName} entity);
        
        void Delete(int id);
    }
}

4.3 生成完整CRUD服务层

using ${nameSpace}.Entities;
using ${nameSpace}.Repositories;

namespace ${nameSpace}.Services
{
    public class ${entityName}Service
    {
        private readonly I${entityName}Repository _repository;

        public ${entityName}Service(I${entityName}Repository repository)
        {
            _repository = repository;
        }

        public ${entityName} GetById(int id) => _repository.GetById(id);
        
        // 其他CRUD方法...
        
        #foreach($method in $customMethods)
        public ${method.ReturnType} ${method.Name}(${method.Parameters})
        {
            // 自定义方法实现
            throw new System.NotImplementedException();
        }
        
        #end
    }
}

五、高级技巧与最佳实践

5.1 模板继承与包含

## 基础模板(BaseTemplate.vm)
<!DOCTYPE html>
<html>
<head>
    <title>${title}</title>
    #parse("Includes/Header.vm")
</head>
<body>
    #parse($contentTemplate)
</body>
</html>

## 子模板
#set($title = "用户管理")
#set($contentTemplate = "User/List.vm")
#parse("Templates/BaseTemplate.vm")

5.2 自定义指令开发

public class UpperDirective : NVelocity.Runtime.Directive.Directive
{
    public override string Name => "upper";
    public override DirectiveType Type => DirectiveType.LINE;

    public override bool Render(IInternalContextAdapter context, TextWriter writer, INode node)
    {
        var param = node.GetChild(0).Value(context).ToString();
        writer.Write(param.ToUpper());
        return true;
    }
}

// 注册指令
props.AddProperty(RuntimeConstants.CUSTOM_DIRECTIVES, "upper,Namespace.UpperDirective");

5.3 性能优化建议

  1. 模板缓存:启用模板缓存减少IO

    props.AddProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, "true");
    props.AddProperty(RuntimeConstants.RESOURCE_MANAGER_CACHE_ENABLED, "true");
    
  2. 预编译常用模板:对高频使用模板进行预编译

  3. 合理设计模板结构:避免过度嵌套和复杂逻辑

5.4 错误处理策略

try
{
    velocityEngine.MergeTemplate(templateName, Encoding.UTF8.HeaderName, context, writer);
}
catch (ResourceNotFoundException ex)
{
    // 处理模板未找到
}
catch (ParseErrorException ex)
{
    // 处理语法错误
}
catch (MethodInvocationException ex)
{
    // 处理方法调用异常
}

六、实际应用案例

6.1 生成EF Core数据库上下文

using Microsoft.EntityFrameworkCore;
using ${nameSpace}.Entities;

namespace ${nameSpace}.Data
{
    public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions<AppDbContext> options) 
            : base(options) { }

#foreach($entity in $entities)
        public DbSet<${entity}> ${entity}Set { get; set; }
#end

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // 配置实体关系...
        }
    }
}

6.2 生成API控制器

using Microsoft.AspNetCore.Mvc;
using ${nameSpace}.Services;

namespace ${nameSpace}.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class ${entityName}Controller : ControllerBase
    {
        private readonly ${entityName}Service _service;

        public ${entityName}Controller(${entityName}Service service)
        {
            _service = service;
        }

        [HttpGet("{id}")]
        public IActionResult Get(int id)
        {
            var entity = _service.GetById(id);
            return Ok(entity);
        }
        
        // 其他API方法...
    }
}

6.3 生成单元测试类

using Xunit;
using ${nameSpace}.Services;
using Moq;

namespace ${nameSpace}.Tests
{
    public class ${entityName}ServiceTests
    {
        private readonly ${entityName}Service _service;
        private readonly Mock<I${entityName}Repository> _mockRepo;

        public ${entityName}ServiceTests()
        {
            _mockRepo = new Mock<I${entityName}Repository>();
            _service = new ${entityName}Service(_mockRepo.Object);
        }

        [Fact]
        public void GetById_ShouldReturnEntity_WhenExists()
        {
            // 测试代码...
        }
        
        // 其他测试方法...
    }
}

七、常见问题与解决方案

7.1 模板加载失败问题

问题现象:收到ResourceNotFoundException - 检查文件路径是否正确 - 确认FILE_RESOURCE_LOADER_PATH配置 - 验证模板文件是否存在且有读取权限

7.2 变量输出为空处理

使用$!variable语法可避免变量为空时输出:

Hello $!userName ## 当userName为null时输出"Hello "而不是"Hello null"

7.3 特殊字符转义

#set($dollar = "$")
输出美元符号:${dollar}

#set($hash = "#")
输出井号:${hash}

7.4 性能瓶颈分析

八、总结与扩展方向

8.1 NVelocity代码生成的优势

8.2 可能的扩展方向

  1. 与Roslyn结合:生成后直接编译
  2. CLI工具开发:创建代码生成命令行工具
  3. 可视化模板编辑:开发模板设计器
  4. 智能提示:为模板添加IDE智能感知

8.3 推荐学习资源

通过合理应用NVelocity,开发者可以显著提升代码编写效率,将精力集中在核心业务逻辑的实现上。建议从简单模板开始,逐步构建复杂的代码生成系统。 “`

推荐阅读:
  1. C#模板引擎NVelocity实战项目演练
  2. .Net 使用NVelocity模板

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

nvelocity

上一篇:springboot中如何使用mybatis-plus表单更新null值

下一篇:如何解决某些HTML字符打不出来的问题

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》