java使用的页面静态化技术_java秒杀系列(2)- 页面静态化技术

###前言

通过代码片段分别介绍服务端渲染、客户端渲染、对象缓存三种方式的写法。

代码片段仅供参考,具体实现需要根据业务场景自行适配,但思想都是一样。

一、服务端渲染方式

####1、接口返回html页面的设置

```java

@Autowired

ThymeleafViewResolver thymeleafViewResolver;

@Autowired

ApplicationContext applicationContext;

@RequestMapping(value="/to_list", produces="text/html")

@ResponseBody

public String goodsList() {

// 业务逻辑

}

####2、先从缓存中取,有就返回。

```java

//取缓存

String html = redisService.get(GoodsKey.getGoodsList, "", String.class);

if(!StringUtils.isEmpty(html)) {

return html;

}

3、缓存中没有,就手动渲染。

springboot1.5.x的写法:

List goodsList = goodsService.listGoodsVo();

model.addAttribute("goodsList", goodsList);

SpringWebContext ctx = new SpringWebContext(request,response, request.getServletContext(),request.getLocale(), model.asMap(), applicationContext );

//手动渲染

html = thymeleafViewResolver.getTemplateEngine().process("goods_list", ctx);

springboot2.x的写法:

WebContext ctx = new WebContext(request, response, request.getServletContext(), request.getLocale(), model.asMap());

//手动渲染

html = thymeleafViewResolver.getTemplateEngine().process("goods_list", ctx);

4、最后再将渲染内容加入到redis

if(!StringUtils.isEmpty(html)) {

redisService.set(GoodsKey.getGoodsList, "", html);

}

二、客户端渲染方式(商品详情页)

####1、找到跳转到商品详情页的路径,修改为一个静态html的路径。

在商品列表页,找到跳转到详情页的动态路径,直接修改为一个静态路径,后缀为htm或shtml,总之不要是html即可,因为application.properties中一般会配置后缀为html的都访问templates文件夹下的。

注意代码中详情的链接,指向一个静态页面goods_detail.htm:

```html

秒杀商品列表

商品名称商品图片商品原价秒杀价库存数量详情

```

2、根据1的路径,在static目录下新建一个goods_detail.htm文件,原本动态页面上的模板语言都去掉,换成id=“xx”,然后使用ajax来渲染静态文件中的数据即可。

原始动态页面:

秒杀商品详情

您还没有登录,请登陆后再操作

没有收货地址的提示。。。

商品名称
商品图片
秒杀开始时间

秒杀倒计时:

秒杀进行中

秒杀已结束

立即秒杀

商品原价
秒杀价
库存数量

静态化之后的页面:可以看到,动态模板语言都去掉了,直接通过JS来赋值。

秒杀商品详情

您还没有登录,请登陆后再操作

没有收货地址的提示。。。

商品名称
商品图片
秒杀开始时间

立即秒杀

商品原价
秒杀价
库存数量

核心js代码:

$(function(){

getDetail();

});

function getDetail(){

var goodsId = g_getQueryString("goodsId");

$.ajax({

url:"/goods/detail/"+goodsId,

type:"GET",

success:function(data){

if(data.code == 0){

render(data.data);

}else{

layer.msg(data.msg);

}

},

error:function(){

layer.msg("客户端请求有误");

}

});

}

function render(detail){

var miaoshaStatus = detail.miaoshaStatus;

var remainSeconds = detail.remainSeconds;

var goods = detail.goods;

var user = detail.user;

if(user){

$("#userTip").hide();

}

$("#goodsName").text(goods.goodsName);

$("#goodsImg").attr("src", goods.goodsImg);

$("#startTime").text(new Date(goods.startDate).format("yyyy-MM-dd hh:mm:ss"));

$("#remainSeconds").val(remainSeconds);

$("#goodsId").val(goods.id);

$("#goodsPrice").text(goods.goodsPrice);

$("#miaoshaPrice").text(goods.miaoshaPrice);

$("#stockCount").text(goods.stockCount);

countDown(); // 判断秒杀开始状态

}

// 判断秒杀开始状态

function countDown(){

var remainSeconds = $("#remainSeconds").val();

var timeout;

if(remainSeconds > 0){//秒杀还没开始,倒计时

$("#buyButton").attr("disabled", true);

$("#miaoshaTip").html("秒杀倒计时:"+remainSeconds+"秒");

timeout = setTimeout(function(){

$("#countDown").text(remainSeconds - 1);

$("#remainSeconds").val(remainSeconds - 1);

countDown();

},1000);

}else if(remainSeconds == 0){//秒杀进行中

$("#buyButton").attr("disabled", false);

if(timeout){

clearTimeout(timeout);

}

$("#miaoshaTip").html("秒杀进行中");

$("#verifyCodeImg").attr("src", "/miaosha/verifyCode?goodsId="+$("#goodsId").val());

$("#verifyCodeImg").show();

$("#verifyCode").show();

}else{//秒杀已经结束

$("#buyButton").attr("disabled", true);

$("#miaoshaTip").html("秒杀已经结束");

$("#verifyCodeImg").hide();

$("#verifyCode").hide();

}

}

