mysql 查询 静态化_移动商城第六篇【单品查询、静态化页面】

tags: 移动商城项目

单品页查询

当点击某个商品的时候,查看该商品的详细信息:

AAffA0nNPuCLAAAAAElFTkSuQmCC

修改每个商品的超链接:

class="lazyload" src="https://i-blog.csdnimg.cn/blog_migrate/a6535358e53b6a218d537b84d5dcb04c.png" data-original="${file_path}${item.imgs}" alt="摩托罗拉XT319"/>

提供对应的controller方法

/**

* 查看商品的单品页信息

*

* @return

*/

@RequestMapping("/toProductDetail.do")

public String toProductDetail() {

return "productDetail";

}

进入到页面上,我们来查看一下有什么属性要展示出来的:

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

我们发现这些数据涉及到了多张表的查询,下面就来分析一下吧:

item实体表

feature属性表

paraValue存放属性值的表

sku库存表

specValue库存特殊属性值表

大字段数据 clob表

我们主要查询的是商品的信息,因此商品需要联合上边那些关联关系一次查询出来!

编写SQL

SELECT *

FROM EB_ITEM eb, EB_SKU sku, EB_PARA_VALUE pa, EB_FEATURE fe, EB_SPEC_VALUE sv,EB_ITEM_CLOB ic

WHERE eb.ITEM_ID = sku.ITEM_ID

AND fe.FEATURE_ID = pa.FEATURE_ID

AND ic.ITEM_ID = eb.ITEM_ID

AND pa.ITEM_ID = eb.ITEM_ID

AND sku.SKU_ID = sv.SKU_ID

AND eb.ITEM_ID = 3100

上面就是我们的sql语句。联合了6张表进行查询。

在联合查询的时候需要注意,如果某一张表的数据不存在,在联合的时候另一张表的数据就查询不出来了。因此,我们是需要考虑是否需要外连接把数据查询出来的。!

经过我们的分析得出,商品是可以没有最小销售单元的特殊值的。因此用到了外连接

SELECT *

FROM EB_ITEM eb, EB_SKU sku, EB_PARA_VALUE pa, EB_FEATURE fe, EB_SPEC_VALUE sv, EB_ITEM_CLOB ic

WHERE eb.ITEM_ID = sku.ITEM_ID

AND fe.FEATURE_ID = pa.FEATURE_ID

AND ic.ITEM_ID = eb.ITEM_ID

AND pa.ITEM_ID = eb.ITEM_ID

AND sku.SKU_ID = sv.SKU_ID(+)

AND eb.ITEM_ID = 3100

实体关联数据

在Item实体中,我们需要关联对应的数据!

//对应大字段关系

private EbItemClob clob;

//对应最小销售单元关系

private List ebSkus;

//参数值数据

private List paraList;

//set\get方法

在参数值实体表中关联属性表的名称:

//关联与属性表的关系,由于通过featureId已经能够体现一对一的,我们这里就可以直接使用名称了。

//当然了,我们在这里也是可以直接使用对象的,但是为了方便就使用属性而已。

private String featureName;

编写dao、service、mapper、controller

mapper:

SELECT *

FROM EB_ITEM eb, EB_SKU sku, EB_PARA_VALUE pa, EB_FEATURE fe, EB_SPEC_VALUE sv, EB_ITEM_CLOB ic

WHERE eb.ITEM_ID = sku.ITEM_ID

AND fe.FEATURE_ID = pa.FEATURE_ID

AND ic.ITEM_ID = eb.ITEM_ID

AND pa.ITEM_ID = eb.ITEM_ID

AND sku.SKU_ID = sv.SKU_ID(+)

AND eb.ITEM_ID = #{itemId}

dao:

public EbItem selectItemDetail(Long itemId) {

return this.getSqlSession().selectOne(nameSpace + "selectItemDetail", itemId);

}

service:

public EbItem selectItemDetail(Long itemId) {

return itemDao.selectItemDetail(itemId);

}

controller:

/**

* 查看商品的单品页信息

*

* @return

*/

@RequestMapping("/toProductDetail.do")

public String toProductDetail(Long itemId,Model model) {

EbItem ebItem = itemService.selectItemDetail(itemId);

model.addAttribute("item", ebItem);

return "productDetail";

}

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

同步价钱、规格、库存

当我们点击16g、32G、64G的时候,价钱和库存应该要同步起来。

AAffA0nNPuCLAAAAAElFTkSuQmCC

因此,我们需要用到ajax

首先,为每个a标签绑定单机事件

.....a标签

ajax:

//为每个a标签绑定事件

