通用型产品发布解决方案(SpringBoot+SpringCloud+Spring CloudAlibaba+Vue+ElementUI) 04

通用型产品发布解决方案(基于分布式微服务技术栈:SpringBoot+SpringCloud+Spring CloudAlibaba+Vue+ElementUI+MyBatis-Plus+MySQL+Git+Maven+Linux+Docker+Nginx - 《04》

@[toc]

SpringBoot 使用引入 thymeleaf 标签模块的使用

引入 thymeleaf 模板(SpringBoot 推荐使用的模板,使用方便,利于 seo ,在 有 thymeleaf 标签的情况下,仍然可以正常显示,作为完整的技术体系,我们这里使用 thymeleaf 来进行一个页面的渲染。渲染页面)

使用 thymeleaf 标签模块,需要在 pom.xml 文件当中引入相关的 jar 依赖。如下:

xml 复制代码
       <!-- thymeleaf 模板引擎 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

同时我们需要在对应的 application.yaml文件当中配置对于 thymeleaf 模板的相关的配置信息。如下:**注意在 yaml 当中层级关系表示的作用"缩进表示层级关系"

yaml 复制代码
spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.56.100:3306/hspliving_commodity?useUnicode=true&characterEncoding=utf-8&useSSL=false
    driver-class-name: com.mysql.cj.jdbc.Driver
#    driver-class-name: com.mysql.jdbc.Driver
# 配置 阿里云 oss
  cloud:
  # 注意: thymeleaf 是在 spring.cloud 对齐,同一层级下的
  # 1. 关闭 thymeleaf 的缓存,这样当前前端页面变化时,就会看到效果
  # 2. 当在生产环境时,需要将 cache 设置为 true ,表示开启 thymeleaf 的缓存机制,提高效率
  thymeleaf:
    cache: false
yaml 复制代码
spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.56.100:3306/hspliving_commodity?useUnicode=true&characterEncoding=utf-8&useSSL=false
    driver-class-name: com.mysql.cj.jdbc.Driver
#    driver-class-name: com.mysql.jdbc.Driver
# 配置 阿里云 oss
  cloud:
    alicloud:
      oss:
        endpoint: oss-cn-hangzhou.aliyuncs.com # 杭州位置
      access-key: LTAI5tP4G6hDJqh7FPe1Cahh
      secret-key: vl5kaBORH1QADEzKq9NInpRdD8JJeF
#  将  RainbowSealiving-commodity 模块配置注册到 nacos 上
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 #  Nacos 服务的地址
  application:
    name: rainbowSealiving-commodity # 该微服务的 name 信息
  # 注意: thymeleaf 是在 spring.cloud 对齐,同一层级下的
  # 1. 关闭 thymeleaf 的缓存,这样当前前端页面变化时,就会看到效果
  # 2. 当在生产环境时,需要将 cache 设置为 true ,表示开启 thymeleaf 的缓存机制,提高效率
  thymeleaf:
    cache: false

# 配置 mybatis-pus
mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto # 配置主键信息
      logic-delete-value: 0 # 逻辑已经被删除值(默认为1,这里我们调整为我们自己的 0 )
      logic-not-delete-value: 1 # 逻辑未被删除值(默认值为0,这里我们调整成我们自己的)
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

我们需要在创建一个 controller 是作为该项目的 index的首页显示的作用,处理首页请求的处理。如下:

java 复制代码
package com.rainbowsea.rainbowsealiving.commodity.controller;


import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
 * @author
 * @version 1.0
 */
@Controller
public class IndexController {
    @GetMapping(value = {"/","index.html"})
    private String indexPage(Model model) {
     //默认找的是 "classpath\templates\"+"index"+".html"
        // 注意:这里它默认找的是我们自己配置上的路径显示:"classpath\templates\+index+.html"
        // classpath 就是我们当前模块的 resources 根路径下
        return "index";
    }
}
html 复制代码
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

测试输入:http://localhost:9090/

实现 2,3 级分类信息并显示在首页

简单分析实现思路-Model - Springboot 中的 Model 使用

首先我们在,我们的首页 indexController处理的,增加一个返回一级分类的代码,使用 Model 模块,处理回显。

java 复制代码
package com.rainbowsea.rainbowsealiving.commodity.controller;


import com.rainbowsea.rainbowsealiving.commodity.entity.CategoryEntity;
import com.rainbowsea.rainbowsealiving.commodity.service.CategoryService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
 * @author
 * @version 1.0
 */
@Controller
public class IndexController {

    @Resource
    private CategoryService categoryService;


    @GetMapping(value = {"/","index.html"})
    private String indexPage(Model model) {

        //1、查出所有的一级分类
        List<CategoryEntity> categoryEntities =
                categoryService.getLevel1Categorys();
        model.addAttribute("categories",categoryEntities);
     //默认找的是 "classpath\templates\"+"index"+".html"
        // 注意:这里它默认找的是我们自己配置上的路径显示:"classpath\templates\+index+.html"
        // classpath 就是我们当前模块的 resources 根路径下
        return "index";
    }
}
java 复制代码
package com.rainbowsea.rainbowsealiving.commodity.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.rainbowsea.common.utils.PageUtils;
import com.rainbowsea.rainbowsealiving.commodity.entity.CategoryEntity;

import java.util.List;
import java.util.Map;

/**
 * 商品分类表
 *
 * @author rainbowsea
 * @email [email protected]
 * @date 2025-03-04 16:38:22
 */
public interface CategoryService extends IService<CategoryEntity> {

    List<CategoryEntity> getLevel1Categorys();

    /**
     *  返回所有分类及其子分类(层级关系-即树形)
     */
    List<CategoryEntity> listTree();

    PageUtils queryPage(Map<String, Object> params);

    /**
     * 找到 cascadedCategoryId 的[第 1 级分类 id, 第 2 级分类 id, 第 3 级分类 id]
     */
    Long[] getCascadedCategoryId(Long categoryId);
}
java 复制代码
package com.rainbowsea.rainbowsealiving.commodity.service.impl;

import com.rainbowsea.common.utils.PageUtils;
import com.rainbowsea.common.utils.Query;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;


import com.rainbowsea.rainbowsealiving.commodity.dao.CategoryDao;
import com.rainbowsea.rainbowsealiving.commodity.entity.CategoryEntity;
import com.rainbowsea.rainbowsealiving.commodity.service.CategoryService;


@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {


    @Override
    public List<CategoryEntity> getLevel1Categorys() {
        List<CategoryEntity> categoryEntities = this.baseMapper.selectList(
                new QueryWrapper<CategoryEntity>().eq("parent_id", 0));
        return categoryEntities;
    }



}

返回 2 级和 3 级 JSON 数据的处理,进行回显处理

通过查看可以返回 1 级 /2 /3 级菜单的数据,当鼠标移动到某个 1 级分类,就会发出 ajax 请求,要相应的数据。

**难点:**前端开发人员要的 JSON 数据格式,这个完成有一定难度,分析: Map List>

VO 类的设计 这是重点,难点:这里是根据上面的 JSON 格式的显示,处理设计的一个 VO 的 Bean 类对象。这里我们使用的一个内部类的方式,存储下一层级的信息内容。

java 复制代码
package com.rainbowsea.rainbowsealiving.commodity.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
 * @author RainbowSea
 * @version 1.0
 * Catalog2Vo 返回给前端的二级分类数据
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Catalog2Vo {

    /**
     * 一级父类的id
     */
    private String catalog1Id;

    /**
     * 三级分类的信息-集合
     */
    private List<Category3Vo> catalog3List;
    /**
     * 二级分类本身的信息
     */
    private String id;
    private String name;


    /**
     * 三级分类的类型-静态内部类
     */

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Category3Vo {
        /**
         * 父级分类-二级分类的id
         */
        private String catalog2Id;
        /**
         * 三级分类本身的信息
         */
        private String id;
        private String name;

    }
}

这里我们使用:流 式 计 算 Stramp API - 将 集 合 根 据 业 务 需 求 转 成 map 知 识 点 <font style="color:rgb(8,8,8);">Map<String, List<Catalog2Vo>></font> 进行一个处理显示。

java 复制代码
package com.rainbowsea.rainbowsealiving.commodity.controller;


import com.rainbowsea.rainbowsealiving.commodity.entity.CategoryEntity;
import com.rainbowsea.rainbowsealiving.commodity.service.CategoryService;
import com.rainbowsea.rainbowsealiving.commodity.vo.Catalog2Vo;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
 * @author
 * @version 1.0
 */
@Controller
public class IndexController {



    @Resource
    private CategoryService categoryService;

    //返回 json 数据
    @GetMapping(value = "/index/catalog.json")
    @ResponseBody
    public Map<String, List<Catalog2Vo>> getCatalogJson() {
        Map<String, List<Catalog2Vo>> catalogJson =
                categoryService.getCatalogJson();
        return catalogJson;
    }


    @GetMapping(value = {"/","index.html"})
    private String indexPage(Model model) {

        //1、查出所有的一级分类
        List<CategoryEntity> categoryEntities =
                categoryService.getLevel1Categorys();
        model.addAttribute("categories",categoryEntities);
     //默认找的是 "classpath\templates\"+"index"+".html"
        // 注意:这里它默认找的是我们自己配置上的路径显示:"classpath\templates\+index+.html"
        // classpath 就是我们当前模块的 resources 根路径下
        return "index";
    }
}
java 复制代码
package com.rainbowsea.rainbowsealiving.commodity.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.rainbowsea.common.utils.PageUtils;
import com.rainbowsea.rainbowsealiving.commodity.entity.CategoryEntity;
import com.rainbowsea.rainbowsealiving.commodity.vo.Catalog2Vo;

import java.util.List;
import java.util.Map;

/**
 * 商品分类表
 *
 * @author rainbowsea
 * @email [email protected]
 * @date 2025-03-04 16:38:22
 */
public interface CategoryService extends IService<CategoryEntity> {

    Map<String, List<Catalog2Vo>> getCatalogJson();

    List<CategoryEntity> getLevel1Categorys();

    /**
     *  返回所有分类及其子分类(层级关系-即树形)
     */
    List<CategoryEntity> listTree();

    PageUtils queryPage(Map<String, Object> params);

    /**
     * 找到 cascadedCategoryId 的[第 1 级分类 id, 第 2 级分类 id, 第 3 级分类 id]
     */
    Long[] getCascadedCategoryId(Long categoryId);
}
java 复制代码
package com.rainbowsea.rainbowsealiving.commodity.service.impl;

import com.rainbowsea.common.utils.PageUtils;
import com.rainbowsea.common.utils.Query;
import com.rainbowsea.rainbowsealiving.commodity.vo.Catalog2Vo;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;


import com.rainbowsea.rainbowsealiving.commodity.dao.CategoryDao;
import com.rainbowsea.rainbowsealiving.commodity.entity.CategoryEntity;
import com.rainbowsea.rainbowsealiving.commodity.service.CategoryService;


@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {

    private List<CategoryEntity> getParent_cid(List<CategoryEntity> selectList, Long parentCid) {
        List<CategoryEntity> categoryEntities = selectList.stream().filter(item ->
                item.getParentId().equals(parentCid)).collect(Collectors.toList());
        return categoryEntities;

        // return this.baseMapper.selectList(
// new QueryWrapper<CategoryEntity>().eq("parent_cid", parentCid));
    }


    @Override
    public Map<String, List<Catalog2Vo>> getCatalogJson() {
//将数据库的多次查询变为一次
        List<CategoryEntity> selectList = this.baseMapper.selectList(null);
//1、查出所有分类
//1、1)查出所有一级分类
        List<CategoryEntity> level1Categorys = getParent_cid(selectList, 0L);
//封装数据
        Map<String, List<Catalog2Vo>> parentCid =
                level1Categorys.stream().collect(Collectors.toMap(k -> k.getId().toString(), v ->
                {
//1、每一个的一级分类,查到这个一级分类的二级分类
                    List<CategoryEntity> categoryEntities = getParent_cid(selectList, v.getId());
//2、封装上面的结果
                    List<Catalog2Vo> catalog2Vos = null;
                    if (categoryEntities != null) {
                        catalog2Vos = categoryEntities.stream().map(l2 -> {
                            Catalog2Vo catalog2Vo =
                                    new Catalog2Vo(v.getId().toString(), null, l2.getId().toString(),
                                            l2.getName().toString());
//1、找当前二级分类的三级分类封装成 vo
                            List<CategoryEntity> level3Catelog = getParent_cid(selectList,
                                    l2.getId());
                            if (level3Catelog != null) {
                                List<Catalog2Vo.Category3Vo> category3Vos =
                                        level3Catelog.stream().map(l3 -> {
//2、封装成指定格式
                                            Catalog2Vo.Category3Vo category3Vo =
                                                    new Catalog2Vo.Category3Vo(l2.getId().toString(),
                                                            l3.getId().toString(), l3.getName());
                                            return category3Vo;
                                        }).collect(Collectors.toList());
                                catalog2Vo.setCatalog3List(category3Vos);
                            }
                            return catalog2Vo;
                        }).collect(Collectors.toList());
                    }
                    return catalog2Vos;
                }));
        return parentCid;
    }


    @Override
    public List<CategoryEntity> getLevel1Categorys() {
        List<CategoryEntity> categoryEntities = this.baseMapper.selectList(
                new QueryWrapper<CategoryEntity>().eq("parent_id", 0));
        return categoryEntities;
    }


    /**
     * 核心方法: 返回所有分类及其子分类(带有层级关系-即树形)
     * 这里我们会使用 java8的,流式计算(stream api) + 递归操作(有一定难度)
     *
     * @return
     */
    @Override
    public List<CategoryEntity> listTree() {
        // 老韩思路分析-步骤:
        // 1. 查出所有的分类数据
        List<CategoryEntity> entities = baseMapper.selectList(null);

        // 2.组装成层级树形结构使用到 Java8 的 stream api + 递归操作
        // 思路:
        // 1.过滤,返回1级分类
        // 2.2 进行 map 映射操作,给每个分类设置对应的子分类(这个过程会使用到递归)
        // 2.3 进行排序 sorted 操作
        // 2.4 将处理好的数据收集/转换到集合

        // 3.返回 带有层级关系数据-即树形
        // 需求:从 List 中过滤出 person.id % 2 != 0 的 person对象
        // list.stream() : 把 List 转成流对象,目的是为了使用流的方法,
        // 这样就可以处理一些比较负载的业务

        List<CategoryEntity> categoryTree =
                entities.stream().filter(categoryEntity -> {
                    // 2.1 过滤filter,返回 1级分类
                    return categoryEntity.getParentId() == 0; // 0 就是一级分类
                }).map(category -> {
                    // 2.2 进行map映射操作,给每个分类设置对应的子分类(这个过程会使用到递归)
                    category.setChildrenCategories(getChildrenCategories(category, entities));
                    return category;
                }).sorted((category1, category2) -> {
                    // 2.3 进行排序sorted 操作,按照 sort 的升序排列
                    return (category1.getSort() == null ? 0 : category1.getSort()) -
                            (category2.getSort() == null ? 0 : category2.getSort());
                }).collect(Collectors.toList());  // // 2.4 将处理好的数据收集 collect/转换到集合中


        // 3. 返回带有层级关系的-即树形
        return categoryTree;
    }


}
javascript 复制代码
$.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://localhost:9090/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());
            }
        });
    });
