目录:
(1)问题详解
(2)首页商品分类实现
(3)修改web-all模块
(4)页面渲染
(1)问题详解
(2)首页商品分类实现
前面做了商品详情,我们现在来做首页分类,我先看看京东的首页分类效果,我们如何实现类似效果:
思路:
- 首页属于并发量比较高的访问页面,我看可以采取页面静态化方式实现,或者把数据放在缓存中实现
- 我们把生成的静态文件可以放在nginx访问或者放在web-all模块访问
(3)修改web-all模块
修改pom.xml
<dependencies>
<dependency>
<groupId>com.atguigu.gmall</groupId>
<artifactId>service-item-client</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.atguigu.gmall</groupId>
<artifactId>service-product-client</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
由于商品分类信息在service-product模块,我们在该模块封装数据,数据结构为父子层级
商品分类保存在base_category1、base_category2和base_category3表中,由于需要静态化页面,我们需要一次性加载所有数据,前面我们使用了一个视图base_category_view,所有我从视图里面获取数据,然后封装为父子层级
视图包含三级分类的所有数据
数据结构如下:json 数据结构
[
{
"index": 1,
"categoryChild": [
{
"categoryChild": [
{
"categoryName": "电子书", # 三级分类的name
"categoryId": 1
},
{
"categoryName": "网络原创", # 三级分类的name
"categoryId": 2
},
...
],
"categoryName": "电子书刊", #二级分类的name
"categoryId": 1
},
...
],
"categoryName": "图书、音像、电子书刊", # 一级分类的name
"categoryId": 1
},
...
"index": 2,
"categoryChild": [
{
"categoryChild": [
{
"categoryName": "超薄电视", # 三级分类的name
"categoryId": 1
},
{
"categoryName": "全面屏电视", # 三级分类的name
"categoryId": 2
},
...
],
"categoryName": "电视", #二级分类的name
"categoryId": 1
},
...
],
"categoryName": "家用电器", # 一级分类的name
"categoryId": 2
}
]
二级:
三级:
ManageService接口
/**
* 获取全部分类信息
* @return
*/
List<JSONObject> getBaseCategoryList();
ManageServiceImpl 实现类
com.alibaba.fastjson
三级分类视图: 一级,二级分类有重复的,三级分类没有重复的
发现有重复数据,需要去重:
使用distinct一次只能去重一个字段
使用分组去重,但是分组后,就不好获取其他数据了
所以最后是在java中利用api处理重复数据了
stream中的API有一个可以实现分组
Map<Long, List<BaseCategoryView>> category1Map =baseCategoryViewList.stream().collect(Collectors.groupingBy(BaseCategoryView::getCategory1Id));
一级分类:
二级分类:
三级分类:没有重复的不需要分组
@Override
@GmallCache(prefix = "basecategoryList:")
public List<JSONObject> getBaseCategoryList() {
// 声明几个json 集合
ArrayList<JSONObject> list = new ArrayList<>();
// 声明获取所有分类数据集合
List<BaseCategoryView> baseCategoryViewList = baseCategoryViewMapper.selectList(null);
// 循环上面的集合并安一级分类Id 进行分组 value 是一级分类对应的所有数据
Map<Long, List<BaseCategoryView>> category1Map = baseCategoryViewList.stream().collect(Collectors.groupingBy(BaseCategoryView::getCategory1Id));
//定义一级分类的序号
int index = 1;
// 获取一级分类下所有数据
for (Map.Entry<Long, List<BaseCategoryView>> entry1 : category1Map.entrySet()) {
// 每一个entry 是一个键值对,key 一级分类的id value一级分类的所有数据
// 获取一级分类Id
Long category1Id = entry1.getKey();
// 获取一级分类下面的所有集合
List<BaseCategoryView> category2List1 = entry1.getValue();
//category2List1.get(0).getCategory1Name() 一级分类的名字,一级分类的名字都是一样的,随便获取一个
JSONObject category1 = new JSONObject();
category1.put("index", index);
category1.put("categoryId",category1Id);
// 一级分类名称
category1.put("categoryName",category2List1.get(0).getCategory1Name());
// 变量迭代
index++;
// 循环获取二级分类数据
Map<Long, List<BaseCategoryView>> category2Map = category2List1.stream().collect(Collectors.groupingBy(BaseCategoryView::getCategory2Id));
// 声明二级分类对象集合
List<JSONObject> category2Child = new ArrayList<>();
// 循环遍历
for (Map.Entry<Long, List<BaseCategoryView>> entry2 : category2Map.entrySet()) {
// 获取二级分类Id
Long category2Id = entry2.getKey();
// 获取二级分类下的所有集合
List<BaseCategoryView> category3List = entry2.getValue();
// 声明二级分类对象
JSONObject category2 = new JSONObject();
category2.put("categoryId",category2Id);
category2.put("categoryName",category3List.get(0).getCategory2Name());
List<JSONObject> category3Child = new ArrayList<>();
// 循环三级分类数据
category3List.stream().forEach(category3View -> {
JSONObject category3 = new JSONObject();
category3.put("categoryId",category3View.getCategory3Id());
category3.put("categoryName",category3View.getCategory3Name());
category3Child.add(category3);
});
// 将三级数据放入二级里面
category2.put("categoryChild",category3Child);
// 添加到二级分类集合
category2Child.add(category2);
}
// 将二级数据放入一级里面
category1.put("categoryChild",category2Child);
list.add(category1);
}
return list;
}
控制器ProductApiController
/**
* 首页数据获取三级分类信息
* @return
*/
@GetMapping("getBaseCategoryList")
public Result getBaseCategoryList(){
List<JSONObject> list = manageService.getBaseCategoryList();
return Result.ok(list);
}
成功的添加到了Reids缓存
封装远程调用:
service-product-client添加接口
ProductFeignClient
/**
* 获取全部分类信息
* @return
*/
@GetMapping("/api/product/getBaseCategoryList")
Result getBaseCategoryList();
降级函数
ProductDegradeFeignClient
@Override
public Result getBaseCategoryList() {
return Result.fail();
}
(4)页面渲染
创建indexController:
页面模版渲染
第一种缓存渲染方式:
package com.atguigu.gmall.all.controller;
@Controller
public class IndexController {
@Autowired
private ProductFeignClient productFeignClient;
@GetMapping({"/","index.html"})
public String index(HttpServletRequest request){
// 获取首页分类数据
Result result = productFeignClient.getBaseCategoryList();
request.setAttribute("list",result.getData());
return "index/index";
}
}
可以额外添加功能:我们这里没做
第二种:生成页面,nginx做静态代理方式:
@Autowired
private TemplateEngine templateEngine;
@GetMapping("createIndex")
@ResponseBody
public Result createIndex(){
// 获取后台存储的数据
Result result = productFeignClient.getBaseCategoryList();
// 设置模板显示的内容
Context context = new Context();
context.setVariable("list",result.getData());
// 定义文件输入位置
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter("D:\\index.html");
} catch (IOException e) {
e.printStackTrace();
}
// 调用process();方法创建模板
templateEngine.process("index/index",context,fileWriter);
return Result.ok();
}
将生成的静态页面与css 放入html 中即可!
页面生成了不能直接访问,他需要css,js..
复制项目里的css..
然后再双击index,就可以看了:
nginx先试用Windows版本的nginx
修改本地的nginx配置文件:添加:
把生成的静态页面放到nginx目录下:
启动nginx
直接访问nginx的端口号:
就可以通过nginx实现代理访问静态资源 ,使用nginx他抗并发的能力非常强