Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)十六(商品排序,Thymeleaf快速入门,商品详情页的展示)

Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)十六(商品详情页的展示)

一、商品排序

1、完善页面信息

在这里插入图片描述
这是用来做排序的,默认按照综合排序。

点击新品,应该按照商品创建时间排序,点击价格应该按照价格排序。

因为我们没有统计销量和评价,这里咱们以新品价格为例,进行讲解,做法是相通的。

排序需要知道两个内容:

  • 排序的字段

  • 排序的方式

    因此,我们首先在search中记录这两个信息,因为created钩子函数会对search进行覆盖,因此我们在钩子函数中对这两个信息进行初始化即可:

在这里插入图片描述

            //对排序进行初始化,默认为“”,代表不排序
            search.sortBy = search.sortBy || "";
            //对排序方式进行初始化,转为布尔值
            search.descending = search.descending === "true" || false;

然后,在页面上给按钮绑定点击事件,修改sortBydescending的值:
在这里插入图片描述

					<li :class="{active:!search.sortBy}" @click="search.sortBy=''">
                            <a href="#">综合</a>
                        </li>
                        <li>
                            <a href="#">销量</a>
                        </li>
                        <li @click="search.sortBy='createTime'" :class="{active: search.sortBy==='createTime'}">
                            <a href="#">新品</a>
                        </li>
                        <li>
                            <a href="#">评价</a>
                        </li>
                        <li @click="search.sortBy='price'; search.descending = !search.descending"
                            :class="{active: search.sortBy==='price'}">
                            <a href="#">
                                价格
                                <v-icon v-show="search.descending">arrow_drop_down</v-icon>
                                <v-icon v-show="!search.descending">arrow_drop_up</v-icon>
                            </a>
                        </li>

2、实现后台逻辑

接下来,后台需要接收请求参数中的排序信息,然后在搜索中加入排序的逻辑。

(1)我们的请求参数对象SearchRequest中,需要进行扩展:

在这里插入图片描述

package com.leyou.search.pojo;

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

public class SearchRequest {

    private String key;//搜索字段
    private Integer page;//当前页
    private static final Integer DEFAULT_SIZE = 20;//每页个数
    private static final Integer DEFAULT_PAGE = 1;//默认页

    private String sortBy;//排序字段
    private Boolean descending;//是否降序

    //过滤条件
    private Map<String,String> filter;

    public String getSortBy() {
        return sortBy;
    }

    public void setSortBy(String sortBy) {
        this.sortBy = sortBy;
    }

    public Boolean getDescending() {
        return descending;
    }

    public void setDescending(Boolean descending) {
        this.descending = descending;
    }

    public Map<String, String> getFilter() {
        return filter;
    }

    public void setFilter(Map<String, String> filter) {
        this.filter = filter;
    }

    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    public Integer getPage() {
        if(page == null){
            return DEFAULT_PAGE;
        }
        //获取页码的时候进行校验,不能小于1
        return Math.max(DEFAULT_PAGE,page);// Math.max返回DEFAULT_PAGE,page之间的最大值
    }
    public void setPage(Integer page) {
        this.page = page;
    }
    public static Integer getSize() {
        return DEFAULT_SIZE;
    }

    @Override
    public String toString() {
        return "SearchRequest{" +
                "key='" + key + '\'' +
                ", page=" + page +
                ", filter=" + filter +
                '}';
    }
}
(3)然后在搜索业务逻辑中,添加排序条件:

在这里插入图片描述

        //设置排序
        String sortBy = request.getSortBy();
        Boolean desc = request.getDescending();
        if(StringUtils.isNotBlank(sortBy)){
            //如果不为空,则进行排序
            queryBuilder.withSort(SortBuilders.fieldSort(sortBy).order(desc ? SortOrder.DESC : SortOrder.ASC));
        }
(4)运行测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、商品页面详情展示

当用户搜索到商品,肯定会点击查看,就会进入商品详情页,接下来我们完成商品详情页的展示

1、 Thymeleaf

官网文档地址
https://www.thymeleaf.org/documentation.html

在商品详情页中,我们会使用到Thymeleaf来渲染页面(替代传统的JSP)

Thymeleaf是适用于 Web 和独立环境的现代服务器端 Java 模板引擎。

Thymeleaf 的主要目标是为您的开发工作流程带来优雅的自然模板——HTML可以在浏览器中正确显示,也可以作为静态原型工作,从而加强开发团队的协作。

在线文档地址

https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#what-kind-of-templates-can-thymeleaf-process

在这里插入图片描述

在这里插入图片描述

Spring官方支持的服务的渲染模板中,并不包含jsp。

而是Thymeleaf和Freemarker等,而Thymeleaf与SpringMVc的视图技术,

及SpringBoot的自动化配置集成非常完美,几乎没有任何成本,

你只用关注Thymeleaf的语法即可。

2、商品详情页服务(工程搭建)

商品详情浏览量比较大,并发高,我们会独立开启一个微服务,用来展示商品详情。

(1)创建工程模块

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

(2)引入依赖

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>leyou</artifactId>
        <groupId>com.leyou.parent</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.service</groupId>
    <artifactId>ly-page</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
         <dependency>
            <groupId>com.leyou.service</groupId>
            <artifactId>ly-item-interface</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>

    </dependencies>


</project>
(3)项目开始前先编写测试类学习一下
1)编写HelloController

在这里插入图片描述

2)在resources下创建固定文件夹名称的文件夹(templates)

在这里插入图片描述

3)在templates当中创建后缀为html的文件(hello.html会作为视图返回)

在这里插入图片描述
原理:访问当前的HelloController会自动找hello.html显示
在这里插入图片描述

4)在HelloController添加模型数据

在这里插入图片描述

package com.leyou.page.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HelloController {

    @GetMapping("hello")
    public String toHello(Model model){
        //将消息添加到模型当中
        model.addAttribute("msg","hello, thymeleaf!");
        return "hello";//普通字符串会被当成视图名称,综合前缀和后缀寻找视图
    }

}

