概述
最近在修改springboot架构的项目,项目之前配置的是Thymeleaf模板,
但是在我新加的功能中,我非常想用Freemarker模板来新加一些页面功能。
看到网上很多其他地方描述,要么用不同的文件后缀来区分(如html文件为Thymeleaf,ftl为Freemarker),要么放到不同的文件夹。
我不想这么做,因为会限制我后面的功能修改。
本人单独用一个类来转换Freemarker模板的html文件。
软件环境
eclipse:Version: 2021-06 (4.20.0)
jdk:1.8
项目已有的Thymeleaf
这里和大家习惯使用的一样,项目原来使用的简单描述一下,非常熟悉的就跳过Thymeleaf描述吧,
在application.properties中配置
spring.thymeleaf.enabled=true
spring.thymeleaf.cache=false
在pom.xml中加入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
登录页面,后台java
@GetMapping("/LogIn")public String LogIn(Model model, HttpServletRequest request, HttpServletResponse response) {KeyPairGenerator keyPairGen = null;KeyPair keyPair = null;String tmp = null;RSAPrivateKey prk = null;RSAPublicKey pubK = null;// System.out.println("AABBCCDDGGFFTTR112 = " +// PciVerify.PciMathCountHexChars("AABBCCDDGGFFTTR112"));request.getSession().setMaxInactiveInterval(GlobalConfig.mSessionSecondTimeout);if (GlobalConfig.mIsDebugMode) {model.addAttribute("DefaultUserName", "pci_test");model.addAttribute("DefaultPassword", "123456");model.addAttribute("DefaultVerifyCode", "123456");} else {model.addAttribute("DefaultUserName", "");model.addAttribute("DefaultPassword", "");model.addAttribute("DefaultVerifyCode", "");}model.addAttribute("UseDebugMode", GlobalConfig.mIsDebugMode);model.addAttribute("UseVerifyCode", GlobalConfig.mIsLoginUseVerifyCode);pubK = null;prk = null;tmp = null;tmp = (String) request.getSession().getAttribute("SessionKeyRsaPri");// System.out.println("SessionKeyRsaPri = " + tmp);if (tmp != null) {prk = Crypto.RsaPrikeyGetFromPkcs8Base64String(tmp);}if (prk != null) {pubK = Crypto.rsaGetPubKeyFromPriKey(prk);}// System.out.println("pubK = " + pubK);if (pubK == null) {try {keyPairGen = KeyPairGenerator.getInstance("RSA");keyPairGen.initialize(new RSAKeyGenParameterSpec(2048, BigInteger.valueOf(65537)));keyPair = keyPairGen.generateKeyPair();pubK = (RSAPublicKey) keyPair.getPublic();} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {// TODO Auto-generated catch blocke.printStackTrace();}tmp = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());tmp = tmp.replace("\r", "");tmp = tmp.replace("\n", "");// System.out.println("setAttribute SessionKeyRsaPri = " + tmp);request.getSession().setAttribute("SessionKeyRsaPri", tmp);}tmp = Base64.getEncoder().encodeToString(pubK.getEncoded());tmp = tmp.replace("\r", "");tmp = tmp.replace("\n", "");model.addAttribute("RsaPub", tmp);response.setHeader("Etag", "\"11223344556677889900/login\"");return "main_login";}
前端xml
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>User Login</title><link rel="stylesheet" type="text/css" href="/static/css/Login.css"/><script type="text/javascript" src="/static/js/main_login.js"></script><script type="text/javascript" src="/static/js/rsacrypto.js" ></script>
</head>
<body onload="onLoadLogIn()"><script type="text/javascript">onSetTranserRsaPub('{{session_rsa_pub}}');</script><span id="idTmpRsaPub" style="display:none;" th:text="${RsaPub}"></span><div id="login" style="top: 35%;"><center><img id="idImgLogo" style="align:center;max-width:160px;max-height:160px;" onclick="onGetUserNameLogo()"></center><h1 class="title">用户登陆</h1><form action="/login" method="post"><nobr><input id="id_username" type="text" required="required" placeholder="用户" name="username" onkeypress="return runScriptEnter(event)" th:value="${DefaultUserName}" onkeyup="onUserNameInputChange()" onchange="onUserNameInputChange()"></input></nobr><nobr><input id="id_password" type="password" required="required" placeholder="密码" name="password" onkeypress="return runScriptEnter(event)" th:value="${DefaultPassword}"></input></nobr><nobr style="vertical-align:top;" th:if="${UseVerifyCode}"><input style="width:120px;height:24px" id="idInputVerifyCode" type="text" required="required" placeholder="验证码" name="verifycode" onkeypress="return runScriptEnter(event)" th:value="${DefaultVerifyCode}"></input><img id="idImgVerifyCode" onclick="this.src='/main_login/code?'+ Math.random()"></nobr></form><span th:if="${UseVerifyCode}"><button id="idLogin" class="but" onclick="onClickLogIn('', 1)">登陆</button></span><span th:if="${not UseVerifyCode}"><button id="idLogin" class="but" onclick="onClickLogIn('', 0)">登陆</button></span><div id="show_status"><h5></h5></div></div><div class="bottom"><span class="style4"> </span><span an class="style4"> </span><span class="style4"></span> <br/></div>
</body></html>
这里就不详细描述运行效果等,因为牵涉到其他变量,且功能不是本文说的重点。
Freemarker配置依赖
在pom.xml中加入依赖
<dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.23</version>
</dependency>
Freemarker处理的java类
这里是最重要最关键的
新建一个类FreemarkerConvert,html文件放在resource/templates目录下
package com.shenweihong.main;import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.Map;import org.springframework.util.ResourceUtils;import com.shenweihong.global.GlobalSysParam;import freemarker.core.ParseException;
import freemarker.template.Configuration;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import freemarker.template.TemplateNotFoundException;public class FreemarkerConvert {private static Configuration mConfig = null;public static void initConfig(Class cl) {if (mConfig != null) {return;}mConfig = new Configuration(Configuration.getVersion());try { if (GlobalSysParam.mIsJarRun) {mConfig.setClassForTemplateLoading(cl, "/templates");} else {mConfig.setDirectoryForTemplateLoading(ResourceUtils.getFile("classpath:templates"));}mConfig.setDefaultEncoding("UTF-8");mConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);} catch (IOException e) {e.printStackTrace();}}public static void WriteToStream(String fileName, Map<String, Object> dataMap, OutputStream outStream) {Template template = null;FreemarkerWriter writer = null;try {writer = new FreemarkerWriter(outStream);template = mConfig.getTemplate(fileName);template.process(dataMap, writer);} catch (TemplateNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (MalformedTemplateNameException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (ParseException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (TemplateException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}class FreemarkerWriter extends Writer {private OutputStream mOutStream = null;FreemarkerWriter(OutputStream outStream) {mOutStream = outStream;}@Overridepublic void write(char[] cbuf, int off, int len) throws IOException {// TODO Auto-generated method stub//System.out.println("write");//System.out.println(new String(cbuf, off, len));String str = new String(cbuf, off, len);mOutStream.write(str.getBytes("UTF8"));}@Overridepublic void flush() throws IOException {// TODO Auto-generated method stub//System.out.println("Writer flush");mOutStream.flush();}@Overridepublic void close() throws IOException {// TODO Auto-generated method stub//System.out.println("Writer close");//mOutStream.close();}}
initConfig在启动的时候调用一次
依赖的一个外部boolean变量:GlobalSysParam.mIsJarRun
这是表示是否为jar包运行,还是java代码IDE调试运行,在main里面赋值的
if (MainStartApplication.class.getResource("").getProtocol().equals("jar") == false) {GlobalSysParam.mIsJarRun = false;
} else {GlobalSysParam.mIsJarRun = true;
}
main函数调用
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, FreeMarkerAutoConfiguration.class })
@SpringBootApplication
@ServletComponentScan
@ComponentScan("com.shenweihong.controller")
public class MainStartApplication {public static void main(String[] args) {if (MainStartApplication.class.getResource("").getProtocol().equals("jar") == false) {GlobalSysParam.mIsJarRun = false;} else {GlobalSysParam.mIsJarRun = true;}FreemarkerConvert.initConfig(MainStartApplication.class);SpringApplication.run(MainStartApplication.class, args);}
}
注意注解FreeMarkerAutoConfiguration.class ,如果不确定就全部拷贝类MainStartApplication 前面的注解,@ComponentScan(“com.shenweihong.controller”)除外。
Contoller里面调用
@RequestMapping(value = "/Function/UserManageMent/AddUserShow", method = RequestMethod.GET)public void AddUserShow(HttpServletRequest request, HttpServletResponse response) {Map<String, Object> dataMap = new HashMap<String, Object>();int i = 0;String[] listPriviliges = null;listPriviliges = new String[GlobalConfig.mMapPriviliges.length / 2];for (i = 0; i < listPriviliges.length; i++) {listPriviliges[i] = GlobalConfig.mMapPriviliges[i * 2 + 1];}dataMap.put("list_privilleges", listPriviliges); dataMap.put("show_privilleges", true); response.setContentType("text/html; charset=utf-8");try {FreemarkerConvert.WriteToStream("fun_user_mgt_add.html", dataMap, response.getOutputStream());} catch (IOException e) { // TODO Auto-generated catch blocke.printStackTrace();}}
用到的一个外部变量GlobalConfig.mMapPriviliges:
public static final String[] mMapPriviliges = {"1", "超级管理员","100", "密钥超级管理A","101", "密钥超级管理B","1000", "密钥管理A","1001", "密钥管理B","1002", "银联认证测试验证","1003", "银联认证测试验证管理","1100", "悦泰管理员","1101", "悦泰经销商","1102", "悦泰工厂拆单员","1103", "悦泰安装师傅","1104", "悦泰售后师傅","1105", "悦泰生产工人","1106", "悦泰用户","1200", "远程文件系统管理","1201", "远程文件系统"};
html显示
这是整个页面某一个局部(其他如导航栏,用户信息栏),所以没有标签html、head、body
<h2>添加用户</h2>
<h5>用户名:</h5>
<input id="idInputUserName"></input>
<hr>
<h5>密码:</h5>
<input id="idInputPassword"></input>
<button id="idAddUserGenPassword" onclick="UserManagementAddUserGenPassword()">随机生成</button>
<hr>
<#if show_privilleges>
<p><span class="span_account_label">权限:</span></p>
<p id="idAllUserPrivileges">
<#assign list_cnt=0>
<table class="clTableManageUserPrivillages" id="idTableManageUserPrivillages">
<#list list_privilleges as privilleges><#if (list_cnt % 5)==0><tr></#if><td style="vertical-align:middle; text-align:left;cursor:default;"><input type="checkbox" value="${privilleges}" unchecked>${privilleges}</input><span></span></td><#assign list_cnt=list_cnt+1><#if (list_cnt % 5)==0></tr></#if>
</#list>
<#if (list_cnt % 5)!=0>
</tr>
</#if>
</table>
</p>
<hr>
</#if>
<#if show_privilleges>
<button id="idAddUser" onclick="UserManagementAddUser(1)">添加</button>
<#else>
<button id="idAddUser" onclick="UserManagementAddUser(0)">添加</button>
</#if>
<p id="idStShow" style="font-size:16px;color:blue;display:none"></p>