$("#skuChange a").click(function () {

//点击某一个时,样式发生改变

$(this).attr("class", "here");

//其他的样式去除掉

$(this).siblings().attr("class","");

//得到a标签的自定义属性skuId

var skuId = $(this).attr("skuId");

$.ajax({

url: "${path}/item/updatePriceAndStock",

type: "post",

data:{skuId:skuId},

success: function (responseText) {

},

error:function () {

}

});

controller:

/**

* 更新页面上的库存和价钱

*

* @return

*/

@RequestMapping("/updatePriceAndStock.do")

public void updatePriceAndStock(Long skuId, HttpServletResponse response) {

if (skuId != null) {

//得到具体的库存对象

EbSku ebSku = skuService.selectByPrimaryKey(skuId);

//将对象写成JSON返回出去

JSONObject jsonObject = new JSONObject();

jsonObject.accumulate("sku", ebSku);

String result = jsonObject.toString();

ResourcesUtils.printJSON(result,response);

}

}

ajax补全:

//为每个a标签绑定事件

$("#skuChange a").click(function () {

//点击某一个时,样式发生改变

$(this).attr("class", "here");

//其他的样式去除掉

$(this).siblings().attr("class","");

//得到a标签的自定义属性skuId

var skuId = $(this).attr("skuId");

$.ajax({

url: "${path}/item/updatePriceAndStock.do",

type: "post",

data:{skuId:skuId},

success: function (responseText) {

var parseJSON = $.parseJSON(responseText);

//将价钱设置为当前库存的

$("#skuPrice").html(parseJSON.sku.skuPrice);

$("#marketPrice").html(parseJSON.sku.marketPrice);

//判断是否有货

var stock = parseJSON.sku.stockInventory;

console.log(stock);

if(stock>0) {

$("#stock").html("有货");

}else {

$("#stock").html("无货");

}

},

error:function () {

}

});

});

到目前为止,我们已经能够联动更新了...

还有值得注意的是:想要一进去就联动更新我们的库存和价钱。我们可以使用jquery的trigger方法:

$("#skuChange a:first").trigger("click");

静态化页面

首先,我们要知道为什么使用静态化页面???

静态页面= 模版+数据

我们的单品页面会经常被访问到,而每次我们都是需要去访问数据库来查询具体的数据。这样很耗费性能

AAffA0nNPuCLAAAAAElFTkSuQmCC

那么能不能不访问数据库就能够查询出数据的数据呢??

这类似于我们数据库连接池这么一个概念,把连接都创建了,需要的时候就使用。

当用户访问单品页面的之前,我们就可以把页面静态化(模版+数据),那么用户访问被静态化的页面,也就是html就行了。这样一来,查看单品页就不用访问数据库了。。

那怎么使用呢??

将我们的单品页弄成是静态页:

AAffA0nNPuCLAAAAAElFTkSuQmCC

我们的静态页到最后是变成HTML格式的,因此是不能用半点的JAVA语法的。因此要把动态的数据改成是freemaker所熟悉的语法来更替掉

常用的语法

使用frermarker语法 定义path的变量

这种不用改,我们只要将item传入map中就行了。

AAffA0nNPuCLAAAAAElFTkSuQmCC

forEach和if标签都要修改

修改前:

${spec.specValue }

${spec.specValue }

修改后:

${spec.specValue }

#list>

${spec.specValue }

#list>

#if>

#list>

freemarker语法自动带有,号的数值类型,我们一般不使用。于是使用?c来格式化

skuId="${sku.skuId?c }

时间的转换:

${sendTime?string("yyyy-MM-dd HH:mm:ss")}

freemarker工具类

package com.rl.ecps.utils;

import java.io.BufferedWriter;

import java.io.File;

import java.io.FileOutputStream;

import java.io.OutputStreamWriter;

import java.io.Writer;

import java.util.Map;

import freemarker.template.Configuration;

import freemarker.template.Template;

public class FMutil {

/**

*

* @param ftlName:模板名

* @param fileName:生成的html名字

* @param map 数据库中的数据

* @throws Exception

*/

public void ouputFile(String ftlName, String fileName, Map map) throws Exception{

//创建fm的配置

Configuration config = new Configuration();

//指定默认编码格式

config.setDefaultEncoding("UTF-8");

//设置模板的包路径

config.setClassForTemplateLoading(this.getClass(), "/com/rl/ecps/ftl");

//获得包的模板

Template template = config.getTemplate(ftlName);

//指定文件输出的路径

String path = "X:\\Users\\ozc\\Desktop\\parent1\\portal\\src\\main\\webapp\\static";

//定义输出流,注意的必须指定编码

Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(path+"/"+fileName)),"UTF-8"));

//生成模板

template.process(map, writer);

}

}