5)在hello.html当中获取对应的数据

和jsp类似只不过${}是在属性值里面写的,这样做的好处就是在没有后台java的情况下前端页面更加规范,并且不会报错
在这里插入图片描述

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>hello</title>
</head>
<body>
    <h1>
        msg:<span th:text="${msg}"></span>
    </h1>
</body>
</html>
6)编写启动类测试运行

在这里插入图片描述
修改包路径
在这里插入图片描述
在这里插入图片描述

package com.leyou;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class LyPageApplication {

    public static void main(String[] args) {

        SpringApplication.run(LyPageApplication.class);

    }

}

刷新一下Maven项目
在这里插入图片描述
启动微服务
在这里插入图片描述
访问8080端口
在这里插入图片描述
访问成功
在这里插入图片描述

7)Thymeleaf变量
  • a、创建User实体类
    在这里插入图片描述
    在这里插入图片描述
package com.leyou.page.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    String name;
    int age;
    User friend;

}

  • b、完善HelloController

在这里插入图片描述

package com.leyou.page.web;

import com.leyou.page.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HelloController {

    @GetMapping("hello")
    public String toHello(Model model){

        User user = new User();

        user.setAge(21);
        user.setName("Jack Chen");
        user.setFriend(new User("李小龙",30,null));

        //将消息添加到模型当中
        model.addAttribute("user",user);
        return "hello";//普通字符串会被当成视图名称,综合前缀和后缀寻找视图
    }

}

  • c、在hello.html
    在这里插入图片描述
    在这里插入图片描述
   <h1>
        msg:<span th:text="${user.toString()}"></span>
    </h1>

重新运行

在这里插入图片描述
刷新页面
页面效果
在这里插入图片描述

8)其他用法

在这里插入图片描述

    <span th:text="'<font color=\'red\'>hello</font>'"></span><br>
    <span th:text="'<font color=\'red\'>hello</font>'"></span>

刷新页面,发现只展示了文本
在这里插入图片描述
展示真正的标签

在这里插入图片描述

 <span th:utext="'<font color=\'red\'>hello</font>'"></span><br>
 <span th:utext="'<font color=\'red\'>hello</font>'"></span>

刷新页面
在这里插入图片描述

9)内置对象
  • dates
    在这里插入图片描述
    完善hello.html
    在这里插入图片描述
    刷新页面
    在这里插入图片描述
    格式化日期
    在这里插入图片描述
 <span th:text="${#dates.format(#dates.createNow(),'yyyy-MM-dd')}"></span>

刷新页面
在这里插入图片描述

10)Thymeleaf自己的一些功能
  • 运算(加减乘除 判断 布尔运算 三元运算符)
    在这里插入图片描述
 <h1>
        <span th:text="100 * 200"></span>
    </h1>

刷新页面

在这里插入图片描述

  • 循环
    修改HelloController
    在这里插入图片描述
package com.leyou.page.web;

import com.leyou.page.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.ArrayList;

@Controller
public class HelloController {

    @GetMapping("hello")
    public String toHello(Model model){

        User user1 =  new User("李1龙",30,null);
        User user2 =  new User("李2龙",22,null);
        User user3 =  new User("李3龙",20,null);
        User user4 =  new User("李4龙",31,null);
        User user5 =  new User("李5龙",35,null);

        ArrayList<User> users = new ArrayList<>();
        users.add(user1);
        users.add(user2);
        users.add(user3);
        users.add(user4);
        users.add(user5);

        //将消息添加到模型当中
        model.addAttribute("users",users);
        model.addAttribute("user",user1);
        return "hello";//普通字符串会被当成视图名称,综合前缀和后缀寻找视图
    }

}

完善hello.html
在这里插入图片描述


    <h1 th:each="user :  ${ users }">
        <span th:text="${ user.toString() }"></span>
    </h1>

刷新页面
在这里插入图片描述

11) JS模板(内联模板)

在这里插入图片描述

<script th:inline="javascript">
    const users = /*[[${users}]]*/[];
    const user = users[0];
    console.log(user);
    for (let u of users) {
        console.log(u);
    }

</script>

浏览器控制台
在这里插入图片描述

3、创建item.html

在这里插入图片描述

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
	<meta charset="utf-8"/>
	<meta http-equiv="X-UA-Compatible" content="IE=9; IE=8; IE=7; IE=EDGE">
	<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7"/>
	<title>乐优商城--商品详情页</title>
	<link rel="icon" href="/img/assets/img/LOGO.ico">
	<link rel="stylesheet" type="text/css" href="/css/webbase.css"/>
	<link rel="stylesheet" type="text/css" href="/css/pages-item.css"/>
	<link rel="stylesheet" type="text/css" href="/css/pages-zoom.css"/>
	<link rel="stylesheet" type="text/css" href="/css/widget-cartPanelView.css"/>

	<style type="text/css">
		.goods-intro-list li {
			display: inline-block;
			width: 300px;
		}

		.Ptable {
			margin: 10px 0;
		}

		.Ptable-item {
			padding: 12px 0;
			line-height: 220%;
			color: #999;
			font-size: 12px;
			border-bottom: 1px solid #eee;
		}

		.Ptable-item h3 {
			width: 110px;
			text-align: right;
		}

		.Ptable-item h3, .package-list h3 {
			font-weight: 400;
			font-size: 12px;
			float: left;
		}

		h3 {
			display: block;
			font-size: 1.17em;
			-webkit-margin-before: 1em;
			-webkit-margin-after: 1em;
			-webkit-margin-start: 0px;
			-webkit-margin-end: 0px;
			font-weight: bold;
		}

		.Ptable-item dl {
			margin-left: 110px;
		}

		dl {
			display: block;
			-webkit-margin-before: 1em;
			-webkit-margin-after: 1em;
			-webkit-margin-start: 0px;
			-webkit-margin-end: 0px;
		}

		.Ptable-item dt {
			width: 160px;
			float: left;
			text-align: right;
			padding-right: 5px;
		}

		.Ptable-item dd {
			margin-left: 210px;
		}

		dd {
			display: block;
			-webkit-margin-start: 40px;
		}

		.package-list {
			padding: 12px 0;
			line-height: 220%;
			color: #999;
			font-size: 12px;
			margin-top: -1px;
		}

		.package-list h3 {
			width: 130px;
			text-align: right;
		}

		.package-list p {
			margin-left: 155px;
			padding-right: 50px;
		}
	</style>

