springboot中Thymeleaf模板插入Freemarker模板页面

news2024/11/17 23:46:10

概述

最近在修改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 block
				e.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 block
			e.printStackTrace();
		} catch (MalformedTemplateNameException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TemplateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

class FreemarkerWriter extends Writer {
	private OutputStream mOutStream = null;
	
	FreemarkerWriter(OutputStream outStream) {
		mOutStream = outStream;
	}
	
	@Override
	public 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"));
	}

	@Override
	public void flush() throws IOException {
		// TODO Auto-generated method stub
		//System.out.println("Writer flush");
		mOutStream.flush();
	}

	@Override
	public 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 block
			e.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>

测试界面效果

在这里插入图片描述

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

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

相关文章

【java 程序设计实训】学生请假管理系统

学生请假管理系统 运行结果学生请假管理系统需求分析GUI 编程事件处理数据库编程部分代码项目结构实体类 Admin.javaLeaveData.javaUserLogin.javaMainWindow.javaTeacherReviewFrame.javaleaveList.java 注&#xff1a;完整内容可下载查看完整报告 运行结果 学生请假管理系统需…

mac配置VScode主题加makefile etc

profile配置&#xff1a; 参考链接&#xff1a;https://www.bilibili.com/video/BV1YW4y1M7uX/?spm_id_from333.999.0.0&vd_sourced75fca5b05d8be06d13cfffd2f4f7ab5 https://code.visualstudio.com/docs/cpp/config-clang-mac vscode profiles如下&#xff1a; {//…

蓝桥杯专题-试题版-【九宫重排】【格子刷油漆】【回文数字】【国王的烦恼】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

空间曲线的切线和法平面与曲面的切平面和法线

&#xff08;一&#xff09;空间曲线的切线和法平面 1. 参数方程的形式 理解和记住如下逻辑&#xff1a; 该两个公式&#xff0c;笔者可以理解但是无法证明。 2. 参数方程外的第二种形式&#xff1a; 此种变换的本质&#xff0c;就是将多元函数转换为参数方程的形式。如此看…

English Learning - L3 作业打卡 Lesson7 Day54 2023.6.29 周四

English Learning - L3 作业打卡 Lesson7 Day54 2023.6.29 周四 引言&#x1f349;句1: I daydreamed like I did as a little girl and I imagined myself walking gracefully, helping other people through my journey and snowboarding again.成分划分连读爆破语调 &#x…

Learn Mongodb 可是工具及基本命令的使用 ③

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; PHP MYSQL &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &#x1f44…

Spark 3.4.0新特性--UI支持存储在RocksDB中

背景 对于Spark来说&#xff0c;目前存储所有的事件信息以及UI所需要的信息都是默认存储在内存中&#xff0c;这在CS中&#xff0c;对于以Spark作为 Server的模式下&#xff0c;会导致OOM&#xff0c;也会导致造成之前作者提交PR&#xff1a;Multi sparkSession should share …

Java泛型详解:为什么使用泛型?如何使用泛型?

Java泛型详解&#xff1a;为什么使用泛型&#xff1f;如何使用泛型&#xff1f; &#x1f498;一、为什么使用泛型&#xff1f;&#x1f498;二、如何使用泛型&#xff1f;&#x1f496;1. 泛型类的使用&#xff1a;&#x1f496;2. 泛型方法的使用&#xff1a;&#x1f496;3.…

什么是ABP?

1、ABP背后的思想——DDD&#xff08;领域驱动设计&#xff09; ABP架构&#xff1a; ABP实现了多层架构&#xff08;领域层&#xff0c;应用层&#xff0c;基础设施层和表示层&#xff09;&#xff0c;以及领域驱动设计&#xff08;实体&#xff0c;存储库&#xff0c;领域服…

(R)-tert-Bu4-DOTAGA,817562-90-6,(R)-DOTAGA-四叔丁酯,的反应特点及性质研究

​ 规格单位&#xff1a;g |货期&#xff1a;按​照具体的库存进行提供 | 纯度&#xff1a;95% 试剂描述&#xff1a; (R)-tert-Bu4-DOTAGA大环化合物是一种多齿配体&#xff0c;其配位原子位于环的骨架上&#xff0c;大环的配位原子可以是O、N、S、Se、P、As等。有二维的…

C++primer(第五版)第七章(类)

类的基本思想是数据抽象和封装. 数据抽象是一种依赖于接口和实现的分离的编程技术. 封装实现了类的接口和实现的分离. 7.1定义抽象数据类型 定义一个抽象数据类型使用关键字struct或是clas(差别仅在于默认访问权限修饰符). //这是一个简单的类定义 class Student{ …

C++ 结合 opencv读取图片与视频

C 结合 opencv读取图片与视频 文章目录 C 结合 opencv读取图片与视频一、安装opencv二 、配置文件准备2.1 新建立文件夹2.2 .vscode文件下配置文件&#xff08;1&#xff09;配置tasks.json文件&#xff08;1&#xff09;配置launch.json 三 、src文件下代码编写3.1 图片的读取…

matplotlib设置坐标轴为象限模式

import numpy as np import matplotlib.pyplot as pltx np.linspace(-np.pi, np.pi, 1000) cosy np.cos(x) siny np.sin(x)plt.xlim(min(x), max(x)) plt.ylim(min(cosy), max(cosy)0.5) plt.plot(x, cosy) plt.plot(x, siny) # 设置坐标刻度 plt.xticks([-np.pi, -np.pi/2,…

ubuntu安装python

ubuntu安装python 安装包下载 切换到想要的文件夹&#xff1a;如 cd /usr/local/python3 下载安装包 wget https://www.python.org/ftp/python/3.8.10/Python-3.8.10.tgz 网速慢的话也可以现在本电脑下载tgz文件&#xff0c;然后上传到服务器 第一次上传失败&#xff01; Py…

SFP3012A-ASEMI代理海矽美快恢复二极管SFP3012A

编辑&#xff1a;ll SFP3012A-ASEMI代理海矽美快恢复二极管SFP3012A 型号&#xff1a;SFP3012A 品牌&#xff1a;MHCHXM&#xff08;海矽美&#xff09; 芯片个数&#xff1a;单芯片 封装&#xff1a;TO-247 恢复时间&#xff1a;≤75ns 工作温度&#xff1a;-40C~175C …

JS中的异步与Promise使用

同步与异步 我们知道JS是一个单线程的语言&#xff0c;即在同一时间只能做一件事情。为什么设计为当线程呢。&#xff1f;在早期JS是为了在浏览器中运行&#xff0c;我们可以利用JS来制作一些页面的效果也可以和用户做一些交互。所以设计为单线程也是为了避免复杂度。比如在网…

常见面试题之线程中并发锁(一)

1. 讲一下synchronized关键字的底层原理&#xff1f; 1.1. 基本使用 如下抢票的代码&#xff0c;如果不加锁&#xff0c;就会出现超卖或者一张票卖给多个人 Synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】&#xff0c;其它线程再想获取这…

常州工学院计算机组成原理(样卷)

微程序控制器&#xff1a;仿照程序设计的基本方法&#xff0c;将实现指令系统中所有指令所需要的所有控制信号按照一定的规则编码成微指令&#xff0c;若干条实现同一条指令功能的微指令构成一段微程序&#xff0c;将实现所有指令的微程序存放在一个只读存储器ROM中&#xff0c…

一套A股量化系统

shares A 股量化交易系统后台开发语言 Go/Python gmsec算法使用&#xff1a;pytorch全链路量化&#xff0c;行业板块分析&#xff0c;直接贴图。欢迎体验

【计算机视觉】最新综述:南洋理工和上海AI Lab提出基于Transformer的视觉分割综述

文章目录 一、导读二、摘要三、内容解读3.1 研究动机3.2 这篇综述的特色&#xff0c;以及与以往的Transformer综述有什么区别&#xff1f;3.3 Transformer-Based 分割和检测方法总结与对比3.4 相关研究领域的方法总结与对比3.5 不同方法的实验结果对比3.6 未来可以进行的方向 一…