Loading

谷粒商城-商城业务(首页渲染和nginx)

部署架构

image-20221013105258327

动静分离,把静态资源放在nginx中,这样每次请求静态资源,网关就不需要在把请求转发到微服务中了,分担了微服务的压力。

商品业务

首页

引入依赖

使用Thymeleaf渲染

  1. 导入Thymeleaf的依赖

    <!--不写版本号,版本交给spring进行管理-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    
  2. 复制静态资源页面,static文件夹是存放静态资源的,template文件夹是存放页面模板的。

    image-20221013110356042

  3. 测试期间,先修改一下Thymeleaf的配置。

    spring:
        thymeleaf:
            cache: false
    
  4. 新建一个web包,用来开发web页面(页面跳转)。实际上这里的controller包是做分离的接口。可以用来做app的对接。

    image-20221013110945169

  5. 刷新maven,重启product服务。打开localhost:<端口>

    image-20221013112051789

渲染一级分类

  1. 创建一个首页控制器类。

    @Controller
    public class IndexController {
    
        final private CategoryService categoryService;
    
        public IndexController(CategoryService categoryService) {
            this.categoryService = categoryService;
        }
    
        @GetMapping({"/", "/index.html"})
        public String indexPage(Model model){
            // 获取一级目录
            List<CategoryEntity> level1Categories = categoryService.getLevel1Categories();
            // 绑定属性
            model.addAttribute("level1Categories", level1Categories);
            return "index";
        }
    }
    
  2. index.html中使用Thymeleaf语法,渲染出一级目录

    <div class="header_main_left">
        <ul>
            <li class="header_li2" th:each=" category : ${level1Categories}">
                <a href="#" class="header_main_left_a" th:attr="ctg-data=${category.catId}"><b th:text="${category.name}"></b></a>
            </li>
        </ul>
    </div>
    
  3. 渲染结果

    image-20221014103954236

在服务内使用Thymeleaf模板的话,可以启动devtools依赖,这样就可以快速部署了,每次修改页面后可以快速更新,就不需要总是重启服务了。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <!--不指定版本号,交给spring进行统一管理-->
    <optional>true</optional>
</dependency>

渲染二级和三级分类

在鼠标移动到某个一级分类时,会在右边展示出二级和三级分类。

image-20221014104330970

需要先找到二级和三级分类是在哪里处理的。

image-20221014104507641

static/index/js/catalogLoader.js中可以看到,目录结构是由一个接口返回得到的(现在是用一个json存放了假数据),所以需要分析一下它需要什么样结构的数据,然后我们编写一个接口,返回相同结构的数据。

{
  "11": [
    {
      "catalog1Id": "11",
      "catalog3List": [
        {
          "catalog2Id": "61",
          "id": "610",
          "name": "商务休闲鞋"
        },
        {
          "catalog2Id": "61",
          "id": "611",
          "name": "正装鞋"
        }
      ],
      "id": "61",
      "name": "流行男鞋"
    }
  ],
  "12": [...],
}

大致分析一下:首先,这个json中的结构应该是一个map: <一级分类id, 二级分类对象列表>,然后二级分类实体中有4个属性:catalog1Id, catalog3List, id, name,三级分类实体中有3个属性:catalog2Id, id, name

/**
 * 首页二级分类结构
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Level2CategoryVo {
    /**
     * 二级分类id
     */
    private String id;
    /**
     * 二级分类名称
     */
    private String name;
    /**
     * 所属的一级分类的id,也就是父id
     */
    private String catalog1Id;
    /**
     * 该二级分类下的三级分类列表
     */
    private List<Level3CategoryVo> catalog3List;
}
/**
 * 首页三级分类结构
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Level3CategoryVo {
    /**
     * 三级分类id
     */
    private String id;
    /**
     * 三级分类名称
     */
    private String name;
    /**
     * 所属的二级分类id,父id
     */
    private String catalog2Id;
}

我们编写一个接口,把所有的分类获取出来,也组装成这么一个结构,返回给首页,就可以了。