javascript 复制代码
$(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://localhost:9090/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());
            }
        });
    });
});

运行测试:

注意:locak 生成的无参/有参数的构造器的方法,的逻辑顺序的,是属性字段的前后顺序决定的

分页导航处理

完成商品点 SPU 信息的检索(分页+ 条件)

  • 检索的条件这里设置的是为:分类,品牌,状态和关键字
  • 特殊的:说明输入的关键字,我们定义的是一个业务的需求,如果视为 ID 就是等于 ,如果视为名称就是模糊查询。

带有条件的分页查询:

java 复制代码
import java.util.Arrays;
import java.util.Map;

//import org.apache.shiro.authz.annotation.RequiresPermissions;
import com.rainbowsea.rainbowsealiving.commodity.service.SkuInfoService;
import com.rainbowsea.rainbowsealiving.commodity.vo.SpuSaveVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.rainbowsea.rainbowsealiving.commodity.entity.SpuInfoEntity;
import com.rainbowsea.rainbowsealiving.commodity.service.SpuInfoService;
import com.rainbowsea.common.utils.PageUtils;
import com.rainbowsea.common.utils.R;

import javax.annotation.Resource;


/**
 * 商品 spu 信息
 *
 * @author rainbowsea
 * @email [email protected]
 * @date 2025-03-24 20:31:43
 */