</head>

<body>

<!-- 头部栏位 -->
<!--页面顶部,由js动态加载-->
<div id="itemApp">
	<div id="nav-bottom">
		<ly-top/>
	</div>
	<div class="py-container">
		<div id="item">
			<div class="crumb-wrap">
				<ul class="sui-breadcrumb">
					<li th:each="c : ${categories}">
						<a href="#" th:text="${c.name}">手机</a>
					</li>
					<li>
						<a href="#" th:text="${brand.name}">Apple</a>
					</li>
					<li class="active" th:text="${title}">Apple iPhone 6s</li>
				</ul>
			</div>
			<!--product-info-->
			<div class="product-info">
				<div class="fl preview-wrap">
					<!--放大镜效果-->
					<div class="zoom">
						<!--默认第一个预览-->
						<div id="preview" class="spec-preview">
							<span class="jqzoom">
								<img :jqimg="images[0]" :src="images[0]" width="400px" height="400px"/>
							</span>
						</div>
						<!--下方的缩略图-->
						<div class="spec-scroll">
							<a class="prev">&lt;</a>
							<!--左右按钮-->
							<div class="items">
								<ul>
									<li v-for="img in images">
										<img :src="img" :bimg="img" onmousemove="preview(this)"/>
									</li>
								</ul>
							</div>
							<a class="next">&gt;</a>
						</div>
					</div>
				</div>
				<div class="fr itemInfo-wrap">
					<div class="sku-name">
						<h4 v-text="sku.title"></h4>
					</div>
					<div class="news"><span th:utext="${subTitle}">Apple iPhone 6s 4GB 128GB 土豪金</span></div>
					<div class="summary">
						<div class="summary-wrap">
							<div class="fl title"><i>价  格</i></div>
							<div class="fl price">
								<i>¥</i><em v-text="ly.formatPrice(sku.price)"></em><span>降价通知</span>
							</div>
							<div class="fr remark"><i>累计评价</i><em>612188</em></div>
						</div>
						<div class="summary-wrap">
							<div class="fl title">
								<i>促  销</i>
							</div>
							<div class="fl fix-width">
								<i class="red-bg">加价购</i>
								<em class="t-gray">满999.00另加20.00元,或满1999.00另加30.00元,或满2999.00另加40.00元,即可在购物车换
									购热销商品</em>
							</div>
						</div>
					</div>
					<div class="support">
						<div class="summary-wrap">
							<div class="fl title">
								<i>支  持</i>
							</div>
							<div class="fl fix-width">
								<em class="t-gray">以旧换新,闲置手机回收 4G套餐超值抢 礼品购</em>
							</div>
						</div>
						<div class="summary-wrap">
							<div class="fl title">
								<i>配 送 至</i>
							</div>
							<div class="fl fix-width">
								<em class="t-gray">上海 <span v-text="sku.stock > 0 ? '有货' : '缺货'"></span></em>
							</div>
						</div>
					</div>
					<div class="clearfix choose">
						<div id="specification" class="summary-wrap clearfix">
							<dl v-for="(options,id) in specialSpec" :key="id">
								<dt>
									<div class="fl title">
										<i v-text="params[id]"></i>
									</div>
								</dt>
								<dd v-for="(o,i) in options" :key="i" @click="selectSku(id,i)">
									<a href="javascript:;" :class="{selected:i === indexes[id], locked:locked(id, i)}">
										{{o}}<span title="点击取消选择">&nbsp;</span>
									</a>
								</dd>
							</dl>
						</div>

						<div class="summary-wrap">
							<div class="fl title">
								<div class="control-group">
									<div class="controls">
										<input autocomplete="off" type="text" disabled v-model="num" minnum="1"
											   class="itxt"/>
										<a href="javascript:void(0)" class="increment plus" @click="increment">+</a>
										<a href="javascript:void(0)" class="increment mins" @click="decrement">-</a>
									</div>
								</div>
							</div>
							<div class="fl">
								<ul class="btn-choose unstyled">
									<li>
										<a href="#" @click.prevent="addCart" target="_blank"
										   class="sui-btn  btn-danger addshopcar">加入购物车</a>
									</li>
								</ul>
							</div>
						</div>
					</div>
				</div>
			</div>
			<!--product-detail-->
			<div class="clearfix product-detail">
				<div class="fl aside">
					<ul class="sui-nav nav-tabs tab-wraped">
						<li class="active">
							<a href="#index" data-toggle="tab">
								<span>相关分类</span>
							</a>
						</li>
						<li>
							<a href="#profile" data-toggle="tab">
								<span>推荐品牌</span>
							</a>
						</li>
					</ul>
					<div class="tab-content tab-wraped">
						<div id="index" class="tab-pane active">
							<ul class="part-list unstyled">
								<li>手机</li>
								<li>手机壳</li>
								<li>内存卡</li>
								<li>Iphone配件</li>
								<li>贴膜</li>
								<li>手机耳机</li>
								<li>移动电源</li>
								<li>平板电脑</li>
							</ul>
							<ul class="goods-list unstyled">
								<li>
									<div class="list-wrap">
										<div class="p-img">
											<img src="/img/_/part01.png"/>
										</div>
										<div class="attr">
											<em>Apple苹果iPhone 6s (A1699)</em>
										</div>
										<div class="price">
											<strong>
												<em>¥</em>
												<i>6088.00</i>
											</strong>
										</div>
										<div class="operate">
											<a href="javascript:void(0);" class="sui-btn btn-bordered">加入购物车</a>
										</div>
									</div>
								</li>
								<li>
									<div class="list-wrap">
										<div class="p-img">
											<img src="/img/_/part02.png"/>
										</div>
										<div class="attr">
											<em>Apple苹果iPhone 6s (A1699)</em>
										</div>
										<div class="price">
											<strong>
												<em>¥</em>
												<i>6088.00</i>
											</strong>
										</div>
										<div class="operate">
											<a href="javascript:void(0);" class="sui-btn btn-bordered">加入购物车</a>
										</div>
									</div>
								</li>
								<li>
									<div class="list-wrap">
										<div class="p-img">
											<img src="/img/_/part03.png"/>
										</div>
										<div class="attr">
											<em>Apple苹果iPhone 6s (A1699)</em>
										</div>
										<div class="price">
											<strong>
												<em>¥</em>
												<i>6088.00</i>
											</strong>
										</div>
										<div class="operate">
											<a href="javascript:void(0);" class="sui-btn btn-bordered">加入购物车</a>
										</div>
									</div>
									<div class="list-wrap">
										<div class="p-img">
											<img src="/img/_/part02.png"/>
										</div>
										<div class="attr">
											<em>Apple苹果iPhone 6s (A1699)</em>
										</div>
										<div class="price">
											<strong>
												<em>¥</em>
												<i>6088.00</i>
											</strong>
										</div>
										<div class="operate">
											<a href="javascript:void(0);" class="sui-btn btn-bordered">加入购物车</a>
										</div>
									</div>
									<div class="list-wrap">
										<div class="p-img">
											<img src="/img/_/part03.png"/>
										</div>
										<div class="attr">
											<em>Apple苹果iPhone 6s (A1699)</em>
										</div>
										<div class="price">
											<strong>
												<em>¥</em>
												<i>6088.00</i>
											</strong>
										</div>
										<div class="operate">
											<a href="javascript:void(0);" class="sui-btn btn-bordered">加入购物车</a>
										</div>
									</div>
								</li>
							</ul>
						</div>
						<div id="profile" class="tab-pane">
							<p>推荐品牌</p>
						</div>
					</div>
				</div>
				<div class="fr detail">
					<div class="clearfix fitting">
						<h4 class="kt">选择搭配</h4>
						<div class="good-suits">
							<div class="fl master">
								<div class="list-wrap">
									<div class="p-img">
										<img src="/img/_/l-m01.png"/>
									</div>
									<em>¥5299</em>
									<i>+</i>
								</div>
							</div>
							<div class="fl suits">
								<ul class="suit-list">
									<li class="">
										<div id="e">
											<img src="/img/_/dp01.png"/>
										</div>
										<i>Feless费勒斯VR</i>
										<label data-toggle="checkbox" class="checkbox-pretty">
											<input type="checkbox"><span>39</span>
										</label>
									</li>
									<li class="">
										<div id=""><img src="/img/_/dp02.png"/></div>
										<i>Feless费勒斯VR</i>
										<label data-toggle="checkbox" class="checkbox-pretty">
											<input type="checkbox"><span>50</span>
										</label>
									</li>
									<li class="">
										<div id=""><img src="/img/_/dp03.png"/></div>
										<i>Feless费勒斯VR</i>
										<label data-toggle="checkbox" class="checkbox-pretty">
											<input type="checkbox"><span>59</span>
										</label>
									</li>
									<li class="">
										<div id=""><img src="/img/_/dp04.png"/></div>
										<i>Feless费勒斯VR</i>
										<label data-toggle="checkbox" class="checkbox-pretty">
											<input type="checkbox"><span>99</span>
										</label>
									</li>
								</ul>
							</div>
							<div class="fr result">
								<div class="num">已选购0件商品</div>
								<div class="price-tit"><strong>套餐价</strong></div>
								<div class="price">¥5299</div>
								<button class="sui-btn  btn-danger addshopcar">加入购物车</button>
							</div>
						</div>
					</div>
					<div class="tab-main intro">
						<ul class="sui-nav nav-tabs tab-wraped">
							<li class="active">
								<a href="#one" data-toggle="tab">
									<span>商品介绍</span>
								</a>
							</li>
							<li>
								<a href="#two" data-toggle="tab">
									<span>规格与包装</span>
								</a>
							</li>
							<li>
								<a href="#three" data-toggle="tab">
									<span>售后保障</span>
								</a>
							</li>
							<li>
								<a href="#four" data-toggle="tab">
									<span>商品评价</span>
								</a>
							</li>
							<li>
								<a href="#five" data-toggle="tab">
									<span>手机社区</span>
								</a>
							</li>
						</ul>
						<div class="clearfix"></div>
						<div class="tab-content tab-wraped">
							<div id="one" class="tab-pane active">
								<ul class="goods-intro-list unstyled" style="list-style: none;">
									<li>分辨率:1920*1080(FHD)</li>
									<li>后置摄像头:1200万像素</li>
									<li>前置摄像头:500万像素</li>
									<li>核 数:其他</li>
									<li>频 率:以官网信息为准</li>
									<li>品牌: Apple</li>
									<li>商品名称:APPLEiPhone 6s Plus</li>
									<li>商品编号:1861098</li>
									<li>商品毛重:0.51kg</li>
									<li>商品产地:中国大陆</li>
									<li>热点:指纹识别,Apple Pay,金属机身,拍照神器</li>
									<li>系统:苹果(IOS)</li>
									<li>像素:1000-1600万</li>
									<li>机身内存:64GB</li>
								</ul>
								<!--商品详情-->
								<div class="intro-detail">
									<div th:utext="${detail.description}"></div>
								</div>
							</div>
							<div id="two" class="tab-pane">
								<div class="Ptable">
									<div class="Ptable-item" v-for="group in specGroups" :key="group.id">
										<h3 v-text="group.name"></h3>
										<dl>
            <span v-for="param in group.params" :key="param.id">
				<dt v-text="param.name"></dt><dd v-text="param.value + (param.unit || '')"></dd>
			</span>
										</dl>
									</div>
								</div>
								<div class="package-list">
									<h3>包装清单</h3>
									<p th:text="${detail.packingList}">手机X1、快速指南X1、华为SuperCharge 充电器X1、三包凭证X1、Type-C
										数字耳机X1、Type-C 数据线X1、取卡针X1、TPU保护壳X1、USB Type-C转3.5mm耳机转接线X1(备注:最终以实物为准)</p>
								</div>

							</div>
							<div id="three" class="tab-pane">
								<p th:text="${detail.afterService}">售后保障</p>
							</div>
							<div id="four" class="tab-pane">
								<p>商品评价</p>
							</div>
							<div id="five" class="tab-pane">
								<p>手机社区</p>
							</div>
						</div>
					</div>
				</div>
			</div>
			<!--like-->
			<div class="clearfix"></div>
			<div class="like">
				<h4 class="kt">猜你喜欢</h4>
				<div class="like-list">
					<ul class="yui3-g">
						<li class="yui3-u-1-6">
							<div class="list-wrap">
								<div class="p-img">
									<img src="/img/_/itemlike01.png"/>
								</div>
								<div class="attr">
									<em>DELL戴尔Ins 15MR-7528SS 15英寸 银色 笔记本</em>
								</div>
								<div class="price">
									<strong>
										<em>¥</em>
										<i>3699.00</i>
									</strong>
								</div>
								<div class="commit">
									<i class="command">已有6人评价</i>
								</div>
							</div>
						</li>
						<li class="yui3-u-1-6">
							<div class="list-wrap">
								<div class="p-img">
									<img src="/img/_/itemlike02.png"/>
								</div>
								<div class="attr">
									<em>Apple苹果iPhone 6s/6s Plus 16G 64G 128G</em>
								</div>
								<div class="price">
									<strong>
										<em>¥</em>
										<i>4388.00</i>
									</strong>
								</div>
								<div class="commit">
									<i class="command">已有700人评价</i>
								</div>
							</div>
						</li>
						<li class="yui3-u-1-6">
							<div class="list-wrap">
								<div class="p-img">
									<img src="/img/_/itemlike03.png"/>
								</div>
								<div class="attr">
									<em>DELL戴尔Ins 15MR-7528SS 15英寸 银色 笔记本</em>
								</div>
								<div class="price">
									<strong>
										<em>¥</em>
										<i>4088.00</i>
									</strong>
								</div>
								<div class="commit">
									<i class="command">已有700人评价</i>
								</div>
							</div>
						</li>
						<li class="yui3-u-1-6">
							<div class="list-wrap">
								<div class="p-img">
									<img src="/img/_/itemlike04.png"/>
								</div>
								<div class="attr">
									<em>DELL戴尔Ins 15MR-7528SS 15英寸 银色 笔记本</em>
								</div>
								<div class="price">
									<strong>
										<em>¥</em>
										<i>4088.00</i>
									</strong>
								</div>
								<div class="commit">
									<i class="command">已有700人评价</i>
								</div>
							</div>
						</li>
						<li class="yui3-u-1-6">
							<div class="list-wrap">
								<div class="p-img">
									<img src="/img/_/itemlike05.png"/>
								</div>
								<div class="attr">
									<em>DELL戴尔Ins 15MR-7528SS 15英寸 银色 笔记本</em>
								</div>
								<div class="price">
									<strong>
										<em>¥</em>
										<i>4088.00</i>
									</strong>
								</div>
								<div class="commit">
									<i class="command">已有700人评价</i>
								</div>
							</div>
						</li>
						<li class="yui3-u-1-6">
							<div class="list-wrap">
								<div class="p-img">
									<img src="/img/_/itemlike06.png"/>
								</div>
								<div class="attr">
									<em>DELL戴尔Ins 15MR-7528SS 15英寸 银色 笔记本</em>
								</div>
								<div class="price">
									<strong>
										<em>¥</em>
										<i>4088.00</i>
									</strong>
								</div>
								<div class="commit">
									<i class="command">已有700人评价</i>
								</div>
							</div>
						</li>
					</ul>
				</div>
			</div>
		</div>
	</div>

