首页 > 其他分享 >类NoCRUD项目开发手册 模版引擎FreeMarker 命令行制作器Picocli

类NoCRUD项目开发手册 模版引擎FreeMarker 命令行制作器Picocli

时间:2024-11-25 20:22:34浏览次数:7  
标签:upperKey throwIf FreeMarker NoCRUD Page 制作器 key import ThrowUtils

初次发布于我的个人文档

参考资料

[FreeMarker官方文档(英文)](Apache FreeMarker Manual)

FreeMarker 中文官方参考手册

Picocli官方文档(英文)

picocli-中文博客

1.安装依赖

// https://mvnrepository.com/artifact/org.freemarker/freemarker
implementation("org.freemarker:freemarker:2.3.33")
// https://mvnrepository.com/artifact/info.picocli/picocli
implementation("info.picocli:picocli:4.7.6")

2.编写Freemarker demo

参考官方文档,编写一个简单Freemarker的demo,生成一个Java文件。

import freemarker.template.Configuration
import freemarker.template.TemplateExceptionHandler
import java.io.File
import java.io.OutputStreamWriter


fun main() {
    // 创建配置对象
    val config = Configuration(Configuration.VERSION_2_3_33)
    // 设置模板文件存放的目录
    config.setDirectoryForTemplateLoading(File("src/main/resources/templates"))
    // 设置默认的编码格式
    config.defaultEncoding = "UTF-8"
    // 设置异常处理器
    config.templateExceptionHandler = TemplateExceptionHandler.RETHROW_HANDLER
    /*
    利用HashMap创建数据模型
    {
    "user": "Big Joe",
    "latestProduct": {
        "url": "https://github.com/ColaBlack",
        "name": "No CRUD"
    }
     */
    val hashMap = HashMap<String, Any>()
    hashMap["user"] = "ColaBlack"
    val latest: MutableMap<String, Any> = HashMap()
    hashMap["latestProduct"] = latest
    latest["url"] = "https://github.com/ColaBlack"
    latest["name"] = "No CRUD"
    // 获取模板文件
    val template = config.getTemplate("demo.ftl")
    val out = OutputStreamWriter(File("src/main/java/edu/zafu/generated/demo.java").outputStream())
    // 输出渲染后的内容
    template.process(hashMap, out)
    // 关闭输出流
    out.close()
}

对应的模版文件demo.ftl如下:

package edu.zafu.generated;

public class demo {
    public static void main(String[] args) {
        System.out.println("Hello ${user}");
        System.out.println("The latest product is ${latestProduct.name}");
        System.out.println("You can find it at ${latestProduct.url}");
    }
}

将模版文件放入src/main/resources/templates目录下,运行main
函数,将生成的Java文件输出到src/main/java/edu/zafu/generated/demo.java文件中。

3.编写命令行picocli demo

参考官方文档,编写一个命令行demo,实现一个简单的ls命令。

import picocli.CommandLine
import picocli.CommandLine.*
import java.io.File
import kotlin.system.exitProcess

/**
 * ls命令demo
 *
 * @author ColaBlack
 */
// 定义一个dir命令,name为ls,description为该命令的描述信息,mixinStandardHelpOptions为true,表示该命令需要自动生成help选项
@Command(name = "dir", description = ["列出当前目录的目录结构"], mixinStandardHelpOptions = true)
// 定义一个dir类,继承Runnable接口,实现run方法,用于执行ls命令,其中Callable的泛型int表示call方法的返回值类型
class Dir : Runnable {

    // 该参数在命令行中指定,索引为0,description为描述信息
    @Parameters(index = "0", description = ["要列出的目录路径"])
    var path: String? = null // 定义一个path变量,用于接收命令行参数

    // 该选项缩写为-a,全称为--all,description为描述信息
    @Option(names = ["-a", "--all"], description = ["显示所有文件,包括隐藏文件"])
    var showHidden = false // 定义一个showHidden变量,用于接收-a选项,是否显示隐藏文件

    // 用户执行命令时,会调用run方法
    override fun run() {
        if (path == null) {
            println("文件路径不能为空")
            return
        }
        val file = File(path!!)
        if (!file.exists()) {     // 判断目录是否存在
            println("文件路径不存在: $path")
            return
        }
        if (!file.isDirectory) {  // 判断是否为目录
            println("$path 不是一个目录")
            return
        }
        val files = file.listFiles()
        if (files == null) {       // 判断目录是否为空
            println("目录为空")
            return
        }
        for (item in files) {
            if (showHidden || !item.name.startsWith(".")) {
                println(item.name)
            }
        }
    }
}