@RestController
@RequestMapping("commodity/spuinfo")
public class SpuInfoController {
    @Autowired
    private SpuInfoService spuInfoService;



    @Resource
    private SkuInfoService skuInfoService;

    //商品上架
    @PostMapping(value = "/{spuId}/up")
    public R spuUp(@PathVariable("spuId") Long spuId) {
        spuInfoService.up(spuId);
        return R.ok();
    }

    //商品下架
    @PostMapping(value = "/{spuId}/down")
    public R spuDown(@PathVariable("spuId") Long spuId) {
        spuInfoService.down(spuId);
        return R.ok();
    }


    /**
     * 列表
     */
    @RequestMapping("/list")
//@RequiresPermissions("commodity:spuinfo:list")
    public R list(@RequestParam Map<String, Object> params) {
//PageUtils page = spuInfoService.queryPage(params);//注销
//换成 带条件查询
//        PageUtils page = spuInfoService.queryPageByCondition(params);
        /**
         * 带条件分页查询
         */
        PageUtils page = skuInfoService.queryPageByCondition(params);
        return R.ok().put("page", page);
    }
}
java 复制代码
package com.rainbowsea.rainbowsealiving.commodity.service.impl;

import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Map;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rainbowsea.common.utils.PageUtils;
import com.rainbowsea.common.utils.Query;

