05畅购商品详情页

5.畅购商品详情页

5.1需求分析

当系统审核完成商品,需要将商品详情页进行展示,那么采用静态页面生成的方式生成,并部署到高性能的web服务器中进行访问是比较合适的。所以,开发流程如下图所示:
在这里插入图片描述

此处MQ我们使用Rabbitmq即可。
执行步骤解释:
系统管理员(商家运维人员)修改或者审核商品的时候, 会更改数据库中商品上架状态并发送商品id给rabbitMq中的上架交换器上架交换器会将商品id发给静态页生成队列静态页微服务设置监听器, 监听静态页生成队列, 根据商品id获取商品详细数据并使用thymeleaf的模板技术生成静态页

5.2商品静态化微服务创建

5.2.1需求分析

该微服务只用于生成商品静态页,不做其他事情。

5.2.2搭建项目

(1)在changgou-service下创建一个名称为changgou_service_page的项目,作为静态化页面生成服务
(2)changgou-service-page中添加起步依赖,如下

<dependency>
            <groupId>com.changgou</groupId>
            <artifactId>changgou_common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>com.changgou</groupId>
            <artifactId>changgou_service_goods_api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

(3)修改application.yml的配置

server:
  port: 9011
spring:
  application:
    name: page
  rabbitmq:
    host: 192.168.200.128
  main:
    allow-bean-definition-overriding: true #当遇到同样名字的时候,是否允许覆盖注册
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:6868/eureka
  instance:
    prefer-ip-address: true
feign:
  hystrix:
    enabled: false
  client:
    config:
      default:   #配置全局的feign的调用超时时间  如果 有指定的服务配置 默认的配置不会生效
        connectTimeout: 600000 # 指定的是 消费者 连接服务提供者的连接超时时间 是否能连接  单位是毫秒
        readTimeout: 600000  # 指定的是调用服务提供者的 服务 的超时时间()  单位是毫秒
#hystrix 配置
hystrix:
  command:
    default:
      execution:
        timeout:
          #如果enabled设置为false,则请求超时交给ribbon控制
          enabled: true
        isolation:
          strategy: SEMAPHORE
# 生成静态页的位置
pagepath: D:\items

(4)创建系统启动类

package com.changgou.page;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

import java.awt.print.Pageable;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.changgou.goods.feign"})
public class PageApplication {

    public static void main(String[] args) {
        SpringApplication.run(PageApplication.class,args);
    }
}

5.3生成静态页

5.3.1需求分析

页面发送请求,传递要生成的静态页的商品的SpuID.后台controller 接收请求,调用thyemleaf的原生API生成商品静态页。

在这里插入图片描述

上图是要生成的商品详情页,从图片上可以看出需要查询SPU的3个分类作为面包屑显示,同时还需要查询SKU和SPU信息。

5.3.2Feign创建

一会儿需要查询SPU和SKU以及Category,所以我们需要先创建Feign,修改changgou-service-goodsapi,添加CategoryFeign,并在CategoryFeign中添加根据ID查询分类数据,代码如下:

@FeignClient(name = "goods")
public interface CategoryFeign {
@GetMapping("/category/{id}")
public Result<Category> findById(@PathVariable("id") Integer id);
}

在changgou-service-goods-api,添加SkuFeign,并添加根据SpuID查询Sku集合,代码如下:

package com.changgou.goods.feign;

import com.changgou.goods.pojo.Sku;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.List;

@FeignClient(name = "goods")
public interface SkuFeign {

    @GetMapping("/sku/spu/{spuId}")
    public List<Sku> findSkuListBySpuId(@PathVariable("spuId") String spuId);
}

在changgou-service-goods-api,添加SpuFeign,并添加根据SpuID查询Spu信息,代码如下:

package com.changgou.goods.feign;

import com.changgou.entity.Result;
import com.changgou.goods.pojo.Spu;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name = "goods")
public interface SpuFeign {

    @GetMapping("/spu/findSpuById/{id}")
    public Result<Spu> findSpuById(@PathVariable("id") String id);
}

5.3.3静态页生成代码

在这里插入图片描述

(1)创建PageService

package com.changgou.page.service;

public interface PageService {

    //生成静态化页面
    void generateHtml(String spuId);
}

(2)创建PageServiceImpl