fun main(args: Array<String>) {
    val exitCode = CommandLine(Dir()).execute(*args)    // 执行命令
    exitProcess(exitCode)    // 退出程序
}

运行main函数并设置参数就可以使用CLI

4.编写需要制作成模版的代码

编写需要制作成模版的代码,例如本项目的controller代码:

package $cn.cola.controller;

import cn.cola.model.dto.user.UserUpdateRequest;
import cn.cola.model.dto.user.UserQueryRequest;
import cn.cola.model.dto.user.UserAddRequest;
import cn.cola.common.constant.UserConstant;
import cn.cola.common.exception.ThrowUtils;
import cn.cola.common.DeleteRequest;
import cn.cola.common.BaseResponse;
import cn.cola.common.ResultUtils;
import cn.cola.common.AuthCheck;
import cn.cola.common.ErrorCode;
import cn.cola.model.po.User;
import cn.cola.model.vo.UserVO;
import cn.cola.service.UserService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.web.bind.annotation.*;
import org.springframework.beans.BeanUtils;
import lombok.extern.slf4j.Slf4j;

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

/**
 * 用户接口
 *
 * @author ColaBlack
 */
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {

    @Resource
    private UserService userService;

    // region 增删改查

    /**
     * 插入用户(仅管理员)
     *
     * @param userAddRequest 用户添加请求体
     * @return 新增的用户ID
     */
    @PostMapping("/insert")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Long> insertUser(@RequestBody UserAddRequest userAddRequest) {
        ThrowUtils.throwIf(userAddRequest == null, ErrorCode.PARAMS_ERROR, "参数不能为空");
        ThrowUtils.throwIf(userAddRequest.getUserAccount() == null || userAddRequest.getUserAccount().isEmpty(), ErrorCode.PARAMS_ERROR, "账号不能为空");
        User user = new User();
        BeanUtils.copyProperties(userAddRequest, user);
        int res = userService.getBaseMapper().insert(user);
        ThrowUtils.throwIf(res <= 0, ErrorCode.OPERATION_ERROR, "数据库异常,增加用户失败");
        return ResultUtils.success(user.getId());
    }

    /**
     * 删除用户(仅管理员)
     *
     * @param deleteRequest 删除请求体
     * @return 删除的记录数
     */
    @PostMapping("/delete")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Integer> deleteUser(@RequestBody DeleteRequest deleteRequest) {
        ThrowUtils.throwIf(deleteRequest == null, ErrorCode.PARAMS_ERROR, "参数不能为空");
        ThrowUtils.throwIf(deleteRequest.getId() <= 0, ErrorCode.PARAMS_ERROR, "参数错误");
        int res = userService.getBaseMapper().deleteById(deleteRequest.getId());
        ThrowUtils.throwIf(res <= 0, ErrorCode.OPERATION_ERROR, "数据库异常,删除用户失败");
        return ResultUtils.success(res);
    }

    /**
     * 修改用户(仅管理员)
     *
     * @param userUpdateRequest 用户更新请求体
     * @return 更新的记录数
     */
    @PostMapping("/update")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Integer> updateUser(@RequestBody UserUpdateRequest userUpdateRequest) {
        ThrowUtils.throwIf(userUpdateRequest == null, ErrorCode.PARAMS_ERROR, "参数不能为空");
        ThrowUtils.throwIf(userUpdateRequest.getId() <= 0, ErrorCode.PARAMS_ERROR, "参数错误");
        User user = new User();
        BeanUtils.copyProperties(userUpdateRequest, user);
        int res = userService.getBaseMapper().updateById(user);
        ThrowUtils.throwIf(res <= 0, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(res);
    }

    /**
     * 分页查询用户列表(仅管理员)
     *
     * @param userQueryRequest 条件查询请求体
     * @return 用户列表
     */
    @PostMapping("/select/page")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Page<User>> selectUserByPage(@RequestBody UserQueryRequest userQueryRequest) {
        long current = userQueryRequest.getCurrent();
        long size = userQueryRequest.getPageSize();
        ThrowUtils.throwIf(current <= 0 || size <= 0 || size > 100, ErrorCode.PARAMS_ERROR, "参数错误");
        Page<User> page = new Page<>(current, size);
        QueryWrapper<User> queryWrapper = userService.getQueryWrapper(userQueryRequest);
        Page<User> res = userService.getBaseMapper().selectPage(page, queryWrapper);
        return ResultUtils.success(res);
    }

    /**
     * 根据ID查询用户信息(仅管理员)
     *
     * @param userQueryRequest 条件查询请求体
     * @return 用户信息
     */
    @PostMapping("/select/id")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<User> selectUserById(@RequestBody UserQueryRequest userQueryRequest) {
        ThrowUtils.throwIf(userQueryRequest == null, ErrorCode.PARAMS_ERROR, "参数不能为空");
        ThrowUtils.throwIf(userQueryRequest.getId() <= 0, ErrorCode.PARAMS_ERROR, "参数错误");
        User user = userService.getBaseMapper().selectById(userQueryRequest.getId());
        return ResultUtils.success(user);
    }

    /**
     * 根据ID查询用户信息(全体用户)
     */
    @GetMapping("/get/id")
    public BaseResponse<UserVO> getUserById(@RequestParam("id") long id) {
        ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR, "参数错误");
        User user = userService.getBaseMapper().selectById(id);
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user, userVO);
        return ResultUtils.success(userVO);
    }

    /**
     * 分页查询用户信息(全体用户)
     */
    @PostMapping("/get/page")
    public BaseResponse<Page<UserVO>> getUserByPage(@RequestBody UserQueryRequest userQueryRequest) {
        long current = userQueryRequest.getCurrent();
        long size = userQueryRequest.getPageSize();
        ThrowUtils.throwIf(current <= 0 || size <= 0 || size > 20, ErrorCode.PARAMS_ERROR, "参数错误");
        Page<User> page = new Page<>(current, size);
        QueryWrapper<User> queryWrapper = userService.getQueryWrapper(userQueryRequest);
        Page<User> res = userService.getBaseMapper().selectPage(page, queryWrapper);
        Page<UserVO> userVoPage = new Page<>();
        BeanUtils.copyProperties(res, userVoPage);
        List<UserVO> records = userVoPage.getRecords();
        records.clear();
        for (User user : res.getRecords()) {
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);
            records.add(userVO);
        }
        return ResultUtils.success(userVoPage);
    }
    // endregion

    // region 其他接口

    // todo: 此处补充其他接口

    // endregion
}