import com.rainbowsea.rainbowsealiving.commodity.dao.SkuInfoDao;
import com.rainbowsea.rainbowsealiving.commodity.entity.SkuInfoEntity;
import com.rainbowsea.rainbowsealiving.commodity.service.SkuInfoService;


@Service("skuInfoService")
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoDao, SkuInfoEntity> implements SkuInfoService {


    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        QueryWrapper<SkuInfoEntity> queryWrapper = new QueryWrapper<>();
//带上查询条件
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)) {
            queryWrapper.and((wrapper) -> {
                wrapper.eq("sku_id", key).or().like("sku_name", key);
            });
        }

        //带上分类
        String catelogId = (String) params.get("catelogId");
        if (!StringUtils.isEmpty(catelogId) && !"0".equalsIgnoreCase(catelogId)) {
            queryWrapper.eq("catalog_id", catelogId);
        }


        //带上品牌
        String brandId = (String) params.get("brandId");
        if (!StringUtils.isEmpty(brandId) && !"0".equalsIgnoreCase(brandId)) {

            queryWrapper.eq("brand_id", brandId);
        }
//价格范围
        String min = (String) params.get("min");
        if (!StringUtils.isEmpty(min)) {
            queryWrapper.ge("price", min);
        }
        String max = (String) params.get("max");
//校验传递的价格范围合理性, 如果 max 有值,并且大于 0,
//才有必要封装到查询条件
        if (!StringUtils.isEmpty(max)) {
            try {
                BigDecimal bigDecimal = new BigDecimal(max);
                if (bigDecimal.compareTo(new BigDecimal("0")) == 1) {
                    queryWrapper.le("price", max);
                }
            } catch (Exception e) {
            }
        }
        IPage<SkuInfoEntity> page = this.page(
                new Query<SkuInfoEntity>().getPage(params), queryWrapper
        );
        return new PageUtils(page);
    }

    @Override
    public void saveSkuInfo(SkuInfoEntity skuInfoEntity) {
        this.baseMapper.insert(skuInfoEntity);
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SkuInfoEntity> page = this.page(
                new Query<SkuInfoEntity>().getPage(params),
                new QueryWrapper<SkuInfoEntity>()
        );

        return new PageUtils(page);
    }

}

实现搜索框的检索

引入家居上线搜索首页,并配置能正常显示

家居检索页面,可以根据查询条件分页返回数据,并在家居网前台页面显示

完成功能说明: 带条件分页查询, 可以对 关键字/分类 进行分页检索

业务需求:前端页面/html 模板,需要的数据形式为,后端返回检索结果的业务处理,都需要以此为基础

重点: JSON 格式 vue-springboot

如下分析如下 JSON 格式的内容,如下的 JSON 格式就是我们

json 复制代码
(commodity=[SkuInfoEntity(skuId=25, spuId=14, skuName= 海 信 21-21 100*100 黑 色 ,
skuDesc=null,
catalogId=301,brandId=1,skuDefaultImg=https://hspliving-10002.oss-cn-beijing.aliyuncs.com/
15-hsp.jpg, skuTitle= 海 信 21-21 100*100 黑 色 , skuSubtitle=, price=0.0000, saleCount=0),
SkuInfoEntity(skuId=26, spuId=14, skuName= 海 信 21-21 100*100 红 色 , skuDesc=null,
catalogId=301, brandId=1,
skuDefaultImg=https://hspliving-10002.oss-cn-beijing.aliyuncs.com/15-hsp.jpg, skuTitle=海信
21-21 100*100 红 色 , skuSubtitle=, price=0.0000, saleCount=0)], pageNum=1, total=2,
totalPages=1, pageNavs=[1])

创建一个 Bean 实体类对象,用于存储我上面这个前端所需要的 JSON 格式的对象格式表示。

如下我们创建一个:这个 Bean 实体类是根据具体前端所需要的具体内容所设置的。

java 复制代码
package com.rainbowsea.rainbowsealiving.commodity.vo;


import com.rainbowsea.rainbowsealiving.commodity.entity.SkuInfoEntity;
import lombok.Data;

import java.util.List;

@Data
public class SearchResult {
    /**
     * 查询到的所有家居商品信息
     */
    private List<SkuInfoEntity> commodity;
    /**
     * 当前页码
     */
    private Integer pageNum;
    /**
     * 总记录数
     */
    private Long total;
    /**
     * 总页码
     */
    private Integer totalPages;
    private List<Integer> pageNavs;
}

SearchController.java , 增加分页检索代码

java 复制代码
import com.rainbowsea.common.utils.PageUtils;
import com.rainbowsea.rainbowsealiving.commodity.entity.SkuInfoEntity;
import com.rainbowsea.rainbowsealiving.commodity.service.SkuInfoService;
import com.rainbowsea.rainbowsealiving.commodity.vo.SearchResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Controller
public class SearchController {


