1. 商品模块实现
1.1 业务分析
1.1.1 表设计
1.1.2 编辑POJO对象
/**
* @author 刘昱江
* 时间 2021/4/7
*/
@TableName("item")
@Data
@Accessors(chain = true)
public class Item extends BasePojo{
@TableId(type = IdType.AUTO)
private Integer id; //商品Id号
private String title; //商品标题信息
private String sellPoint; //卖点信息
private Integer price; //商品价格 扩大100倍 缩小100倍值不变
private Integer num; //商品数量
private String images; //商品图片
private Integer itemCatId; //商品分类ID号
private Boolean status; //状态信息 0 下架 1 上架
}
1.1.3 编辑Item的层级代码
1.1.4 实现前台页面跳转
页面效果展现:
1.2 商品列表展现
1.2.1 页面JS分析
1.生命周期函数
created() {
//1.获取商品列表数据
this.getItemList()
},
2.实现页面Ajax请求
//实现商品信息分页查询
async getItemList() {
const {
data: result
} = await this.$http.get("/item/getItemList", {
params: this.queryItemInfo
})
if (result.status !== 200) return this.$message.error("商品列表查询失败")
this.itemList = result.data.rows
this.total = result.data.total
},
1.2.2 业务接口说明
- 请求路径: /item/getItemList?query=&pageNum=1&pageSize=10
- 请求类型: get
- 请求参数: 使用pageResult对象接收
参数名称 | 参数说明 | 备注信息 |
---|---|---|
query | 用户查询的数据 | 可以为null |
pageNum | 分页查询的页数 | 必须赋值不能为null |
pageSize | 分页查询的条数 | 必须赋值不能为null |
- 返回值结果:
参数名称 | 参数说明 | 备注 |
---|---|---|
status | 状态信息 | 200表示服务器请求成功 201表示服务器异常 |
msg | 服务器返回的提示信息 | 可以为null |
data | 服务器返回的业务数据 | 商品分页对象 |
1.2.3 编辑ItemController
/**
* 需求: 查询商品列表 分页查询
* URL: /item/getItemList?query=&pageNum=1&pageSize=10
* 参数: pageResult
* 返回值: SysResult(pageResult)
*/
@GetMapping("/getItemList")
public SysResult getItemList(PageResult pageResult){//3
//参照user模块完成商品分页查询.
pageResult = itemService.getItemList(pageResult);//+2
return SysResult.success(pageResult);
}
1.2.4 编辑ItemService
/**
* 需求: 实现商品分页查询
* @param pageResult
* @return
*/
@Override
public PageResult getItemList(PageResult pageResult) {
IPage page = new Page(pageResult.getPageNum(),pageResult.getPageSize());
QueryWrapper<Item> queryWrapper = new QueryWrapper<>();
//判断条件: 用户传递query 则添加where条件
String query = pageResult.getQuery();
boolean flag = StringUtils.hasLength(query);
queryWrapper.like(flag,"title",query);
//page接口原来只有2个,经过分页查询之后,有四个结果
page = itemMapper.selectPage(page,queryWrapper);
long total = page.getTotal();
List<Item> rows = page.getRecords();
return pageResult.setTotal(total).setRows(rows);
}
1.2.5 页面效果展现
列宽度修改: 由于按钮显示不全,所以可以将width改为300px.
1.3 VUE过滤器用法
1.3.1 需求说明
说明: 需要将价格信息缩小100倍. 保留2位小数.
1.3.2 过滤器使用
1.3.3 过滤器定义
说明: 由于过滤器是全局变量,写在main.js中
/* 定义过滤器
1.参数: 将|左侧的数据,当作参数传递给函数.
2.返回值: 必须添加返回值!!!
Vue.filter("过滤器名称",过滤器动作函数(参数){
})
*/
Vue.filter("priceFormat",function(price){
return (price / 100).toFixed(2)
})
1.4 添加商品
1.4.1 商品新增页面跳转
当用户点击添加商品时,应该跳转到商品添加页面
2. 页面跳转
3. 页面效果展现
1.4.2 商品新增分析
1.点击按钮分析
<!-- 定义添加商品按钮-->
<el-button type="primary" class="addItemBtnClass" @click="addItemBtn">添加商品</el-button>
2.检查JS函数
/* 添加商品按钮 */
async addItemBtn(){
//console.log(this.addItemForm)
//1.完成表单校验
this.$refs.addItemFormRef.validate( valid => {
if(!valid) return this.$message.error("请输入商品必填项")
})
//2.完成商品参数的封装
//2.0 将商品价格扩大100倍
this.addItemForm.price = this.addItemForm.price * 100
//2.1 将商品图片的数据转化为字符串
this.addItemForm.images = this.addItemForm.images.join(",")
//2.5 实现商品数据提交
let submitAddItem = {
item : this.addItemForm,
itemDesc: this.itemDesc
}
console.log(submitAddItem)
let {data: result} = await this.$http.post("/item/saveItem",submitAddItem)
if(result.status !== 200) return this.$message.error("商品添加失败")
this.$message.success("商品添加成功")
//2.5添加完成之后,将数据重定向到商品展现页面
this.$router.push("/item")
}
1.4.3 业务接口说明
- 请求路径: http://localhost:8091/item/saveItem
- 请求类型: post
- 前端传递参数分析
{
item: {
images: "/2021/05/20/da0c1d4781c1499399f090da8b60f359.jpg,/2021/05/20/2ac1c34776a7465887eb019655354c3c.jpg"
itemCatId: 560
num: "100"
price: 718800
sellPoint: "【华为官方直供,至高12期免息0首付,原装正品】送华为原装无线充+运动蓝牙耳机+蓝牙音箱+三合一多功能数据线+钢化膜等!"
title: "华为P40 Pro 5G手机【12期免息可选送豪礼】全网通智能手机"
},
itemDesc: {
itemDesc: "<ul><li>品牌: <a href=https://list.jd.com/list.html"....... "
},
itemParam: {
dynamicArray: [
{paramId: 1, paramVals: "亮黑色,釉白色"},
{paramId: 2, paramVals: "8GB+128GB,8GB+256GB"}
],
staticArray: [
{"paramId": 3,"paramVals": "华为Mate 40 Pro"},
{"paramId": 4,"paramVals": "0.575kg"}.....
]
}
}
- 请求参数: 使用ItemVO对象接收
参数名称 | 参数类型 | 参数说明 | 备注 |
---|---|---|---|
item | Item | 商品基本信息对象封装 | 不能为null |
itemDesc | ItemDesc | 商品详情信息 | 不能为null |
itemParam | ItemParam | 商品参数信息 | 不能为null |
- ItemVO参数详解:
- Item对象
参数名称 | 参数类型 | 参数说明 | 备注 |
---|---|---|---|
title | String | 商品标题信息 | 不能为null |
sellPoint | String | 商品卖点信息 | 不能为null |
price | Integer | 商品价格信息 | 不能为null 需要将数据扩大100倍 |
num | Integer | 商品数量信息 | 不能为null |
images | String | 商品图片地址信息 | 不能为null |
itemCatId | Integer | 商品父级分类ID | 不能为null |
status | Boolean | 商品状态信息 | 不能为null |
- itemDesc 对象
-
为了降低商品提交代码的耦合性,将大字段信息详情,采用ItemDesc对象进行封装
参数名称 | 参数类型 | 参数说明 | 备注 |
---|---|---|---|
id | Integer | 商品Id信息 | 因为Item和ItemDesc是一对一关系 所以需要依赖Item对象的Id值 |
itemDesc | String | 商品详情信息 | 内部包含了大量的html语句 |
/**
* @author 刘昱江
* 时间 2021/4/16
*/
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class ItemVO { //该对象封装商品所有的参数信息
private Item item;
private ItemDesc itemDesc;
private ItemParam itemParam;
}
1.5 商品状态修改
1.5.1 业务分析
//1.修改按钮的JS
<el-table-column prop="status" label="状态" width="80px">
<template slot-scope="scope">
<el-switch v-model="scope.row.status" active-color="#13ce66" inactive-color="#ff4949"
@change="updateStatus(scope.row)"></el-switch>
</template>
</el-table-column>
async updateStatus(item) {
const {
data: result
} = await this.$http.put("/item/updateItemStatus", {
id: item.id,
status: item.status
})
if (result.status !== 200) return this.$message.error("更新状态失败")
this.$message.success("更新状态成功")
},
1.5.2 业务接口
- 请求路径: /item/updateItemStatus
- 请求类型: put
- 请求参数: 使用对象接收
参数名称 | 参数说明 | 备注 |
---|---|---|
id | 商品id | 不能为null |
status | 状态信息 | 不能为null |
- 返回值结果:
参数名称 | 参数说明 | 备注 |
---|---|---|
status | 状态信息 | 200表示服务器请求成功 201表示服务器异常 |
msg | 服务器返回的提示信息 | 可以为null |
data | 服务器返回的业务数据 | 可以为null |
1.5.3 编辑ItemController
/**
* 需求: 实现商品状态修改
* URL: /item/updateItemStatus
* 参数: {id,status} json串
* 返回值: SysResult
* 问题: 什么时候使用restFul,什么时候使用get/put/delete请求方式?
*
*/
@PutMapping("/updateItemStatus")
public SysResult updateStatus(@RequestBody Item item){
itemService.updateStatus(item);
return SysResult.success();
}
1.5.4 编辑ItemService
@Override
public void updateStatus(Item item) {
itemMapper.updateById(item);
}
1.6 商品详情说明
1.6.1 业务说明
说明: Item中存储的是商品的基本信息,通常用于检索,或者数据展现. itemDesc一般存储的都是商品的详情信息. 为了用户的检索效率更好,所以一般先查询item数据,(itemDesc一般采用大字段的形式,存储html代码的片段).
要求: 一个商品对应一个详情信息, 所以 item和itemDesc一对一
一个商品对应一个详情
一个详情对应一个商品
隐藏属性: item.id = itemDesc.id
补充知识: 数据库中常见对应关系
一对一: 老婆和老公(通常)
一对多: 老公和情人
多对多: 老师和学生
一个老师对应多个学生
一个学生对应多个老师
1.6.2 表设计
1.6.3 编辑ItemDesc
1.6.4 重构ItemServiceImpl
//实现商品入库操作
@Override
@Transactional
public void saveItem(ItemVO itemVO) {
//item 主键自增 数据库入库之后,才会有主键!!!
Item item = itemVO.getItem();
item.setStatus(true);
itemMapper.insert(item);
//问题: 入库之后才有ID,现阶段item.id=null
//mybatis实现业务功能,自动回显主键!!!
//MP自动的将主键的回显功能实现!!!
//规则: itemId与ItemDescId是一样的.
ItemDesc itemDesc = itemVO.getItemDesc();
itemDesc.setId(item.getId());
itemDescMapper.insert(itemDesc);
}
1.7 富文本编辑器
说明: 使用富文本编辑器,可以得到 “所见即所得”
用法:
- 引入JS
/* 导入富文本编辑器 */ import VueQuillEditor from 'vue-quill-editor' /* 导入富文本编辑器对应的样式 */ import 'quill/dist/quill.core.css' // import styles import 'quill/dist/quill.snow.css' // for snow theme import 'quill/dist/quill.bubble.css' // for bubble theme
- 页面展现
<!-- 定义富文本编辑器--> <quill-editor ref="myQuillEditor" v-model="itemDesc.itemDesc"> </quill-editor>
注意事项: 图片/视频默认转化为01字节信息,并且以16进制的方式展现.
3.页面效果
2 关于数据库主外键说明
说明:
1. 数据库提供了主外键的约束关系, 操作数据时必须严格的遵守.但是如果添加了主键/外键,则必然会影响执行的效率. 所以一般主键和外键的约束由程序员通过代码进行控制.
2. 一般项目中 很少直接定义主键/外键.