freemarker实现代码生成器

这个主要是黑马的ihrm课程中讲的代码生成器的部分内容。

文章目录

    • 应用场景
      • 第一个FreeMarker程序(数据+模板 = 文件输出)
    • 概述
      • 数据模型
      • 模板的常用标签
      • 模板的常用指令
    • 元数据
      • 数据库元数据
      • 参数元数据
      • 结果集元数据
  • 代码生成器
    • 思路分析
    • 搭建环境
      • 导入坐标
      • 配置实体类
      • 导入工具类
  • 代码生成器实现
    • 构造数据模型
      • 数据分析
    • 自定义数据
    • 元数据处理
    • 路径处理
  • 制作模板
    • 模板的约定
    • 需求分析
    • SpringBoot通用模板
      • 实体类
      • 持久化层
      • Service层
      • Controller
      • 配置文件

页面=模板+数据模型
在这里插入图片描述
FreeMarker 不是 Web 应用框架。它是 Web 应用框架中的一个适用的组件,但是FreeMarker 引擎本身并不知道
HTTP 协议或 Servlet。它仅仅来生成文本。即便这样,它也非常适用于非 Web 应用环境的开发

应用场景

动态页面
基于模板配置和表达式生成页面文件,可以像jsp一样被客户端访问
页面静态化
对于系统中频繁使用数据库进行查询但是内容更新很小的应用,都可以用FreeMarker将网页静态化,这样就避免
了大量的数据库访问请求,从而提高网站的性能

代码生成器
可以自动根据后台配置生成页面或者代码

第一个FreeMarker程序(数据+模板 = 文件输出)

先导入依赖

<!--        freemarker核心包--><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.20</version></dependency>

创建模板:

欢迎您:${username}
public class testFreemarker01 {@Testpublic void test01() throws Exception {// 1.创建FreeMarker配置类Configuration cfg = new Configuration();//2. 指定模板加速器: 将模板存入缓存// 文件路径加载器FileTemplateLoader ftl = new FileTemplateLoader(new File("templates"));cfg.setTemplateLoader(ftl);// 3. 获取模板Template template = cfg.getTemplate("template01.ftl");// 4. 构造数据模型Map<String, Object> dataModel = new HashMap<>();dataModel.put("username","ZHNSHknlnd");dataModel.put("flag",1);List<String> list = new ArrayList<>();list.add("星期一");list.add("星期二");list.add("星期三");list.add("星期四");list.add("星期五");dataModel.put("weeks",list);// 5.文件输出/*** 参数一:数据模型* 参数二:writer(FileWriter(文件输出),printWriter(控制台输出))*/
//        template.process(dataModel, new FileWriter("E:\\tmp\\a.txt"));template.process(dataModel,new PrintWriter(System.out));}
}

其实Java代码是其次的,最重要的还是模板最重要的。

概述

FreeMarker模板文件主要有5个部分组成:

  1. 数据模型:模板能用的所有数据
  2. 文本,直接输出的部分
  3. 注释,即<#–…–>格式不会输出
  4. 插值(Interpolation):即${…}或者#{…}格式的部分,将使用数据模型中的部分替代输出
  5. FTL指令:FreeMarker指令,和HTML标记类似,名字前加#予以区分,不会输出。

数据模型

FreeMarker(还有模板开发者)并不关心数据是如何计算的,FreeMarker 只是知道真实的数据是什么。模板能用的所有数据被包装成 data-model 数据模型
在这里插入图片描述

模板的常用标签

在FreeMarker模板中可以包括下面几个特定部分:

  1. ${…}:称为interpolations,FreeMarker会在输出时用实际值进行替代。
  • ${name}可以取得root中key为name的value。
  • ${person.name}可以取得成员变量为person的name属性
  1. <#…>:FTL标记(FreeMarker模板语言标记):类似于HTML标记,为了与HTML标记区分
  2. <@>:宏,自定义标签
  3. 注释:包含在<#–和–>(而不是)之间

模板的常用指令