    @Resource
    private SkuInfoService skuInfoService;


    // 注意:这里我们使用了一个方法的重载,这个方法多了一个 Model参数
    @RequestMapping("/list.html")
    public String searchList
            (@RequestParam Map<String, Object> params,Model model, HttpServletRequest request) {
        /**
         * 带条件分页查询
         */
        PageUtils page = skuInfoService.querySearchPageByCondition(params);
//将 page 转成前端需要的数据格式[注意,不同前端页面要的结果可能不一样]
        SearchResult searchResult = new SearchResult();
        searchResult.setTotal((long) page.getTotalCount());
        int totalPage = page.getTotalPage();
        searchResult.setTotalPages(page.getTotalPage());
        searchResult.setPageNum(page.getCurrPage());
        searchResult.setCommodity((List<SkuInfoEntity>) page.getList());
        List<Integer> pageNavs = new ArrayList<>();
        for (int i = 1; i <= totalPage; i++) {
            pageNavs.add(i);
        }
        searchResult.setPageNavs(pageNavs);
        model.addAttribute("result", searchResult);
        System.out.println("result= " + searchResult);

        return "list";

    }
}
java 复制代码
package com.rainbowsea.rainbowsealiving.commodity.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.rainbowsea.common.utils.PageUtils;
import com.rainbowsea.rainbowsealiving.commodity.entity.SkuInfoEntity;

import java.util.Map;

/**
 * sku 信息
 *
 * @author rainbowsea
 * @email [email protected]
 * @date 2025-03-24 22:01:45
 */
public interface SkuInfoService extends IService<SkuInfoEntity> {

    //返回家居网前台,购买用户检索结果
    PageUtils querySearchPageByCondition(Map<String, Object> params);

    PageUtils queryPageByCondition(Map<String, Object> params);

    PageUtils queryPage(Map<String, Object> params);

    void saveSkuInfo(SkuInfoEntity skuInfoEntity);
}
java 复制代码
package com.rainbowsea.rainbowsealiving.commodity.service.impl;

import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Map;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rainbowsea.common.utils.PageUtils;
import com.rainbowsea.common.utils.Query;

import com.rainbowsea.rainbowsealiving.commodity.dao.SkuInfoDao;
import com.rainbowsea.rainbowsealiving.commodity.entity.SkuInfoEntity;
import com.rainbowsea.rainbowsealiving.commodity.service.SkuInfoService;


@Service("skuInfoService")
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoDao, SkuInfoEntity> implements SkuInfoService {

    @Override
    public PageUtils querySearchPageByCondition
            (Map<String, Object> params) {
        QueryWrapper<SkuInfoEntity> queryWrapper = new QueryWrapper<>();
//带上查询条件
        String key = (String) params.get("keyword");
        if(!StringUtils.isEmpty(key)){
            queryWrapper.and((wrapper)->{
                wrapper.eq("sku_id",key).or().like("sku_name",key);
            });
        }
//带上分类[第三级分类]
        String catelogId = (String) params.get("catalog3Id");
        if(!StringUtils.isEmpty(catelogId)&&!"0".equalsIgnoreCase(catelogId)){
            queryWrapper.eq("catalog_id",catelogId);
        }
//带上品牌
        String brandId = (String) params.get("brandId");
        if(!StringUtils.isEmpty(brandId)&&!"0".equalsIgnoreCase(brandId)){
            queryWrapper.eq("brand_id",brandId);
        }
        IPage<SkuInfoEntity> page = this.page(
                new Query<SkuInfoEntity>().getPage(params),
                queryWrapper
        );
        return new PageUtils(page);
    }


    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        QueryWrapper<SkuInfoEntity> queryWrapper = new QueryWrapper<>();
//带上查询条件
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)) {
            queryWrapper.and((wrapper) -> {
                wrapper.eq("sku_id", key).or().like("sku_name", key);
            });
        }

        //带上分类
        String catelogId = (String) params.get("catelogId");
        if (!StringUtils.isEmpty(catelogId) && !"0".equalsIgnoreCase(catelogId)) {
            queryWrapper.eq("catalog_id", catelogId);
        }


        //带上品牌
        String brandId = (String) params.get("brandId");
        if (!StringUtils.isEmpty(brandId) && !"0".equalsIgnoreCase(brandId)) {

            queryWrapper.eq("brand_id", brandId);
        }
//价格范围
        String min = (String) params.get("min");
        if (!StringUtils.isEmpty(min)) {
            queryWrapper.ge("price", min);
        }
        String max = (String) params.get("max");
//校验传递的价格范围合理性, 如果 max 有值,并且大于 0,
//才有必要封装到查询条件
        if (!StringUtils.isEmpty(max)) {
            try {
                BigDecimal bigDecimal = new BigDecimal(max);
                if (bigDecimal.compareTo(new BigDecimal("0")) == 1) {
                    queryWrapper.le("price", max);
                }
            } catch (Exception e) {
            }
        }
        IPage<SkuInfoEntity> page = this.page(
                new Query<SkuInfoEntity>().getPage(params), queryWrapper
        );
        return new PageUtils(page);
    }

    @Override
    public void saveSkuInfo(SkuInfoEntity skuInfoEntity) {
        this.baseMapper.insert(skuInfoEntity);
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SkuInfoEntity> page = this.page(
                new Query<SkuInfoEntity>().getPage(params),
                new QueryWrapper<SkuInfoEntity>()
        );

        return new PageUtils(page);
    }

}

取出返回的 result ,并通过 thymeleaf 渲染页面

