商品详情页-数据显示

运用Freemarker技术来实现商品详细页的静态化。通过地址栏输入某地址,如下形式
http://localhost:9101/gen_item.do?goodsId=149187842867979
能在本地电脑某目录生成商品详细页,页面的名称为商品id.html

工程搭建

服务接口层

  • 创建pinyougou-page-interface工程
  • 创建com.pinyougou.page.service包
  • 包下创建接口ItemPageService
package com.pinyougou.page.service;
/**

* Title: ItemPageService

* Description: 生成页面
 
* @author: 张楚楚

* @date 2019年2月28日下午3:01:38

*/
public interface ItemPageService {

	/**
	 * 生成商品详细页
	 * @param goodsId
	 * @return
	 */
	public boolean genItemHtml(Long goodsId);
	
}

服务实现层

  • 创建war工程pinyougou-page-service
  • pom.xml引入依赖 参见其它服务工程, 另外添加freemarker依赖
<!-- freemarker -->
	<dependency>
		<groupId>org.freemarker</groupId>
		<artifactId>freemarker</artifactId>
	</dependency>  
  • 添加web.xml 参见其它服务工程

运用Freemarker技术来实现商品详细页的静态化

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">	
	
	<!-- 加载spring容器 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath*:spring/applicationContext*.xml</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	
</web-app>
  • spring配置文件 参见其它服务工程 ,另外配置:
    这是spring提供的对freemarker支持的配置文件,属性分别为模板目录和字符集
    在WEB-INF下创建ftl目录
  <bean id="freemarkerConfig"	class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
		<property name="templateLoaderPath" value="/WEB-INF/ftl/" />
		<property name="defaultEncoding" value="UTF-8" />
	</bean>

网页生成目录也可写入配置文件中

  • 创建属性文件page.properties
    运用Freemarker技术来实现商品详细页的静态化
pagedir=d:\\item\\
  • 建立com.pinyougou.page.service.impl包
  • 包下建立类ItemPageServiceImpl
@Service
public class ItemPageServiceImpl implements ItemPageService {

	@Value("${pagedir}")
	private String pagedir;
	
	@Autowired
	private FreeMarkerConfig freeMarkerConfig;
	
	@Autowired
	private TbGoodsMapper goodsMapper;
	
	@Autowired
	private TbGoodsDescMapper goodsDescMapper;
		