3、记得服务端返回json格式数据,给静态页面做数据绑定。

三、客户端渲染方式(秒杀接口)

和第二点的操作基本一样,也是去除动态模板语言,改为ajax渲染。

不同的地方:

1)、多了一些springboot的配置;

2)、GET和POST的区别,这里一定要用POST,有一些场景比如删除操作,如果用了GET比如delete?id=XX这样的写法,那么搜索引擎扫描到会自动帮你删除了,所以一定要写清楚类型。

1、springboot-1.5.x的配置

spring.resources.add-mappings=true #是否启用默认资源处理

spring.resources.cache-period= 3600 #缓存时间

spring.resources.chain.cache=true #是否在资源链中启用缓存

spring.resources.chain.enabled=true #是否启用Spring资源处理链。默认情况下,禁用,除非至少启用了一个策略。

spring.resources.chain.gzipped=true #是否对缓存压缩

spring.resources.chain.html-application-cache=true #是否启用HTML5应用程序缓存清单重写

spring.resources.static-locations=classpath:/static/ #静态资源的位置

####2、springboot2.1.1的官方配置

```properties

spring.resources.add-mappings=true # 是否启用默认资源处理

spring.resources.cache.cachecontrol.cache-private= # 表示响应消息是针对单个用户的,不能由共享缓存存储。

spring.resources.cache.cachecontrol.cache-public= # 表示任何缓存都可以存储响应

spring.resources.cache.cachecontrol.max-age= # 响应被缓存的最大时间,如果没有指定持续时间后缀,以秒为单位。

spring.resources.cache.cachecontrol.must-revalidate= # 表明,一旦缓存过期,在未与服务器重新验证之前,缓存不能使用响应。

spring.resources.cache.cachecontrol.no-cache= # 表示缓存的响应只有在服务器重新验证时才能重用

spring.resources.cache.cachecontrol.no-store= # 表示在任何情况下都不缓存响应

spring.resources.cache.cachecontrol.no-transform= # 指示中介(缓存和其他)它们不应该转换响应内容

spring.resources.cache.cachecontrol.proxy-revalidate= # 与“must-revalidate”指令的含义相同,只是它不适用于私有缓存。

spring.resources.cache.cachecontrol.s-max-age= # 响应被共享缓存缓存的最大时间,如果没有指定持续时间后缀,以秒为单位。

spring.resources.cache.cachecontrol.stale-if-error= # 当遇到错误时,响应可能使用的最大时间,如果没有指定持续时间后缀,以秒为单位。

spring.resources.cache.cachecontrol.stale-while-revalidate= # 如果没有指定持续时间后缀,则响应在过期后可以提供的最长时间(以秒为单位)。

spring.resources.cache.period= # 资源处理程序提供的资源的缓存周期。如果没有指定持续时间后缀,将使用秒。

spring.resources.chain.cache=true # 是否在资源链中启用缓存。

spring.resources.chain.compressed=false # 是否启用已压缩资源(gzip, brotli)的解析。

spring.resources.chain.enabled= # 是否启用Spring资源处理链。默认情况下,禁用,除非至少启用了一个策略。

spring.resources.chain.html-application-cache=false # 是否启用HTML5应用缓存清单重写。

spring.resources.chain.strategy.content.enabled=false # 是否启用内容版本策略。

spring.resources.chain.strategy.content.paths=/** # 应用于内容版本策略的以逗号分隔的模式列表。

spring.resources.chain.strategy.fixed.enabled=false # 是否启用固定版本策略。

spring.resources.chain.strategy.fixed.paths=/** # 用于固定版本策略的以逗号分隔的模式列表。

spring.resources.chain.strategy.fixed.version= # 用于固定版本策略的版本字符串。

spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/ # 静态资源的位置。

```

####3、第二点在点击按钮时调用的JS方法getMiaoshaPath()如下

```javascript

```

四、对象缓存

最基本最常用的缓存处理逻辑:

失效:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。

命中:应用程序从cache中取数据,取到后返回。

更新:先把数据存到数据库中,成功后,再让缓存失效。

参考代码:

// 先查缓存,再查数据库。

public MiaoshaUser getById(long id) {

//取缓存

MiaoshaUser user = redisService.get(MiaoshaUserKey.getById, ""+id, MiaoshaUser.class);

if(user != null) {

return user;

}

//取数据库

user = miaoshaUserDao.getById(id);

if(user != null) {

redisService.set(MiaoshaUserKey.getById, ""+id, user);

}

return user;

}