html 复制代码
<!--排序内容-->
<div class="rig_tab">
  <div th:each="commodity : ${result.getCommodity()}">
    <div class="ico">
      <i class="iconfont icon-weiguanzhu"></i>
      <a href="#">关注</a>
    </div>
    <p class="da">
      <a href="#" title="购买 AppleCare+,获得原厂 2 年整机保修(含电池),和多达 2
        次意外损坏的保修服务。购买勾选:保障服务、原厂保 2 年。">
        <img th:src="${commodity.skuDefaultImg}" class="dim">
      </a>
    </p>
    <ul class="tab_im">
      <li><a href="#" title="黑色">
        <img th:src="${commodity.skuDefaultImg}"></a></li>
    </ul>
    <p class="tab_R">
      <span th:text="'¥' + ${commodity.price}">¥5199.00</span>
    </p>
    <p class="tab_JE">
      <a href="#" th:utext="${commodity.skuTitle}">
        北欧风格沙发 10000#号
      </a>
    </p>
    <p class="tab_PI">已有<span>11 万+</span>热门评价
      <a href="#">二手有售</a>
    </p>
    <p class="tab_CP"><a href="#" title="家居网 Apple 产品专营店">家居网 Apple 产
      品...</a>
      <a href='#' title="联系供应商进行咨询">
        <img src="search/img/xcxc.png">
      </a>
    </p>
    <div class="tab_FO">
      <div class="FO_one">
        <p>自营
          <span>家居网自营,品质保证</span>
        </p>
        <p>满赠
          <span>该商品参加满赠活动</span>
        </p>
      </div>
    </div>
  </div>
</div>
<!--分页-->
<div class="filter_page">
  <div class="page_wrap">
    <span class="page_span1">
      <a href="#" th:attr="pn=${result.pageNum - 1}" th:if="${result.pageNum>1}">< 上一页</a>
        <a class="page_a"
          th:attr="pn=${navs},style=${navs == result.pageNum?'border:0;color:#ee2222;background: #fff':''}"
          th:each="navs : ${result.pageNavs}">[[${navs}]]</a>
        <a href="#" th:attr="pn=${result.pageNum + 1}"
          th:if="${result.pageNum<result.totalPages}">下一页 ></a>
          </span><span class="page_span2">
          <em>共<b>[[${result.totalPages}]]</b>页&nbsp;&nbsp;到第</em>
          <input type="number" value="1">
          <em>页</em>
          <a href="#">确定</a></span>
          </div>
          </div>
  • limit 参数,表示每页显示几条记录
  • keyword 参数,表示按照 id 或者名字作为关键字检索
  • catalog3ld 参数,表示按照分类。

说明:图片,没有显示,是因为后台在发布产品的问题,只要后台发布家居产品能正常显示图片,前端页面就会正常显示。

支持在搜索框输入关键字, 进行检索

http://localhost:9090/list.html?keyword=%E6%B5%B7%E4%BF%A1&catalog3Id=301

list.html , 增加当用户输入条件,点击搜索按钮的处理代码.

html 复制代码
    <div class="header_form">
        <input id="keyword_input" type="text" placeholder="家居"/>
        <a href="javascript:searchByKeyword()">搜索</a>
    </div>

加入 Nginx - 完成反向代理,负载均衡,动静分离

首先使用 XShell 登录 VB 虚拟机,这里我们需配置 sshd

  1. sudo vi /etc/ssh/sshd_config
shell 复制代码
sudo vi /etc/ssh/sshd_config
  1. 将 PasswordAuthentication 的 no 改成 yes
  1. 重启服务 service sshd restart

提醒: 修改文件权限不够,请使用 sudo

ip a 查看 IP 地址

shell 复制代码
ip a

用户名 root : 密码是: vagrant

测试是否可以进入到 mysql

shell 复制代码
sudo docker restart mysql
sudo docker exec -it mysql /bin/bash

在 Linux 安装&配置 Nginx -能正确访问到 Nginx

首先需要确保,我们的虚拟机 Linux 可以访问到外网:

shell 复制代码
[root@localhost ~]# ping www.baidu.com

这里我们将 Nginx 安装在 mydata 目录下。

shell 复制代码
[root@localhost ~]# cd /mydata

在 mydata 目录下创建一个 nginx 目录用于存放安装的 Nginx

shell 复制代码
[root@localhost mydata]# mkdir nginx

安装,拉取 Nginx1.10 的镜像

shell 复制代码
[root@localhost mydata]# docker run -p 80:80 --name nginx -d nginx:1.10
  1. 将容器内的配置文件拷贝到当前目录
shell 复制代码
[root@localhost mydata]# cd nginx/
shell 复制代码
[root@localhost mydata]# docker container cp nginx:/etc/nginx .
Successfully copied 26.6kB to /mydata/.
  1. 终止原容器, 并删除原容器, 保留配置文件即可
shell 复制代码
[root@localhost nginx]# docker stop nginx
nginx
[root@localhost nginx]# docker rm nginx
nginx
[root@localhost nginx]# 
  1. 修改文件名, 并把 conf 移动到 /mydata/nginx 下
shell 复制代码
[root@localhost mydata]# mv nginx/ conf
shell 复制代码
[root@localhost mydata]# mv conf/ ./nginx/
  1. 创建新的 nginx

特别注意:必须必须必须,对于配置的 conf 配置文件的路径位置存在,才会创建 Nginc 成功,如果对于路径没有 conf 文件/目录,是会创建失败的。

shell 复制代码
[root@localhost conf]# docker run --name nginx -p 80:80 \
> -v/mydata/nginx/html:/usr/share/nginx/html \
> -v /mydata/nginx/logs:/var/log/nginx \
> -v/mydata/nginx/conf:/etc/nginx \
> --privileged=true -itd nginx:1.10
shell 复制代码
docker run --name nginx -p 80:80 \
-v/mydata/nginx/html:/usr/share/nginx/html \
-v /mydata/nginx/logs:/var/log/nginx \
-v/mydata/nginx/conf:/etc/nginx \
--privileged=true -itd nginx:1.10

