品优购10——网页静态化解决方案

因为生成静态页面属于一个单独的功能,我们新建一个单独的工程来实现

1. 服务层

1)创建pinyougou-page-interface工程,创建com.pinyougou.page.service包,包下创建接口

2)创建war工程pinyougou-page-service

3)依赖

<dependency>
		<groupId>org.freemarker</groupId>
		<artifactId>freemarker</artifactId>
</dependency> 

4)spring配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- 访问Dubbox所要占用的端口(自己要占用的端口) 该配置这里不可以省略,否则后面会出现端口占用的情况-->
    <dubbo:protocol name="dubbo" port="20885"></dubbo:protocol>
    
	<dubbo:application name="pinyougou-page-service"/>  
	
	<!-- 这里的端口是服务端提供的端口号,是服务器上注册中心提供的端口 -->
    <dubbo:registry address="zookeeper://192.168.25.130:2181"/>
    <dubbo:annotation package="com.pinyougou.page.service.impl" />  
   
   <!-- 配置freemarker -->
   <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>
   
   
</beans>

5)其他配置

6)代码编写

package com.pinyougou.page.service.impl;

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import com.alibaba.dubbo.config.annotation.Service;
import com.pinyougou.mapper.TbGoodsDescMapper;
import com.pinyougou.mapper.TbGoodsMapper;
import com.pinyougou.mapper.TbItemMapper;
import com.pinyougou.page.service.ItemPageService;
import com.pinyougou.pojo.TbGoods;
import com.pinyougou.pojo.TbGoodsDesc;
import com.pinyougou.pojo.TbItem;

import freemarker.core.ParseException;
import freemarker.template.Configuration;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.Template;
import freemarker.template.TemplateNotFoundException;

/**商品详细页实现类
 * @author Administrator
 *
 */
@Service(timeout=50000)
public class ItemPageServiceImpl implements ItemPageService{
	
	@Resource
	private TbGoodsMapper goodsMapper;
	
	@Resource
	private TbGoodsDescMapper goodsDescMapper;
	
	@Resource
	private FreeMarkerConfigurer freeMarkerConfigurer;
	
	@Value("${pageDir}")
	private String pageDir;
	
	@Override
	public boolean genItemHtml(Long goodsId) {
		Writer out = null;
		try {
			// 获取配置对象
			Configuration configuration = freeMarkerConfigurer.getConfiguration();
			
			// 获取模板对象
			Template template = configuration.getTemplate("item.ftl");
			
			// 创建数据模型
			Map dataModel = new HashMap();
			// 1. 查询SPU信息
			TbGoods goods = goodsMapper.selectByPrimaryKey(goodsId);
			dataModel.put("goods", goods);
			// 2. 查询SPU详情
			TbGoodsDesc goodsDesc = goodsDescMapper.selectByPrimaryKey(goodsId);
			dataModel.put("goodsDesc", goodsDesc);
			
			// 创建目标文件的输出流对象
			out = new FileWriter(pageDir + goodsId + ".html");
			
			// 写数据到目标文件
			template.process(dataModel,out);
			
			return true;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally{
			if(null != out){
				try {
					out.close();
				} catch (IOException e) {
					System.out.println("关闭流文件失败");
				}
			}
		}
		
		return false;
	}
	
}

7)模板改造

<div class="sku-name">
	<h4>${goods.goodsName}</h4>
</div>

详情页什么时候生成了?应该是在商品审核之后,就要生成该文件,所以在运营商后台(manager-web)调用该工程

2. 控制层

2.1 测试服务方法

先做个测试,测试服务是否好用,在goodsController中新增一个方法genHtml

	@RequestMapping("/genHtml")
	public void genHtml(Long goodsId){
		boolean flag = itemPageService.genItemHtml(goodsId);
		if(flag){
			System.out.println("生成文件成功!");
		} else{
			System.out.println("生成文件失败!");
		}
	}

然后启动服务,在页面输入http://localhost:9101/goods/genHtml.do?goodsId=149187842867971 查看item目录文件是否生成

文件生成,打开文件,如图:

商品标题生成成功。

3. 商品详情页模板构建

3.1 模板模块化引入

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

3.2 改造模板文件

3.2.1 生成基础数据

在模板中找到合适的位置,用插值替换静态文本

<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>

3.2.2 生成图片列表

编辑模板文件

<#--图片列表 -->
<#assign imageList=goodsDesc.itemImages?eval />

这一句要转换图片列表的json字符串
图片部分的代码
 

<!--默认第一个预览-->
<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>

3.2.3 生成扩展属性列表

修改模板   首先进行json转换

<#--扩展属性列表 -->
<#assign customAttributeList=goodsDesc.customAttributeItems?eval />

显示扩展属性数据,如果扩展属性为空则不显示此条数据

 <#list customAttributeList as item>
	<#if item.value??>
		 <li>${item.text} :${item.value}</li>
	</#if>
