关于用户前端,我们不采用前后端分离的方式进行完成;
而是使用thymeleaf由后端进行路由+渲染;
此部分的架构图如下图所示:

但是,每个微服务都独立管理着自己的前端项目,独立部署、运行、升级;
同时为了减轻服务端的压力,采用动静分离的方式实现:
所有的静态文件全部分离到nginx静态代理中;
后端程序只处理需要服务器处理的请求;
一、整合thymeleaf模板引擎(以product模块为例)
1、添加依赖 pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> <version>2.1.5.RELEASE</version> </dependency>
2、完成前端页面(当然我有现成的页面),放入resources文件夹下:
根据springboot的规则:
-
resources/static 目录下 静态资源(js/css/json/image等)
-
resources/templates 目录下 页面(html文件)

3、修改 application.yml 配置(开发期间,关闭thymeleaf缓存):
spring: thymeleaf: cache: false #开发期间关闭缓存功能,否则修改文件没有效果
4、创建新的包 com.jiguiquan.zidanmall.product.web里面全部用来管理里面的dispatcher:
5、然后重启项目:访问 http://localhost:10000

当然,现在看到的都还全是静态页面,静态文件;
包括首页,也不是通过后端dispatch路由过来的,而是springboot整合thymeleaf默认的在“respurces/templates”下查找到的index.html页面(默认首页);
可查看Springboot的自动配置类: WebMvcAutoConfiguration.java 中
二、整合dev-tools渲染一级分类数据
1、首先,我们需要写一个路由接口,此接口可以获取到所有的1级分类目录,并放到Model作用域中,供页面使用;
@Controller
public class IndexController {
@Autowired
CategoryService categoryService;
@GetMapping({"/","index.html"})
public String indexPage(Model model){
//查出所有的一级分类
List<CategoryEntity> categorys = categoryService.getLevel1Categorys();
//视图解析器进行拼串
//默认前缀 classpath:/templates/ 默认后缀 .html
model.addAttribute("categorys", categorys);
return "index";
}
}
2、首先代码中,我们就可以获取作用域中的“categorys”对象,进行使用
我们使用thymeleaf作为模板引擎进行渲染,thymeleaf的官方文档(中文版)下载链接:
我的网盘链接:https://pan.baidu.com/s/1cHkaQN-b-AUYD5R5o214sA
提取码:1234
3、Thymeleaf的使用,就不多讲了,主要就是:
-
添加名称空间《 xmlns:th="http://www.thymeleaf.org" 》;
-
使用thymeleaf自有的表达式语法进行赋值使用;
4、为了让页面修改完,实时更新(不重启服务),我们整合dev-tools工具
pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>
在每次修改完.html文件后,使用Ctrl + Shift + F9(只编译当前文件)或 Ctrl + F9(编译项目),然后页面就能看到效果了!
还有thymeleaf的缓存在开发期间一定要关闭,不然根本看不到效果!
5、使用 th:each 遍历渲染一级分类目录:
<ul>
<li th:each="category : ${categorys}">
<a href="#" class="header_main_left_a" th:attr="ctg-data=${category.catId}"><b th:text="${category.name}">家用电器111</b></a>
</li>
</ul>
渲染效果如下:

渲染成功!
三、首页——渲染二级三级分类数据
1、二级三级分类数据,是在页面打开的时候,发送的一个请求,获取到的数据;
$(function(){
$.getJSON("index/catalog.json",function (data) {
var ctgall=data;
$(".header_main_left_a").each(function(){
var ctgnums= $(this).attr("ctg-data");
if(ctgnums){
var panel=$("<div class='header_main_left_main'></div>");
var panelol=$("<ol class='header_ol'></ol>");
var ctgnumArray = ctgnums.split(",");
$.each(ctgnumArray,function (i,ctg1Id) {
var ctg2list= ctgall[ctg1Id];
$.each(ctg2list,function (i,ctg2) {
var cata2link=$("<a href='#' style= 'color: #111;' class='aaa'>"+ctg2.name+" ></a>");
console.log(cata2link.html());
var li=$("<li></li>");
var ctg3List=ctg2["catalog3List"];
var len=0;
$.each(ctg3List,function (i,ctg3) {
var cata3link = $("<a href=\"http://search.gmall.com/list.html?catalog3Id="+ctg3.id+"\" style=\"color: #999;\">" + ctg3.name + "</a>");
li.append(cata3link);
len=len+1+ctg3.name.length;
});
if(len>=46&&len<92){
li.attr("style","height: 60px;");
}else if(len>=92){
li.attr("style","height: 90px;");
}
panelol.append(cata2link).append(li);
});
});
panel.append(panelol);
$(this).after(panel);
$(this).parent().addClass("header_li2");
console.log($(".header_main_left").html());
}
});
});
});
2、我们对应需要在后端编写接口,首先需要一个vo类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Catalog2Vo {
private String catalog1Id; //1级父分类id
private List<Catalog3Vo> catalog3List; //3级子分类List
private String id;
private String name;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Catalog3Vo{
private String catalog2Id;
private String id;
private String name;
}
}
3、indexController.java中的接口
@GetMapping("index/catalog.json")
@ResponseBody
public Map<String, List<Catalog2Vo>> getCatalogJson(){
return categoryService.getCatalogJson();
}
4、CategoryServiceImpl.java中的实现:
@Override
public Map<String, List<Catalog2Vo>> getCatalogJson() {
Map<String, Catalog2Vo> map = new HashMap<>();
//查出所有一级分类
List<CategoryEntity> level1 = getLevel1Categorys();
//逐个封装Map中的数据
Map<String, List<Catalog2Vo>> result = level1.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
List<CategoryEntity> level2 = baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid", v.getCatId()));
if (!CollectionUtils.isEmpty(level2)) {
return level2.stream().map(item -> {
Catalog2Vo catalog2Vo = new Catalog2Vo(v.getCatId().toString(), null, item.getCatId().toString(), item.getName());
//查询三级分类
List<CategoryEntity> level3 = baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid", item.getCatId()));
if (!CollectionUtils.isEmpty(level3)){
List<Catalog2Vo.Catalog3Vo> catalog3Vos = level3.stream().map(e -> new Catalog2Vo.Catalog3Vo(item.getCatId().toString(), e.getCatId().toString(), e.getName())).collect(Collectors.toList());
catalog2Vo.setCatalog3List(catalog3Vos);
}
return catalog2Vo;
}).collect(Collectors.toList());
}
return null;
}));
return result;
}
5、最终页面效果:

到这里,我们首页的一级、二级、三级分类的展示就全部完成了!!!