如果 docker ps 发现 nginx 并没有启动的话,可以执行

shell 复制代码
[root@localhost nginx]# docker run -d nginx:1.10
  1. 在 nginx/html 目录下创建 index.html
html 复制代码
<h1>RainbowSealiving</h1>

在 windows 访问 nginx 的 index.html , 默认端口是 80 , 如果访问不到, 检查网络是否畅

通, 防火墙是否打开了该端口, 这些我们在讲解 Linux 时候, 是讲过的

访问成功

Nginx + Windows 搭建域名访问环境

也就是通过域名来访问网站, 比如 rainbowsealiving.com

  • 分析我们当前项目的架构情况

  • 通过 Nginx 可以实现 反向代理、负载均衡和动静分离

搭建域名环境

  • 注意需要让虚拟机 Linux 可以 ping 主机。
  • 同时也要让主机 可以 Ping Linux

配置域名位置: C:\Windows\System32\drivers\etc\hosts

配置 hspliving, 根据实际情况配置

shell 复制代码
192.168.56.100 www.RainbowSealiving.com

完成测试 , 浏览器输入 www.rainbowsealiving.com/

注意一个小细节 , 访问的 url 不要写成 https://www.rainbowsealiving.com/, 否则访问不到

配置 Nginx 完成反向代理

让 Nginx 完成反向代理, 所有来自 hspliving.com 的请求都转到 家居商品服务

HsplivingCommodityApplication :9090/ - 暂时不使用网关,后面再整合, 一步一步来

  1. 首先我们将 default.conf 的备份一份,复制命名为 rainbowsealiving.conf
shell 复制代码
cp default.conf rainbowsealiving.conf
shell 复制代码
[root@localhost conf.d]# cp default.conf rainbowsealiving.conf
shell 复制代码
[root@localhost conf.d]# vi rainbowsealiving.conf

更新了 Nginx 配置,重启 Nginx 读取配置

shell 复制代码
[root@localhost conf.d]# docker restart nginx

另外一定要保证 你的虚拟机 可以 访问到 windows 部署的 各个服务,即网络是畅通

的比如这里 虚拟机 ip 是 192.168.56.100 windows 是 192.168.56.1 就必须可以 ping 通测试的时候,可以暂时关闭 windows 的防火墙

配置负载均衡到网关

  1. 配置负载均衡到网关,即加入网关实现负载均衡
  2. 请求->nginx->网关->真正的服务

配置实现

  1. vi /mydata/nginx/conf/nginx.conf
shell 复制代码
[root@localhost conf.d]# vi /mydata/nginx/conf/nginx.conf
properties 复制代码
    upstream rainbowsealiving {
         server 192.168.153.1:5050;
    }
  1. vi /mydata/nginx/conf/conf.d/hspliving.conf
shell 复制代码
[root@localhost conf.d]# vi /mydata/nginx/conf/conf.d/rainbowsealiving.conf
shell 复制代码
location / {
        proxy_pass http://rainbowsealiving;
    }
  1. sudo docker restart nginx //重启 nginx
shell 复制代码
[root@localhost conf.d]# sudo docker restart nginx
yaml 复制代码
# for nginx 增加一组路由
        - id: hspliving_host_route
          uri: lb://rainbowSealiving-commodity
          predicates:
            - Host=**.rainbowsealiving.com
yaml 复制代码
server:
  port: 5050 #gateway监听端口
spring:
  cloud:
    #配置网关
    #http://localhost:5050/api/commodity/brand/list
    #http://www.hspliving.com/api/commodity/brand/list
    gateway:
      routes: #配置路由,可以有多个路由
