品优购项目记录:day12

本文介绍如何使用Freemarker生成商品详情页,并实现商品数据的动态展示及前端交互逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今日目标:

(1)掌握 Freemarker常用的指令与内建函数

(2)完成商品详细页的数据显示

(3)完成商品详细页的动态显示

(4)完成商品详细页读取SKU信息的业务逻辑

(5)完成商品审核调用功能

 

目录

1、商品详细页-数据显示

1.1 配置

1.2 服务层

1.3 基本测试

1.4 替换模板基本信息为插值

1.5 替换模板图片列表

1.6 生成扩展属性列表

1.7 生成规格列表

1.8 生成商品类型面包屑

2、商品详细页-前端逻辑

2.1 数量的加减

2.2 规格选择

3、商品详细页-读取SKU信息

3.1 服务层实现(page-service)

3.2 加载默认的SKU标题和价格

3.3 选择规格加载对应的标题和价格

3.4 预留加入购物车方法

4、审核商品生成商品详细页

4.1 控制层(manager-web)

其他:与搜索模块对接

1、配置Nginx

2、运行测试,执行http://localhost:9101/goods/genHtml.do?goodsId=149187842867981

3、对接


 

1、商品详细页-数据显示

准备工作:搭建工程(page-interface、page-service),并编写相关配置和引入相关依赖

 

1.1 配置

(1)配置Freemarker的bean,在WEB-INF下创建ftl文件夹

	<!-- 配置freemarker-bean -->
	<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>

(2)配置存放商品详细页的位置,注意保证文件夹存在,还需要将样式文件拷入该目录

## 商品详细页存放位置
PAGE_DIR=D:\\item\\

 

 

1.2 服务层

(1)page-interface,编写ItemPageService接口

package com.pinyougou.page.service;

/**
 * 商品详细页静态化
 * Author xushuai
 * Description
 */
public interface ItemPageService {

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

(2)page-service,编写ItemPageServiceImpl实现

package com.pinyougou.page.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.pinyougou.mapper.TbGoodsDescMapper;
import com.pinyougou.mapper.TbGoodsMapper;
import com.pinyougou.page.service.ItemPageService;
import com.pinyougou.pojo.TbGoods;
import com.pinyougou.pojo.TbGoodsDesc;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

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

/**
 * 商品详情页静态化实现
 * Author xushuai
 * Description
 */
@Service
@Transactional
public class ItemPageServiceImpl implements ItemPageService {

    @Autowired
    private FreeMarkerConfigurer FreeMarkerConfigurer;
    @Autowired
    private TbGoodsMapper goodsMapper;
    @Autowired
    private TbGoodsDescMapper goodsDescMapper;

    @Value("PAGE_DIR")
    private String PAGE_DIR;

