- 頁面靜態化+前後端分離
- 1. 常用技術AngularJS、Vue.js
- 2. 優點:利用瀏覽器的緩存
- 商品詳情頁靜態化
- 1、 爲了在瀏覽器端進行緩存,以及控制緩存時間,在application.properties裏面添加配置靜態資源配置項:
- 2、在static資源文件夾下面新建我們的靜態資源頁面文件,(我們以.htm格式結尾),這裏爲什麼不能用.html文件結尾是因爲如果不修改繼續用.html後綴,系統會默認去找templates下面的同名文件,所以我們修改它以示區別
- 3、定義一個GoodsDetailVo封裝來專門給頁面傳值。
- 4、改造商品列表頁面(goods_list.html)裏面的跳轉邏輯,修改跳轉請求
- 5、 修改之前的商品詳情頁面,刪除thymeleaf具有的標籤,讓它成爲最初始的html靜態頁面(現在靜態頁面不需要thymeleaf),修改使其都使用id來標識各個組件。
- 6、 剛轉到goods_detail.htm頁面時,js初始化,執行下面方法:
- 7、 getDetail()方法使用ajax異步請求後臺取得該頁面需要的數據,然後拿到數據之後調用render()方法渲染我們的靜態頁面,注意在getDetail中第一步做的是去獲取商品的goodsId,因爲list頁面的商品詳情請求是:
- 9、倒計時countDown()方法:
- 10、 將後端GoodsController裏面接收商品詳情頁的請求的接口修改爲下面代碼:
頁面靜態化+前後端分離
1. 常用技術AngularJS、Vue.js
2. 優點:利用瀏覽器的緩存
本文只是簡單的實現頁面靜態化:
將頁面直接緩存到用戶的瀏覽器上面,好處:用戶訪問數據的時候,不用去請求服務器,直接在本地緩存中取得需要的頁面緩存。
未作頁面靜態化:請求某一個頁面,訪問緩存,查看緩存中是否有,緩存中有直接返回,緩存中沒有的話,將數據渲染到html頁面再存到緩存,再將整個html頁面返回給客戶端顯示。
做了頁面靜態化:第一次是去請求後臺要渲染好的html頁面,之後的請求都是直接訪問用戶本地瀏覽器的緩存的html頁面 ,靜態資源,然後前端通過Ajax來訪問後端,只去獲取頁面需要顯示的數據返回即可。
商品詳情頁靜態化
在先前的操作中我們將商品詳情頁面進行了redis緩存,因爲這個接口只是展示相應產品詳情和秒殺倒計時等信息,只要顯示幾個關鍵信息即可,所以其他的都可以實現靜態化。這種技術,實際就是前端分爲兩部分,一部分是不改變的html塊,還有一塊就是數據,它只要後端傳數據到前端即可,用到ajax技術來請求數據。
1、 爲了在瀏覽器端進行緩存,以及控制緩存時間,在application.properties裏面添加配置靜態資源配置項:
#static 靜態資源配置,設置靜態文件路徑css,js,圖片等等
#spring.mvc.static-path-pattern=/static/** spring.mvc.static-path-pattern=/**
spring.resources.add-mappings=true
spring.resources.cache-period=3600
spring.resources.chain.cache=true
spring.resources.chain.enabled=true
spring.resources.chain.gzipped=true
spring.resources.chain.html-application-cache=true
spring.resources.static-locations=classpath:/static/
2、在static資源文件夾下面新建我們的靜態資源頁面文件,(我們以.htm格式結尾),這裏爲什麼不能用.html文件結尾是因爲如果不修改繼續用.html後綴,系統會默認去找templates下面的同名文件,所以我們修改它以示區別
3、定義一個GoodsDetailVo封裝來專門給頁面傳值。
/**
* 爲了給頁面傳值
*/
public class GoodsDetailVo {
// 秒殺狀態量初始值
private int status = 0;
// 開始時間倒計時
private int remailSeconds = 0;
private GoodsVo goodsVo;
private MiaoshaUser user;
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public int getRemailSeconds() {
return remailSeconds;
}
public void setRemailSeconds(int remailSeconds) {
this.remailSeconds = remailSeconds;
}
public GoodsVo getGoodsVo() {
return goodsVo;
}
public void setGoodsVo(GoodsVo goodsVo) {
this.goodsVo = goodsVo;
}
public MiaoshaUser getUser() {
return user;
}
public void setUser(MiaoshaUser user) {
this.user = user;
}
}
4、改造商品列表頁面(goods_list.html)裏面的跳轉邏輯,修改跳轉請求
之前的請求路徑:
<td><a th:href="'/goods/to_detail/'+${goods.id}">詳情</a></td>
現在的請求路徑:
<td><a th:href="'/goods_detail.htm?goodsId='+${goods.id}">詳情</a></td>
而我們現在是不需要再去服務端請求跳轉,直接去客戶端靜態資源裏面請求商品詳情靜態頁面goods_detail.htm,這裏注意一下修改一下後綴名稱
5、 修改之前的商品詳情頁面,刪除thymeleaf具有的標籤,讓它成爲最初始的html靜態頁面(現在靜態頁面不需要thymeleaf),修改使其都使用id來標識各個組件。
6、 剛轉到goods_detail.htm頁面時,js初始化,執行下面方法:
$(function(){
getDetail();
});
getDetail方法:
function getDetail(){
//getQueryString獲取請求路徑中的參數
var goodsId=getQueryString("goodsId");
//alert(goodsId);
$.ajax({
url:"/goods/detail/"+goodsId,
type:"GET",
success:function(data){
if(data.code==0){
//使用render方法渲染頁面
render(data.data);
}else{
layer.msg(data.msg);
}
},
error:function(){
layer.msg("請求有誤!");
}
});
}
7、 getDetail()方法使用ajax異步請求後臺取得該頁面需要的數據,然後拿到數據之後調用render()方法渲染我們的靜態頁面,注意在getDetail中第一步做的是去獲取商品的goodsId,因爲list頁面的商品詳情請求是:
<td><a th:href="'/goods_detail.htm?goodsId='+${goods.id}">詳情</a></td>
商品詳情點擊鏈接裏面是帶有我們的商品的goodsId的,那麼我們通過方法getQueryString來獲取請求路徑url裏面參數的值
function getQueryString(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if (r != null) {
return unescape(r[2]);
}
return null;
}
8、 獲取到參數之後就可以去請求後端接口,獲取數據去渲染:
function render(detail) {
//alert(detail.status);
var miaoshaStatus = detail.status;
var remailSeconds = detail.remailSeconds;
var goods = detail.goodsVo;
var user = detail.user;
if (user != null) {
//展示相應的
$("#userTip").hide();
}
$("#goodsName").text(goods.goodsName);
$("#goodsImg").attr("src", goods.goodsImg);//.text();
$("#startTime").text(goods.startDate);//還沒有格式化
$("#remailSeconds").val(remailSeconds);
$("#goodsId").val(goods.id);
$("#goodsPrice").text(goods.goodsPrice);
$("#miaoshaPrice").text(goods.miaoshaPrice);
$("#stockCount").text(goods.goodsStock);
countDown();
}
9、倒計時countDown()方法:
function countDown(){
//獲取秒殺倒計時進行判斷,0-->正在進行秒殺,-1-->秒殺結束,remailSeconds>0-->代表倒計時
var remailSeconds=$("#remailSeconds").val();
//alert("remailSeconds:"+remailSeconds);
var timeout;
if(remailSeconds>0){//秒殺還沒有開始,進行倒計時功能
$("#buyButton").attr("disabled",true);
$("#miaoshaTip").html("秒殺倒計時:"+remailSeconds+"秒");
//倒計時
timeout=setTimeout(function(){
$("#countDown").text(remailSeconds-1);
$("#remailSeconds").val(remailSeconds-1);//remailSeconds這是input
countDown();
},1000);//一秒鐘之後回調函數
}else if(remailSeconds==0){//正在進行秒殺
$("#buyButton").attr("disabled",false);
if(timeout){//如果timeout有值的情況
clearTimeout(timeout);
}
//將文案修改 df1fab4272a24cdf9432adb9fd69cb38
$("#miaoshaTip").html("秒殺進行中");
}else{
//小於0的情況,秒殺結束,將秒殺按鈕設置爲不可點擊
$("#buyButton").attr("disabled",true);
$("#miaoshaTip").html("秒殺結束");
}
}
10、 將後端GoodsController裏面接收商品詳情頁的請求的接口修改爲下面代碼:
/**
* 作頁面靜態化的商品詳情
* 頁面存的是html
* 動態數據通過接口從服務端獲取
* @param model
* @param user
* @param goodsId
* @return
*/
@RequestMapping(value="/detail/{goodsId}") //produces="text/html"
@ResponseBody
public Result<GoodsDetailVo> toDetail_staticPage(Model model,MiaoshaUser user,
HttpServletRequest request,HttpServletResponse response,@PathVariable("goodsId")long goodsId) {//id一般用snowflake算法
System.out.println("頁面靜態化/detail/{goodsId}");
model.addAttribute("user", user);
GoodsVo goodsVo=goodsService.getGoodsVoByGoodsId(goodsId);
model.addAttribute("goods", goodsVo);
//既然是秒殺,還要傳入秒殺開始時間,結束時間等信息
long start=goodsVo.getStartDate().getTime();
long end=goodsVo.getEndDate().getTime();
long now=System.currentTimeMillis();
//秒殺狀態量
int status=0;
//開始時間倒計時
int remailSeconds=0;
//查看當前秒殺狀態
if(now<start) {//秒殺還未開始,--->倒計時
status=0;
remailSeconds=(int) ((start-now)/1000); //毫秒轉爲秒
}else if(now>end){ //秒殺已經結束
status=2;
remailSeconds=-1; //毫秒轉爲秒
}else {//秒殺正在進行
status=1;
remailSeconds=0; //毫秒轉爲秒
}
model.addAttribute("status", status);
model.addAttribute("remailSeconds", remailSeconds);
GoodsDetailVo gdVo=new GoodsDetailVo();
gdVo.setGoodsVo(goodsVo);
gdVo.setStatus(status);
gdVo.setRemailSeconds(remailSeconds);
gdVo.setUser(user);
//將數據填進去,傳至頁面
return Result.success(gdVo);
}
goods_detail.htm完整代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>商品詳情</title>
<!-- jquery -->
<!-- <script type="text/javascript" src="@{/js/jequery.min.js}"></script> -->
<script type="text/javascript" src="/jquery-validation/lib/jquery-1.11.1.js"></script>
<link type="text/css" rel="stylesheet" href="/bootstrap/css/bootstrap.css"/>
<script type="text/javascript" src="/bootstrap/js/bootstrap.min.js"></script>
<!-- layer -->
<script type="text/javascript" src="/layer/layer.js"></script>
</head
<body>
<div class="panel panel-default">
<div class="panel-heading">秒殺商品詳情</div>
<div class="panel-body">
<span id="userTip">您還沒有登錄,請登錄後再操作</span>
<span>沒有收貨地址的提示。。。</span>
<input type="hidden" id="goodsId" > <!-- $("#goodsId").val(goods.id); -->
</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="80" height="60"></img></td>
</tr>
<tr>
<td>秒殺開始時間</td>
<td id="startTime"></td>
<td id="">
<!-- 先取得這個時間 -->
<input type="hidden" id="remailSeconds"></input>
<span id="miaoshaTip"></span>
</td>
<td>
<form id="miaoshaForm" method="post" action="/miaosha/do_miaosha">
<button class="btn btn-primary btn-block" type="submit" id="buyButton">立即秒殺</button>
<input type="hidden" name="goodsId" id="goodsId"></input>
</form>
</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 type="text/javascript">
//獲取秒殺地址
function getMiaoshaPath(){
var goodsId=$("#goodsId").val();
}
//做輪詢
function getMiaoshaResult(goodsId){
$.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);
},50);//50ms之後繼續輪詢
layer.msg(data.msg);
}else{
layer.confirm("恭喜你,秒殺成功!查看訂單?",{btn:["確定","取消"]},
function(){
//秒殺成功,跳轉詳情頁面
window.location.href="order_detail.htm?orderId="+result;
},
function(){
layer.closeAll();
});
}
//輪詢
//getMiaoshaResult($("#goodsId").val());
}else{
layer.msg(data.msg);
}
},
error:function(){
layer.msg("請求有誤!");
}
//token如果cookie裏面有,會自己帶過去
});
}
function doMiaosha(){
alert("秒殺!");
$.ajax({
url:"/miaosha/do_miaosha_ajaxcache",
type:"POST",
data:{
goodsId:$("#goodsId").val()
},
success:function(data){
if(data.code==0){
//秒殺成功,跳轉詳情頁面
//window.location.href="order_detail.htm?orderId="+data.data.id;
//輪詢
getMiaoshaResult($("#goodsId").val());
}else{
layer.msg(data.msg);
}
},
error:function(){
layer.msg("請求有誤!");
}
//token如果cookie裏面有,會自己帶過去
});
}
$(function(){
//countDown();
getDetail();
});
//渲染頁面--------5-17
function render(detail){
//alert(detail.status);
var miaoshaStatus=detail.status;
var remailSeconds=detail.remailSeconds;
var goods=detail.goodsVo;
var user=detail.user;
if(user!=null){
//展示相應的
$("#userTip").hide();
}
$("#goodsName").text(goods.goodsName);
$("#goodsImg").attr("src",goods.goodsImg); //.text();
$("#startTime").text(goods.startDate); //還沒有格式化
$("#remailSeconds").val(remailSeconds);
$("#goodsId").val(goods.id);
$("#goodsPrice").text(goods.goodsPrice); //goodsStock----- stockCount
$("#miaoshaPrice").text(goods.miaoshaPrice);
$("#stockCount").text(goods.goodsStock);
countDown();
}
function getQueryString(name){
var reg=new RegExp("(^|&)"+name+"=([^&]*)(&|$)");
var r=window.location.search.substr(1).match(reg);
if(r!=null){
return unescape(r[2]);
}
return null;
}
function getDetail(){
var goodsId=getQueryString("goodsId");
//alert(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(){
//獲取秒殺倒計時進行判斷,0-->正在進行秒殺,-1-->秒殺結束,remailSeconds>0-->代表倒計時
var remailSeconds=$("#remailSeconds").val();
//alert("remailSeconds:"+remailSeconds);
var timeout;
if(remailSeconds>0){//秒殺還沒有開始,進行倒計時功能
$("#buyButton").attr("disabled",true);
$("#miaoshaTip").html("秒殺倒計時:"+remailSeconds+"秒");
//倒計時
timeout=setTimeout(function(){
$("#countDown").text(remailSeconds-1);
$("#remailSeconds").val(remailSeconds-1);//remailSeconds這是input
countDown();
},1000);//一秒鐘之後回調函數
}else if(remailSeconds==0){//正在進行秒殺
$("#buyButton").attr("disabled",false);
if(timeout){//如果timeout有值的情況
clearTimeout(timeout);
}
//將文案修改 df1fab4272a24cdf9432adb9fd69cb38
$("#miaoshaTip").html("秒殺進行中");
}else{
//小於0的情況,秒殺結束,將秒殺按鈕設置爲不可點擊
$("#buyButton").attr("disabled",true);
$("#miaoshaTip").html("秒殺結束");
}
}
</script>
</html>