// Controller类
@ResponseBody
@GetMapping("/index/catalog.json")
public Map<String, List<Level2CategoryVo>> getCatalogJson(){
    return categoryService.getCatalogJson();
}
// static/index/js/catalogLoader.js
$.getJSON("/index/catalog.json",function (data) {}
// serviceImpl,使用之前的listWithTree()获取树状分类结构,慢慢解析
@Override
public Map<String, List<Level2CategoryVo>> getCatalogJson() {
    Map<String, List<Level2CategoryVo>> map = new HashMap<>();
    List<CategoryEntityVo> categoryEntityLevel1VoList = this.listWithTree();
    // 1.先获取所有一级分类的id,因为是要组合成:map<一级分类id, 二级分类对象列表>
    for (CategoryEntityVo categoryEntityLevel1 : categoryEntityLevel1VoList) {
        String category1Id = String.valueOf(categoryEntityLevel1.getCatId());
        List<CategoryEntityVo> categoryEntityLevel2VoList = categoryEntityLevel1.getChildren();
        List<Level2CategoryVo> catalog2List = new ArrayList<>();
        // 2.获取一级分类下的二级分类
        for (CategoryEntityVo categoryEntityLevel2 : categoryEntityLevel2VoList) {
            String category2Id = String.valueOf(categoryEntityLevel2.getCatId());
            String category2Name = categoryEntityLevel2.getName();
            List<CategoryEntityVo> categoryEntityLevel3VoList = categoryEntityLevel2.getChildren();
            List<Level3CategoryVo> catalog3List = new ArrayList<>();
            // 3.获取二级分类下的三级分类
            for (CategoryEntityVo categoryEntityLevel3 : categoryEntityLevel3VoList) {
                String category3Id = String.valueOf(categoryEntityLevel3.getCatId());
                String category3Name = categoryEntityLevel3.getName();
                Level3CategoryVo level3CategoryVo = new Level3CategoryVo(category3Id, category3Name, category2Id);
                catalog3List.add(level3CategoryVo);
            }
            Level2CategoryVo level2CategoryVo = new Level2CategoryVo(category2Id, category2Name, category1Id, catalog3List);
            catalog2List.add(level2CategoryVo);
        }
        String catId = String.valueOf(categoryEntityLevel1.getCatId());
        map.put(catId, catalog2List);
    }
    return map;
}

Nginx+Windows搭建域名访问环境

配置nginx

image-20221014110105880

  1. 修改hosts文件,将虚拟机ip和一个域名进行绑定(本地)

    image-20221014113442191

  2. 尝试访问

    image-20221014114138291

  3. 配置Nginx做一个反向代理

    image-20221014114223025

    1. 查看nginx的配置文件

      image-20221014115113015

    2. conf.d文件夹下添加gulimall.conf的配置文件(复制一份默认配置,再做修改)

      image-20221014115227528

    3. 修改gulimall.conf

      每一份的配置文件都是一个单独的server配置。

      修改前:

      image-20221014115445700

      修改后:

      注意,每条语句后面都需要分号。

      image-20221014131229675

      image-20221014114635395

      请求商城主页的整个过程是:访问gulimall.com --> 访问192.168.121.138:80 --> 即nginx服务器 --> nginx识别请求头中的Host --> 匹配到指定(根据server_name匹配)的server块中 --> 通过配置的规则将请求转发到指定的位置(product服务)。

    4. 保存完配置后,重启nginx。

      image-20221014131607160

加入网关

现在的nginx配置是越过了网关,直接将请求转发到服务里面。

现在需要加上网关,让网关做统一的请求转发、负载均衡。

  1. nginx.conf中配置上游服务器,用于负载均衡

    上游服务器名称随意。

    image-20221014132957415

  2. 修改gulimall.conf中的server块

    image-20221014133156517

  3. 修改网关的配置,接收nginx转发过来的请求。

    使用Host来判断。

    image-20221014134415229

    image-20221014135708941

  4. 测试页面

    image-20221014135741681

    还是不行,404!

    是由于:nginx代理给网关的时候,会丢失请求的host信息。所以需要在nginx里再设置。

    注意:是在gulimall.conf里配置,只给gulimall的请求加上请求头的host。

    image-20221014141507129

注意!

这时又有一个非常需要注意的点!!!

网关配置中的路由规则,nginx转发的规则一定不能放在最前面,而且一定要放在最后面。

因为它的路由规则覆盖面太大了。每次用gulimall.com请求,都会匹配成功。这种覆盖面广的规则一定要放在精确的规则的后面。

          # nginx服务器
        - id: gulimall-host-route
          uri: lb://gulimall-product
          predicates:
            - Host=gulimall.com
posted @ 2022-10-14 14:34  KledKled  阅读(311)  评论(0编辑  收藏  举报