许学 学习FreeMarker

前言:

在这使用的比较流行的模板引擎:jsp后来学习了Thymeleaf,发现其实也是有需要一点语法的,到现在学习一下FreeMarker,其实这三者呢都是模板引擎,都有各自的优缺点,说白了就是各有各的好,可以根据实际情况来使用

What is Apache FreeMarker™?

简单来说:就是一个模板引擎,一个Java库,根据模板和不断变化的数据生成文本输出(HTML,网页,电子邮件,配置文件,源代码等),虽然FreeMarker也有编程能力,但大多数时候都是由java程序来准备要显示得数据。官网有更加详细的说明:https://freemarker.apache.org/index.html

FreeMarker执行流程:

上面是一个模板文件,下面是Java代码通过FreeMarker解析获取最后输出显示到页面,这种方式也成为MVC(模型视图控制器),动态网页中特别流行,可以在web程序中使用,也可以用于非web应用程序环境中

FreeMarker使用场景:

1,动态页面

基于模板配置和表达式生成页面文件,可以像jsp一样被客户端访问

2,页面静态化

对于系统中频繁使用数据库进行查询但是内容更新很小的应用,都可以用FreeMarker将网页静态化,这样就避免了大量的数据库访问请求,从而提高网站的性能

3,代码生成器

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

freeMarker得特征和亮点:(官网也有详细的说明)

  • 强大得模板语言:条件块,迭代,赋值,字符串和算术运算和格式,宏和函数(包括其他模板),默认转义(可选)等
  • 多用途,轻量级:零依赖性,任何输出格式,可以从任何位置加载模板(可插拔),许多配置选项
  • 国际化/本地化意识:区域设置敏感的数字和日期/时间格式,本地化的模板变体。
  • XML处理功能:将XML DOM放入数据模型并遍历它们,甚至进行声明式处理
  • 通用的数据模型:Java对象通过可插拔适配器以变量树的形式暴露于模板,该适配器决定了模板如何看待它们。

FreeMarker基本使用:

1,导入依赖:

官网的jar包更新到了2.3.29

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<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>
2,在src同级目录下新建一个文件夹templates然后新建一个模板文件template01.ftl
1
欢迎您:${username},学习FreeMarker
3,新建一个测试类

输出方式有两种:一种是输出到文件,一种输出到控制台,也能转换成为一个HTMl文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package cn.itcast.freemarker.test;

import freemarker.cache.FileTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.junit.Test;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
* 第一个测试程序
*/
public class FreeMarkerTest01 {

@Test
public void test01() throws IOException, TemplateException {

//1.创建FreeMarker的配置类
Configuration cfg = new Configuration();
//2.指定模板的加载路径,将其存入缓存中
//2.1指定文件的加载路径
FileTemplateLoader loader = new FileTemplateLoader(new File("templates"));
cfg.setTemplateLoader(loader);
//3.获取模板
Template template = cfg.getTemplate("template01.ftl");
//4.构造数据模型
Map<String,Object> map = new HashMap();
map.put("username","小棋");
//5.文件输出
//template.process(map,new FileWriter(new File("D:\\saas\\11-代码生成器原理分析及环境搭建\\代码\\a.txt"))); //输出一个文件
template.process(map,new PrintWriter(System.out));//打印到控制台

}

}

同样也可以导出为一个html文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Test
public void test02() throws Exception {

String dir ="D:\\src\\SpringBoot\\Saas\\codeutils\\templates";
Configuration conf = new Configuration();
//加载模板文件(模板的路径)
conf.setDirectoryForTemplateLoading(new File(dir));
// 加载模板
Template template = conf.getTemplate("/template01.ftl");
// 定义数据

Map root = new HashMap();
root.put("world", "Hello World");
// 定义输出
Writer out = new FileWriter(dir + "/freemarker.html");
template.process(root, out);
System.out.println("转换成功");
out.flush();
out.close();

}

A,字符串模板

和之前以获取文件的方式是差不多的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package cn.itcast.freemarker.test;

import freemarker.cache.FileTemplateLoader;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;

/**
* 测试字符串模板
*/
public class FreeMarkerTest02 {

@Test
public void test() throws IOException, TemplateException {

//1.创建FreeMarker的配置类
Configuration cfg = new Configuration();
//2.指定加载器
cfg.setTemplateLoader(new StringTemplateLoader());
//3.创建字符串模板
//i.字符串
String loader = "欢迎:${username}学习";
//i.通过字符串创建模板
Template template = new Template("name",new StringReader(loader),cfg);
//4.构造数据模型
Map<String,Object> map = new HashMap<String, Object>();
map.put("username","张三");
//5.处理模板
template.process(map,new PrintWriter(System.out));

}

}