</div>
<script src="/js/vue/vue.js"></script>
<script src="/js/axios.min.js"></script>
<script src="/js/common.js"></script>

<script th:inline="javascript">
	const specialSpec = JSON.parse(/*[[${detail.specialSpec}]]*/ "");
	const genericSpec = JSON.parse(/*[[${detail.genericSpec}]]*/ "");
	const skus = /*[[${skus}]]*/ [];
	const specs = /*[[${specs}]]*/ [];
	const params = {};
	specs.forEach(group => {
		group.params.forEach(param => {
			params[param.id] = param.name;
		})
	});
	// 初始化特有规格参数默认选中一个
	const indexes = {};
	const initIndex = skus[0].indexes.split("_");
	Object.keys(specialSpec).forEach((id, i) => {
		indexes[id] = parseInt(initIndex[i]);
	})
	const indexArr = skus.map(s => s.indexes);

</script>
<script>
	var itemVm = new Vue({
		el: "#itemApp",
		data: {
			ly,
			specialSpec,// 特有规格参数模板
			params,// 参数对象数组
			indexes,// 初始化被选中的参数
			num: 1,
		},
		methods: {
			decrement() {
				if (this.num > 1) {
					this.num--;
				}
			},
			increment() {
				this.num++;
			},
			addCart() {
				// 判断是否登录
				ly.http.get("/auth/verify").then(() => {
					// 已登录
					ly.http.post("/cart", {
						skuId: this.sku.id,
						title: this.sku.title,
						image: this.images[0],
						price: this.sku.price,
						num: this.num,
						ownSpec: JSON.stringify(this.ownSpec)
					}).then(() => {
						// 跳转到购物车列表页
						window.location.href = "http://www.leyou.com/cart.html";
					}).catch(() => {
						alert("添加购物车失败,请重试!");
					})
				}).catch(() => {
					// 获取以前的购物车
					const carts = ly.store.get("carts") || [];
					// 获取与当前商品id一致的购物车数据
					const cart = carts.find(c => c.skuId === this.sku.id);
					if (cart) {
						// 存在,修改数量
						cart.num += this.num;
					} else {
						// 不存在,新增
						carts.push({
							skuId: this.sku.id,
							title: this.sku.title,
							image: this.images[0],
							price: this.sku.price,
							num: this.num,
							ownSpec: JSON.stringify(this.ownSpec)
						})
					}
					// 未登录
					ly.store.set("carts", carts);
					// 跳转到购物车列表页
					window.location.href = "http://www.leyou.com/cart.html";
				})
			},
			locked(id, i) {
				// 如果只有一个可选项,永不锁定
				if(specialSpec[id].length === 1) return false;
				// 如果有其它项未选,不锁定
				let boo = true;
				Object.keys(this.indexes).forEach(key => {
					if (key !== id && this.indexes[key] == null) {
						boo = false;
						return;
					}
				});
				if (!boo) return false;
				// 如果当前项的组合不存在,锁定
				const {...o} = this.indexes;
				o[id] = i;
				const index = Object.values(o).join("_");
				return !indexArr.includes(index);
			},
			selectSku(id, i) {
				// 先判断当前选中的是否是锁定项
				const isLocked = this.locked(id, i);
				// 无论是否是锁定项,都允许修改
				this.indexes[id] = i;
				// 如果是锁定项,则需要调整其它项的选中状态
				if (isLocked) {
					Object.keys(this.indexes).forEach(key => {
						if (key !== id) {
							const remainSpec = specialSpec[key].filter((e, j) => !this.locked(key, j));
							this.indexes[key] = remainSpec.length === 1 ? specialSpec[key].findIndex(e => e === remainSpec[0]) : null;
						}
					})
				}

			}
		},
		computed: {
			sku() {
				if (Object.values(this.indexes).includes(null)) {
					return skus[0];
				}
				// 获取选中的规格参数的索引
				const index = Object.values(this.indexes).join("_");
				// 去skus集合寻找与index一致的sku
				return skus.find(s => s.indexes === index);
			},
			images() {
				return this.sku.images ? this.sku.images.split(",") : [];
			},
			specGroups() {
				// 获取特有规格参数值
				const ownSpec = JSON.parse(this.sku.ownSpec);
				specs.forEach(group => {
					group.params.forEach(param => {
						if (param.generic) {
							param.value = genericSpec[param.id];
						} else {
							param.value = ownSpec[param.id];
						}
					})
				})
				return specs;
			},
			ownSpec() {
				const ownSpec = JSON.parse(this.sku.ownSpec);
				const obj = {};
				Object.keys(ownSpec).forEach(id => {
					obj[this.params[id]] = ownSpec[id];
				})
				return obj;
			}
		},
		components: {
			lyTop: () => import('/js/pages/top.js')
		}
	});