</#list>

3.2.4 生成规格列表

修改模板  转换规格列表

<#--规格列表 -->
<#assign specificationList=goodsDesc.specificationItems?eval />

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

<#list specificationList as specification>							
	<dl>
		<dt>
			<div class="fl title">
				<i>${specification.attributeName}</i>
			</div>
		</dt>								
		<#list specification.attributeValue as item>						
			<dd><a href="javascript:;" >${item}</a></dd>
		</#list>
	</dl>
</#list>	

3.2.5 生成商品类型面包屑

修改ItemPageServiceImpl ,读取三级商品分类名称,加入到数据模型中

//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);

修改模板,展示商品分类面包屑

<ul class="sui-breadcrumb">
	<li><a href="#">${itemCat1}</a></li>
	<li><a href="#">${itemCat2}</a></li>
	<li><a href="#">${itemCat3}</a></li>					
</ul>

4. 前端逻辑

4.1 购买数量加减操作

1)在item目录添加angularJS文件

2)前端控制层

将base.js拷贝到js目录下
在js目录下构建controller文件夹,创建itemController.js
 

app.controller("itemController",function($scope){
	
	$scope.num = 1;

	// 数量加减
	$scope.addNum = function(x){
		$scope.num += x;
		if( $scope.num < 1 ){
			$scope.num = 1;
		}
	}


	
});

注意:要控制一下数量不能小于1

3)在模板中引入头文件与添加指令

引入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">

4)调用方法

<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>

4.2 规格选择

最终我们需要实现的效果:

实现思路:

创建一个对象({ '网络':'移动4G' }),用于存储用户选择的规格 

点击标签的时候,更改此对象

前端控制层创建方法,用于判断当前规格与选项是否被选中

4.2.1 前端控制层

修改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;
	}		
}

4.2.2 修改模板

<dd>
	<a  class="{{isSelected('${specification.attributeName}','${item}')?'selected':''}}" 
	ng-click="selectSpecification('${specification.attributeName}','${item}')">
	 ${item}								   			
<span title="点击取消选择">&nbsp;</span>
    </a>
</dd>

5.2 SKU信息的读取

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

5.2.1 页面生成SKU列表变量

1)后端代码

// 4. 读取SKU列表数据
TbItemExample example = new TbItemExample();
Criteria criteria = example.createCriteria();
criteria.andGoodsIdEqualTo(goodsId);
criteria.andStatusEqualTo("1");// 状态有效
example.setOrderByClause("is_default desc"); // 按是否默认降序排序,目的是让返回的第一条结果为默认的sku
List<TbItem> itemList = itemMapper.selectByExample(example);
dataModel.put("itemList", itemList);

2)修改模板

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

5.2.2 显示SKU标题和价格

1)加载默认sku信息

//加载默认SKU
$scope.loadSku=function(){
	$scope.sku=skuList[0];		
	$scope.specificationItems= JSON.parse(JSON.stringify($scope.sku.spec)) ;
}

2)修改模板

1. 调用方法

<body ng-app="pinyougou" ng-controller="itemController" ng-init="num=1;loadSku()">

2. 显示标题等信息

<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>

3)选择规格更新sku

// 4. 规格的联动效果
// 4.1 定义函数,用于比较两个json对象是否相等
matchjson = function(obj1,obj2){
	for(var key in obj1){
		if(obj1[key] != obj2[key]){
			return false;
		}
	}

	for(var key in obj2){
		if(obj2[key] != obj1[key]){
			return false;
		}
	}
	return true;
}
// 4.2 定义查询函数
searchSku = function(){
	for( var i = 0 ; i < skuList.length ; i ++ ){
		if( matchjson(skuList[i].spec,$scope.specs) ){
			$scope.sku = skuList[i];
			return;
		}
	}
	$scope.sku = {id:-1,title:'该规格没有商品',price:-1,spec:{}};
}

6. 商品审核生成详细页

修改pinyougou-manager-web的GoodsController.java 

@RequestMapping("/updateStatus")
public Result updateStatus(Long[] ids,String status){
	try {
		goodsService.updateStatus(ids, status);						
		//按照SPU ID查询 SKU列表(状态为1)		
		if(status.equals("1")){//审核通过
			List<TbItem> itemList = goodsService.findItemListByGoodsIdandStatus(ids, status);						
			//调用搜索接口实现数据批量导入
			if(itemList.size()>0){				
				itemSearchService.importList(itemList);					
			}else{
				System.out.println("没有明细数据");
			}				
			//静态页生成
			for(Long goodsId:ids){
				itemPageService.genItemHtml(goodsId);
			}				
		}					
		return new Result(true, "修改状态成功"); 
	} catch (Exception e) {
		e.printStackTrace();
		return new Result(false, "修改状态失败");
	}
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值