这篇是讲页面优化技术的第二项:页面静态化、前后端分离。
之前的代码的请求逻辑是:
- 客户端请求;
- 服务端的servlet或controller接收请求(后端控制路由与渲染页面,整个项目开发的权重大部分在后端);
- 调用service,dao层代码完成业务逻辑;
- 返回页面;
- 页面展现一些动态的代码;
前后端分离的新的方式是:
- 浏览器发送请求;
- 直接到达html页面(前端控制路由与渲染页面,整个项目开发的权重前移);
- html页面负责调用服务端接口产生数据(通过ajax等等);
- 后台返回json格式数据,json数据格式因为简洁高效而取代xml;
- 填充html,展现动态效果,在页面上进行解析并操作DOM。
优点:
- 减少后端服务器的并发/负载压力。除了接口以外的其他所有http请求全部转移到前端nginx上,接口的请求调用tomcat,参考nginx反向代理tomcat。且除了第一次页面请求外,浏览器会大量调用本地缓存。
- 即使后端服务暂时超时或者宕机了,前端页面也会正常访问,只不过数据刷不出来而已。
- 页面显示的东西再多也不怕,因为是异步加载。
- 发现bug,可以快速定位是谁的问题,不会出现互相踢皮球的现象。页面逻辑,跳转错误,浏览器兼容性问题,脚本错误,页面样式等问题,全部由前端工程师来负责。接口数据出错,数据没有提交成功,应答超时等问题,全部由后端工程师来解决。双方互不干扰,前端与后端是相亲相爱的一家人。
更多优点及详情参考:https://blog.csdn.net/dream_cat_forever/article/details/80709503
在本项目中,主要改造的有:GoodsController、MiaoshaController、OrderController。
这边就以MiaoshaController举例吧。
优化前的代码:
@RequestMapping("/do_miaosha")
public String list(Model model, HttpServletResponse response, @RequestParam("goodsId") long goodsId,
@CookieValue(value = MiaoshaUserService.COOKI_NAME_TOKEN,required = false) String cookieToken,
@RequestParam(value = MiaoshaUserService.COOKI_NAME_TOKEN,required = false) String paramToken) {
if (StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)) {
return "login";
}
String token = StringUtils.isEmpty(paramToken)?cookieToken:paramToken;
MiaoshaUser user = userService.getByToken(response,token);//从token中读用户信息
model.addAttribute("user", user);
if (user == null) {
return "login";
}
//判断库存
GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
int stock = goods.getStockCount();
if (stock <= 0) {
model.addAttribute("errmsg", CodeMsg.MIAO_SHA_OVER.getMsg());
return "miaosha_fail";
}
//判断是否已经秒杀到了
MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
if (order != null) {
model.addAttribute("errmsg", CodeMsg.REPEATE_MIAOSHA.getMsg());
return "miaosha_fail";
}
//3步:减库存 下订单 写入秒杀订单,事务中完成
OrderInfo orderInfo = miaoshaService.miaosha(user, goods);
model.addAttribute("orderInfo", orderInfo);
model.addAttribute("goods", goods);
return "order_detail";
}
前后端分离优化后的代码
@RequestMapping(value = "/do_miaosha", method = RequestMethod.POST)
@ResponseBody
public Result<OrderInfo> miaosha(Model model, @RequestParam("goodsId") long goodsId, HttpServletResponse response,
@CookieValue(value = MiaoshaUserService.COOKI_NAME_TOKEN,required = false) String cookieToken,
@RequestParam(value = MiaoshaUserService.COOKI_NAME_TOKEN,required = false) String paramToken) {
if (StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)) {
return Result.error(CodeMsg.SESSION_ERROR);//token不存在或失效
}
String token = StringUtils.isEmpty(paramToken) ? cookieToken : paramToken;
MiaoshaUser user = userService.getByToken(response, token);//从token中读用户信息
//判断库存
GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);//10个商品,req1 req2
int stock = goods.getStockCount();
if (stock <= 0) {
return Result.error(CodeMsg.MIAO_SHA_OVER);
}
//判断是否已经秒杀到了
MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
if (order != null) {
return Result.error(CodeMsg.REPEATE_MIAOSHA);
}
//减库存 下订单 写入秒杀订单
OrderInfo orderInfo = miaoshaService.miaosha(user, goods);
return Result.success(orderInfo);
}
可以看到,和原来的代码相比最重要的改变是使用了jason的形式和返回值的改变。当然要添加相应的htm页面。(前端小白htm页面搞了一下午。。这里就省略了)
采用以下配置,使浏览器缓存页面:
#static
spring.resources.add-mappings=true
spring.resources.cache.period=3600
spring.resources.chain.cache=true
spring.resources.chain.enabled=true
spring.resources.chain.html-application-cache=true
spring.resources.static-locations=classpath:/static/
做完这些后,运行试一下,第一次访问该页面时http头部Status Code为200,表示访问成功;刷新网站再次访问时,Status Code为304,表示 自从上次请求后,请求的网页未修改过。在谷歌浏览器中不能很好的说明,可以在火狐浏览器中查看,头部Cache-Control: max-age=3600,页面是缓存的。