您的位置:首页 > 游戏 > 游戏 > html电影网页设计教程_app定制开发收费_想做电商应该怎么入门_自助建站系统哪个好用

html电影网页设计教程_app定制开发收费_想做电商应该怎么入门_自助建站系统哪个好用

2025/2/24 20:27:40 来源:https://blog.csdn.net/weixin_45284646/article/details/145761177  浏览:    关键词:html电影网页设计教程_app定制开发收费_想做电商应该怎么入门_自助建站系统哪个好用
html电影网页设计教程_app定制开发收费_想做电商应该怎么入门_自助建站系统哪个好用

第二章 代码生成

前言

本笔记主要用途是学习up 主程序员鱼皮的项目:代码生成器时的一些学习心得。

代码地址:https://github.com/Liucc-123/yuzi-generator.git
项目教程:https://www.codefather.cn/course/1790980795074654209

本节重点

本节属于项目的第一阶段:开发本地代码生成器。重点内容包括:

  1. 项目初始化。
  2. 静态文件生成。
  3. 动态文件代码生成。
  4. FreeMarker 模板引擎入门及实战。
  5. 动静结合 - ACM 示例项目模板代码生成。

一、项目初始化

  1. 初始化根目录
    • 使用 IDEA创建一个干净的文件夹 yuzi-generator 作为整个项目的根目录。

    • 使用 Git 管理项目,建议在项目根目录中初始化 Git 仓库。

      在这里插入图片描述

  2. 忽略无用提交
    • 使用 .gitignore 文件忽略项目中不需要提交的文件(如IDE自动生成的工程文件)。

    • 推荐使用IDE插件(如.ignore插件)生成.gitignore文件,并手动添加需要忽略的目录和文件。

      在这里插入图片描述

    • 忽略文件常见配置项设置

      ### Custom template
      .idea
      target
      yuzi-generator.iml
      .DS_Store### Java template
      # Compiled class file
      *.class# Log file
      *.log# BlueJ files
      *.ctxt# Mobile Tools for Java (J2ME)
      .mtj.tmp/# Package Files #
      *.jar
      *.war
      *.nar
      *.ear
      *.zip
      *.tar.gz
      *.rar# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
      hs_err_pid*
      replay_pid*### JetBrains template
      # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
      # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839# User-specific stuff
      .idea/**/workspace.xml
      .idea/**/tasks.xml
      .idea/**/usage.statistics.xml
      .idea/**/dictionaries
      .idea/**/shelf# AWS User-specific
      .idea/**/aws.xml# Generated files
      .idea/**/contentModel.xml# Sensitive or high-churn files
      .idea/**/dataSources/
      .idea/**/dataSources.ids
      .idea/**/dataSources.local.xml
      .idea/**/sqlDataSources.xml
      .idea/**/dynamic.xml
      .idea/**/uiDesigner.xml
      .idea/**/dbnavigator.xml# Gradle
      .idea/**/gradle.xml
      .idea/**/libraries# Gradle and Maven with auto-import
      # When using Gradle or Maven with auto-import, you should exclude module files,
      # since they will be recreated, and may cause churn.  Uncomment if using
      # auto-import.
      # .idea/artifacts
      # .idea/compiler.xml
      # .idea/jarRepositories.xml
      # .idea/modules.xml
      # .idea/*.iml
      # .idea/modules
      # *.iml
      # *.ipr# CMake
      cmake-build-*/# Mongo Explorer plugin
      .idea/**/mongoSettings.xml# File-based project format
      *.iws# IntelliJ
      out/# mpeltonen/sbt-idea plugin
      .idea_modules/# JIRA plugin
      atlassian-ide-plugin.xml# Cursive Clojure plugin
      .idea/replstate.xml# SonarLint plugin
      .idea/sonarlint/# Crashlytics plugin (for Android Studio and IntelliJ)
      com_crashlytics_export_strings.xml
      crashlytics.properties
      crashlytics-build.properties
      fabric.properties# Editor-based Rest Client
      .idea/httpRequests# Android studio 3.1+ serialized cache file
      .idea/caches/build_file_checksums.ser
    • 如果文件已被Git跟踪,需执行git rm -rf --cached .命令取消跟踪。

  3. 创建 Demo 示例代码工程
    • 新建 yuzi-generator-demo-projects 目录,存放所有示例代码。
    • 下载并复制 ACM 示例模板代码到该目录下(可通过云盘下载)。
  4. 创建本地代码生成器项目
    • 在项目根目录下新建 yuzi-generator-basic 项目,使用Maven管理项目。

    • JDK选择1.8,取消Git仓库勾选(因为外层已托管)。

    • 在项目的 pom.xml 文件中引入 Hutool、Apache Commons Collections、Lombok 和 JUnit 等依赖。

      <dependencies><!-- https://doc.hutool.cn/ --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.16</version></dependency><!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-collections4</artifactId><version>4.4</version></dependency><!-- https://projectlombok.org/ --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version><scope>provided</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency>
      </dependencies>
      