</script>

<script type="text/javascript" src="/js/plugins/jquery/jquery.min.js"></script>
<script type="text/javascript">
	$(function () {
		$("#service").hover(function () {
			$(".service").show();
		}, function () {
			$(".service").hide();
		});
		$("#shopcar").hover(function () {
			$("#shopcarlist").show();
		}, function () {
			$("#shopcarlist").hide();
		});

	})
</script>
<script type="text/javascript" src="/js/model/cartModel.js"></script>
<script type="text/javascript" src="/js/plugins/jquery.easing/jquery.easing.min.js"></script>
<script type="text/javascript" src="/js/plugins/sui/sui.min.js"></script>
<script type="text/javascript" src="/js/plugins/jquery.jqzoom/jquery.jqzoom.js"></script>
<script type="text/javascript" src="/js/plugins/jquery.jqzoom/zoom.js"></script>
<script type="text/javascript" src="index/index.js"></script>
</body>

</html>

4、删除刚刚创建的一些测试内容

在这里插入图片描述

4、在resources下创建配置文件application.yml

在这里插入图片描述
在这里插入图片描述

server:
  port: 8086
spring:
  application:
    name: page-service
  thymeleaf:
    cache: false  #设置缓存关闭
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
  instance:
    lease-renewal-interval-in-seconds: 5 # 每隔5秒发送一次心跳
    lease-expiration-duration-in-seconds: 10 # 10秒不发送就过期