这个文档最先是在我的另一个个人文档网站的,但是在文档迁移的时候这个文件出了问题,里面的内容是我手工复原的,这段模版代码可能有问题,但是这不影响这篇文章的内容。

5.编写FreeMarker模版

将原代码中可以被参数化的部分用${}包裹起来就得到了模版,例如:

package ${packageName}.controller;

import ${packageName}.model.dto.${key}.${upperKey}UpdateRequest;
import ${packageName}.model.dto.${key}.${upperKey}QueryRequest;
import ${packageName}.model.dto.${key}.${upperKey}AddRequest;
import ${packageName}.common.constant.${upperKey}Constant;
import ${packageName}.common.exception.ThrowUtils;
import ${packageName}.common.DeleteRequest;
import ${packageName}.common.BaseResponse;
import ${packageName}.common.ResultUtils;
import ${packageName}.common.AuthCheck;
import ${packageName}.common.ErrorCode;
import ${packageName}.model.po.${upperKey};
import ${packageName}.model.vo.${upperKey}VO;
import ${packageName}.service.${upperKey}Service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.web.bind.annotation.*;
import org.springframework.beans.BeanUtils;
import lombok.extern.slf4j.Slf4j;

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

/**
 * ${name}接口
 *
 * @author ${author}
 */
@RestController
@RequestMapping("/${key}")
@Slf4j
public class ${upperKey}Controller {

    @Resource
    private ${upperKey}Service ${key}Service;

    // region 增删改查

    /**
     * 插入${name}(仅管理员)
     *
     * @param ${key}AddRequest ${name}添加请求体
     * @return 新增的${name}ID
     */
    @PostMapping("/insert")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Long> insert${upperKey}(@RequestBody ${upperKey}AddRequest ${key}AddRequest) {
        ThrowUtils.throwIf(${key}AddRequest == null, ErrorCode.PARAMS_ERROR, "参数不能为空");
        ThrowUtils.throwIf(${key}AddRequest.get${upperKey}Account() == null || ${key}AddRequest.get${upperKey}Account().isEmpty(), ErrorCode.PARAMS_ERROR, "账号不能为空");
        ${upperKey} ${key} = new ${upperKey}();
        BeanUtils.copyProperties(${key}AddRequest, ${key});
        int res = ${key}Service.getBaseMapper().insert(${key});
        ThrowUtils.throwIf(res <= 0, ErrorCode.OPERATION_ERROR, "数据库异常,增加${name}失败");
        return ResultUtils.success(${key}.getId());
    }

