目录
1.使用缓存
页面缓存+URL缓存+对象缓存
使用这些缓存的优点:
1.减轻数据库压力(核心)
2.提高用户体验
3.增强系统的并发能力
(1)页面缓存
@ApiOperation(httpMethod = "POST", value = "商品列表", notes = "查询所有商品")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "商品id", required = true, dataType = "Long")
})
@RequestMapping(value = "toList", produces = "text/html")
@ResponseBody
public String toList(
HttpServletRequest request, HttpServletResponse response,
Model model, MiaoshaUser user) {
model.addAttribute("user", user.toString());
List<GoodsVO> goodsList = goodsService.listGoodsVo();
model.addAttribute("goodsList", goodsList);
//取缓存
String html = redisService.get(GoodsKey.getGoodsList, "", String.class);
if (!StringUtils.isEmpty(html)) {
return html;
}
WebContext ctx = new WebContext(request, response,
request.getServletContext(), request.getLocale(), model.asMap());
//手动渲染
html = thymeleafViewResolver.getTemplateEngine().process("goodsList", ctx);
if (!StringUtils.isEmpty(html)) {
redisService.set(GoodsKey.getGoodsList, "", html);
}
return html;
}
新建一个GoodsKey的类:
public class GoodsKey extends BasePrefix{
public GoodsKey(int expireSeconds, String prefix) {
super(expireSeconds, prefix);
}
public static GoodsKey getGoodsList = new GoodsKey(60,"goodsList");
public static GoodsKey getGoodsDetail = new GoodsKey(60,"goodsDetail");
}
(2)URL缓存
截取片段如下:
@ApiOperation(httpMethod = "POST", value = "商品详情", notes = "某一个商品详情")
@ApiImplicitParams({
@ApiImplicitParam(name = "goodsId", value = "商品id", required = true, dataType = "Long")
})
@RequestMapping(value = "toDetail/{goodsId}", produces = "text/html")
@ResponseBody
public String toDetail(
HttpServletRequest request, HttpServletResponse response,
Model model, MiaoshaUser user,
@PathVariable("goodsId") long goodsId) {
//snowflake
//取缓存
String html = redisService.get(GoodsKey.getGoodsList, "" + goodsId, String.class);
if (!StringUtils.isEmpty(html)) {
return html;
}
logger.info("id:" + goodsId);
GoodsVO goodsVO = goodsService.getGoodsVoByGoodsId(goodsId);
model.addAttribute("goods", goodsVO);
model.addAttribute("user", user.toString());
logger.info("goods:" + goodsVO);
//开始 结束 时间
long startAt = goodsVO.getStartDate().getTime();
long endAt = goodsVO.getEndDate().getTime();
long now = System.currentTimeMillis();
logger.info("now:" + now + "\t" + "startAt:" + startAt + "\t" + "endAt:" + endAt);
//开始状态
int miaoshaStatus = 0;
//时间
int remainSeconds = 0;
//秒杀倒计时 开始 结束 进行中
if (now < startAt) {
remainSeconds = (int) ((startAt - now) / 1000);
} else if (now > endAt) {
miaoshaStatus = 2;
remainSeconds = -1;
} else {
miaoshaStatus = 1;
}
logger.info("miaoshaStatus:" + miaoshaStatus + "\t" + "remainSeconds:" + remainSeconds);
model.addAttribute("miaoshaStatus", miaoshaStatus);
model.addAttribute("remainSeconds", remainSeconds);
// return "goodsDetail";
//手动渲染
WebContext ctx = new WebContext(request, response,
request.getServletContext(), request.getLocale(), model.asMap());
//手动渲染
html = thymeleafViewResolver.getTemplateEngine().process("GoodsDetail", ctx);
if (!StringUtils.isEmpty(html)) {
redisService.set(GoodsKey.getGoodsDetail, "" + goodsId, html);
}
return html;
}
(3)对象缓存
截取片段如下:
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;
}
MiaoshaUserKey:
public class MiaoshaUserKey extends BasePrefix{
private static final int TOKEN_EXPIRE = (3600 * 24 * 2);
public MiaoshaUserKey(String prefix) {
super(prefix);
}
public MiaoshaUserKey(int expireSeconds, String prefix) {
super(expireSeconds, prefix);
}
public static MiaoshaUserKey token = new MiaoshaUserKey(TOKEN_EXPIRE,"tk");
public static MiaoshaUserKey getById = new MiaoshaUserKey(0,"id");
}
2.页面静态化
页面静态化的优点:
- 提高速度
比如jsp这一类的动态网页,需要进行数据库查询,这时访问量增加,数据库查询的次数也会随之增加,会占用很大的资源,影响到网站的反应速度。如果把首页、内容静态化的话,就会去除了查询数据库的次数,减少一部分环节,加快网站反应速度。
2.搜索引擎的收录
从网站的优化上来说,搜索引擎更喜欢静态网页,也容易进行抓取,SEO排名也会更高。比如百度、阿里巴巴、搜狐都使用静态网页或者伪静态网页来显示,方便搜索引擎的抓取与排名。
3.安全性
静态网页不容易被黑客所攻破。静态网页没有查询数据库,不会让黑客看到数据库里的内容。
4.网站稳定性
如果后台程序、数据库等出现错误,影响网站的访问,影响用户的体验度,降低了用户的信任度,而静态网页就不会出现这种情况。
(1)商品详情页静态化
1.GoodsController:
/**
* 商品详情页面静态化
*/
@ApiOperation(httpMethod = "POST", value = "商品详情", notes = "某一个商品详情")
@ApiImplicitParams({
@ApiImplicitParam(name = "goodsId", value = "商品id", required = true, dataType = "Long")
})
@RequestMapping(value = "to_detail2/{goodsId}")
@ResponseBody
public Result<GoodsDetailVO> toDetail2(
HttpServletRequest request, HttpServletResponse response,
Model model, MiaoshaUser user,
@PathVariable("goodsId") long goodsId) {
GoodsVO goodsVO = goodsService.getGoodsVoByGoodsId(goodsId);
logger.info("-------goodsVO:" + goodsVO);
//开始 结束 时间
long startAt = goodsVO.getStartDate().getTime();
long endAt = goodsVO.getEndDate().getTime();
long now = System.currentTimeMillis();
logger.info("now:" + now + "\t" + "startAt:" + startAt + "\t" + "endAt:" + endAt);
//开始状态
int miaoshaStatus = 0;
//时间
int remainSeconds = 0;
//秒杀倒计时 开始 结束 进行中
if (now < startAt) {
remainSeconds = (int) ((startAt - now) / 1000);
} else if (now > endAt) {
miaoshaStatus = 2;
remainSeconds = -1;
} else {
miaoshaStatus = 1;
}
GoodsDetailVO vo = new GoodsDetailVO();
vo.setGoods(goodsVO);
vo.setUser(user);
vo.setRemainSeconds(remainSeconds);
vo.setMiaoshaStatus(miaoshaStatus);
return Result.success(vo);
}
2.新建一个GoodsDetailVO工具类:
@Data
public class GoodsDetailVO implements Serializable {
//秒杀状态
private int miaoshaStatus = 0;
//剩余时间时间
private int remainSeconds = 0;
private GoodsVO goods;
private MiaoshaUser user;
public int getMiaoshaStatus() {
return miaoshaStatus;
}
public void setMiaoshaStatus(int miaoshaStatus) {
this.miaoshaStatus = miaoshaStatus;
}
public int getRemainSeconds() {
return remainSeconds;
}
public void setRemainSeconds(int remainSeconds) {
this.remainSeconds = remainSeconds;
}
public GoodsVO getGoods() {
return goods;
}
public void setGoods(GoodsVO goods) {
this.goods = goods;
}
public MiaoshaUser getUser() {
return user;
}
public void setUser(MiaoshaUser user) {
this.user = user;
}
}
3.在goodsList.html中做出如下修改
<!--<td><a th:href="'/goods/toDetail/'+${goods.id}">详情</a></td>-->
<td><a th:href="'/goodsDetail.htm?goodsId='+${goods.id}">详情</a></td>
4.新建一个goodsDetail.htm页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>商品详情页</title>
</head>
<!-- jquery -->
<script type="text/javascript" src="/js/jquery.min.js"></script>
<!-- bootstrap -->
<link rel="stylesheet" type="text/css" href="/bootstrap/css/bootstrap.min.css"/>
<script type="text/javascript" src="/bootstrap/js/bootstrap.min.js"></script>
<!-- jquery-validator -->
<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>
<!-- layer -->
<script type="text/javascript" src="/layer/layer.js">
</script>
<!-- md5.js -->
<script type="text/javascript" src="/js/md5.min.js"></script>
<!-- common.js -->
<script type="text/javascript" src="/js/common.js"></script>
<body>
<div class="panel panel-default">
<div class="panel-heading">秒杀商品详情</div>
<div class="panel-body">
<span id="userTip"> 您还没有登录,请登陆后再操作<br/></span>
<span>没有收货地址的提示!</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>
<button class="btn btn-primary btn-block" type="button" id="buyButton" onclick="doMiaosha()">立即秒杀</button>
<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>
<script>
function doMiaosha(){
}
$(function () {
getDetail();
})
function getDetail() {
//获取url参数
const goodsId = g_getQueryString("goodsId");
$.ajax({
url: "/goods/to_detail2/" + goodsId,
type: "POST",
success: function (data) {
if (data.code === 0) {
// layer.msg("渲染页面")
//渲染页面
render(data.data);
} else {
layer.msg(data.msg());
}
},
error: function (data) {
layer.msg("客户端请求有误")
}
})
}
/**
* 渲染页面信息
*/
function render(detail) {
const miaoshaStatus = detail.miaoshaStatus;
const remainSeconds = detail.remainSeconds;
const user = detail.user;
const goods = detail.goods;
if (user) {
//如果user存在,说明已经登录,不再显示
$("#userTip").hide();
}
//填充页面数据
if (goods) {
$("#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() {
const remainSeconds = $("#remainSeconds").val();
let 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("秒杀进行中");
//秒杀已经结束
} else {
$("#buyButton").attr("disabled", true);
$("#miaoshaTip").html("秒杀已经结束");
}
}
</script>
</body>
</html>
(2)秒杀静态化
MiaoshaController:
@ApiOperation(httpMethod = "POST",value = "秒杀",notes = "立即秒杀")
@ApiImplicitParam(name = "id",value = "商品id",required = true ,dataType = "Long")
@RequestMapping("do_miaosha")
public String doSha(Model model, MiaoshaUser user,
@RequestParam("goodsId") long goodsId) {
model.addAttribute("user", user);
if (user == null) {
return "login";
}
//判断库存
GoodsVO goodsVO = goodsService.getGoodsVoByGoodsId(goodsId);
int stock = goodsVO.getStockCount();
if (stock <= 0) {
model.addAttribute("errmsg", CodeMsg.MIAOSHA_OVER.getMsg());
return "miaosha_fail";
}
//判断是否已经秒杀到了
MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
if (order != null) {
model.addAttribute("errmsg", CodeMsg.MIAOSHA_REPET.getMsg());
return "miaosha_fail";
}
//减少库存 下订单 写入秒杀订单
OrderInfo orderInfo = miaoshaService.miaosha(user, goodsVO);
model.addAttribute("orderInfo", orderInfo);
model.addAttribute("goods",goodsVO);
logger.info("goods:"+goodsVO+"\t"+"orderInfo:"+orderInfo);
return "order_detail";
}
}
3.静态资源优化
常用的优化手段:
1.JS/CSS压缩,减少流量;
2.多个JS/CSS组合,减少连接数;
3.CDN就近访问。
相关工具扩展:
Tengine
Tengine是由淘宝网发起的Web服务器顶目,它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性, Tengine的性能和稳定性已经在大型的网站如淘宝网,天猫商城等得到了很好的检验.它的最终目标是打造一个高效、稳定、安全、易用的web平台。
webpack
webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
CDN
CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。