关于用户前端,我们不采用前后端分离的方式进行完成;
而是使用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、最终页面效果:
到这里,我们首页的一级、二级、三级分类的展示就全部完成了!!!