    /**
     * 删除${name}(仅管理员)
     *
     * @param deleteRequest 删除请求体
     * @return 删除的记录数
     */
    @PostMapping("/delete")
    @AuthCheck(mustRole = $UserConstant.ADMIN_ROLE)
    public BaseResponse<Integer> delete${upperKey}(@RequestBody DeleteRequest deleteRequest) {
        ThrowUtils.throwIf(deleteRequest == null, ErrorCode.PARAMS_ERROR, "参数不能为空");
        ThrowUtils.throwIf(deleteRequest.getId() <= 0, ErrorCode.PARAMS_ERROR, "参数错误");
        int res = ${key}Service.getBaseMapper().deleteById(deleteRequest.getId());
        ThrowUtils.throwIf(res <= 0, ErrorCode.OPERATION_ERROR, "数据库异常,删除${name}失败");
        return ResultUtils.success(res);
    }

    /**
     * 修改${name}(仅管理员)
     *
     * @param ${key}UpdateRequest ${name}更新请求体
     * @return 更新的记录数
     */
    @PostMapping("/update")
    @AuthCheck(mustRole = $UserConstant.ADMIN_ROLE)
    public BaseResponse<Integer> update${upperKey}(@RequestBody ${upperKey}UpdateRequest ${key}UpdateRequest) {
        ThrowUtils.throwIf(${key}UpdateRequest == null, ErrorCode.PARAMS_ERROR, "参数不能为空");
        ThrowUtils.throwIf(${key}UpdateRequest.getId() <= 0, ErrorCode.PARAMS_ERROR, "参数错误");
        ${upperKey} ${key} = new ${upperKey}();
        BeanUtils.copyProperties(${key}UpdateRequest, ${key});
        int res = ${key}Service.getBaseMapper().updateById(${key});
        ThrowUtils.throwIf(res <= 0, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(res);
    }

    /**
     * 分页查询${name}列表(仅管理员)
     *
     * @param ${key}QueryRequest 条件查询请求体
     * @return ${name}列表
     */
    @PostMapping("/select/page")
    @AuthCheck(mustRole = $UserConstant.ADMIN_ROLE)
    public BaseResponse<Page<${upperKey}>> select${upperKey}ByPage(@RequestBody ${upperKey}QueryRequest ${key}QueryRequest) {
        long current = ${key}QueryRequest.getCurrent();
        long size = ${key}QueryRequest.getPageSize();
        ThrowUtils.throwIf(current <= 0 || size <= 0 || size > 100, ErrorCode.PARAMS_ERROR, "参数错误");
        Page<${upperKey}> page = new Page<>(current, size);
        QueryWrapper<${upperKey}> queryWrapper = ${key}Service.getQueryWrapper(${key}QueryRequest);
        Page<${upperKey}> res = ${key}Service.getBaseMapper().selectPage(page, queryWrapper);
        return ResultUtils.success(res);
    }

    /**
     * 根据ID查询${name}信息(仅管理员)
     *
     * @param ${key}QueryRequest 条件查询请求体
     * @return ${name}信息
     */
    @PostMapping("/select/id")
    @AuthCheck(mustRole = $UserConstant.ADMIN_ROLE)
    public BaseResponse<${upperKey}> select${upperKey}ById(@RequestBody ${upperKey}QueryRequest ${key}QueryRequest) {
        ThrowUtils.throwIf(${key}QueryRequest == null, ErrorCode.PARAMS_ERROR, "参数不能为空");
        ThrowUtils.throwIf(${key}QueryRequest.getId() <= 0, ErrorCode.PARAMS_ERROR, "参数错误");
        ${upperKey} ${key} = ${key}Service.getBaseMapper().selectById(${key}QueryRequest.getId());
        return ResultUtils.success(${key});
    }

    /**
     * 根据ID查询${name}信息(全体用户)
     */
    @GetMapping("/get/id")
    public BaseResponse<${upperKey}VO> get${upperKey}ById(@RequestParam("id") long id) {
        ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR, "参数错误");
        ${upperKey} ${key} = ${key}Service.getBaseMapper().selectById(id);
        ${upperKey}VO ${key}VO = new ${upperKey}VO();
        BeanUtils.copyProperties(${key}, ${key}VO);
        return ResultUtils.success(${key}VO);
    }