	@Override
	public boolean genItemHtml(Long goodsId){				
		try {
			Configuration configuration = freeMarkerConfig.getConfiguration();
			Template template = configuration.getTemplate("item.ftl");
			Map dataModel=new HashMap<>();			
			//1.加载商品表数据
			TbGoods goods = goodsMapper.selectByPrimaryKey(goodsId);
			dataModel.put("goods", goods);			
			//2.加载商品扩展表数据			
			TbGoodsDesc goodsDesc = goodsDescMapper.selectByPrimaryKey(goodsId);
			dataModel.put("goodsDesc", goodsDesc);						
			Writer out=new FileWriter(pagedir+goodsId+".html");
			template.process(dataModel, out);
			out.close();
			return true;			
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
}
  • 将item.html拷贝至web-inf/ftl下
  • 修改扩展名为ftl
    运用Freemarker技术来实现商品详细页的静态化
  • 将商品名称用插值代替
<div class="sku-name">
	<h4>${goods.goodsName}</h4>
</div>

在D盘建立文件夹item,将必要的样式表和Js拷贝到此目录下,此目录为生成的目录

运营商管理后台

  • pinyougou-manager-web引入依赖pinyougou-page-interface

Maven->Add Dependency

  • 在GoodsController.java中新增方法
@Reference(timeout=40000)
	private ItemPageService itemPageService;
	/**
	 * 生成静态页(测试)
	 * @param goodsId
	 */
	@RequestMapping("/genHtml")
	public void genHtml(Long goodsId){
		itemPageService.genItemHtml(goodsId);	
	}

商品详情页模板构建

  • 模板模块化引入

此时我们的item.ftl内容较多,当我们编辑时不容易快速找到编辑的位置,所以我们将头部分拆分到head.ftl ,将尾部拆分到foot.ftl ,用include指令在item.ftl中引入 。

生成基本数据

  • 在模板中找到合适的位置,用插值替换静态文本
<div class="news"><span>${goods.caption}</span></div>
<div class="fl price"><i>¥</i><em>${goods.price}</em><span>降价通知</span></div>
<div class="intro-detail"><!-- 商品详情 -->	${goodsDesc.introduction}</div>
<div id="two" class="tab-pane"><p>${goodsDesc.packageList}</p></div>
<div id="three" class="tab-pane"><p>${goodsDesc.saleService}</p></div>

生成图片列表

  • 编辑模板文件

运用Freemarker技术来实现商品详细页的静态化
转换图片列表的json字符串

<#--图片列表 -->
<#assign imageList=goodsDesc.itemImages?eval />
  • 图片部分的代码
<!--默认第一个预览-->
<div id="preview" class="spec-preview">
		<span class="jqzoom">
				<#if (imageList?size>0)>
					<img jqimg="${imageList[0].url}" src="${imageList[0].url}" width="400px" height="400px" />
				</#if>
		</span>
</div>
<!--下方的缩略图--><div class="spec-scroll">
		<div class="items">
		<ul>
		<#list imageList as item>
			<li><img src="${item.url}" bimg="${item.url}" onmousemove="preview(this)" /></li>
		</#list>
		</ul>
	</div>
</div>
  • 生成效果
    运用Freemarker技术来实现商品详细页的静态化

生成扩展属性列表

运用Freemarker技术来实现商品详细页的静态化
显示在商品介绍区域

  • 修改模板
<#--扩展属性列表 -->
<#--进行json转换-->
<#assign customAttributeList=goodsDesc.customAttributeItems?eval />
  • 显示扩展属性数据
 <#list customAttributeList as item>
		<#if item.value??><#--如果扩展属性为空则不显示此条数据-->
			 <li>${item.text} :${item.value}</li>
		</#if>
</#list>
  • 效果
    运用Freemarker技术来实现商品详细页的静态化

生成规格列表

运用Freemarker技术来实现商品详细页的静态化

  • 修改模板 转换规格列表
<#--规格列表 -->
<#assign specificationList=goodsDesc.specificationItems?eval />

此时,我们需要使用嵌套循环

<#list specificationList as spec>				
		<dl>
			<dt>
					<div class="fl title">
							<i>${spec.attributeName}</i>
					</div>
			</dt>								
			<#list spec.attributeValue as item>						
				<dd><a href="javascript:;" >${item}</a></dd>
			</#list>
		</dl>
</#list>	
  • 效果
    运用Freemarker技术来实现商品详细页的静态化

生成商品类型面包屑

运用Freemarker技术来实现商品详细页的静态化
tb_goods表

  • 修改ItemPageServiceImpl ,读取三级商品分类名称,加入到数据模型中
@Service
public class ItemPageServiceImpl implements ItemPageService {

	@Autowired
	private FreeMarkerConfig freeMarkerConfig;
	
	@Autowired
	private TbGoodsMapper goodsMapper;
	
	@Autowired
	private TbGoodsDescMapper goodsDescMapper;
	
	@Autowired
	private TbItemCatMapper itemCatMapper;
	
	@Override
	public boolean genItemHtml(Long goodsId){
				
		try {
			Configuration configuration = freeMarkerConfig.getConfiguration();
			Template template = configuration.getTemplate("item.ftl");
			Map dataModel=new HashMap<>();
			
			//1.加载商品表数据
			TbGoods goods = goodsMapper.selectByPrimaryKey(goodsId);
			dataModel.put("goods", goods);
			
			//2.加载商品扩展表数据			
			TbGoodsDesc goodsDesc = goodsDescMapper.selectByPrimaryKey(goodsId);
			dataModel.put("goodsDesc", goodsDesc);
			
			//3.商品分类
			String itemCat1 = itemCatMapper.selectByPrimaryKey(goods.getCategory1Id()).getName();
			String itemCat2 = itemCatMapper.selectByPrimaryKey(goods.getCategory2Id()).getName();
			String itemCat3 = itemCatMapper.selectByPrimaryKey(goods.getCategory3Id()).getName();
			dataModel.put("itemCat1", itemCat1);
			dataModel.put("itemCat2", itemCat2);
			dataModel.put("itemCat3", itemCat3);
			
			Writer out=new FileWriter("d:\\item\\"+goodsId+".html");
			template.process(dataModel, out);
			out.close();
			return true;			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
	}
}
  • 修改模板,展示商品分类面包屑
<ul class="sui-breadcrumb">
	<li><a href="#">${itemCat1}</a></li>
	<li><a href="#">${itemCat2}</a></li>
	<li><a href="#">${itemCat3}</a></li>					
</ul>
  • 效果
    运用Freemarker技术来实现商品详细页的静态化

商品详情页-前端逻辑

购买数量加减操作

  • 将angularJS库加入d:\item的plugins下
    运用Freemarker技术来实现商品详细页的静态化
  • 前端控制层
    • 将base.js拷贝到js目录下
      运用Freemarker技术来实现商品详细页的静态化

    • 在js目录下构建controller文件夹,创建itemController.js

//商品详细页(控制层)
app.controller('itemController',function($scope){
	//数量操作
	$scope.addNum=function(x){
		$scope.num=$scope.num+x;
		if($scope.num<1){
			$scope.num=1;
		}
	}		
});

增加就传入正数,减少就传入负数,数量不能小于1

  • 模板

  • 引入js

<script type="text/javascript" src="plugins/angularjs/angular.min.js">  </script>
<script type="text/javascript" src="js/base.js">  </script>
<script type="text/javascript" src="js/controller/itemController.js">  </script> 
  • 添加指令
<body ng-app="pinyougou" ng-controller="itemController" ng-init="num=1">
  • 调用操作数量的方法
<div class="controls">
	<input autocomplete="off" type="text" value="{{num}}" minnum="1" class="itxt" />
	<a href="javascript:void(0)" class="increment plus" ng-click="addNum(1)" >+</a>
	<a href="javascript:void(0)" class="increment mins" ng-click="addNum(-1)">-</a>
</div>
  • 效果
    运用Freemarker技术来实现商品详细页的静态化

规格选择

创建一个对象 格式为:{‘网络’:’移动3G’,“机身内存”:“64G”} 用于存储用户选择的规格
点击标签的时候,更改此对象
前端控制层创建方法,用于判断当前规格与选项是否被选中

  • 前端控制层
    修改itemController.js
$scope.specificationItems={};//记录用户选择的规格
	//用户选择规格
	$scope.selectSpecification=function(name,value){	
		$scope.specificationItems[name]=value;
	}	
	//判断某规格选项是否被用户选中
	$scope.isSelected=function(name,value){
		if($scope.specificationItems[name]==value){
			return true;
		}else{
			return false;
		}		
	}
  • 模板
    页面调用控制器的方法
<#list specificationList as spec>
							<dl>
								<dt>
									<div class="fl title">
									<i>${spec.attributeName}</i>
								</div>
								</dt>
									<#list spec.attributeValue as item>
								<dd><a href="javascript:;"  
										class="{{isSelected('${spec.attributeName}','${item}')?'selected':''}}"
										ng-click="selectSecification('${spec.attributeName}','${item}')">${item}
										<span title="点击取消选择">&nbsp;</span>
										</a></dd>
									</#list>
							</dl>
							</#list>

如果被选中,会有红色的框样式,即class=“selected”,执行isSelected()方法,采用三元运算符来判断是否被选中,选中则加样式

  • 效果
    运用Freemarker技术来实现商品详细页的静态化

商品详情页-读取SKU信息

SPU = Standard Product Unit (标准产品单位)SPU是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。
在商品信息电子化过程中,商品的特性可以由多个“属性|属性值对”进行描述。“属性|属性值对”完全相同的商品,可以抽象成为一个SPU。
另一方面,这些“属性|属性值对”在SPU中固化下来,逐步标准化。
基于SPU的商品信息结构,可以实现丰富的应用,比如商品信息与资讯、评论、以及其它SPU的整合。
例如:iPhone X 可以确定一个产品即为一个SPU。

SKU=Stock Keeping Unit(库存量单位)。
针对电商而言:
1、SKU是指一款商品,每款都有出现一个SKU,便于电商品牌识别商品。
2、一款商品多色,则是有多个SKU,例:一件衣服,有红色、白色、蓝色,则SKU编码也不相同,如相同则会出现混淆,发错货。
例如:iPhone X 64G 银色 则是一个SKU。

需求:当我们选择规格后,应该在页面上更新商品名称为SKU的商品标题,价格也应该为SKU的商品价格。

页面生成SKU列表变量

  • 后端服务层
  • 修改pinyougou-page-service的ItemPageServiceImpl.java
@Autowired
	private TbItemMapper  itemMapper;
	
	@Override
	public boolean genItemHtml(Long goodsId) {
		
		Configuration configuration = freeMarkerConfigurer.getConfiguration();
		try {
			Template template = configuration.getTemplate("item.ftl");
			
			//创建数据模型
			Map dataModel=new HashMap<>();
			//1.商品主表数据
			TbGoods goods = goodsMapper.selectByPrimaryKey(goodsId);
			dataModel.put("goods", goods);
			//2.商品扩展表数据
			TbGoodsDesc goodsDesc = goodsDescMapper.selectByPrimaryKey(goodsId);
			dataModel.put("goodsDesc", goodsDesc);
			//3.读取商品分类
			String itemCat1 = itemCatMapper.selectByPrimaryKey(goods.getCategory1Id()).getName();
			String itemCat2 = itemCatMapper.selectByPrimaryKey(goods.getCategory2Id()).getName();
			String itemCat3 = itemCatMapper.selectByPrimaryKey(goods.getCategory3Id()).getName();
			dataModel.put("itemCat1", itemCat1);
			dataModel.put("itemCat2", itemCat2);
			dataModel.put("itemCat3", itemCat3);
			//4.读取SKU列表数据
			TbItemExample example=new TbItemExample();
			Criteria criteria = example.createCriteria();
			criteria.andGoodsIdEqualTo(goodsId);//SPU ID
			criteria.andStatusEqualTo("1");//状态有效
			example.setOrderByClause("is_default desc");//按是否默认字段降序排序,目的是返回的结果第一条为默认SKU
			List<TbItem> itemList = itemMapper.selectByExample(example);
			dataModel.put("itemList", itemList);
			
			Writer out=new FileWriter(pagedir+goodsId+".html");
			
			template.process(dataModel, out);//输出
			
			out.close();
			
			return true;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}  
		
		
	}

  • 模板
  • 修改模板
<script>
       //SKU商品列表
	   var skuList=[    	    
	    	    <#list itemList as item>  	    	    	
		    		{
		    		"id":${item.id?c},
		    		"title":"${item.title!''}",
		    		"price":${item.price?c},		    		
		    		"spec": ${item.spec}	
		    		} ,     		
	    		</#list>
	   ];  
    </script>

${item.id?c} c函数将数字转换成字符串(去除数字间的逗号)

  • 测试(执行控制层方法)生成,发现页面源代码中生成了变量
    运用Freemarker技术来实现商品详细页的静态化

显示SKU标题和价格

  • 加载默认SKU信息
  • 修改itemController.js
//加载默认SKU
	$scope.loadSku=function(){
		$scope.sku=skuList[0];
		//深克隆		
		$scope.specificationItems= JSON.parse(JSON.stringify($scope.sku.spec)) ;
	}
  • 修改模板item.ftl
<body ng-app="pinyougou" ng-controller="itemController" ng-init="num=1;loadSku()">
  • 修改模板,显示标题
<div class="sku-name"><h4>{{sku.title}}</h4></div>
  • 显示价格
<div class="summary-wrap">
	<div class="fl title"><i>价  格</i></div>
<div class="fl price"><i>¥</i> <em>{{sku.price}}</em> <span>降价通知</span></div>
</div>

选择规格更新SKU

  • 修改itemController.js , 编写匹配对象的方法
//匹配两个对象是否相等
	matchObject=function(map1,map2){
		
		for(var k in map1){
			if(map1[k]!=map2[k]){
				return false;
				
			}
			
		}
		
		for(var k in map2){
			if(map2[k]!=map1[k]){
				return false;
				
			}
			
		}
		
		return true;
		
	}
  • 编写方法,在SKU列表中查询当前用户选择的SKU
	//根据规格查询sku
	searchSku=function(){
		
		for(var i=0;i<skuList.length;i++){
			if(matchObject(skuList[i].spec,$scope.specificationItems)){
				$scope.sku=skuList[i];
				return;
				
			}
			
		}
		
		$scope.sku={id:0,title:'------',price:0};//如果没有匹配的
	}
  • 在用户选择规格后触发读取方法
//用户选择规格
$scope.selectSpecification=function(name,value){	
		$scope.specificationItems[name]=value;
		searchSku();//读取sku
}
  • 效果
    运用Freemarker技术来实现商品详细页的静态化
    运用Freemarker技术来实现商品详细页的静态化

相关文章:

  • 2022-02-12
  • 2021-07-10
  • 2021-07-30
  • 2021-07-15
  • 2021-10-16
  • 2021-11-07
猜你喜欢
  • 2021-06-04
  • 2021-06-22
  • 2021-05-23
  • 2021-10-20
  • 2022-12-23
相关资源
相似解决方案