#        - id: member_routh01 # 路由id, 由程序员指定,保证唯一
#          # 当前配置完成的需求说明:
#          # 如果到网关的请求时 http://localhost:5050/commodity/brand/list ,gateway 通过断言。
#          # 最终将请求路由转发到 http://localhost:9090/commodity/brand/list = >url=uri+path
#          uri: http://localhost:9090
#          predicates:
#            - Path=/commodity/brand/list #断言,路径相匹配的进行路由
        - id: raibnowsealiving_service_route # 路由id, 由程序员指定,保证唯一
            # 当前配置完成的需求说明:
            # 如果到网关的请求时 http://localhost:5050/api/service/???/??? ,gateway 通过断言。
            # 最终将请求路由转发到 http://rainbowSealiving-service [注册到 nacosd  renren-fast 服务ip+端口]/????? = >url=uri+path
            # 因为我们要去掉断言到 Path的/api ,所以这里我们需要使用上路径重写。
          uri: lb://rainbowsealiving-service
          predicates:
            - Path=/api/service/** #断言,路径相匹配的进行路由
          filters:
            # 也就是通过路径重写,最终的url 就是 http://localhost:7070
            - RewritePath=/api/service/(?<segment>.*), /$\{segment}
        - id: rainbowSealiving_commodity_route # 路由id, 由程序员指定,保证唯一
            # 当前配置完成的需求说明:
            # 如果到网关的请求时 http://localhost:5050/api/commodity/list/tree ,gateway 通过断言。
            # 最终将请求路由转发到 http://rainbowSealiving-commodity [注册到 nacosd  renren-fast 服务ip+端口]/????? = >url=uri+path
            # 因为我们要去掉断言到 Path的/api ,所以这里我们需要使用上路径重写。
            # 说明: /api/commodity/是一个更加精确的路径,必须将这组路由放在 /api/这里上
            # 否则会报错
          uri: lb://rainbowSealiving-commodity
          predicates:
            - Path=/api/commodity/** #断言,路径相匹配的进行路由
          filters:
            # 也就是通过路径重写,最终的url 就是 http://localhost:9090
            - RewritePath=/api/(?<segment>.*), /$\{segment}
        - id: rainbowsealiving_renren_fast_route # 路由id, 由程序员指定,保证唯一
            # 当前配置完成的需求说明:
            # 如果到网关的请求时 http://localhost:5050/api/???/??? ,gateway 通过断言。
            # 最终将请求路由转发到 http://renren-fast [注册到 nacosd  renren-fast 服务ip+端口]/????? = >url=uri+path
            # 因为我们要去掉断言到 Path的/api ,所以这里我们需要使用上路径重写。
          uri: lb://renren-fast
          predicates:
            - Path=/api/** #断言,路径相匹配的进行路由
          filters:
            # 也就是通过路径重写,最终的url 就是 http://localhost:8090
            - RewritePath=/api/(?<segment>.*), /renren-fast/$\{segment}
        # for nginx 增加一组路由
        - id: hspliving_host_route
          uri: lb://rainbowSealiving-commodityy
          predicates:
            - Host=**.rainbowsealiving.com
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 #配置nacos地址
  application:
    name: rainbowsealiving-gateway
  1. 重启网关, 再访问,会依然错误, 因为 nginx 在转发请求到网关会丢掉一些信息,比如host,因此需要重新配置

  2. 再次修改 vi /mydata/nginx/conf/conf.d/rainbowsealiving.conf

shell 复制代码
[root@localhost conf.d]#  vi /mydata/nginx/conf/conf.d/rainbowsealiving.conf
properties 复制代码
location / {
        proxy_set_header Host $host;
        proxy_pass http://rainbowsealiving;
    }
  1. sudo docker restart nginx //重启 nginx
shell 复制代码
[root@localhost conf.d]# sudo docker restart nginx
  1. 重启该模块项目,rainbowsealiving-gateway

host 的网关丢失,host 的优先级,注意事项

  1. 不要把 Host 路由配置到前面, 否则按照域名+api 方式的路由就不会成功了, 因为会优先匹配到 Host
  1. 将路由配置放在其它路由配置后面, 再测试就 OK 了

Nginx 的 <font style="color:rgb(0,0,0);">配置动静分离</font>

配置实现

  1. 在 Nginx 创建 static 目录
shell 复制代码
[root@localhost html]# mkdir static
  1. 把后端项目的静态资源 ,E:\Java\project\RainbowSealiving\RainbowSealiving-commodity\src\main\resources\static目录下所有静态资源文件 , 上传到Nginx下的static目录 , 然后删除 E:\Java\project\RainbowSealiving\RainbowSealiving-commodity\src\main\resources\static下所有文件

-这时 rebuild ,然后重启 RainbowSealiving-commodity 模块, 访问 首页面, 会出现如下情况, 如果 还看到图片,是因为缓存原因, 可以换一个浏览器,或者禁用缓存。

正确的是,我们访问的结果应该是如下的,RainbowSealiving-commodity 模块项目是无法访问到我们配置到 Nginx 当中的静态文件资源的,因为我们并没有在 Nginx 当中配置该 static 静态文件的路由路径,所以项目是无法找到该 Nginx 当中的 /mydata/nginx/html/static 路径的静态资源的。

  1. 对 index.html 和 list.html 模板文件访问静态资源路径进行替换修改

IDEA 快捷键:选择要替换的文本内容,Ctrl + R

shell 复制代码
\"index
\"/static/index
shell 复制代码
\"search
\"/static/search
shell 复制代码
\"\.\/search
\"/static/search
  1. 对 Nginx 进行配置,配置对 Nginx 下配置的 static 静态资源进行路由路径的配置

所 Nginx 配置路径,在如下位置:

properties 复制代码
 location /static/ {
        root /usr/share/nginx/html;
    }
    location / {
        proxy_set_header Host $host;
        proxy_pass http://rainbowsealiving;
    }
  1. 重启 Nginx
shell 复制代码
[root@localhost conf.d]# docker restart nginx
  1. 重启 RainbowSealiving-commodity 服务, 这时访问 页面, 就正常了, 也实现了动静分离

配置首页点击分类 到检索页面

  1. 修改 Nginx 当中的 catalogLoader.js

该文件所在路径是在 <font style="color:rgb(0,0,0);">/mydata/nginx/html/static/index/js</font>

properties 复制代码
                        $.each(ctg3List, function (i, ctg3) {
                            var cata3link = $("<a href=\"/list.html?catalog3Id=" + ctg3.id + "\" style=\"color: #999;\">" + ctg3.name + "</a>");
  1. 重启 Nginx 服务
shell 复制代码
[root@localhost js]# docker restart nginx
  1. 测试访问: www.rainbowsealiving.com/list.html?p...

最后:

"在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。"

相关推荐
zcyf080912 分钟前
kafka理论学习汇总
java·分布式·学习·kafka
再拼一次吧29 分钟前
Spring进阶篇
java·后端·spring
爱编程的小庄34 分钟前
Maven 4.0.0 模式-pom.xml配置详解
xml·java·maven
黄雪超36 分钟前
JVM——引入
java·jvm
wkj00137 分钟前
java 和 C#操作数据库对比
java·数据库·c#
WuWuII1 小时前
gateway
java·gateway
浩宇软件开发1 小时前
Android开发,实现一个简约又好看的登录页
android·java·android studio·android开发
南客先生1 小时前
多级缓存架构设计与实践经验
java·面试·多级缓存·缓存架构
anqi271 小时前
如何在 IntelliJ IDEA 中编写 Speak 程序
java·大数据·开发语言·spark·intellij-idea
m0_740154671 小时前
maven相关概念深入介绍
java·maven