// 更新数据库后,缓存也要做同步更新。

public boolean updatePassword(String token, long id, String formPass) {

//取user

MiaoshaUser user = getById(id);

if(user == null) {

throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);

}

//更新数据库

MiaoshaUser toBeUpdate = new MiaoshaUser();

toBeUpdate.setId(id);

toBeUpdate.setPassword(MD5Util.formPassToDBPass(formPass, user.getSalt()));

miaoshaUserDao.update(toBeUpdate);

//处理缓存

redisService.delete(MiaoshaUserKey.getById, ""+id);

user.setPassword(toBeUpdate.getPassword());

redisService.set(MiaoshaUserKey.token, token, user);

return true;

}

总结

服务端渲染:利用模板引擎技术生成静态html页面到指定目录或者是redis等缓存中间件中去,页面上的访问路径直接指向到该目录下的静态html,这种方式实际上还是属于服务端渲染的静态化方式。

客户端渲染:将原本的模板语言渲染的html,改变为纯静态的htm/shtml,然后用js/ajax渲染数据,加上spring配置文件的相关配置指定静态文件存放路径,达到利用浏览器缓存页面的方式。推荐使用这种方式,这种属于前后端分离的客户端渲染方式,性能更好。

对象缓存:对象级缓存主要是在service中对一些对象的缓存处理,要按照合理的步骤,先取缓存,再取数据库,缓存中有就返回缓存对象,没有就返回数据库数据,最后将数据库数据再放入缓存中。

如果对缓存处理逻辑感兴趣,可以参考这篇博客:http://blog.csdn.net/tTU1EvLDeLFq5btqiK/article/details/78693323

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

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

相关文章

activex for chrome扩展程序 下载”_Chrome扩展程序一键生成网页骨架屏

对于依赖接口渲染的页面,在拿到数据之前页面往往是空白的,为了提示用户当前正在加载中,往往会使用进度条、loading图标或骨架屏的方式。对于前两种方案而言,实现比较简单;本文主要研究骨架屏的应用及实现,并…

python定时器 循环_python从写定时器学习Thread