测试

@Test

public void TestFreemarker() throws Exception {

EbItem ebItem = itemService.selectItemDetail((long) 3100);

Map map = new HashMap();

map.put("item", ebItem);

FMutil fMutil = new FMutil();

fMutil.ouputFile("productDetail.ftl", ebItem.getItemId() + ".html", map);

}

最终生成我们的静态页面:

AAffA0nNPuCLAAAAAElFTkSuQmCC

访问静态页面:

AAffA0nNPuCLAAAAAElFTkSuQmCC

发布静态页面

我们上边是通过test的方式来生成我们的静态页面的。明显地,我们生成静态页面就不是在portal进行处理的。应该是交由console来进行处理的。

那现在问题来了,怎么将console处理后的页面交由到portal中呢??

console和portal是属于两台不同的机器的(IP地址是不同的)。是在不同的工作目录下的。

由于IP地址不同,是两台不同的机器,我们就可以想到webservice!

由portal中发布服务,console进行调用,那么portal就能够有对应的静态页面了!

编写webService代码:

@WebService

public interface EbWSItemService {

public String publishItem(Long itemId, String password) throws Exception;

}

@Service

public class EbWSItemServiceImpl implements EbWSItemService {

@Autowired

private EbItemDao itemDao;

public String publishItem(Long itemId, String password) throws Exception {

String pass = ResourcesUtils.readProp("ws_pass");

if(StringUtils.equals(password, pass)){

EbItem item = itemDao.selectItemDetail(itemId);

Map map = new HashMap();

map.put("item", item);

FMutil fm = new FMutil();

fm.ouputFile("productDetail.ftl", item.getItemId()+".html", map);

return "success";

}else{

return "pass_error";

}

}

}

使用CXF框架将我们的webService服务在portal端发布:

cxf-servlet.xml配置文件:

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"

xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd

http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd

http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd

http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd">

portal端进行加载该配置文件:

org.springframework.web.context.ContextLoaderListener

contextConfigLocation

classpath*:beans.xml,classpath*:cxf-servlet.xml

cxf

org.apache.cxf.transport.servlet.CXFServlet

cxf

/services/*

当访问portal端的services的时候,就可以看到服务进行发出去了!

AAffA0nNPuCLAAAAAElFTkSuQmCC

使用IDEA的工具将WSDL地址转成是Java类

AAffA0nNPuCLAAAAAElFTkSuQmCC

得出这么一堆对象

AAffA0nNPuCLAAAAAElFTkSuQmCC

在service层调用这么一些对象(也就是portal发布的服务)

public String publishItem(Long itemId, String password) throws Exception {

EbWSItemServiceService itemServiceService = new EbWSItemServiceService();

EbWSItemService ebWSItemServicePort = itemServiceService.getEbWSItemServicePort();

return ebWSItemServicePort.publishItem(itemId, password);

}

controller调用service

@RequestMapping("/publishItem.do")

public void publishItem(Long itemId, PrintWriter out) throws Exception {

String password = ResourcesUtils.readProp("ws_pass");

String result = itemService.publishItem(itemId, password);

out.write(result);

}

前台时候ajax进行调用:

function publishItem(itemId) {

$.ajax({

url:"${path}/item/publishItem.do",

type:"post",

dataType:"text",

data:{

itemId:itemId

},

success:function(responseText){

if(responseText == "success"){

alert("发布成功");

}else{

alert("密码错误");

}

tipHide("#importLoadDiv");

},

error:function(){

alert("系统错误");

}

})

}

这样一来,console是调用portal发布的webservice程序。那么生成的静态页面就是portal上的。

总结

关联查询数据的时候,要想想如果有一张表没有数据时,另一张表的数据是否要查询出来。要使用外连接!

在获取后台数据的时候,可以在html中自定义属性来进行获取。很好用。

使用trigger方法能够用程序的方式来响应我们的事件

使用静态化页面能够减少对数据库的访问,浏览速度会大大加快

使用freemarker语法将JSTL的标签替换掉,再将后缀改成是ftl就行了。

使用工具类将模版渲染成html类型

由于前后端的分离,将模版渲染成html类型是在后端干的。但在访问的时候是在前台的工作目录上。

问题就是怎么将后台生成的html页面发送给前台

因为前台和后台的电脑是不一样的,IP地址也是不一样的。

要使用到webservice,webservice能够调用远程的服务。

在portal上发布远程的服务

console调用portal的服务,生成的数据就在portal上了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值