内置指令:

if指令

可以使用if,elseif和else指令来条件判断是否越过模板的一个部分

使用方式:

java代码传递值过来进行判断分别输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<#if flag=1>
传入数据=1
<#elseif flag=2>
传入数据=2
<#else>
传入数据=其他
</#if>
<#--也可以只有if没有elseif和else-->
<#if x == 1>
传入数据=1
</#if>
<#--也可以只有if没有elseif和else-->
<#if x == 1>
传入数据=1
<#else>
传入数据=2
</#if>

list指令:

为weeks取一个别名,循环输出全部内容

1
2
3
4
5
6
List<String> list = new ArrayList<String>();
list.add("星期一");
list.add("星期二");
list.add("星期三");
list.add("星期四");
map.put("weeks",list);
1
2
3
<#list weeks as abc>
${abc}
</#list>

include指令

你可以使用它们在你的模板中插入另外FreeMarker模板文件(由 *path* 参数指定)。

1
2
3
<#include path> 

<#include path options>

使用方式:

新建一个模板然后直接复制他的名字即可

1
2
<#--模板包含-->
<#include "template02.ftl">

assign指令

使用该指令你可以创建一个新的变量,或者替换一个已经存在的变量,注意的是:仅仅顶级变量可以被创建/替换也就是说你不能创建/替换 some_hash.subvar, 除了 some_hash)。

使用方式:

1
2
3
4
5
6
7
<#assign name="张三">/0
${name}

<#assign name>
capture this
</#assign>
${name}

内置函数:

1
欢迎您:${'username'?substring(3)},学习FreeMarker 取子串
1
欢迎您:${'username'?cap_first},学习FreeMarker  <#--首字母大写-->
1
欢迎您:${'username'?uncap_first},学习FreeMarker <#--首字母小写-->

以上指令参考官网指令:http://freemarker.foofun.cn/ref_builtins_string.html#ref_builtin_trim

数据库之元数据

1,什么是数据元数据?

元数据(MetData)就是用来描述数据的数据,举个例子:比如你的游戏图片,游戏名字,等等。。。这些叫做数据,而元数据是描述数据的数据称为元数据,比如你的游戏名字有多长,你的游戏图片有多大

2,数据库元数据的作用

应用设计时候能够充分地利用数据元数据

深入理解了数据库的组织结构,再去理解数据访问相关框架的实现原理会比较容易。

3,如何获取元数据

JDBC来处理数据库的接口主要有三个,即ConnectionPreparedStatementResultSet这三个,而对于这三个接口,还可以获取不同类型的元数据,通过这些元数据类获得一些数据库的信息。下面将对这三种类型的元数据对象进行各自的介绍并通过使用MYSQL数据库进行案例说明;

1.1数据库元数据

我们可以使用:java.sql下的(DatabaseMetaData)获取数据库的一些整体信息,比如数据库的产品名称,数据库的版本号,数据库的URL,是否支持事务等等。

API中一些常用的方法

  • getDatabaseProductName() 检索该数据库产品的名称。

  • getDatabaseProductName() 检索该数据库产品的名称

  • getUserName() 检索此数据库所知的用户名。

  • getURL() 检索此数据库管理系统的网址。

  • getDriverName() 检索该JDBC驱动程序的名称。

  • getDriverVersion() 检索该JDBC驱动程序的版本号为 String

  • isReadOnly:查看数据库是否只允许读操作

  • supportsTransactions:查看数据库是否支持事务

1.2 案例:

1,首先导入数据库的依赖包,这里使用的是mysql作为测试

1
2
3
4
5
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.7.12</version>
</dependency>