5、nginx反向代理

在这里插入图片描述

server {
        listen       80;
        server_name  www.leyou.com;

        proxy_set_header X-Forwarded-Host $host;
		proxy_set_header X-Forwarded-Server $host;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;


        location /item {
            proxy_pass http://192.168.58.2:8086; #主机地址 下的8086端口
            proxy_connect_timeout 600;
			proxy_read_timeout 600;
        }
		location / {
            proxy_pass http://192.168.58.2:9002; #主机地址 下的9001端口
            proxy_connect_timeout 600;
			proxy_read_timeout 600;
        }

}

重新加载nginx
在这里插入图片描述

6、完善启动类

在这里插入图片描述

package com.leyou;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class LyPageApplication {

    public static void main(String[] args) {

        SpringApplication.run(LyPageApplication.class);

    }

}

6、完善search.html页面实现对应点击商品查看详情功能

在这里插入图片描述

<a :href="'/item/'+goods.id+'.html'" target="_blank">
                                    <img :src="goods.selectedSku.images" height="200"/>
                                </a>

7、创建PageController

在这里插入图片描述
在这里插入图片描述

package com.leyou.page.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@Controller
public class PageController {

    @GetMapping("item/{id}.html")
    public String toItemPage(@PathVariable("id") Long spuId, Model model){
        //准备模型数据
        //返回视图
        return "/item";
    }
}

