(10)SprintBoot 2.X 页面优化技术(页面静态化,前后端分离)(一)商品详情静态化
1.为什么使用页面静态化?
2. 代码实现
2.1 application.properities中引入依赖
2.2 改变goods_list.html的跳转商品详情页方式
2.3 修改后端GoodsController接收商品详情页的请求的接口
2.4 页面静态化后的goods_detail.htm
1.为什么使用页面静态化?
使用页面静态化前:点击链接,访问后端controller 访问业务层,成功获取数据,将数据渲染到html页面再将整个html页面返回给客户显示
使用页面静态化后::点击链接,除了第一次访问。访问直接访问用户本地的缓存的html页面 (浏览器会缓存下来静态static下文件),静态资源,然后通过前端ajAx来访问后端,获取页面需要显示的数据返回即可。说白了就是把动态网页中从服务器获取数据部分用ajax方式请求服务器接口获得,再通过angular、vue、react等前端框架渲染出来
优点: (1)减轻服务器负担,浏览网页无需调用系统数据库。 (2)有利于搜索引擎优化SEO,Baidu、Google都会优先收录静态页面,不仅被收录的快还收录的全; (3)加快页面打开速度,静态页面无需连接数据库打开速度较动态页面有明显提高; (4)网站更安全,HTML页面不会受php程序相关漏洞的影响;观看一下大一点的网站基本全是静态页面,而且可以减少攻击,防sql注入。数据库出错时,不影响网站正常访问。 (5)数据库出错时,不影响网站的正常访问。 (6)最主要是可以增加访问速度,减轻服务器负担,当数据量有几万,几十万或是更多的时候你知道哪个更快了. 而且还容易被搜索引擎找到。生成html文章虽操作上麻烦些,程序上繁杂些,但为了更利于搜索,为了速度更快些,更安全,这些牺牲还是值得的。
2. 代码实现
2.1 application.properities中引入依赖
spring.resources.add- mappings=true
spring.resources.cache.period= 3600s
spring.resources.chain.cache=true
spring.resources.chain.enabled=true
spring.resources.chain.compressed=true
spring.resources.chain.html- application- cache=true
spring.resources.static- locations=classpath: /static/
2.2 改变goods_list.html的跳转商品详情页方式
< td> < a th: href= " ' /goods_detail.htm?goodsId=' +${goods.id}" > 详情 a> td>
2.3 修改后端GoodsController接收商品详情页的请求的接口
@RequestMapping ( value = "/detail/{goodsId}" )
@ResponseBody
public Result< GoodsDetailVo> detail ( HttpServletRequest request, HttpServletResponse response, Model model, MiaoshaUser user, @PathVariable ( "goodsId" ) long goodsId) {
GoodsVo goods = goodsService. getGoodsVoByGoodsId ( goodsId) ;
model. addAttribute ( "goods" , goods) ;
long startTime = goods. getStartDate ( ) . getTime ( ) ;
long endTime = goods. getEndDate ( ) . getTime ( ) ;
long now = System. currentTimeMillis ( ) ;
int miaoshaStatus = 0 ;
int remainSeconds = 0 ;
if ( now < startTime) {
miaoshaStatus = 0 ;
remainSeconds = ( int ) ( ( startTime - now) / 1000 ) ;
} else if ( now > endTime) {
miaoshaStatus = 2 ;
remainSeconds = - 1 ;
} else {
miaoshaStatus = 1 ;
remainSeconds = 0 ;
}
GoodsDetailVo vo = new GoodsDetailVo ( ) ;
vo. setGoods ( goods) ;
vo. setUser ( user) ;
vo. setRemainSeconds ( remainSeconds) ;
vo. setMiaoshaStatus ( miaoshaStatus) ;
return Result. success ( vo) ;
}
2.4 页面静态化后的goods_detail.htm
getDetail() 通过ajax方式从服务端获取商品详情信息(GoodsDetailVo)后,交由render()进行页面渲染
< html >
< head>
< title> 商品详情 title>
< meta http-equiv = " Content-Type" content = " text/html; charset=UTF-8" />
< script type = " text/javascript" src = " /js/jquery.min.js" > script>
< link rel = " stylesheet" type = " text/css" href = " /bootstrap/css/bootstrap.min.css" />
< script type = " text/javascript" src = " /bootstrap/js/bootstrap.min.js" > script>
< script type = " text/javascript" src = " /jquery-validation/jquery.validate.min.js" > script>
< script type = " text/javascript" src = " /jquery-validation/localization/messages_zh.min.js" > script>
< script type = " text/javascript" src = " /layer/layer.js" > script>
< script type = " text/javascript" src = " /js/md5.min.js" > script>
< script type = " text/javascript" src = " /js/common.js" > script>
head>
< body>
< div class = " panel panel-default" >
< div class = " panel-heading" > 秒杀商品详情 div>
< div class = " panel-body" >
< span id = " userTip" > 您还没有登录,请登陆后再操作< br/> span>
div>
< table class = " table" id = " goodslist" >
< tr>
< td> 商品名称 td>
< td colspan = " 3" id = " goodsName" > td>
tr>
< tr>
< td> 商品图片 td>
< td colspan = " 3" > < img id = " goodsImg" width = " 200" height = " 200" /> td>
tr>
< tr>
< td> 秒杀开始时间 td>
< td id = " startTime" > td>
< td >
< input type = " hidden" id = " remainSeconds" />
< span id = " miaoshaTip" > span>
td>
< td>
< div class = " row" >
< div class = " form-inline" >
< img id = " verifyCodeImg" width = " 80" height = " 32" style =" display : none" onclick = " refreshVerifyCode()" />
< input id = " verifyCode" class = " form-control" style =" display : none" />
立即秒杀 button>
div>
div>
< input type = " hidden" name = " goodsId" id = " goodsId" />
td>
tr>
< tr>
< td> 商品原价 td>
< td colspan = " 3" id = " goodsPrice" > td>
tr>
< tr>
< td> 秒杀价 td>
< td colspan = " 3" id = " miaoshaPrice" > td>
tr>
< tr>
< td> 库存数量 td>
< td colspan = " 3" id = " stockCount" > td>
tr>
table>
div>
body>
< script>
function getMiaoshaPath ( ) {
var goodsId = $ ( "#goodsId" ) . val ( ) ;
g_showLoading ( ) ;
$. ajax ( {
url: "/miaosha/path" ,
type: "GET" ,
data: {
goodsId: goodsId,
verifyCode: $ ( "#verifyCode" ) . val ( )
} ,
success: function ( data) {
if ( data. code == 0 ) {
var path = data. data;
doMiaosha ( path) ;
} else {
layer. msg ( data. msg) ;
}
} ,
error: function ( ) {
layer. msg ( "客户端请求有误" ) ;
}
} ) ;
}
function getMiaoshaResult ( goodsId) {
g_showLoading ( ) ;
$. ajax ( {
url: "/miaosha/result" ,
type: "GET" ,
data: {
goodsId: $ ( "#goodsId" ) . val ( ) ,
} ,
success: function ( data) {
if ( data. code == 0 ) {
var result = data. data;
if ( result < 0 ) {
layer. msg ( "对不起,秒杀失败" ) ;
} else if ( result == 0 ) {
setTimeout ( function ( ) {
getMiaoshaResult ( goodsId) ;
} , 200 ) ;
} else {
layer. confirm ( "恭喜你,秒杀成功!查看订单?" , { btn: [ "确定" , "取消" ] } ,
function ( ) {
window. location. href= "/order_detail.htm?orderId=" + result;
} ,
function ( ) {
layer. closeAll ( ) ;
} ) ;
}
} else {
layer. msg ( data. msg) ;
}
} ,
error: function ( ) {
layer. msg ( "客户端请求有误" ) ;
}
} ) ;
}
function doMiaosha ( path) {
$. ajax ( {
url: "/miaosha/" + path+ "/do_miaosha" ,
type: "POST" ,
data: {
goodsId: $ ( "#goodsId" ) . val ( )
} ,
success: function ( data) {
if ( data. code == 0 ) {
getMiaoshaResult ( $ ( "#goodsId" ) . val ( ) ) ;
} 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 ( ) ;
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 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 ( ) ;
}
}
function refreshVerifyCode ( ) {
$ ( "#verifyCodeImg" ) . attr ( "src" , "/miaosha/verifyCode?goodsId=" + $ ( "#goodsId" ) . val ( ) + "×tamp=" + new Date ( ) . getTime ( ) ) ;
}
script>
html>