2,获取数据库一些综合信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.junit.Before;
import org.junit.Test;
import org.omg.CORBA.FREE_MEM;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
* 测试元数据
*/
public class DataBaseMetaDataTest {
Connection connection = null;
@Before
public void init() throws ClassNotFoundException, SQLException {
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("remarkReporting","true");
properties.put("user",username);
properties.put("password",password);

//1,获取连接
Class.forName(driver);
connection = DriverManager.getConnection(url, properties);
}

//获取数据库基本信息
@Test
public void test01() throws SQLException, ClassNotFoundException {

//2,获取元数据
DatabaseMetaData metaData = connection.getMetaData();
//3,获取数据库基本信息
System.out.println(metaData.getUserName());

System.out.println(metaData.supportsTransactions()); //查看数据库是否支持事务

System.out.println(metaData.getDatabaseProductName());//获取数据库的名称

//还有一些其他方法可以自行尝试

}

3,获取数据库列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 查询数据库列表名称
*/
@Test
public void test02() throws SQLException {
//2,获取元数据
DatabaseMetaData metaData = connection.getMetaData();

//获取数据信息
ResultSet resultSet = metaData.getCatalogs();
while (resultSet.next()){
System.out.println(resultSet.getString(1));
}
resultSet.close();
connection.close();
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//获取指定数据库表中的信息
@Test
public void test03() throws SQLException {

//2,获取元数据
DatabaseMetaData metaData = connection.getMetaData();

//获取库中表的名称
/**
* String catalog, 代表当前操作的数据库
* String schemaPattern, 在mysql中可以为空,在Oracle中是需要填写上用户名的,
* String tableNamePattern, 可以填空代表查询所有表,非空就是查询目标
* String tableNamePattern, 可以填空代表查询所有表,非空就是查询目标
* String types[] 查询
*/
ResultSet resultSet = metaData.getTables(null, null,null, new String[]{"TABLE"});

while (resultSet.next()){
System.out.println(resultSet.getString("TABLE_NAME"));
}
}

5,获取指定表中的字段信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//获取指定表中的字段信息
@Test
public void test04() throws SQLException {

//2,获取元数据
DatabaseMetaData metaData = connection.getMetaData();

//获取表的字段名
/**
* 最后一个参数可以写成null表示查询所有的字段名,
* String catalog,
* String schemaPattern,
* String tableNamePattern, 表示查询那个表的字段
* String columnNamePattern
*/
ResultSet res = metaData.getColumns(null, null, "bs_user", null);

while (res.next()){
System.out.println(res.getString("column_name"));
}

}

1.3 参数元数据

参数元数据(ParameterMetaData):是由PreparedStatement对象通过getParameterMetaData方法获取而
来,主要是针对PreparedStatement对象和其预编译的SQL命令语句提供一些信息,ParameterMetaData能提供

占位符参数的个数,获取指定位置占位符的SQL类型等等

API中一些常用的方法:

  • getParameterCount() 检索中的参数数目 PreparedStatement对象,这个对象包含的信息 ParameterMetaData

案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import org.junit.Before;
import org.junit.Test;

import java.sql.*;
import java.util.Properties;

public class PreparedMetaDataTest {

Connection connection = null;
@Before
public void init() throws ClassNotFoundException, SQLException {
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("remarkReporting","true");
properties.put("user",username);
properties.put("password",password);

//1,获取连接
Class.forName(driver);
connection = DriverManager.getConnection(url, properties);
}


@Test
public void test01() throws SQLException {
String sql = "select * from bs_user where id=?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, "1063705482939731968");

//获取参数元数据
ParameterMetaData parameterMetaData = pstmt.getParameterMetaData();

int count = parameterMetaData.getParameterCount();

System.out.println(count);
}

}

1.4 结果集元数据

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

API中常用方法:

  • getColumnCount() 在这 ResultSet对象返回的列数。

  • getColumnType(int column) 检索指定列的SQL类型。

  • getColumnTypeName(int column) 检索指定的列的数据库特定类型名称。

案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import org.junit.Before;
import org.junit.Test;


import java.sql.*;
import java.util.Properties;

/**
* 测试结果集元数据(ResultSetMetaData)
* 通过ResultSet获取
* 获取查询结果的信息
*/
public class ResultSetMetaDataTest {

Connection connection = null;
@Before
public void init() throws ClassNotFoundException, SQLException {
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("remarkReporting","true");
properties.put("user",username);
properties.put("password",password);

//1,获取连接
Class.forName(driver);
connection = DriverManager.getConnection(url, properties);
}

@Test
public void test() throws SQLException {
String sql = "select * from bs_user where id=?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, "1063705482939731968");
//执行sql语句
ResultSet rs = pstmt.executeQuery() ;
//获取ResultSetMetaData对象
ResultSetMetaData metaData = rs.getMetaData();
//获取查询字段数量
int columnCount = metaData.getColumnCount() ;
for (int i=1;i<=columnCount;i++) {
//获取表名称
String columnName = metaData.getColumnName(i);
//获取java类型
String columnClassName = metaData.getColumnClassName(i);
//获取sql类型
String columnTypeName = metaData.getColumnTypeName(i);
System.out.println(columnName+"---"+columnClassName+"---"+columnTypeName);
}
System.out.println(columnCount);
}
}