    @Override
    public boolean genItemPage(Long goodsId) {
        try {
            // 查询商品基本信息和商品扩展信息
            TbGoods tbGoods = goodsMapper.selectByPrimaryKey(goodsId);
            TbGoodsDesc tbGoodsDesc = goodsDescMapper.selectByPrimaryKey(goodsId);
            // 将查询到的数据封装到Map
            Map<String, Object> data = new HashMap<>();
            data.put("goods", tbGoods);
            data.put("goodsDesc", tbGoodsDesc);

            // 创建文件输出流
            Writer out = new FileWriter(PAGE_DIR + goodsId + ".html");

            // 使用模板生成商品详细页
            Configuration configuration = FreeMarkerConfigurer.getConfiguration();
            Template template = configuration.getTemplate("item.ftl");
            template.process(data, out);

            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}

 

 

1.3 基本测试

(1)拷贝静态原型的item.html作为模板

 

(2)修改模板中的商品标题为插值:${goods.goodsName}

 

(3)测试

 

 

1.4 替换模板基本信息为插值

(1)将item.ftl中的头部和尾部分别放入另外两个模板中,在item.ftl中使用<#include>导入

 

(2)将商品基本信息使用插值替换到模板中

 

 

1.5 替换模板图片列表

(1)因为图片列表为json串,我们需要将json串转换为对象

<#-- 处理图片列表Json串 -->
<#assign imageList = goodsDesc.itemImages?eval>

(2)遍历生成的对象,展示图片,注意限制图片放大镜的最大宽高

(3)效果

 

 

1.6 生成扩展属性列表

(1)将扩展信息的json串转换为对象

<#-- 处理扩展属性Json串 -->
<#if goodsDesc.customAttributeItems??>
    <#assign attrList = goodsDesc.customAttributeItems?eval>
</#if>

(2)遍历展示扩展信息

(3)效果

 

 

1.7 生成规格列表

(1)将规格列表信息的json串转换为对象

<#-- 处理规格列表Json串 -->
<#if goodsDesc.specificationItems??>
    <#assign specList = goodsDesc.specificationItems?eval>
</#if>

(2)展示规格信息

(3)效果

 

 

1.8 生成商品类型面包屑

(1)服务层实现(page-interface),修改ItemPageServiceImpl中的代码,主要为:查询分类信息

package com.pinyougou.page.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.pinyougou.mapper.TbGoodsDescMapper;
import com.pinyougou.mapper.TbGoodsMapper;
import com.pinyougou.mapper.TbItemCatMapper;
import com.pinyougou.page.service.ItemPageService;
import com.pinyougou.pojo.TbGoods;
import com.pinyougou.pojo.TbGoodsDesc;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

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

/**
 * 商品详情页静态化实现
 * Author xushuai
 * Description
 */
@Service
@Transactional
public class ItemPageServiceImpl implements ItemPageService {

    @Autowired
    private FreeMarkerConfigurer FreeMarkerConfigurer;
    @Autowired
    private TbGoodsMapper goodsMapper;
    @Autowired
    private TbGoodsDescMapper goodsDescMapper;
    @Autowired
    private TbItemCatMapper itemCatMapper;

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

    @Override
    public boolean genItemPage(Long goodsId) {
        try {
            // 获取数据
            Map<String, Object> data = getDataMap(goodsId);

            // 创建文件输出流
            Writer out = new FileWriter(PAGE_DIR + goodsId + ".html");

            // 使用模板生成商品详细页
            Configuration configuration = FreeMarkerConfigurer.getConfiguration();
            Template template = configuration.getTemplate("item.ftl");
            template.process(data, out);

            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 获取模板需要的数据
     * 
     * @param goodsId 商品ID
     * @return java.util.Map<java.lang.String,java.lang.Object> 
     */
    private Map<String, Object> getDataMap(Long goodsId) {
        Map<String, Object> data = new HashMap<>();
        // 查询商品基本信息和商品扩展信息
        TbGoods tbGoods = goodsMapper.selectByPrimaryKey(goodsId);
        TbGoodsDesc tbGoodsDesc = goodsDescMapper.selectByPrimaryKey(goodsId);
        // 查询商品分类信息
        String category1 = itemCatMapper.selectByPrimaryKey(tbGoods.getCategory1Id()).getName();
        String category2 = itemCatMapper.selectByPrimaryKey(tbGoods.getCategory2Id()).getName();
        String category3 = itemCatMapper.selectByPrimaryKey(tbGoods.getCategory3Id()).getName();

        // 将查询到的数据封装到Map
        data.put("goods", tbGoods);
        data.put("goodsDesc", tbGoodsDesc);
        data.put("category1", category1);
        data.put("category2", category2);
        data.put("category3", category3);

        return data;
    }
}

(2)替换模板中的文本

 

(3)效果

 

 

 

 

 

2、商品详细页-前端逻辑

 

 

2.1 数量的加减

(1)拷贝相关的JS文件到存放商品详情页的目录中

 

(2)在js目录中新建controller文件夹,编写itemController.js文件

app.controller('itemController', function ($scope) {
    
    // 数量
	$scope.num = 1;

	// 增加数量
	$scope.incrNum = function() {
		$scope.num ++;
	}

	// 减少数量
	$scope.decrNum = function() {
		if($scope.num > 1) {
			$scope.num --;
		}
	}
});

(2)修改模板,在模板中引入相关JS文件和基本指令

(3)数量输入框绑定变量,+号和-号绑定单击事件

 

 

2.2 规格选择

(1)在itemController.js中新增方法

	// 选中的规格数据
	$scope.specificationItems = {};

	// 点击选中规格
	$scope.selectSpec = function(name, value) {
		// 设置给规格数据
		$scope.specificationItems[name] = value;
	}

	// 判断当前规格是否被选中
	$scope.isSelected = function(name, value) {
		if ($scope.specificationItems[name] == value) {
			return true;
		} else {
			return false;
		}
	}

(2)模板中绑定变量和单击事件

(3)效果

 

 

 

3、商品详细页-读取SKU信息

 

3.1 服务层实现(page-service)

(1)修改ItemPageServiceImpl中的getDataMap方法,新增获取SKU列表数据的逻辑

 

(2)在页面中将获取到的SKU列表数据,生成变量,以后访问都通过访问这个变量

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

(3)测试效果

 

 

3.2 加载默认的SKU标题和价格

(1)在itemController.js中新增方法

	// 当前选择SKU信息
	$scope.sku={};

	// 加载默认的SKU信息
	$scope.loadSku = function() {
		// 将skuList中的默认SKU信息赋给当前选择的SKU信息
		$scope.sku = skuList[0];
	}

(2)在模板标题和价格处,绑定变量

(3)默认选中默认的规格,修改loadSku方法

(4)效果

 

 

 

3.3 选择规格加载对应的标题和价格

(1)在itemController.js中新增方法

	// 判断两个对象是否内容相同
	$scope.matchObject = function(object1, object2) {
		for (var key in object1) {
			// 校验当前键的值是否一致
			if (object1[key] != object2[key]) {
				return false;
			}
		}
		for (var key in object2) {
			// 校验当前键的值是否一致
			if (object2[key] != object1[key]) {
				return false;
			}
		}
		// 内容相同
		return true;
	}

	// 获取当前选中的SKU
	findSku = function() {
		for (var i = 0; i < skuList.length; i++) {
			if ($scope.matchObject($scope.specificationItems,skuList[i].spec)) {// 规格匹配
				// 当前循环到的sku为选中的sku
				$scope.sku = skuList[i];
				return ;
			}
		}
	}

(2)在选择规格时,改变标题和价格,即在selectSpec中调用findSku方法

 

(3)效果

 

 

 

3.4 预留加入购物车方法

(1)在itemController.js中新增方法

	// 加入商品到购物车
	$scope.addToCart = function() {
		alert("SKU:" + $scope.sku.id + "加入购物车成功,购买数量为:" + $scope.num);
	}

(2)加入购物车按钮,绑定事件

(3)效果

 

 

 

 

4、审核商品生成商品详细页

 

4.1 控制层(manager-web)

(1)修改GoodsController中的updateStatus方法,新增逻辑

 

 

 

其他:与搜索模块对接

 

1、配置Nginx

(1)修改生成静态网页的位置(page-service)

## 商品详细页存放位置
PAGE_DIR=E:\\temp\\freemarker\\

(2)将资源文件放入该文件夹中

(3)配置nginx.conf配置文件(windows版,测试用)

 

2、运行测试,执行http://localhost:9101/goods/genHtml.do?goodsId=149187842867981

 

3、对接

(1)修改图片链接地址

 

1.2. 结构化一下 1.3. 图形化一下 1.3.1. 运营商后台 1.3.2. 商家后台 1.3.3. 网页前台 参考京东 2. 技术选型 前端:angularJS + Bootstrap 后台:SSM( springmvc+spring+mybatis) 数据库:mysql,使用mycat读写分离 开发模式:SOA 服务中间件:dubbox,需要和zookeeper配合使用 注册中心:zookeeper 消息中间件:Activemq,使用spring-jms 负载均衡:nginx 搜索:solr集群(solrCloud),配合zookeeper搭建, 使用spring-data-solor 缓存:redis集群,使用spring-data-redis 图片存储:fastDFS集群 网页静态化:freemarker 单点登录:cas 权限管理:SpringSecurity, 跨域:cros 支付:微信扫描 短信验证:阿里大于 密码加密:BCrypt 富文本:KindEditor 事务:声明式事务 任务调度:spring task 所有的技术,都可能涉及到为什么用?怎么用?用的过程中有什么问题? 3. 框架搭建 3.1. 前端 理解baseControler.js、base.js、base_pagination.js,以及每一个xxxController.js里面都公共的做了些什么。 baseControler.js 分页配置 列表刷新 处理checkBox勾选 xxxControler.js 自动生成增删改查 base_pagination.js 带分页 base.js 不带分页 3.2. dao 使用了mybatis逆向工程 4. 模块开发 逐个模块开发就好 4.1. 学会评估模块难不难 一个模块难不难从几方面考虑。 涉及几张表? 1,2张表的操作还是没有什么难度的。 涉及哪些功能? 增删改查,批量删除。 前端展示? 分页列表、树形、面包屑、三级联动、内容格式化。 4.2. 举几个简单模块的例子 4.2.1. 牌管理 单表 分页、新增、删除、修改 4.2.2. 规格管理 2张表 分页、新增、删除、修改、显示化(显示列表内容的一部分) 4.2.3. 模板管理 2张表 分页、新增、删除、修改、显示化(显示列表内容的一部分) 4.2.4. 分类管理 单表 4.2.5. 商家审核 单表 4.3. 举一个复杂模块 4.3.1. 商新增 需要插入3张表,tb_goods、tb_goods_desc、tb_item 前端:三级联动、富文本、图片上传、动态生成内容 4.3.2. 商修改 需要从3张表获取数据,然后进行回显。 4.4. 典型模块设计 4.4.1. 管理后台 商新增、商修改 4.4.2. 前台页面 搜索模块实现 物车模块实现 支付模块实现 秒杀模块实现 5. 开发过程中问题&化 1.1. 登录 单点登录怎么实现 session怎么共享 1.2. 缓存 哪些场景需要用到redis redis存储格式的选择 怎么提高redis缓存利用率 缓存如何同步 1.3. 图片上传 图片怎么存储 图片怎么上传 1.4. 搜索 ​ 怎么实现 数据量大、 并发量高的搜索 怎么分词 1.5. 消息通知 ​ 哪些情况用到activeMq 1.6. 化 seo怎么化 怎么加快访问速度 1.7. 秒杀 ​ 怎么处理高并发 ​ 秒杀过程中怎么控制库存
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值