    /**
     * 分页查询${name}信息(全体用户)
     */
    @PostMapping("/get/page")
    public BaseResponse<Page<${upperKey}VO>> get${upperKey}ByPage(@RequestBody ${upperKey}QueryRequest ${key}QueryRequest) {
        long current = ${key}QueryRequest.getCurrent();
        long size = ${key}QueryRequest.getPageSize();
        ThrowUtils.throwIf(current <= 0 || size <= 0 || size > 20, ErrorCode.PARAMS_ERROR, "参数错误");
        Page<${upperKey}> page = new Page<>(current, size);
        QueryWrapper<${upperKey}> queryWrapper = ${key}Service.getQueryWrapper(${key}QueryRequest);
        Page<${upperKey}> res = ${key}Service.getBaseMapper().selectPage(page, queryWrapper);
        Page<${upperKey}VO> ${key}VoPage = new Page<>();
        BeanUtils.copyProperties(res, ${key}VoPage);
        List<${upperKey}VO> records = ${key}VoPage.getRecords();
        records.clear();
        for (${upperKey} ${key} : res.getRecords()) {
            ${upperKey}VO ${key}VO = new ${upperKey}VO();
            BeanUtils.copyProperties(${key}, ${key}VO);
            records.add(${key}VO);
        }
        return ResultUtils.success(${key}VoPage);
    }
    // endregion

    // region 其他接口

    // todo: 此处补充其他接口

    // endregion
}

6.制作CLI工具

完整代码参考:No CRUD项目

标签:upperKey,throwIf,FreeMarker,NoCRUD,Page,制作器,key,import,ThrowUtils
From: https://www.cnblogs.com/ColaBlack/p/18548480

相关文章

  • freemarker实现动态行单元格合并
    原文链接:https://www.cnblogs.com/10158wsj/p/11211471.htmlhttps://blog.csdn.net/weixin_43667830/article/details/106936546项目需求:项目中有个需求,需要将一些数据库中的数据根据需求导出,生成一个word,研究了一些技术,其中包括POI、freemaker,对比了一下实现过程及技术难度没......
  • 日常记录-FreeMarker模板简单使用
    1.依赖包<dependency>   <groupId>org.freemarker</groupId>   <artifactId>freemarker</artifactId>   <version>2.3.30</version></dependency>2.工具类 importfreemarker.template.Configuration;importfreemarke......
  • java freemarker实现单元格动态合并
    在Java项目中,使用FreeMarker模板引擎来动态生成Excel文件,并实现单元格的动态合并(特别是行合并)。可以通过以下步骤来完成:1.准备数据模型        需要准备一个合适的数据模型,该模型应能表示出哪些单元格需要合并。        例如,如果想要根据某一列的值来决定......
  • Java整合FreeMarker导出Pdf文件
    引入依赖<!--Freemarkerwls--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.30</version> </dependency> <dependency> <groupId>......
  • freemarker 生成前端文件
    Freemarker是一种模板引擎,它允许我们在Java应用程序中分离视图和业务逻辑。在Freemarker中,List是一种非常有用的数据结构,它允许我们存储一组有序的元素。有时候,我们需要判断一个List是否为空,这在程序设计中有许多应用场景。本文将详细介绍如何使用FreemarkerList判断一个List是否......
  • Spring JdbcTemplate+Druid数据源+FreeMarker 开发代码生成器
    虽然在这个时代,几乎所有成熟的开发框架都自带代码生成器,但有时候我们难免会遇到没有代码生成器的开发框架,这个时候,自己手中有一套代码生成器,把模版文件调整一下立马就能用,这就比较惬意了。这里讲一下如何利用SpringJdbcTemplate+Druid数据源+FreeMarker开发一套代码生成器。......
  • edusrc—freemarker模板注入RCE
    freemarker简述FreeMarker是一款模板引擎:即一种基于模板和要改变的数据,并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件信息收集开局一个登入框弱口令admin/123456登入......
  • 使用 FreeMarker 生成静态页面
    在项目开发中,对于一些访问量较大的页面,可以提前基于数据生成静态页面,当数据有变化时再重新生成并更新静态页面,这样可以减轻数据库压力,提高网站的并发访问效率。常用的技术就是使用FreeMarker模板引擎,它是一款高性能的,基于模板和数据,生成输出文本的通用工具。本篇博客基于FreeM......
  • freemarker 引擎模板保留两位小数,去尾法不进行四舍五入的方法
    ${4511.25?string("#.#")} 这个表达式的结果为4511.2;并不是传统的四舍五入规则;正确的应该是下面这个表达式:${4511.25?string("#.#;;roundingMode=halfUp")}这个表达式的结果为4511.3。而${4511.35?string("#.#")}  这个表达式的结果是4511.4FreeMarker默认的规则是5可能......
  • Template Engines for Spring: FreeMarker | Java Server Pages | Thymeleaf | Jade4j
    Besidesthetemplateenginesdescribedsofar,therearequiteafewmoreavailablewhichmaybeused.Let’sreviewsomeofthembriefly.Velocity isanoldertemplateengine,whichisverycomplexbuthasthedisadvantagethatSpringhasdeprecateditsu......