python从写定时器学习Threadpython 如何写一个定时器,循环定时做某一操作呢?Timer 对象from threading import Timerdef hello():print "hello, world"t Timer(10.0, hello)t.start()10秒后输出:hello, world重点研究 t Timer(10…

java创建链表成绩管理系统_成绩管理系统 链表版

1.[代码][C/C]代码/**********************************************************程序描述:学生成绩管理系统*运行环境:Windows 7 SP1 X64*开发环境:CodeBlocks with Win7*作者:耗子、*时间:2015.03******************…

dynamo python修改多个参数_python之函数

a.sort()没有返回值。而sorted(a)是有返回值的。Python的标准比较运算符&#xff1a;<、<、 > 、>、 、 !函数用法和底层分析&#xff1a;函数是一个可重用的程序代码块&#xff0c;函数也代表一个任务和功能&#xff08;function&#xff09;,是代码复用的通用机制…

python开发基础戴歆第四章_第一阶段:Python开发基础 day04 课后练习

第一阶段&#xff1a;Python开发基础 day04 课后作业1.简述python的五大数据类型的作用、定义方式、使用方法数字类型字符串类型列表字典布尔型答&#xff1a;数字类型分为整型(int)和浮点型(float)&#xff1a;整型的作用&#xff1a;表示人的年龄、各种号码、级别等定义方式&…

javascript进制转换_JavaScript 加减危机——为什么会出现这样的结果?

在日常工作计算中&#xff0c;我们如履薄冰&#xff0c;但是 JavaScript 总能给我们这样那样的 surprise~0.1 0.2 &#xff1f;1 - 0.9 &#xff1f;如果小伙伴给出内心的结果&#xff1a;0.1 0.2 0.31 - 0.9 0.1那么小伙伴会被事实狠狠地扇脸&#xff1a;console.log(0.…

python与golang_Golang与python线程详解及简单实例

Golang与python线程详解及简单实例在GO中&#xff0c;开启15个线程&#xff0c;每个线程把全局变量遍历增加100000次&#xff0c;因此预测结果是 15*1000001500000.var sum intvar cccc intvar m *sync.Mutexfunc Count1(i int, ch chan int) {for j : 0; j < 100000; j {cc…

java 树状 子节点_java构建树形列表(带children属性)

/*** 树形表格工具类**authoryanggb*/public classTreeTableUtil {/*** 把列表转换为树结构**paramoriginalList 原始list数据*paramidFieldName 作为唯一标示的字段名称*parampidFieldName 父节点标识字段名*paramchildrenFieldName 子节点(列表)标识字段名*return树结构列表*…

python输出文本内容_python 打印文件里的内容

Android 屏幕旋转 处理 AsyncTask 和 ProgressDialog 的最佳方案 的最佳方案 标签: Android屏幕旋转AsyncTaskProgressDialog 2014-07-19 09:25 39227人阅读 评论(46) 收藏 举报 分类: [android 进阶之 ... Mysql查找所有项目开始时间比之前项目结束时间小的项目ID 这是之前遇到…

python中八皇后如何运算的_python解决八皇后算法

展开全部global col #定义一些全局变量global rowglobal pos_diagglobal nag_diagglobal countdef output(): 输出一种有效结果global countprint rowcount 1def do_queen(i): 生成所有正确解param i: 皇后的数目for j in range(0, 8): #依次62616964757a686964616fe59b9ee7ad…

java实现复制粘贴的计算器_软帝学院教你用java编写计算器(三)

教你用java编写计算器(三)import java.awt.Color;import java.awt.Dimension;import java.awt.event.ActionListener;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JMenu;import javax.swing.JMenuBar;import javax.swing.JMenuItem;import javax…

php 公众号验证回调方法_如何进行公众号文章收集 两种收集方法详解

大家都知道优质的公众号吸引用户最关键的就是要优质的文章&#xff0c;所以会有专人负责进行公众号文章收集工作&#xff0c;下面我们跟随拓途数据一起来了解一下如何进行公众号文章收集的相关资料吧。 如何进行公众号文章收集方案一&#xff1a;基于搜狗入口 在网上能搜索到的…

mysql保存一个文件怎么打开_悄悄告诉你,MySQL 通过SQL语句导出到Excel的方法-sql文件怎么打开...

执行SQL语句select fullname,time,endtime,closed from chat_archive into outfile c:/xxx.xls注意&#xff1a;因为office默认的是gb2312编码&#xff0c;服务器端生成的很有可能是utf-8编码&#xff0c;此时有几种选择1、把查询出来的结果转换为GB2312格式(字段fullname)sele…

gerber文件怎么导贴片坐标_SMT贴片机在线编程调试

SMT贴片机分为离线编程和在线编程调试&#xff0c;在线编程调试就是在 SMT 贴片机上对离线编程的程序进行优化调试编辑。SMT 贴片机在线编程调试总体上就是两个步骤&#xff0c;一个是离线编程的程序进行编程&#xff0c;然后就是总体检查并备份到贴片机电脑内。一、在 SMT 贴片…

java销售额查询_用JSP+JavaBean开发模式实现一个销售额的查询

数据库使用mysql&#xff0c;如下&#xff1a;vo包的Sales类&#xff1a;package com.vo;public class Sales {public String salestime;public float salesnum;public String getSalestime() {return salestime;}public void setSalestime(String salestime) {this.salestime …

python支持函数式编程么_Python 函数式编程

f absprint(f(-20))三、匿名函数其实就是指向函数的变量abs len# print(abs(-10))print(abs([1,2,3,4])四、高阶函数&#xff1a;能接收函数做参数的函数1.变量可以指向函数2.函数的参数可以接收变量3.一个函数可以接收另一个函数作为参数4.能接收函数作参数的函数就是高阶函…

spss数据_怎么建立SPSS数据库、录入数据?

怎么把收集的问卷、测试数据等原始资料转变为“SPSS数据库”&#xff1f;数据包括离散&#xff08;单选题、多选题等&#xff09;、连续&#xff08;年龄、身高、肺活量、人数等&#xff09;两类。以下面四个题目为例&#xff0c;介绍采用SPSS建立数据库的方法&#xff1a;A2.学…

php 开发一个聊天系统,ajax+php 实现一个简单的在线聊天室功能(附带源码)

通过ajax和setInterval()函数&#xff0c;配合phpmysql实现一个简单的在线聊天室的功能。附带详细源码案例。这个聊天室是一个简单的聊天室&#xff0c;通过javascript setInterval()和ajax函数&#xff0c;不停的去获取服务器获取最新的聊天数据信息&#xff0c;并无刷新的写入…

怎么下载完整的python_怎么下载python并安装

Q5&#xff1a;如何在win7下安装Python及配置安装配置如下&#xff1a;下载安装 Pythonhttp://www.python.org/download/http://www.python.org/ftp/python/2.6/python-2.6.msihttp://www.python.org/ftp/python/2.6/python-2.6.amd64.msi如下载 Python 2.6&#xff0c;安装目录…

织梦 php 传值,php获取post参数的几种方式

php获取post参数的几种方式&#xff0c;ajax提交数据的几种类型&#xff0c;PHP默认识别的数据类型是application/x-www.form-urlencoded标准的数据类型。1、$_POST[paramName] 只有在Content-Type为application/x-www-form-urlencoded或者为multipart/form-data的 时候&#x…