二、实现流程

目标:制作本地代码生成器,根据用户输入生成不同的 ACM 示例代码模板。

  1. 需求拆解
    • 将需求拆解为“生成静态文件”和“生成动态文件”两个步骤。
    • 静态文件:直接复制,不做改动(如 README.md)。
    • 动态文件:基于模板文件和用户输入生成代码(如 MainTemplate.java)。
  2. 实现步骤
    • 生成静态文件(通过 Main 方法运行)。
    • 生成动态文件(通过 Main 方法运行)。
    • 同时生成静态和动态文件,得到完整代码。
    • 开发命令行工具,接受用户输入并生成代码。
    • 将工具封装为 jar 包和脚本,供用户调用。

三、静态文件生成

静态文件是指直接复制、不做任何改动的文件。

  1. 现成的工具库复制目录

    • 使用 Hutool 的 FileUtil.copy 方法,一行代码实现目录复制。

    • 示例代码:

      public static void copyFilesByHutool(String inputPath, String outputPath) {FileUtil.copy(inputPath, outputPath, false);
      }
  2. 递归遍历

    • 手动编写递归算法,逐个复制目录和文件。

    • 示例代码:

      public static void copyFilesByRecursive(String inputPath, String outputPath) {File inputFile = new File(inputPath);File outputFile = new File(outputPath);try {copyFileByRecursive(inputFile, outputFile);} catch (Exception e) {System.err.println("文件复制失败");e.printStackTrace();}
      }/*** 文件 A => 目录 B,则文件 A 放在目录 B 下* 文件 A => 文件 B,则文件 A 覆盖文件 B* 目录 A => 目录 B,则目录 A 放在目录 B 下** 核心思路:先创建目录,然后遍历目录内的文件,依次复制* @param inputFile* @param outputFile* @throws IOException*/
      private static void copyFileByRecursive(File inputFile, File outputFile) throws IOException {// 区分是文件还是目录if (inputFile.isDirectory()) {System.out.println(inputFile.getName());File destOutputFile = new File(outputFile, inputFile.getName());// 如果是目录,首先创建目标目录if (!destOutputFile.exists()) {destOutputFile.mkdirs();}// 获取目录下的所有文件和子目录File[] files = inputFile.listFiles();// 无子文件,直接结束if (ArrayUtil.isEmpty(files)) {return;}for (File file : files) {// 递归拷贝下一层文件copyFileByRecursive(file, destOutputFile);}} else {// 是文件,直接复制到目标目录下Path destPath = outputFile.toPath().resolve(inputFile.getName());Files.copy(inputFile.toPath(), destPath, StandardCopyOption.REPLACE_EXISTING);}
      }
      

四、动态文件生成思路

动态文件是指需要根据用户输入生成的文件。

  1. 明确动态生成需求
    • 增加作者注释(如 @author)。
    • 修改程序输出信息。
    • 支持循环读取输入或单次读取。
  2. 动态生成的核心原理
    • 使用模板引擎(如 FreeMarker)实现动态内容生成。
    • 提前编写模板文件,通过用户输入的参数替换模板中的占位符。

五、FreeMarker 模板引擎入门

FreeMarker 是一个开源模板引擎,用于生成动态内容。