重新运行
在这里插入图片描述
点击实现页面跳转
在这里插入图片描述
在这里插入图片描述

8、封装模型数据

首先我们一起来分析一下,在这个页面中需要哪些数据

我们已知的条件是传递来的spu的id,我们需要根据spu的id查询到下面的数据:

  • spu信息
  • spu的详情
  • spu下的所有sku
  • 品牌
  • 商品三级分类
  • 商品规格参数、规格参数组
(1)商品微服务提供接口
1)查询spu,根据页面id查询对应的sup的信息
a、完善GoodsApi

在这里插入图片描述

   /*
    根据spu的id查询spu
     */
    @GetMapping("/spu/{id}")
    Spu querySpuById(@PathVariable("id") Long id);
b、完善GoodsController

在这里插入图片描述

  /*
    根据spu的id查询spu
     */
    @GetMapping("/spu/{id}")
    public ResponseEntity<Spu> querySpuById(@PathVariable("id") Long id){
        return ResponseEntity.ok(goodsService.querySpuById(id));
    }
c、完善goodsService

在这里插入图片描述
在这里插入图片描述


    public Spu querySpuById(Long id) {
        Spu spu = spuMapper.selectByPrimaryKey(id);
        if(spu == null){
            throw  new LyException(ExceptionEnum.GOODS_NOT_FOND);
        }
        //查询sku
        List<Sku> skus = querySkuBySpuId(spu.getId());

        //查询详情detail
        SpuDetail spuDetail = queryDetailById(spu.getId());

        spu.setSkus(skus);
        spu.setSpuDetail(spuDetail);
        return spu;
    }
    
2)查询规格参数组

在这里插入图片描述

a、拓展SpecGroup

在这里插入图片描述

package com.leyou.item.pojo;

import lombok.Data;
import tk.mybatis.mapper.annotation.KeySql;

import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import java.util.List;

@Table(name = "tb_spec_group")
@Data
public class SpecGroup {

    @Id
    @KeySql(useGeneratedKeys = true)
    private Long id;
    private Long cid;
    private String name;

    @Transient
    private List<SpecParam> params;

}

b、完善SpecificationApi

在这里插入图片描述

    @GetMapping("spec/group")
    List<SpecGroup> queryGroupByCid(@RequestParam("cid") Long cid);
c、完善SpecificationController,这里的方法名可以与api当中的方法名不一致,因为调用是通过路径去调用的

在这里插入图片描述

  /*
    根据父类查询规格组以及组内参数
     */
    @GetMapping("group")
    public ResponseEntity<List<SpecGroup>> queryListByCid(@RequestParam("cid") Long cid){

        return ResponseEntity.ok(specificationService.queryListByCid(cid));

    }
d、完善specificationService

在这里插入图片描述
在这里插入图片描述


    public List<SpecGroup> queryListByCid(Long cid) {
        //查询规格参数组
        List<SpecGroup> specGroups = queryGroupByCid(cid);
        //查询当前分类下的参数
        List<SpecParam> specParams = queryParamList(null, cid, null);
        /*
        下拉代码的目的是将specParams集合放入specGroups当中,一一对应
        如果通过双层for循环性能太低
        在specParams集合当中的SpecParam对应拥有SpecGroup的id
        所以将SpecParam对应拥有SpecGroup的id作为键而 List<SpecParam>做为值组合为map集合
        遍历specGroups集合获取其specGroup的id到map当中查询到对应的specParams集合,然后放入到specGroup.setParams当中
         */
        //先把规格参数变为map,map的key是规格组id,map的值是组下的所有参数
        Map<Long,List<SpecParam>> map = new HashMap<>();
        for (SpecParam param : specParams) {
            if(!map.containsKey(param.getGroupId())){//判断map当中是否已经存在param.getGroupId(),如果存在
                //这一组id在map当中不存在
                //新增一个list
                map.put(param.getGroupId(),new ArrayList<>());
            }
            map.get(param.getGroupId()).add(param);//将集合添加到map当中
        }
        //填充param到Group当中
        for (SpecGroup specGroup : specGroups) {
            specGroup.setParams(map.get(specGroup.getId()));
        }

        return specGroups;

    }
(2)实现页面数据的封装
1)在ly-page创建对应的包结构,复制之前在ly-search创建的client

在这里插入图片描述
在这里插入图片描述

2)分析页面所需要的数据

在这里插入图片描述
在这里插入图片描述

3)创建对应的Service

在这里插入图片描述
在这里插入图片描述

package com.leyou.page.service;

import org.springframework.stereotype.Service;

@Service
public class PageService {
}

4)将上述对应的数据在添加到PageController的Model当中
a、完善PageController

在这里插入图片描述

package com.leyou.page.web;

import com.leyou.page.service.PageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Map;

@Controller
@RequestMapping("item")
public class PageController {

    @Autowired
    private PageService pageService;

    @GetMapping("{id}.html")
    public String toItemPage(@PathVariable("id") Long spuId, Model model){
        //查询数据
        Map<String,Object> attributes = pageService.loadModel(spuId);

        //准备模型数据
        model.addAllAttributes(attributes);
        //返回视图
        return "item";
    }
}

b、完善service

在这里插入图片描述
在这里插入图片描述

package com.leyou.page.service;