  • if指令
    分支控制语句
 <#if condition>....<#elseif condition2>...<#elseif condition3>      ...<#else>...</#if>
  • list、break指令
    list指令时一个典型的迭代输出指令,用于迭代输出数据模型中的集合
<#list sequence as item>...</#list>除此之外,迭代集合对象时,还包括两个特殊的循环变量:a、item_index:当前变量的索引值。b、item_has_next:是否存在下一个对象也可以使用<#break>指令跳出迭代<#list ["星期一","星期二","星期三","星期四","星期五"] as x>${x_index +1}.${x} <#if x_has_next>,</#if><#if x = "星期四"><#break></#if></#list>
  • include 指令
    include指令的作用类似于JSP的包含指令,用于包含指定页,include指令的语法格式如下
<#include filename [options]></#include>在上面的语法格式中,两个参数的解释如下a、filename:该参数指定被包含的模板文件b、options:该参数可以省略,指定包含时的选项,包含encoding和parse两个选项,encoding 指定包含页面时所使用的解码集,而parse指定被包含是否作为FTL文件来解析。如果省略了parse选项值,则该选项值默认是true
  • assign指令
    它用于为该模板页面创建或替换一个顶层变量
<#assign name = zhangsan />
  • 内置函数
    FreeMarker还提供了一些内建函数来转换输出,可以在任何变量后紧跟?,?后紧跟内建函数,就可通过内建函
    数来转换输出变量。下面是常用的内建的字符串函数:
  ?html:html字符转义?cap_first: 字符串的第一个字母变为大写形式?lower_case :字符串的小写形式?upper_case :字符串的大写形式?trim:去掉字符串首尾的空格?substring:截字符串?lenth: 取长度?size: 序列中元素的个数?int : 数字的整数部分(比如- 1.9?int 就是- 1?replace:字符串替换

元数据

数据库元数据

(1)元数据(MetaData),是指定义数据结构的数据。那么数据库元数据就是指定义数据库各类对象结构的数据。 例如数据库中的数据库名,表明, 列名、用户名、版本名以及从SQL语句得到的结果中的大部分字符串是元数据
(2)数据库元数据的作用
在应用设计时能够充分地利用数据库元数据深入理解了数据库组织结构,再去理解数据访问相关框架的实现原理会更加容易。
(3)如何获取元数据
在我们前面使用JDBC来处理数据库的接口主要有三个,即Connection,PreparedStatement和ResultSet这三个,而对于这三个接口,还可以获取不同类型的元数据,通过这些元数据类获得一些数据库的信息。下面将对这三种类
型的元数据对象进行各自的介绍并通过使用MYSQL数据库进行案例说明(部分代码再不同数据库中略有不同,学员如有其他需求请查阅API)
数据库元数据(DatabaseMetaData):是由Connection对象通过getMetaData方法获取而来,主要封装了是对
数据库本身的一些整体综合信息,例如数据库的产品名称,数据库的版本号,数据库的URL,是否支持事务等等。
以下有一些关于DatabaseMetaData的常用方法:

  • getDatabaseProductName:获取数据库的产品名称
  • getDatabaseProductName:获取数据库的版本号
  • getUserName:获取数据库的用户名
  • getURL:获取数据库连接的URL
  • getDriverName:获取数据库的驱动名称
  • driverVersion:获取数据库的驱动版本号
  • isReadOnly:查看数据库是否只允许读操作
  • supportsTransactions:查看数据库是否支持事务

获取数据库综合信息

public class DataBaseMetaDataTest {private Connection conn;@Beforepublic void init() throws Exception {Class.forName("com.mysql.jdbc.Driver");Properties props =new Properties();//设置连接属性,使得可获取到表的REMARK(备注)props.put("remarksReporting","true");props.put("user", "root");props.put("password", "111111");conn = java.sql.DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/?
useUnicode=true&amp;characterEncoding=UTF8", props);}@Testpublic void testDatabaseMetaData() throws SQLException {//获取数据库元数据DatabaseMetaData dbMetaData =  conn.getMetaData();//获取数据库产品名称String productName = dbMetaData.getDatabaseProductName();System.out.println(productName);//获取数据库版本号String productVersion = dbMetaData.getDatabaseProductVersion();System.out.println(productVersion);//获取数据库用户名String userName = dbMetaData.getUserName();System.out.println(userName);//获取数据库连接URLString userUrl = dbMetaData.getURL();System.out.println(userUrl);//获取数据库驱动String driverName = dbMetaData.getDriverName();System.out.println(driverName);//获取数据库驱动版本号String driverVersion = dbMetaData.getDriverVersion();System.out.println(driverVersion);//查看数据库是否允许读操作boolean isReadOnly = dbMetaData.isReadOnly();System.out.println(isReadOnly);//查看数据库是否支持事务操作boolean supportsTransactions = dbMetaData.supportsTransactions();System.out.println(supportsTransactions);}
}

获取数据库列表

 @Testpublic void testFindAllCatalogs() throws Exception {//获取元数据DatabaseMetaData metaData = conn.getMetaData();//获取数据库列表ResultSet rs = metaData.getCatalogs();//遍历获取所有数据库表while(rs.next()){//打印数据库名称System.out.println(rs.getString(1));}//释放资源rs.close();conn.close();}

获取数据库中的所有表信息

@Testpublic void testFindAllTable() throws Exception{//获取元数据DatabaseMetaData metaData = conn.getMetaData();//获取所有的数据库表信息ResultSet tablers = metaData.getTables("ihrm", "", "bs_user", new String[]
{"TABLE"});//拼装tablewhile(tablers.next()) {//所属数据库System.out.println(tablers.getString(1));//所属schemaSystem.out.println(tablers.getString(2));//表名System.out.println(tablers.getString(3));//数据库表类型System.out.println(tablers.getString(4));//数据库表备注System.out.println(tablers.getString(5));}}

参数元数据

参数元数据(ParameterMetaData):是由PreparedStatement对象通过getParameterMetaData方法获取而来,主要是针对PreparedStatement对象和其预编译的SQL命令语句提供一些信息,ParameterMetaData能提供占位符参数的个数,获取指定位置占位符的SQL类型等等。
以下有一些关于ParameterMetaData的常用方法:

  • getParameterCount:获取预编译SQL语句中占位符参数的个数

/*** 测试参数元数据ParameterMetaData*      通过PreparedStatement获取*      获取sql参数中的属性信息*/
public class ParameterMetaDataTest {private Connection connection;@Beforepublic void init() throws Exception {String driver = "com.mysql.jdbc.Driver";String url = "jdbc:mysql://localhost:3306/ihrm?useUnicode=true&characterEncoding=utf8&useSSL=false";String username = "root";String password = "root";Properties properties = new Properties();properties.put("user",username);properties.put("password",password);properties.put("remarkReporting","true");   // 获取数据库的备注信息// 1. 获取连接Class.forName(driver); // 注册驱动connection = DriverManager.getConnection(url,properties);}@Testpublic void test() throws Exception {String sql = "select * from bs_user where id=?";PreparedStatement pstmt = connection.prepareStatement(sql);pstmt.setString(1, "1063705482939731968");//获取ParameterMetaData对象ParameterMetaData paramMetaData = pstmt.getParameterMetaData();//获取参数个数int paramCount = paramMetaData.getParameterCount();System.out.println(paramCount);}
}

结果集元数据

结果集元数据(ResultSetMetaData):是由ResultSet对象通过getMetaData方法获取而来,主要是针对由数据
库执行的SQL脚本命令获取的结果集对象ResultSet中提供的一些信息,比如结果集中的列数、指定列的名称、指定
列的SQL类型等等,可以说这个是对于框架来说非常重要的一个对象。
以下有一些关于ResultSetMetaData的常用方法:

  • getColumnCount:获取结果集中列项目的个数
  • getColumnType:获取指定列的SQL类型对应于Java中Types类的字段
  • getColumnTypeName:获取指定列的SQL类型
  • getClassName:获取指定列SQL类型对应于Java中的类型(包名加类名)

代码生成器

思路分析

在这里插入图片描述
如上分析,得知完成代码生成器需要以下几个操作:

  1. 用户填写的数据库信息,工程搭建信息需要构造到实体类对象中方便操作
  2. 数据库表信息,数据库字段信息需要构造到实体类中
  3. 构造Freemarker数据模型,将数据库表对象和基本配置存入到Map集合中
  4. 借助Freemarker完成代码生成
  5. 自定义公共代码模板

搭建环境

导入坐标

<dependencies><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.20</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency>
</dependencies>

配置实体类

(1) UI页面获取的数据库配置,封装到数据库实体类中

//数据库实体类
public class DataBase {private static String mysqlUrl = "jdbc:mysql://[ip]:[port]/[db]?
useUnicode=true&amp;characterEncoding=UTF8";private static String oracleUrl = "jdbc:oracle:thin:@[ip]:[port]:[db]";private String dbType;//数据库类型private String driver;private String userName;private String passWord;private String url;public DataBase() {}public DataBase(String dbType) {this(dbType,"127.0.0.1","3306","");}public DataBase(String dbType,String db) {this(dbType,"127.0.0.1","3306",db);}public DataBase(String dbType,String ip,String port,String db) {this.dbType = dbType;if("MYSQL".endsWith(dbType.toUpperCase())) {this.driver="com.mysql.jdbc.Driver";this.url=mysqlUrl.replace("[ip]",ip).replace("[port]",port).replace("
[db]",db);}else{this.driver="oracle.jdbc.driver.OracleDriver";this.url=oracleUrl.replace("[ip]",ip).replace("[port]",port).replace("
[db]",db);}}public String getDbType() {return dbType;}public void setDbType(String dbType) {this.dbType = dbType;}public String getDriver() {return driver;}public void setDriver(String driver) {this.driver = driver;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getPassWord() {return passWord;}public void setPassWord(String passWord) {this.passWord = passWord;}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}
}

(2) UI页面获取的自动生成工程配置,封装到设置实体类中

public class Settings {private String project="example";private String pPackage="com.example.demo";private String projectComment;private String author;private String path1="com";private String path2="example";private String path3="demo";private String pathAll;public Settings(String project, String pPackage, String projectComment, String
author) {if(StringHelper.isNotBlank(project)) {this.project = project;}if(StringHelper.isNotBlank(pPackage)) {this.pPackage = pPackage;}this.projectComment = projectComment;this.author = author;String[] paths = pPackage.split("\\.");path1 = paths[0];path2 = paths.length>1?paths[1]:path2;path3 = paths.length>2?paths[2]:path3;pathAll = pPackage.replaceAll(".","/");}public Map<String, Object> getSettingMap(){Map<String, Object> map = new HashMap<>();Field[] declaredFields = Settings.class.getDeclaredFields();for (Field field : declaredFields) {field.setAccessible(true);try{map.put(field.getName(), field.get(this));}catch (Exception e){}}return map;}public String getProject() {return project;}public void setProject(String project) {this.project = project;}public String getpPackage() {return pPackage;}public void setpPackage(String pPackage) {this.pPackage = pPackage;}public String getProjectComment() {return projectComment;}public void setProjectComment(String projectComment) {this.projectComment = projectComment;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public String getPath1() {return path1;}public void setPath1(String path1) {this.path1 = path1;}public String getPath2() {return path2;}public void setPath2(String path2) {this.path2 = path2;}public String getPath3() {return path3;}public void setPath3(String path3) {this.path3 = path3;}public String getPathAll() {return pathAll;}public void setPathAll(String pathAll) {this.pathAll = pathAll;}
}

(3) 将查询数据表的元数据封装到Table实体类

public class Table {private String name;//表名称private String name2;//处理后的表名称private String comment;//介绍private String key;// 主键列private List<Column> columns;//列集合public String getName() {return name;}public void setName(String name) {this.name = name;}public String getName2() {return name2;}public void setName2(String name2) {this.name2 = name2;}public String getComment() {return comment;}public void setComment(String comment) {this.comment = comment;}public String getKey() {return key;}public void setKey(String key) {this.key = key;}public List<Column> getColumns() {return columns;}public void setColumns(List<Column> columns) {this.columns = columns;}
}

(4)将查询数据字段的元数据封装到Column实体类

/*** 列对象
*/
public class Column {private String columnName;//列名称private String columnName2;//列名称(处理后的列名称)private String columnType;//列类型private String columnDbType;//列数据库类型private String columnComment;//列备注Dprivate String columnKey;//是否是主键public String getColumnName() {return columnName;}public void setColumnName(String columnName) {this.columnName = columnName;}public String getColumnName2() {return columnName2;}public void setColumnName2(String columnName2) {this.columnName2 = columnName2;}public String getColumnType() {return columnType;}public void setColumnType(String columnType) {this.columnType = columnType;}public String getColumnDbType() {return columnDbType;}public void setColumnDbType(String columnDbType) {this.columnDbType = columnDbType;}public String getColumnComment() {return columnComment;}public void setColumnComment(String columnComment) {this.columnComment = columnComment;}public String getColumnKey() {return columnKey;}public void setColumnKey(String columnKey) {this.columnKey = columnKey;}
}

导入工具类

在这里插入图片描述
在这里插入图片描述

代码生成器实现

  • 实现封装元数据的工具类
  • 实现代码生成器的代码编写
  • 掌握模板创建的

构造数据模型

数据分析

借助Freemarker机制可以方便的根据模板生成文件,同时也是组成代码生成器的核心部分。对于Freemarker而
言,其强调 数据模型 + 模板 = 文件 的思想,所以代码生成器最重要的一个部分之一就是数据模型。在这里数据
模型共有两种形式组成:

  • 数据库中表、字段等信息
    针对这部分内容,可以使用元数据读取并封装到java实体类中
  • 用户自定义的数据
    为了代码生成器匹配多样的使用环境,可以让用户自定义的数据,并且以key-value的形式配置到properties文件中

自定义数据

通过PropertiesUtils工具类,统一对properties文件夹下的所有 .properties 文件进行加载,并存入内存中

/**
* 需要将自定义的配置信息写入到properties文件中
* 配置到相对于工程的properties文件夹下
*/
public class PropertiesUtils {public static Map<String,String> customMap = new HashMap<>();static {File dir = new File("properties");try {List<File> files = FileUtils.searchAllFile(newFile(dir.getAbsolutePath()));for (File file : files) {if(file.getName().endsWith(".properties")) {Properties prop = new Properties();prop.load(new FileInputStream(file));customMap.putAll((Map) prop);}}} catch (IOException e) {e.printStackTrace();}}}

元数据处理

加载指定数据库表,将表信息转化为实体类对象(Table)

 /*** 获取表及字段信息*/public static List<Table> getDbInfo(DataBase db,String tableNamePattern) throws
Exception {//创建连接Connection connection = getConnection(db.getDriver(),db.getUserName(), 
db.getPassWord(), db.getUrl());//获取元数据DatabaseMetaData metaData = connection.getMetaData();//获取所有的数据库表信息ResultSet tablers = metaData.getTables(null, null, tableNamePattern, new
String[]{"TABLE"});List<Table> list=new ArrayList<Table>();//拼装tablewhile(tablers.next()) {Table table = new Table();String tableName=tablers.getString("TABLE_NAME");//如果为垃圾表if(tableName.indexOf("=")>=0 || tableName.indexOf("$")>=0){continue;}table.setName(tableName);table.setComment(tablers.getString("REMARKS"));//获得主键ResultSet primaryKeys = metaData.getPrimaryKeys(null, null, tableName);List<String> keys=new ArrayList<String>();while(primaryKeys.next()){String keyname=primaryKeys.getString("COLUMN_NAME");//判断 表名为全大写 ,则转换为小写if(keyname.toUpperCase().equals(keyname)){keyname=keyname.toLowerCase();//转换为小写}keys.add(keyname);}//获得所有列ResultSet columnrs = metaData.getColumns(null, null, tableName, null);List<Column> columnList=new ArrayList<Column>();while(columnrs.next()){Column column=new Column();//处理字段String columnName=  columnrs.getString("COLUMN_NAME");//字段名称column.setColumnName(columnName);column.setColumnName2(StringUtils.toJavaVariableName(columnName));//字段类型String columnDbType = columnrs.getString("TYPE_NAME");column.setColumnDbType(columnDbType);//数据库原始类型//java类型Map<String, String> convertMap = PropertiesUtils.customMap;String typeName = convertMap.get(columnDbType);//获取转换后的类型if(typeName==null) {typeName=columnrs.getString("TYPE_NAME");}column.setColumnType(typeName);String remarks = columnrs.getString("REMARKS");//备注column.setColumnComment(StringUtils.isBlank(remarks)?
columnName:remarks);//如果该列是主键if(keys.contains(columnName)){column.setColumnKey("PRI");table.setKey(column.getColumnName());}else {column.setColumnKey("");}columnList.add(column);}columnrs.close();table.setColumns(columnList);list.add(table );}tablers.close();connection.close();return list;}

路径处理

使用字符串模板对文件生成路径进行统一处理

   //处理字符串模板private String processTemplateString(String templateString,Map dataMap) throws
Exception {StringWriter out = new StringWriter();Template template = new Template("ts",new StringReader(templateString),conf);template.process(dataMap, out);return out.toString();}

制作模板

不同的工程需要的模板不一样。

模板的约定

(1)模板位置
模板统一放置到相对于当前路径的 模板 文件夹下
在这里插入图片描述
(2)自定义数据
自定义的数据以 .propeties 文件(key-value)的形式存放入相对于当前路径的 properties 文件夹下
(3)数据格式
在这里插入图片描述
table中数据内容:
在这里插入图片描述

需求分析

制作通用的SpringBoot程序的通用模板

  • 实体类
    类路径,类名,属性列表(getter,setter方法)
  • 持久化层
    类路径,类名,引用实体类
  • 业务逻辑层
    类路径,类名,引用实体类,引用持久化层代码
  • 视图层
    类路径,类名,引用实体类,引用业务逻辑层代码,请求路径
  • 配置文件
    pom文件,springboot配置文件

SpringBoot通用模板

实体类

package ${pPackage}.pojo;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* ${comment!}服务层
* @author ${author!"itcast"}
*/
@Entity
@Table(name="${table.name}")
public class ${ClassName} implements Serializable {//定义私有属性<#list table.columns as column><#if column.columnKey??>@Id</#if>private ${column.columnType} ${column.columnName2};</#list>//处理getter,setter方法<#list table.columns as column>public void set${column.columnName2?cap_first}(${column.columnType} value) {this.${column.columnName2} = value;}public ${column.columnType} get${column.columnName2?cap_first}() {return this.${column.columnName2};}</#list>
}

持久化层

package ${pPackage}.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import ${pPackage}.pojo.${ClassName};
/**
* ${comment!}数据访问接口
* @author ${author!"itcast"}
*/
public interface ${ClassName}Dao extends
JpaRepository<${ClassName},String>,JpaSpecificationExecutor<${ClassName}>{}

Service层

<#assign classNameLower = ClassName ? uncap_first>
package ${pPackage}.service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Selection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import util.IdWorker;
import ${pPackage}.dao.${ClassName}Dao;
import ${pPackage}.pojo.${ClassName};
/**
* ${comment!}服务层
* @author ${author!"itcast"}
*/
@Service
public class ${ClassName}Service {@Autowiredprivate ${ClassName}Dao ${classNameLower}Dao;@Autowiredprivate IdWorker idWorker;/*** 查询全部列表* @return*/public List<${ClassName}> findAll() {return ${classNameLower}Dao.findAll();}/*** 分页查询** @param page* @param size* @return*/public Page<${ClassName}> findPage(int page, int size) {PageRequest pageRequest = PageRequest.of(page-1, size);return ${classNameLower}Dao.findAll(pageRequest);}/*** 根据ID查询实体* @param id* @return*/public ${ClassName} findById(String id) {return ${classNameLower}Dao.findById(id).get();}/*** 增加* @param ${ClassName}*/public void add(${ClassName} ${ClassName}) {${ClassName}.setId( idWorker.nextId()+"" );${classNameLower}Dao.save(${ClassName});}/*** 修改* @param ${ClassName}*/public void update(${ClassName} ${ClassName}) {${classNameLower}Dao.save(${ClassName});}/*** 删除* @param id*/public void deleteById(String id) {${classNameLower}Dao.deleteById(id);}
}

Controller

<#assign classNameLower = ClassName ? uncap_first>
package ${pPackage}.controller;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import ${pPackage}.pojo.${ClassName};
import ${pPackage}.service.${ClassName}Service;
import entity.PageResult;
import entity.Result;
/**
* [comment]控制器层
* @author Administrator
*
*/
@RestController
@CrossOrigin
@RequestMapping("/${classNameLower}")
public class ${ClassName}Controller {@Autowiredprivate ${ClassName}Service ${classNameLower}Service;/*** 查询全部数据* @return*/@RequestMapping(method= RequestMethod.GET)public Result findAll(){return new Result(ResultCode.SUCCESS,${classNameLower}Service.findAll());}/*** 根据ID查询* @param id ID* * @return*/@RequestMapping(value="/{id}",method= RequestMethod.GET)public Result findById(@PathVariable String id){return new Result(ResultCode.SUCCESS,${classNameLower}Service.findById(id));}/*** 分页查询全部数据* @param page* @param size* @return*/@RequestMapping(value="/{page}/{size}",method=RequestMethod.GET)public Result findPage(@PathVariable int page,@PathVariable int size){Page<${ClassName}> searchPage = ${classNameLower}Service.findPage(page, size);PageResult<Role> pr = new
PageResult(searchPage.getTotalElements(),searchPage.getContent());return new Result(ResultCode.SUCCESS,pr);}/*** 增加* @param ${classNameLower}*/@RequestMapping(method=RequestMethod.POST)public Result add(@RequestBody ${ClassName} ${classNameLower} ){${classNameLower}Service.add(${classNameLower});return new Result(ResultCode.SUCCESS);}/*** 修改* @param ${classNameLower}*/@RequestMapping(value="/{id}",method= RequestMethod.PUT)public Result update(@RequestBody ${ClassName} ${classNameLower}, @PathVariable
String id ){${classNameLower}.setId(id);${classNameLower}Service.update(${classNameLower}); return new Result(ResultCode.SUCCESS);}/*** 删除* @param id*/@RequestMapping(value="/{id}",method= RequestMethod.DELETE)public Result delete(@PathVariable String id ){${classNameLower}Service.deleteById(id);return new Result(ResultCode.SUCCESS);}
}

配置文件

(1)application.yml

server: port: 9001
spring: application:  name: ${project}-${path3} #指定服务名datasource:  driverClassName: ${driverName}url: ${url}username: ${dbuser}password: ${dbpassword}jpa: database: MySQLshow-sql: true

(2)pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>${path_1}.${path2}</groupId><artifactId>${project}_parent</artifactId><version>0.0.1-SNAPSHOT</version></parent><artifactId>${project}_${path3}</artifactId><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>${path1}.${path2}</groupId><artifactId>${project}_common</artifactId><version>0.0.1-SNAPSHOT</version></dependency></dependencies>  
</project>

目前的代码生成器其实只是一个简单的示例,还有很多的问题,重点是了解freemarker的模板作用。

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

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

相关文章

CloudCompare——体元法计算树冠体积

目录 1.概述2.软件实现3.完整操作4.相关代码 本文由CSDN点云侠原创&#xff0c;CloudCompare——体元法计算树冠体积&#xff0c;爬虫自重。如果你不是在点云侠的博客中看到该文章&#xff0c;那么此处便是不要脸的爬虫与GPT生成的文章。 1.概述 体元法将树冠所在的空间范围划…

python--4函数def,本质、值传递、引用传递、默认值参数、*参数名、**变量、lambda [参数]: 函数、偏函数、递归、递归练习

学习目标&#xff1a; 函数def,本质、值传递、引用传递、默认值参数、*参数名、**变量、lambda [参数]: 函数、偏函数、递归、 递归练习 学习内容&#xff1a; 函数def,本质、值传递、引用传递、默认值参数、*参数名、**变量、lambda [参数]: 函数、偏函数、递归、 递归练习 …

电弧的产生机理

目录&#xff1a; 1、起弧机理 2、电弧特点 3、电弧放电特点 4、实际意义 1&#xff09;电力开关装置 2&#xff09;保险丝 1、起弧机理 电弧的本质是一种气体放电现象&#xff0c;可以理解为绝缘情况下产生的高强度瞬时电流。起弧效果如下图所示&#xff1a; 在电场的…

SpringBoot整合Nacos

文章目录 nacosnacos下载nacos启动nacos相关配置demo-dev.yamldemo-test.yamluser.yaml 代码pom.xmlUserConfigBeanAutoRefreshConfigExampleValueAnnotationExampleDemoApplicationbootstrap.yml测试结果补充.刷新静态配置 nacos nacos下载 下载地址 一键傻瓜试安装即可,官…

【Linux】地址空间虚拟地址

个人主页 &#xff1a; zxctscl 如有转载请先通知 文章目录 1. 虚拟地址1.1 虚拟地址引入1.2 虚拟地址理解1.3 虚拟地址细节问题 2. 地址空间2.1 理解地址空间2.2 页表和写时拷贝 3. 进程调度 1. 虚拟地址 1.1 虚拟地址引入 先先来一个测试代码&#xff1a; 1 #include<st…

微信小程序之点击事件

微信小程序中常用的点击事件主要是 tap&#xff0c;但除此之外还有其他的触摸类事件&#xff0c;用于不同的交互场景。以下是一些常见的点击和触摸相关的事件及其区别&#xff1a; 1、tap——最基本的点击事件&#xff0c;适用于一般的轻触交互&#xff0c;类似于 HTML 中的 c…

Octopus+: An RDMA-Enabled Distributed Persistent Memory File System——泛读笔记

TOS 2021 Paper 分布式元数据论文阅读笔记整理 问题 非易失性存储器&#xff08;NVM&#xff09;和远程直接存储器访问&#xff08;RDMA&#xff09;在存储和网络硬件中提供了极高的性能。然而&#xff0c;现有的分布式文件系统隔离了文件系统和网络层&#xff0c;而且分层的…

Nextjs学习入门 - 创建第一个项目

1 通过npx创建一个nextjs项目 通过命令创建&#xff1a; npx create-next-applatest 得到如下项目结构图&#xff1a; my-app- src //源代码目录- app //引用目录- favicon.ico //网站图标- globals.css //全局css- layout.tsx //布局文件- page.tsx //页面 路径"…

Scikit-Learn 支持向量机分类

Scikit-Learn 支持向量机分类 1、支持向量机&#xff08;SVM&#xff09;1.1、SVM概述1.2、SVM原理1.3、SVM的损失函数 1、支持向量机&#xff08;SVM&#xff09; 1.1、SVM概述 在机器学习中&#xff0c;支持向量机&#xff08;Support Vector Machine&#xff0c;SVM&#x…

华为服务Fellow、首席项目管理专家,华为H5M项目管理标准制定主导者孙虎受邀为PMO大会演讲嘉宾

全国PMO专业人士年度盛会 华为服务Fellow、首席项目管理专家&#xff0c;华为H5M项目管理标准制定主导者孙虎先生受邀为PMO评论主办的2024第十三届中国PMO大会演讲嘉宾&#xff0c;演讲议题为“落地项目管理标准&#xff0c;打赢班长的战争”。大会将于5月25-26日在北京举办&am…

国民经济行业导入数据库码表

目录 1、先去下载word文档图片如下 2、粘贴到excel中形成insert 语句 3、创建临时表存excel中数据 4、创建码表保存信息 5、编写存储过程放入表中 5.1存储第四级码值及父机构 5.2存储第三级码值及父机构 5.3存储第二级码值及父机构 5.4存储第一级码值 6、导入成功查看…

react 使用WEB3.0控件开发包 V3.0接入海康威视摄像头

1、下载官方安装包&#xff1a; 2、安装官方插件 3、引入文件 在public/index 中引入监控依赖&#xff0c;这三个文件可以在下载的官方demo中找到 4、react 中使用 useEffect(() > { const ipInfo :[192.168.xxxx];//初始化摄像头const WebVideoCtrl window.WebVideoCtrl…

Linux下kafka单机版搭建

1.zookeeper的安装 这里使用3.6.4版本 前提&#xff1a;服务器已经安装了jdk&#xff0c;zookeeper运行需要jdk环境 1.1创建放zookeeper的目录 #创建目录 mkdir -p /usr/local/zookeeper#赋予权限 chmod 777 /usr/local/zookeeper1.2安装包的下载 #这里推荐去官网下载 https:…

泛型的初步认识(1)

前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; hellohello~&#xff0c;大家好&#x1f495;&#x1f495;&#xff0c;这里是E绵绵呀✋✋ &#xff0c;如果觉得这篇文章还不错的话还请点赞❤️❤️收藏&#x1f49e; &#x1f49e; 关注&#x1f4a5;&#x…

Java 算法篇-深入了解 BF 与 KMP 算法

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 BF 算法概述 1.1 BF 算法实际使用 2.0 KMP 算法概述 2.1 KMP 算法实际使用 2.2 相比于 BF 算法实现&#xff0c;KMP 算法的重要思想 2.3 为什么要这样设计&#x…

listpack

目录 为什么有listpack? listpack结构 listpack的节点entry 长度length encoding编码方式 listpack的API 1.创建listpack 2.遍历操作 正向遍历 反向遍历 3.查找元素 4.插入/替换/删除元素 总结 为什么有listpack? ziplist是存储在连续内存空间&#xff0c;节省…

华为云服务镜像手动更换

操作步骤&#xff1a; 1、进入华为云首页点击云容器引擎CCE&#xff1b; 2、选择你所要更换镜像的环境【这里以dev环境演示】&#xff1b; 3、点击dev环境后选择顶部的命名空间&#xff0c;点击【工作负载】中右侧栏的【升级】按钮&#xff1b; 4、点【更换镜像】选择你在test…

C++之类和对象三

目录 拷贝构造函数 定义铺垫 浅拷贝 深拷贝 总结 拷贝构造函数 那在创建对象时&#xff0c;可否创建一个与一个对象一某一样的新对象呢&#xff1f; 定义铺垫 构造函数&#xff1a;只有单个形参&#xff0c;该形参是对本类类型对象的引用(一般常用const修饰)&#xff0c…

顺丰同城急送API对接(附源码)

一、背景 最近公司让我对接顺丰同城急送的API&#xff0c;讲讲里面需要注意的几点 官方的API文档有些示例代码也不全&#xff0c;具体细节不多说&#xff0c;如果你现在也需要对接他们API&#xff0c;可以参考本篇博客再配合官方文档结合起来看&#xff0c;可以让您再开发的时…

期权小知识科普

期权的交易时间 上交所期权合约的交易时间为每个交易日9:15至9:25、9:30至11:30、13&#xff1a;00至15:00。 其中&#xff0c;9:15至9:25为开盘集合竞价时间&#xff0c;14:57-15:00为收盘集合竞价时间&#xff0c;其余时段为连续竞价时间&#xff0c;交易所规则另有规定的除…