package com.changgou.page.service.impl;

import com.alibaba.fastjson.JSON;
import com.changgou.entity.Result;
import com.changgou.goods.feign.CategoryFeign;
import com.changgou.goods.feign.SkuFeign;
import com.changgou.goods.feign.SpuFeign;
import com.changgou.goods.pojo.Category;
import com.changgou.goods.pojo.Sku;
import com.changgou.goods.pojo.Spu;
import com.changgou.page.service.PageService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class PageServiceImpl implements PageService {

    @Value("${pagepath}")
    private String pagepath;

    @Autowired
    private TemplateEngine templateEngine;

    @Override
    public void generateHtml(String spuId) {
        //1.获取context对象,用于存储商品的相关数据
        Context context = new Context();

        //获取静态化页面的相关数据
        Map<String,Object> itemData= this.getItemData(spuId);
        context.setVariables(itemData);

        //2.获取商品详情页面的存储位置
        File dir = new File(pagepath);
        //3.判断当前存储位置的文件夹是否存在,如果不存在,则新建
        if (!dir.exists()){
            dir.mkdirs();
        }
        //4.定义输出流,完成文件的生成
        File file = new File(dir+"/"+spuId+".html");
        Writer out = null;
        try{
            out = new PrintWriter(file);
            //生成静态化页面
            /**
             * 1. 模板名称
             * 2.context
             * 3.输出流
             */
            templateEngine.process("item",context,out);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //5.关闭流
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    @Autowired
    private SpuFeign spuFeign;

    @Autowired
    private CategoryFeign categoryFeign;

    @Autowired
    private SkuFeign skuFeign;

    //获取静态化页面的相关数据
    private Map<String, Object> getItemData(String spuId) {
        Map<String, Object> resultMap = new HashMap<>();
        //获取spu
        Spu spu = spuFeign.findSpuById(spuId).getData();
        resultMap.put("spu",spu);
        //获取图片信息
        if (spu != null){
            if (StringUtils.isNotEmpty(spu.getImages())){
                resultMap.put("imageList",spu.getImages().split(","));
            }
        }
        //获取商品的分类信息
        Category category1 = categoryFeign.findById(spu.getCategory1Id()).getData();
        resultMap.put("category1",category1);

        Category category2 = categoryFeign.findById(spu.getCategory2Id()).getData();
        resultMap.put("category2",category2);

        Category category3 = categoryFeign.findById(spu.getCategory3Id()).getData();
        resultMap.put("category3",category3);

        //获取sku的相关信息
        List<Sku> skuList = skuFeign.findSkuListBySpuId(spuId);
        resultMap.put("skuList",skuList);

        //获取商品规格信息
        resultMap.put("specificationList",JSON.parseObject(spu.getSpecItems(),Map.class));
        return resultMap;
    }
}

(3)声明page_create_queue队列,并绑定到商品上架交换机

package com.changgou.page.config;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMQConfig {

    //定义交换机名称
    public static final String GOODS_UP_EXCHANGE="goods_up_exchange";
    public static final String GOODS_DOWN_EXCHANGE="goods_down_exchange";

    //定义队列名称
    public static final String AD_UPDATE_QUEUE="ad_update_queue";
    public static final String SEARCH_ADD_QUEUE="search_add_queue";
    public static final String SEARCH_DEL_QUEUE="search_del_queue";
    public static final String PAGE_CREATE_QUEUE="page_create_queue";

    //声明队列
    @Bean
    public Queue queue(){
        return new Queue(AD_UPDATE_QUEUE);
    }
    @Bean(SEARCH_ADD_QUEUE)
    public Queue SEARCH_ADD_QUEUE(){
        return new Queue(SEARCH_ADD_QUEUE);
    }
    @Bean(SEARCH_DEL_QUEUE)
    public Queue SEARCH_DEL_QUEUE(){
        return new Queue(SEARCH_DEL_QUEUE);
    }
    @Bean(PAGE_CREATE_QUEUE)
    public Queue PAGE_CREATE_QUEUE(){
        return new Queue(PAGE_CREATE_QUEUE);
    }

    //声明交换机
    @Bean(GOODS_UP_EXCHANGE)
    public Exchange GOODS_UP_EXCHANGE(){
        return ExchangeBuilder.fanoutExchange(GOODS_UP_EXCHANGE).durable(true).build();
    }
    @Bean(GOODS_DOWN_EXCHANGE)
    public Exchange GOODS_DOWN_EXCHANGE(){
        return ExchangeBuilder.fanoutExchange(GOODS_DOWN_EXCHANGE).durable(true).build();
    }


    //队列与交换机的绑定
    @Bean
    public Binding GOODS_UP_EXCHANGE_BINDING(@Qualifier(SEARCH_ADD_QUEUE)Queue queue,@Qualifier(GOODS_UP_EXCHANGE)Exchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with("").noargs();
    }
    @Bean
    public Binding PAGE_CREATE_QUEUE_BINDING(@Qualifier(PAGE_CREATE_QUEUE)Queue queue,@Qualifier(GOODS_UP_EXCHANGE)Exchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with("").noargs();
    }
    @Bean
    public Binding GOODS_DOWN_EXCHANGE_BINDING(@Qualifier(SEARCH_DEL_QUEUE)Queue queue,@Qualifier(GOODS_DOWN_EXCHANGE)Exchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with("").noargs();
    }

}

(4)创建PageListener监听类,监听page_create_queue队列,获取消息,并生成静态化页面

package com.changgou.page.listener;

import com.changgou.page.config.RabbitMQConfig;
import com.changgou.page.service.PageService;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class PageListener {

    @Autowired
    private PageService pageService;

    @RabbitListener(queues = RabbitMQConfig.PAGE_CREATE_QUEUE)
    public void receiveMessage(String spuId){
        System.out.println("获取静态化页面的商品id,id的值为:   "+spuId);
        //条用业务层完成静态化页面生成
        pageService.generateHtml(spuId);
    }
}

(6)更新canal中对于spu表的监听类,当商品审核状态从0变1,则将当前spuId发送到消息队列

//获取最新审核商品
if ("0".equals(oldData.get("status")) && "1".equals(newData.get("status"))){
//发送商品spuId
rabbitTemplate.convertAndSend(RabbitMQConfig.GOODS_UP_EXCHANGE,"",newData.get(
"id"));
}
5.3.4模板填充

(1)面包屑数据
修改item.html,填充三个分类数据作为面包屑,代码如下

在这里插入图片描述

(2)商品图片
修改item.html,将商品图片信息输出,在真实工作中需要做空判断,代码如下:
在这里插入图片描述

(3)规格输出

<dl th:each="spec,specStat:${specificationList}">
								<dt>
									<div class="fl title">
									    <i th:text="${spec.key}"></i>
								    </div>
								</dt>
                                <dd th:each="arrValue:${specStat.current.value}">
                                    <a href="javascript:;"
                                       th:v-bind:class="|{selected:sel('${spec.key}','${arrValue}')}|"
                                       th:@click="|selectSpecification('${spec.key}','${arrValue}')|" >
                                        <i th:text="${arrValue}"></i>
                                        <span title="点击取消选择">&nbsp;</span>
                                    </a>
                                </dd>
							</dl>

(4)默认SKU显示
静态页生成后,需要显示默认的Sku,我们这里默认显示第1个Sku即可,这里可以结合着Vue一起实现。可以先定义一个集合,再定义一个spec和sku,用来存储当前选中的Sku信息和Sku的规格,代码如下:

在这里插入图片描述

页面显示默认的Sku信息

在这里插入图片描述

在当前Spu的所有Sku中spec值是唯一的,我们可以根据spec来判断用户选中的是哪个Sku,我们可以在Vue中添加代码来实现,代码如下:
在这里插入图片描述

添加规格点击事件

在这里插入图片描述

(6)样式切换
点击不同规格后,实现样式选中,我们可以根据每个规格判断该规格是否在当前选中的Sku规格中,如果在,则返回true添加selected样式,否则返回false不添加selected样式。
Vue添加代码:


                //是否绑定selected样式
                sel:function(name,value){
                    if(this.spec == undefined){
                        return false;
                    }

                    if(this.spec[name]==value){
                        return true;
                    }else{
                        return false;
                    }
                },

页面添加样式绑定,代码如下:

在这里插入图片描述

5.3.5启动测试

启动eurekea服务端,数据监控服务,商品服务,静态页生成服务. 将spu表中status字段从0更新为1.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值