乐优商城项目---day14-thymeleaf及静态化

1.商品详情

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

1.1.Thymeleaf

在商品详情页中,我们会使用到Thymeleaf来渲染页面,所以需要先了解Thymeleaf的语法。

详见课前资料中《Thymeleaf语法入门.md》

创建leyou-goods-web微服务

导入依赖

<?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.goods</groupId>
    <artifactId>leyou-goods-web</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>com.leyou.item</groupId>
            <artifactId>leyou-item-interface</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.leyou.common</groupId>
            <artifactId>leyou-common</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
    </dependencies>


</project>

创建配置文件

server:
  port: 8084
spring:
  application:
    name: goods-web
  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秒不发送就过期

编写引导类

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class LeyouGoodsWebApplication {
    public static void main(String[] args) {
        SpringApplication.run(LeyouGoodsWebApplication.class, args);
    }
}

详情页页面跳转

编写Controller方法进行测试:

@Controller
public class GoodsController {

    @GetMapping("item/{id}.html")
    public String redirect(@PathVariable("id")Long id, Model model){

        return "item.html";
    }
}

成功跳转:

编写商品微服务的各个API

GoodsApi  

/**
 * 根据spu的id查询spu
 * @param id
 * @return
 */
@GetMapping("spu/{id}")
public Spu querySpuById(@PathVariable("id") Long id);

GoodsController

@GetMapping("spu/{id}")
public ResponseEntity<Spu> querySpuById(@PathVariable("id") Long id){
    Spu spu = this.goodsService.querySpuById(id);
    if(spu == null){
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }
    return ResponseEntity.ok(spu);
}

GoodsService

public Spu querySpuById(Long id) {
    return this.spuMapper.selectByPrimaryKey(id);
}

组内有多个参数,为了方便展示。我们在leyou-item-service中提供一个接口,查询规格组,同时在规格组内的所有参数。,这个是根据组ID,查询出来所有的规格参数的列表

 public List<SpecGroup> queryGroupWithCid(Long cid) {
        //根据Cid查询出来所有的规格参数组
        List<SpecGroup> specGroupList = this.queryGroupWithCid(cid);
        //遍历每个规格参数组,根据组ID进行设置值,根据组ID,可以得到规格参数的列表,然后在将规格参数的列表集合设置到每个组内
        specGroupList.forEach(specGroup -> {
            List<SpecParam> specParamList = this.queryBySpecParam(specGroup.getId(), null, null, null);
            specGroup.setParams(specParamList);
        });
        return specGroupList;
    }

将所有要查询的对象和内容信息都封装到要给Map里面

    public Map<String,Object> loadDate(Long spuId){
        Map<String,Object> map=new HashMap<>();
        //1.根据SpuId查询Spu
        Spu spu = this.goodsClient.querySpuById(spuId);
        //2.根据SpuId查询SpuDetail
        SpuDetail spuDetail = this.goodsClient.queryBySpuId(spuId);
        //3.根据SpuID查询Skus
        List<Sku> skus = this.goodsClient.querBySpu(spuId);
        //4.根据Spu查询品牌
        Brand brand = this.brandClient.queryNameById(spu.getBrandId());
        //5.根据Spu查询分类
        List<Long> cids = Arrays.asList(spu.getCid1(), spu.getCid2(), spu.getCid3());
        List<String> names = this.categoryClient.queryNameByids(cids);
        List<Map<String,Object>> categories=new ArrayList<>();
        for (int i = 0; i < cids.size(); i++) {
            Map<String,Object> maps=new HashMap<>();
            maps.put("id",cids.get(i));
            maps.put("names",names);
            categories.add(maps);
        }
        //6.根据Spu查询规格参数
        List<SpecParam> specParamList = this.specificationClient.querySpecParam(null, spu.getCid3(), false, null);
        Map<Long,Object> params=new HashMap<>();
        specParamList.forEach(specParam -> {
            params.put(specParam.getId(),specParam.getName());
        });
        //7.根据Spu查询规格参数组
        List<SpecGroup> groups = this.specificationClient.queryGroupWithPramId(spu.getCid3());

        map.put("spu",spu);
        map.put("spuDetail",spuDetail);
        map.put("skus",skus);
        map.put("brand",brand);
        map.put("categories",categories);
        map.put("params",params);
        map.put("groups",groups);
        return map;
    }

封装成功:

下面是渲染商品详情页,又是Vue的东西,所以写起来比较棘手,执行完ctrl+Shift+F9之后页面出现错误

经过排查发现是在Category封装的时候,添加names,把整个List给添加进去,导致了错误的循环,需要进行修改

这个Vue的页面渲染的时候,因为使用的是Consst所以JS的获取名称的脚本一定要放到Head的头部分,不然,识别部出来

这个在测试的时候,因为本人对Vue的,语法不熟悉,所以在定义一个变量的时候,Vue要能检测到该模型的前提,必须要在data里面注册过才能检测到,不然就会出现一直检测部到的现象:]

	<script th:inline="javascript">
		// sku集合
		const skus = /*[[${skus}]]*/ [];
		// 规格参数id与name对
		const paramMap = /*[[${paramMap}]]*/ {};
		// 特有规格参数集合
		const specialSpec = JSON.parse(/*[[${spuDetail.specialSpec}]]*/ "");

		const indexes={};

		Object.keys(paramMap).forEach(param =>indexes[param]= 0);

	</script>

测试选中项目:

进行选中数据的渲染

computed: {
			sku(){
				const index = Object.values(this.indexes).join("_");
				return this.skus.find(sku => sku.indexes == index);
			}
        },

渲染大图过程中出现问题

其实根本问题还是Vue的语法掌握的不充足,很多语法部知道怎么拼写,工具也没有检测的机制,,最后发现问题,是在image 和src 前面没有加冒号导致的

下来出现规格参数组查询部出来,发现是Service出现了问题,导致无法封装

继续排查之后还是有问题发现在Specific的Service方法写的有问题

继续排查之后问题解决,页面成功渲染刷新出来

渲染规格与包装售后等信息

 页面静态化,这个过程就非常简单了,执行一个Java代码就可以了

    PrintWriter printWriter=null;
        try {
            //初始化上下文对象
            Context context = new Context();
            context.setVariables(this.goodsService.loadDate(spuId));
            File file = new File("D:\\nginx\\html\\item\\" + spuId + ".html");
            printWriter = new PrintWriter(file);
            this.templateEngine.process("item", context, printWriter);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (printWriter!=null){
                printWriter.close();;
            }
        }

    }
}

页面静态化成功:

页面静态化的访问请求:

今日总结:其实还是数据结构那些地方比较难想的明白,数据结构只要理清楚,其他的代码时很好写出来的

发布了143 篇原创文章 · 获赞 16 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/zgz102928/article/details/104531633