import com.leyou.item.pojo.*;
import com.leyou.page.client.BrandClient;
import com.leyou.page.client.CategoryClient;
import com.leyou.page.client.GoodsClient;
import com.leyou.page.client.SpecificationClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class PageService {

    @Autowired
    private BrandClient brandClient;

    @Autowired
    private CategoryClient categoryClient;

    @Autowired
    private GoodsClient goodsClient;

    @Autowired
    private SpecificationClient specificationClient;


    public Map<String, Object> loadModel(Long spuId) {

        Map<String, Object> model = new HashMap<>();
        //查询spu
        Spu spu = goodsClient.querySpuById(spuId);
        //查询skus
        List<Sku> skus = spu.getSkus();
        //查询spuDetail
        SpuDetail spuDetail = spu.getSpuDetail();
        //查询brand
        Brand brand = brandClient.queryBrandById(spu.getBrandId());
        //查询商品的分类
        List<Category> categories = categoryClient.queryCategoryByIds(Arrays.asList(spu.getCid1(), spu.getCid2(), spu.getCid3()));
        //查询规格参数
        List<SpecGroup> groups = specificationClient.queryGroupByCid(spu.getCid3());

        // 查询特殊的规格参数
        List<SpecParam> params = specificationClient.queryParamList(null, spu.getCid3(), false);
        Map<Long, String> paramMap = new HashMap<>();
        params.forEach(param -> {
            paramMap.put(param.getId(), param.getName());
        });

        model.put("spu",spu);
        model.put("skus",skus);
        model.put("spuDetail",spuDetail);
        model.put("detail",spuDetail);
        model.put("brand",brand);
        model.put("categories",categories);
        model.put("groups",groups);
        model.put("specs",groups);
        model.put("paramMap",paramMap);
        return model;

    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、页面静态化

1、简介

(1)问题分析

现在,我们的页面是通过Thymeleaf模板引擎渲染后返回到客户端。在后台需要大量的数据查询,而后渲染得到HTML页面。会对数据库造成压力,并且请求的响应时间过长,并发能力不高。

大家能想到什么办法来解决这个问题?

首先我们能想到的就是缓存技术,比如之前学习过的Redis。不过Redis适合数据规模比较小的情况。假如数据量比较大,例如我们的商品详情页。每个页面如果10kb,100万商品,就是10GB空间,对内存占用比较大。此时就给缓存系统带来极大压力,如果缓存崩溃,接下来倒霉的就是数据库了。

所以缓存并不是万能的,某些场景需要其它技术来解决,比如静态化。

(2)什么是静态化

静态化是指把动态生成的HTML页面变为静态内容保存,以后用户的请求到来,直接访问静态页面,不再经过服务的渲染。

而静态的HTML页面可以部署在nginx中,从而大大提高并发能力,减小tomcat压力。

(3)如何实现静态化

目前,静态化页面都是通过模板引擎来生成,而后保存到nginx服务器来部署。常用的模板引擎比如:

  • Freemarker
  • Velocity
  • Thymeleaf

我们之前就使用的Thymeleaf,来渲染html返回给用户。Thymeleaf除了可以把渲染结果写入Response,也可以写到本地文件,从而实现静态化。

2、Thymeleaf实现静态化

(1)概念

先说下Thymeleaf中的几个概念:

  • Context:运行上下文
  • TemplateResolver:模板解析器
  • TemplateEngine:模板引擎

Context

上下文: 用来保存模型数据,当模板引擎渲染时,可以从Context上下文中获取数据用于渲染。

当与SpringBoot结合使用时,我们放入Model的数据就会被处理到Context,作为模板渲染的数据使用。

TemplateResolver

模板解析器:用来读取模板相关的配置,例如:模板存放的位置信息,模板文件名称,模板文件的类型等等。

当与SpringBoot结合时,TemplateResolver已经由其创建完成,并且各种配置也都有默认值,比如模板存放位置,其默认值就是:templates。比如模板文件类型,其默认值就是html。

TemplateEngine

模板引擎:用来解析模板的引擎,需要使用到上下文、模板解析器。分别从两者中获取模板中需要的数据,模板文件。然后利用内置的语法规则解析,从而输出解析后的文件。来看下模板引擎进行处理的函数:

templateEngine.process("模板名", context, writer);

三个参数:

  • 模板名称
  • 上下文:里面包含模型数据
  • writer:输出目的地的流

在输出时,我们可以指定输出的目的地,如果目的地是Response的流,那就是网络响应。如果目的地是本地文件,那就实现静态化了。

而在SpringBoot中已经自动配置了模板引擎,因此我们不需要关心这个。现在我们做静态化,就是把输出的目的地改成本地文件即可!

(2)具体实现
1)生成HTML文件

在这里插入图片描述


    public void createHtml(Long spuId) {
        //上下文
        Context context = new Context();
        context.setVariables(loadModel(spuId));
        //输出流(渲染输出)
        File dest = new File("D:/IDEAWORK/leyou/fileupload", spuId + ".html");
        try(PrintWriter writer = new PrintWriter(dest, "UTF-8")){
            //三个参数(- 模板名称 - 上下文:里面包含模型数据 - writer:输出目的地的流)
            templateEngine.process("item", context, writer);
        }catch (Exception e){
            log.error("[静态页服务]  生成静态页异常0",e);
        }
    }
2)编写测试类
a、引入测试的依赖

在这里插入图片描述

 		 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
b、编写测试类和测试方法

在这里插入图片描述

package com.leyou.page.service;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class PageServiceTest {

    @Autowired
    private PageService pageService;

    @Test
    public void createHtmlTest() {
        pageService.createHtml(141L);
    }

}

在这里插入图片描述
对应路径生成了HTML文件
在这里插入图片描述
打开可以看到内部代码
在这里插入图片描述

c、放入nginx当中在nginx的安装目录下当中的HTML目录下创建item目录

在nginx
使用mkdir item
在这里插入图片描述

d、将生成的HTML放入到对应的路径下

在这里插入图片描述

e、修改nginx的配置文件nginx.conf

设置先找本地的HTML文件如果找不到然后在找对应端口号的文件
在这里插入图片描述

		location /item {
			# 先找本地
			root html;
			if (!-f $request_filename) { #请求的文件不存在,就反向代理
				proxy_pass http://192.168.58.2:8086;
				break;
			}
		}

抽象加载nginx -s reload

f、测试

将page服务停掉
在这里插入图片描述
访问:http://www.leyou.com/item/141.html

依旧访问成功
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员猫爪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值