基于SpringBoot和Freemarker的页面静态化
页面静态化能够缓轻数据库的压力,还能提高页面的并发能力,但是网页静态化是比较适合大规模且相对变化不太频繁的数据。
页面静态化在实际应用中还是比较常见的,比如博客详情页、新闻网站或者文章类网站等等。这类数据变化不频繁比较适合静态化页面。该篇博客就是介绍博客详情页的页面静态化输出。
页面静态化实现
导入Jar
compile group: 'org.springframework.boot', name: 'spring-boot-starter-freemarker', version: '2.1.6.RELEASE'
配置文件
server:port: 8015servlet:context-path: /staticftl# freemarker静态资源配置
# 文件路径
spring:freemarker:tempalte-loader-path: classpath:/templates
# 关闭缓存,及时刷新cache: falsecharset: UTF-8content-type: text/htmlsuffix: .htmlmvc:static-path-pattern: /static/**
编写模板文件
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>${blog.title}</title>
</head>
<body>
<h1>${blog.title}</h1>
<h2>${blog.author}</h2>
<div>${blog.content}</div>
</body>
</html>
Freemarker还提供很多其他的常用的指令和函数,功能也是非常强大的。
页面输出
/*** 输出静态化页面* @param root* @param id*/
public void productStaticPage(Map<String,Object> root, String id){Configuration config = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);config.setDefaultEncoding("UTF-8");//输出页面的全名String path = getStaticHtmlPath()+"/" + id + ".html";File f = new File(path);File parentFile = f.getParentFile();if(!parentFile.exists()){parentFile.mkdirs();}Writer out = null;try {//获取模板页面String templatePath =ClassLoader.getSystemResource("templates").getPath();TemplateLoader templateLoader=new FileTemplateLoader(new File(templatePath+"\\blog"));config.setTemplateLoader(templateLoader);Template template = config.getTemplate("detail.html");//输出页面out = new OutputStreamWriter(new FileOutputStream(f), "UTF-8");//处理数据template.process(root, out);} catch (Exception e) {e.printStackTrace();}finally {if(null != out){try {out.close();} catch (IOException e) {e.printStackTrace();}}}
}
通过Freemarker输出静态页面。
/*** 魔改的Freemarker的静态化页面输出地址* 不具备普遍性* @return 静态化页面输出地址*/
public String getStaticHtmlPath(){//Thread.currentThread().getContextClassLoader().getResource("templates").getPath()String path = this.getClass().getClassLoader().getResource("").getPath();if(path==null || path.length()==0){return "";}path=path.substring(0,path.indexOf("build"))+"\\src\\main\\resources\\static\\html";return path;
}
这个代码在实际应用是需要更改的,目前是在本机Windows中,且把静态化页面放到了项目目录中,其实更好的结果是将输出静态化页面放到Nginx服务器中,这样在并发性也更高,而且目录环境也更好解决。
本身使用Freemarker输出静态页面是比较简单的,上述关键代码再加上一些串联代码应该能正常运行了,其中需要注意的就是相关目录,里面涉及到一个模板目录,用于读取模板;一个输出页面目录,目前是使用SpringBoot并把static目录当做静态资源,所以需要把静态页面放入此目录,但是建议使用Nginx来做静态页面的服务器。
加入消息中间件和MongoDB数据库
我又加入了一点小功能,实现当我们将博客数据保存到MongoDB数据库中,使用ActiveMQ队列功能,异步将博客数据静态化到页面中然后输出。
引入Jar
compile group: 'org.springframework.boot', name: 'spring-boot-starter-activemq', version: '2.1.6.RELEASE'
# 需要引入如下Jar包,不然ActiveMQ的配置无法导入。
compile group: 'org.messaginghub', name: 'pooled-jms', version: '1.1.0'
compile group: 'org.springframework.data', name: 'spring-data-mongodb', version: '2.1.6.RELEASE'
配置文件
spring:data:mongodb:host: 127.0.0.1port: 27017database: staticftlactivemq:broker-url: tcp://localhost:61616#true 表示使用内置的MQ,false则连接服务器in-memory: false#true表示使用连接池;false时,每发送一条数据创建一个连接pool:enabled: true#连接池最大连接数max-connections: 10idle-timeout: 30000user: adminpassword: admin
使用MongoDB
import com.plf.learn.staticftl.bean.Blog;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;@Repository
public interface BlogRepository extends MongoRepository<Blog,java.lang.String> {
}
SpringBoot自带的封装MongoDB的操作,使得数据库操作变得非常简单。
使用ActiveMQ
发送队列消息
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.stereotype.Component;@Component
public class ActiveMQProducer {@Autowiredprivate JmsMessagingTemplate jmsMessagingTemplate;/**** @param destination 队列* @param message 信息*/public void sendMessage(String destination,String message){jmsMessagingTemplate.convertAndSend(destination,message);}
}
监听队列,将数据静态化到页面上
import com.plf.learn.staticftl.bean.Blog;
import com.plf.learn.staticftl.service.BlogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;import java.util.HashMap;
import java.util.Map;@Component
public class BlogStaticFtlListener {@Autowiredprivate BlogService blogService;@JmsListener(destination="staticftl.blog")public void ListenBlogQueue(String message){String blog_id = message;//获取到博客信息Blog blog = blogService.getById(blog_id);Map<String,Object> map = new HashMap<>();map.put("blog",blog);//输出静态化页面blogService.productStaticPage(map,blog_id);}
}
上述代码即可实现,将博客文章保存到MongoDB数据库中,然后通过消息中间件消费输出静态化页面,即可直接访问静态资源。完整代码可访问我的Github。
相关文章:
基于SpringBoot和Freemarker的页面静态化
页面静态化能够缓轻数据库的压力,还能提高页面的并发能力,但是网页静态化是比较适合大规模且相对变化不太频繁的数据。 页面静态化在实际应用中还是比较常见的,比如博客详情页、新闻网站或者文章类网站等等。这类数据变化不频繁比较适合静态…...
给软件增加license
搞计算机的,都知道软件license,版权,著作权等。在商业软件中,常用的模式是一年一付,或者五年一付,即软件的使用权不是无限年限的,在设计软件的时候,开发者就需要考虑这个问题。要实现这个功能&a…...
vue中实现订单支付倒计时
需求 创建订单后15分钟内进行支付,否则订单取消。 实现 思路: 获取当前时间和支付超时时间(在创建时间的基础上增加15分钟即为超时时间,倒计时多久根据自己的实际需求,这里为15分钟),支付超时…...
途乐证券-新手炒股快速入门教程?
随着互联网和金融商场的不断发展,越来越多的人开端重视股票商场。但是对于股市新手来说,怎么快速入门炒股成为了一个困扰他们的难题。以下从多个角度分析,提供一份新手炒股快速入门教程。 1. 了解根本概念 首要,股市新手需求了解…...
【冒泡排序及其优化】
冒泡排序及其优化 冒泡排序核心思想 冒泡排序的核⼼思想就是:两两相邻的元素进⾏⽐较 1题目举例 给出一个倒序数组:arr[10]{9,8,7,6,5,4,3,2,1,0} 请排序按小到大输出 1.1题目分析 这是一个完全倒序的数组,所以确定冒泡排序的趟数࿰…...
TypeScript 泛型的深入解析与基本使用
系列文章目录 文章目录 系列文章目录前言一、泛型的概念二、泛型函数三、泛型类四、泛型接口五、泛型约束总结 前言 泛型是TypeScript中的一个重要概念,它允许我们在定义函数、类或接口时使用参数化类型,增强了代码的灵活性和重用性。本文将深入探讨泛型…...
【Terraform学习】保护敏感变量(Terraform配置语言学习)
实验步骤 创建 EC2 IAM 角色 导航到IAM 在左侧菜单中,单击角色 。单击创建角色该按钮以创建新的 IAM 角色。 在创建角色部分,为角色选择可信实体类型: AWS 服务 使用案例:EC2 单击下一步 添加权限:现在,您可以看到…...
海国图志#1:这一周难忘瞬间,吐血整理,不得不看
这里记录每周值得分享的新闻大图,周日发布。 文章以高清大图呈现,解说以汉语为主,英语为辅,英语句子均来自NYTimes、WSJ、The Guardian等权威媒体原刊。 存档时段:20230731-20230806 乌克兰,波罗当卡 一名妇…...
【Android】okhttp爆java.lang.IllegalStateException: closed的解决方法
解决 java.lang.IllegalStateException: closed异常通常是由于OkHttp中的Response对象在调用response.body().string()后被关闭而导致的。 在代码中,在onResponse()方法中如果两次调用了response.body().string(),每次调用都会消耗掉响应体并关闭Respo…...
Django之定时任务--apscheduler
Django--定时任务apscheduler的使用 apscheduler定时任务的使用1、安装包2、配置settings.py3、在manage.py的文件同级目录下创建文件scheduler.py4、在项目的urls.py中调用这个定时计划5、然后启动项目 python manage.py runserver,在admin中查看就能看到你的定时任务及执行的…...
Spring Boot 项目应用消息服务器RabbitMQ(简单介绍)
一、背景 本章讲述的是在用户下单环节,消息服务器RabbitMQ 的应用 1.1 消息服务器的应用 在写一个电商项目的小demo,在电商项目中,消息服务器的应用: 1、订单状态通知:当用户下单、支付成功、订单发货、订单完成等…...
HBuilderX
HX 简介下载安装 简介 HBuilderX 是一款由 DCloud 开发的集成开发环境 (IDE),主要用于前端开发和移动应用开发。它基于 Visual Studio Code 平台,针对 Web 开发、小程序开发、移动端开发等提供了丰富的功能和插件。 DCloud官网: https://www.dcloud.io …...
C数据结构与算法——常见排序算法时间复杂度比较 应用
实验任务 (1) 掌握常见比较排序算法的实现; (2) 掌握常用比较排序算法的性能及其适用场合。 实验内容 (1) 平均时间复杂度O(n2)和O(nlog2n)的算法至少各选两种实现; (2) 待排序的无重复关键字存放在一维整型数组中,数量为60000个ÿ…...
C++并发多线程--死锁问题及解决方法
1--死锁问题 死锁问题:两个线程访问资源时加锁,但都需要对方的资源才能执行释放锁; 代码实例:下面的代码中,当线程 1 使用 my_mutex1 上锁后,会继续使用 my_mutex2 进行上锁,若此时线程 2 已经使…...
【Spring】纯注解开发
1、简介 在Spring3.0升级了纯注解开发模式,使用Java类来代替配置文件,开启了Spring快速开发赛道。 2、定义bean Component Service Controller Repository 3、纯注解开发 使用Configuration声明一个配置类,使用ComponentScan来扫描作为bea…...
【算法心得】正确估计dfs时间复杂度;剪枝优化不怕重构
https://leetcode.cn/problems/verbal-arithmetic-puzzle/ 这题看到题,“表达式中使用的不同字符数最大为 10”,就觉得dfs就完事了,最多不过10!,10!才1e6,1e7这样。如果字符再少点,6! 7! 8!的,…...
通过网关访问微服务,一次正常,一次不正常 (nacos配置的永久实例却未启动导致)
微服务直接访问没问题,通过网关访问,就一次正常访问,一次401错误,交替正常和出错 负载均衡试了 路由配置检查了 最后发现nacos下竟然有2个order服务实例,我明明只开启了一个呀 原来之前的8080端口微服务还残留&…...
div输入框的文字超过指定行数用省略号表示css
实现效果:超过四行用省略号表示 实现方法: .text{overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 4; // 自定义行数-webkit-box-orient: vertical; }...
STM32 F103C8T6学习笔记5:定时器输出不同占空比PWM驱动舵机旋转角度
现在学习使用STM32 F103C8T6的定时器PWM模式,使用PWM驱动舵机转动不同角度,文章提供源码,测试工程,测试动态效果图。 目录 基础原理: 实验目标: 测试视频结果: 测试工程下载: 基…...
液体神经网络:LNN是个啥概念?
一、说明 在在人工智能领域,神经网络已被证明是解决复杂问题的非常强大的工具。多年来,研究人员不断寻求创新方法来提高其性能并扩展其能力。其中一种方法是液体神经网络(LNN)的概念,这是一个利用动态计算功能的迷人框…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
