3.商品规格参数
[taotao]-商品规格参数
1.商品规格概念
(1)规格参数
规格组
|-规格项:规格值
# 其具备如下规律
1.同一类商品的规格项分组相同
2.同一类商品的规格项目是相同的,规格项目是跟商品关联
3.不同商品规格参数的值是不同的
(2)实现方案
方案1:使用多个表存储
每一类商品有多个分组
每个分组下有多个项
每个商品对应不同的规格参数
使用二维数组维护规格数据
- 表一:规格组信息
列名 | 类型 | 长度 | 可以null | 键 | 说明 |
---|---|---|---|---|---|
Id | Int | 否 | P | 主键(自增长) | |
group_name | varchar | 20 | 否 | 规格分组名称 | |
item_cat_id | Int | 否 | F | 商品分类id(外键) |
- 表二:规格项信息
列名 | 类型 | 长度 | 可以null | 键 | 说明 |
---|---|---|---|---|---|
Id | Int | 否 | P | 主键(自增长) | |
param_name | varchar | 20 | 否 | 规格项目名称 | |
group_id | Int | 否 | F | 规格分组id(外键) |
- 表三:商品规格信息
列名 | 类型 | 长度 | 可以null | 键 | 说明 |
---|---|---|---|---|---|
item_id | Int | 否 | P | 商品id(联合主键) | |
param_id | varchar | 否 | P | 规格项id(联合主键) | |
param_value | varchar | 500 | 否 | 规格信息 |
# sql语句
SELECT
pg.group_name,pk.param_name,pv.param_value
FROM
tb_item_param_value pv
LEFT JOIN tb_item_param_key pk ON pv.param_id = pk.id
LEFT JOIN tb_item_param_group pg ON pk.group_id = pg.id
WHERE
item_id = 855739
存在问题
需要创建多张表来描述规格参数之间的关系
查询时需要复杂的sql语句查询
规格参数数据量是商品信息的几十倍,数据量十分庞大,查询时效率很低
如果要求新添加的商品规格项发生改变,之前的商品不变是不能实现的
方案2:使用模板进行管理
可以使用模板的思路来解决此问题,抽离商品公共的信息,每一个商品分类对一个规格参数模板
[
{
"group": "主体", //组名称
"params": [ // 记录规格成员
"品牌",
"型号",
"颜色",
"上市年份",
"上市月份"
]
},
{
"group": "网络", //组名称
"params": [ // 记录规格成员
"4G",
"3G,
"2G"
]
}
]
模板使用
每个商品对应一唯一的规格参数。在添加商品时,可以根据规格参数的模板生成一个表单。在保存规格参数时还可以生成规格参数的json数据并将其保存到数据库中
[
{
"group": "主体",
"params": [
{
"k": "品牌",
"v": "苹果(Apple)"
},
{
"k": "型号",
"v": "iPhone 6 A1589"
},
{
"k": "智能机",
"v": "是 "
}
]
}
]
实现流程
数据库存储:规格参数模板表、商品规格参数表
基于模板的方式实现需要借助表单和json之间的转换,对js的编写要求较高,但这种方案不需要做多表管理,且当新添加的商品规格项发生改变之后还是可以依据模板观念完成商品参数信息绑定,较易扩展
2.规格参数模板
(1)创建规格参数模板
🔖选择商品分类
需求分析:判断模板是否存在
请求的url:
/item/param/query/itemcatid/
参数:itemCatId,从url中获得
返回值:TaotaoResult
dao层
从tb_item_param表中根据商品分类id查询内容(单表操作,可以实现逆向工程的代码)
service层
功能:接收商品分类id。调用mapper查询tb_item_param表,返回结果TaotaoResult
@Service
public class ItemParamServiceImpl implements ItemParamService {
@Autowired
private TbItemParamMapper itemParamMapper;
@Override
public TaotaoResult getItemParamByCid(long cid) {
TbItemParamExample example = new TbItemParamExample();
Criteria criteria = example.createCriteria();
criteria.andItemCatIdEqualTo(cid);
List<TbItemParam> list = itemParamMapper.selectByExample(example);
//判断是否查询到结果
if (list != null && list.size() > 0) {
return TaotaoResult.ok(list.get(0));
}
return TaotaoResult.ok();
}
}
controller层
接收cid参数。调用Service查询规格参数模板。返回TaotaoResult对应json数据
@Controller
@RequestMapping("/item/param")
public class ItemParamController {
@Autowired
private ItemParamService itemParamService;
@RequestMapping("/query/itemcatid/{itemCatId}")
@ResponseBody
public TaotaoResult getItemParamByCid(@PathVariable Long itemCatId) {
TaotaoResult result = itemParamService.getItemParamByCid(itemCatId);
return result;
}
}
JSP
🔖提交规格参数模板
需求分析:提交规格参数模板信息
请求的url:/item/param/save/
请求的参数:Long cid、String paramData
返回值:TaotaoResult
dao层
向tb_item_param表中插入记录,使用逆向工程代码
service层
接收参数:cid、paramData两个参数,创建一个tb_item_param表对应的pojo对象。设置好对象中的属性。调用insert方法,添加一条记录。结果返回TaotaoResult
@Override
public TaotaoResult insertItemParam(Long cid, String paramData) {
//创建一个pojo
TbItemParam itemParam = new TbItemParam();
itemParam.setItemCatId(cid);
itemParam.setParamData(paramData);
itemParam.setCreated(new Date());
itemParam.setUpdated(new Date());
//插入记录
itemParamMapper.insert(itemParam);
return TaotaoResult.ok();
}
controller层
接收两个参数,从url中取cid、从参数中取 paramData。调用Service插入记录,返回TaotaoResult(json数据),需要使用@ResourceBody
@RequestMapping("/save/{cid}")
@ResponseBody
public TaotaoResult insertItemParam(@PathVariable Long cid, String paramData) {
TaotaoResult result = itemParamService.insertItemParam(cid, paramData);
return result;
}
⚡规格模板提交测试
参数说明
提交格式
(2)使用规格参数模板
规格参数模板使用
在商品添加或者商品修改时,根据商品的分类id查询此商品分类对应的规格参数模板。根据规格参数模板,生成一个表单供用户使用
展示规格参数表单:
请求的url:/item/param/query/itemcatid/
在common.js中查看相关的信息
❓可能存在问题
测试的时候发现,针对已有规格参数的商品分类,却没有显示其对应的参数模板,通过F12窗口查看相关信息,接口访问成功,但实际上接口的部分数据却没有封装到返回结果中,控制台输出查找也没有相关的数据,此处将service层查找做了如下调整,此时能够正常查找数据,原因分析:使用mybatis逆向工程生成的dao层代码,在单表查询的时候没有仔细关注每个接口的实际应用,此处出了问题一步步回退查找出错点,发现是使用的接口方法并没有将大字段的paramData检索出来,从而导致数据没有封装,页面获取和显示的数据paramData为null,此处需要参考“MyBatis中selectByExample
与selectByExampleWithBLOBs
”代码区别
ResultMapWithBLOBs 定义时,继承了BaseResultMap,并且自己特殊的字段,该字段通常是longvarchar类型,本例中content就为特殊字段。
content字段类型为text。故如需检索的字段中包含大字段类型时,必须用selectByExampleWithBLOBs,不检索大字段时,用selectByExample就足够了。update的相关用法同样如此。
ResultMapWithBLOBs映射类型是在继承BaseResultMap的基础上对应配置另一个字段paramData,因此如果仅仅只是通过selectByExample查找,其返回的数据类型是BaseResultMap,不会检索大字段paramData,如此设计也是为了减轻数据访问压力
最终测试结果
规格参数提交
需求分析
在商品表单提交之前,先把规格参数的信息,转换成json数据。把json提交到后台插入到表中即可
- 规格模板数据格式
[
{
"group": "主体", //组名称
"params": [ // 记录规格成员
"品牌",
"型号",
"颜色",
"上市年份",
"上市月份"
]
},
{
"group": "网络", //组名称
"params": [ // 记录规格成员
"4G",
"3G,
"2G"]
}
]
- 生成规格数据格式
[
{
"group": "主体",
"params": [
{
"k": "品牌",
"v": "苹果(Apple)"
},
{
"k": "型号",
"v": "iPhone 6 A1589"
},
{
"k": "智能机",
"v": "是"
}
]
}
]
- 生成规格参数json字符串的处理
只需要在Controller中添加一个参数,接收商品的规格参数即可,Service中也需要添加一个参数,增加插入规格参数表的处理
service层
controller层
添加一个接收商品规格参数的形参,完成规格参数的传入
规格参数展示
需求分析
从表中把规格参数json数据取处理,可以在java代码中解析json数据生成html展示到jsp页面。
根据商品id查询规格参数
请求的url:/item/
返回结果:String(逻辑视图)
dao层
单表查询,可以使用逆向工程
service层
接收商品id,根据商品id取规格参数。可以把json转换成java对象。遍历java对象,生成html,返回。
参数:商品id
返回值:字符串(html片段)
@Override
public String getItemParamHtml(Long itemId) {
// 根据商品id查询规格参数
TbItemParamItemExample example = new TbItemParamItemExample();
com.taotao.pojo.TbItemParamItemExample.Criteria criteria = example.createCriteria();
criteria.andItemIdEqualTo(itemId);
// 执行查询
// List<TbItemParamItem> list = itemParamItemMapper.selectByExample(example);
List<TbItemParamItem> list = itemParamItemMapper.selectByExampleWithBLOBs(example);
if (list == null || list.isEmpty()) {
return "";
}
// 取规格参数
TbItemParamItem itemParamItem = list.get(0);
// 获取json数据
String paramData = itemParamItem.getParamData();
// 将json数据转换成java对象
List<Map> mapList = JsonUtils.jsonToList(paramData, Map.class);
// 遍历list生成html
StringBuffer sb = new StringBuffer();
sb.append("<table cellpadding=\"0\" cellspacing=\"1\" width=\"100%\" border=\"1\" class=\"Ptable\">\n");
sb.append(" <tbody>\n");
for (Map map : mapList) {
sb.append(" <tr>\n");
sb.append(" <th class=\"tdTitle\" colspan=\"2\">" + map.get("group") + "</th>\n");
sb.append(" </tr>\n");
// 取规格项
List<Map> mapList2 = (List<Map>) map.get("params");
for (Map map2 : mapList2) {
sb.append(" <tr>\n");
sb.append(" <td class=\"tdTitle\">" + map2.get("k") + "</td>\n");
sb.append(" <td>" + map2.get("v") + "</td>\n");
sb.append(" </tr>\n");
}
}
sb.append(" </tbody>\n");
sb.append("</table>");
return sb.toString();
}
- 模板生成说明
在某个网站中选择模板,右键选择“检查”查看源代码,提取相关属性,封装数据
字符转义技巧:可以通过mysql中查询编辑器完成转义,选中复制的代码,在编辑器中点击右键,选择“含引号复制”-->“JAVA/C#”,完成转义
controller层
接收商品id,调用Service查询规格参数,返回html片段。把html片段传递给jsp。
参数:商品id、Model
@RequestMapping("/page/item/{itemId}")
public String showItemParam(@PathVariable Long itemId, Model model) {
String html = itemService.getItemParamHtml(itemId);
model.addAttribute("myhtml", html);
return"itemparam";
}
创建jsp测试:controller层如果传入html,则可能存在于jsp内置属性冲突,导致出错,最好命名不要有冲突
访问连接测试:
http://localhost:8080/page/item/154684383340439