官方手册:http://freemarker.foofun.cn/

  1. 模板引擎的作用

    • 提供模板文件语法和解析能力。
    • 将数据和模板分离,便于开发和维护。
  2. 模板

    • 使用 FTL(FreeMarker Template Language)编写模板文件。
    • 包含文本、插值(${...})、FTL 指令(<#xxx>)和注释(<#-- ... -->)。
  3. 数据模型

    • 为模板准备的数据,可以是 Java 对象或 HashMap。
  4. Demo 实战

    • 引入 FreeMarker 依赖:

      <dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.32</version>
      </dependency>
    • 创建配置对象、加载模板、创建数据模型、指定输出路径并生成文件。

    • 示例代码:

      Configuration configuration = new Configuration(Configuration.VERSION_2_3_32);
      configuration.setDirectoryForTemplateLoading(new File("src/main/resources/templates"));
      configuration.setDefaultEncoding("utf-8");
      Template template = configuration.getTemplate("myweb.html.ftl");
      Map<String, Object> dataModel = new HashMap<>();
      dataModel.put("currentYear", 2023);
      Writer out = new FileWriter("myweb.html");
      template.process(dataModel, out);
      out.close();
  5. 常用语法

    • 插值:${变量}
    • 分支:<#if condition>...</#if>
    • 默认值:${变量!默认值}
    • 循环:<#list items as item>...</#list>
    • 宏定义:<#macro name>...</#macro>
    • 内建函数:变量?方法

六、动态文件生成实现

实现 ACM 示例模板项目的动态生成。

  1. 定义数据模型

    • 创建 MainTemplateConfig 类,定义模板所需的参数(如作者、是否循环、输出信息)。

    • 示例代码

      /*** 动态模板配置*/
      @Data
      public class MainTemplateConfig {/*** 作者注释信息*/private String author = "liucc"; // 默认值/*** 是否生成循环*/private boolean isLoop;/*** 输出信息*/private String outputText = "求和结果:";
      }
      
  2. 编写动态模板

    • resources/templates 目录下创建 MainTemplate.java.ftl 文件。

    • 使用 FreeMarker 语法编写模板,例如:

      package com.yupi.acm;/*** ACM 输入模板(多数之和)* @author ${author}*/
      public class MainTemplate {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);
      <#if loop>while (scanner.hasNext()) {
      </#if>int n = scanner.nextInt();int[] arr = new int[n];for (int i = 0; i < n; i++) {arr[i] = scanner.nextInt();}int sum = 0;for (int num : arr) {sum += num;}System.out.println("${outputText}" + sum);
      <#if loop>}
      </#if>scanner.close();}
      }
  3. 组合生成

    • DynamicGenerator 类中实现生成逻辑。

    • 示例代码:

      public static void doGenerate(String inputPath, String outputPath, Object model) throws IOException, TemplateException {Configuration configuration = new Configuration(Configuration.VERSION_2_3_32);File templateDir = new File(inputPath).getParentFile();configuration.setDirectoryForTemplateLoading(templateDir);configuration.setDefaultEncoding("utf-8");String templateName = new File(inputPath).getName();Template template = configuration.getTemplate(templateName);Writer out = new FileWriter(outputPath);template.process(model, out);out.close();
      }
  4. 完善优化

    • 给字符串变量设置默认值,避免模板生成时出错。
    • 抽取生成逻辑为方法,提高代码复用性。

七、动静结合 - 生成完整代码

将静态文件生成和动态文件生成结合,生成完整的 ACM 示例代码。

  • 核心代码生成器(静态+动态文件生成)

    package com.liucc;import com.liucc.model.MainTemplateConfig;
    import freemarker.template.TemplateException;import java.io.File;
    import java.io.IOException;/*** 核心模板生成器(静态+动态)*/
    public class MainGenerator {public static void main(String[] args) throws TemplateException, IOException {MainTemplateConfig model = new MainTemplateConfig();model.setAuthor("liucc");model.setLoop(true);model.setOutputText("求和结果:");doGenerate(model);}public static void doGenerate(Object model) throws TemplateException, IOException {String projectPath = System.getProperty("user.dir"); // /Users/liuchuangchuang/code/yuzi-generator/yuzi-generator-basicString parentPath = new File(projectPath).getParentFile().getAbsolutePath();// 输入路径String inputPath = parentPath + File.separatorChar + "yuzi-generator-demo-projects/acm-template";String outputPath = projectPath;// 生成静态文件StaticGenerator.copyFilesByRecursive(inputPath, outputPath);String dynamicInputPath = projectPath + File.separatorChar + "src/main/resources/templates/MainTemplate.java.ftl";String dynamicOutputPath = projectPath + File.separatorChar + "MainTemplate.java";// 生成动态文件DynamicGenerator.doGenerate(dynamicInputPath, dynamicOutputPath, model);}
    }
  • 静态文件生成器

    package com.liucc;import cn.hutool.core.io.FileUtil;
    import cn.hutool.core.util.ArrayUtil;import java.io.File;
    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.StandardCopyOption;public class StaticGenerator {public static void main(String[] args) {// 获取整个项目的根路径String projectPath = System.getProperty("user.dir");File parentFile = new File(projectPath).getParentFile();// 输入路径:ACM 示例代码模板目录String inputPath = new File(parentFile, "yuzi-generator-demo-projects/acm-template").getAbsolutePath();// 输出路径:直接输出到项目的根目录String outputPath = projectPath;copyFilesByRecursive(inputPath, outputPath);}/*** 拷贝文件(Hutool 实现,会将输入目录完整拷贝到输出目录下)*Ω* @param inputPath* @param outputPath*/public static void copyFilesByHutool(String inputPath, String outputPath) {FileUtil.copy(inputPath, outputPath, false);}/*** 递归拷贝文件(递归实现,会将输入目录完整拷贝到输出目录下)* @param inputPath* @param outputPath*/public static void copyFilesByRecursive(String inputPath, String outputPath) {File inputFile = new File(inputPath);File outputFile = new File(outputPath);try {copyFileByRecursive(inputFile, outputFile);} catch (Exception e) {System.err.println("文件复制失败");e.printStackTrace();}}/*** 文件 A => 目录 B,则文件 A 放在目录 B 下* 文件 A => 文件 B,则文件 A 覆盖文件 B* 目录 A => 目录 B,则目录 A 放在目录 B 下** 核心思路:先创建目录,然后遍历目录内的文件,依次复制* @param inputFile* @param outputFile* @throws IOException*/private static void copyFileByRecursive(File inputFile, File outputFile) throws IOException {// 区分是文件还是目录if (inputFile.isDirectory()) {System.out.println(inputFile.getName());File destOutputFile = new File(outputFile, inputFile.getName());// 如果是目录,首先创建目标目录if (!destOutputFile.exists()) {destOutputFile.mkdirs();}// 获取目录下的所有文件和子目录File[] files = inputFile.listFiles();// 无子文件,直接结束if (ArrayUtil.isEmpty(files)) {return;}for (File file : files) {// 递归拷贝下一层文件copyFileByRecursive(file, destOutputFile);}} else {// 是文件,直接复制到目标目录下Path destPath = outputFile.toPath().resolve(inputFile.getName());Files.copy(inputFile.toPath(), destPath, StandardCopyOption.REPLACE_EXISTING);}}}
    
  • 动态模板文件生成

    package com.liucc;import com.liucc.model.MainTemplateConfig;
    import freemarker.template.Configuration;
    import freemarker.template.Template;
    import freemarker.template.TemplateException;import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.Writer;/*** 动态模板文件生成*/
    public class DynamicGenerator {public static void main(String[] args) throws IOException, TemplateException {// 获取整个项目的根路径String projectPath = System.getProperty("user.dir");System.out.println("user.dir:" + projectPath);// 输入路径:FTL 示例代码模板目录String inputPath = projectPath + File.separatorChar + "src/main/resources/templates/MainTemplate.java.ftl";// 输出路径:直接输出到项目的根目录String outputPath = projectPath + File.separatorChar + "MainTemplate.java";// 读取模板配置MainTemplateConfig config = new MainTemplateConfig();config.setAuthor("liucc");config.setLoop(true);config.setOutputText("求和结果:");// 生成模板doGenerate(inputPath, outputPath, config);}/**** @param inputPath 模板读取路径* @param outputPath 动态模板生成路径* @param model 数据模型* @throws IOException* @throws TemplateException*/public static void doGenerate(String inputPath, String outputPath, Object model) throws IOException, TemplateException {// 1、new 出 Configuration 对象,参数为 FreeMarker 版本号Configuration configuration = new Configuration(Configuration.VERSION_2_3_32);File templateFile = new File(inputPath).getParentFile();// 指定模板文件所在的路径configuration.setDirectoryForTemplateLoading(templateFile);// 设置模板文件使用的字符集configuration.setDefaultEncoding("utf-8");// 数字格式设置configuration.setNumberFormat("0.##########");// 2、创建模板对象,加载指定模板String templateName = new File(inputPath).getName();Template template = configuration.getTemplate(templateName);// 3、创建数据模型 ==> model// 4、生成Writer out = new FileWriter(outputPath);template.process(model, out);// 生成文件后别忘了关闭哦out.close();}
    }

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com