目录
-
- 6.3 属性服务
- 6.4 规格参数
- 6.5 平台属性
- 6.6 新增商品
- 6.7 商品管理
- 6.8 仓储服务之仓库管理
- 7 分布式基础总结
6.3 属性服务
6.3.1 spu和sku
- SPU:Standard Product Unit(标准化产品单元)
是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。
iphoneX 是SPU、MI 8 是SPU
iphoneX 64G 黑曜石是SKU
MI8 8+64G+黑色是SKU
- SKU:Stock Keeping Unit(库存量单位)
即库存进出计量的基本单元,可以是以件,盒,托盘等为单位。SKU 这是对于大型连锁超市DC(配送中心)物流管理的一个必要的方法。现在已经被引申为产品统一编号的简称,每种产品均对应有唯一的SKU 号。
个人理解:
-
商品介绍、规格包装这些都是spu,每一个spu下的所有的sku都具备同样的属性。
-
颜色和内存都是销售属性,因为这个是决定每一个sku的不同的价格的。决定sku的属性我们叫做销售属性。每一个sku的商品介绍的图片和文字这些都是一样的。
-
基本属性就是指的主体中的型号或者是长度等。这些都是基本属性。
6.3.2 基本属性【规格参数】与销售属性
6.3.3 属性分组准备工作
如下图,这个是属性分组的效果展示。
1、前端组件
从老师给的课件资源中找到sys_menus.sql
,将其复制后,在数据库gulimall_admin中进行找到sys_menus这张表进行完善。即可出现。
注意这里有一个坑:就是看清楚sql文件中的语句是否和你数据库中对应的表的名称一样,否则不管运行多少次sql都不会生效。
- 在moudules下新建common/categroy.vue,这是一个公共组件,后面我们要引用他,即树形结构。这里我们可以直接将以前写过的category.vue复制,然后进行简单的删除即可。
<!-- -->
<template>
<el-tree :data="menus" :props="defaultProps" node-key="catId" ref="menuTree">
</el-tree>
</template>
<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';
export default {
//import引入的组件需要注入到对象中才能使用
components: {},
data() {
//这里存放数据
return {
menus: [],
expandedKey: [],
defaultProps: {
children: "children", //子节点
label: "name", //name属性作为标签的值,展示出来
},
};
},
//监听属性 类似于data概念
computed: {},
//监控data中的数据变化
watch: {},
//方法集合
methods: {
getMenus() {
this.$http({
url: this.$http.adornUrl("/product/category/list/tree"),
method: "get",
}).then(({ data }) => {
console.log("成功了获取到菜单数据....", data.data);
this.menus = data.data;
});
},
},
//生命周期 - 创建完成(可以访问当前this实例)
created() {
this.getMenus();
},
//生命周期 - 挂载完成(可以访问DOM元素)
mounted() {},
beforeCreate() {}, //生命周期 - 创建之前
beforeMount() {}, //生命周期 - 挂载之前
beforeUpdate() {}, //生命周期 - 更新之前
updated() {}, //生命周期 - 更新之后
beforeDestroy() {}, //生命周期 - 销毁之前
destroyed() {}, //生命周期 - 销毁完成
activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
};
</script>
<style scoped>
</style>
- 将逆向生成的前端代码复制到product下面。
- 在modules/product/下创建attgroup.vue组件
- 左侧6 用来显示菜单,右侧18用来显示表格
- 引入公共组件Category, AddOrUpdate
- 剩下的复制生成的
attrgroup.vue
<!-- -->
<template>
<el-row :gutter="20">
<el-col :span="6"><category></category></el-col>
<el-col :span="18"
><div class="mod-config">
<el-form
:inline="true"
:model="dataForm"
@keyup.enter.native="getDataList()"
>
<el-form-item>
<el-input
v-model="dataForm.key"
placeholder="参数名"
clearable
></el-input>
</el-form-item>
<el-form-item>
<el-button @click="getDataList()">查询</el-button>
<el-button
v-if="isAuth('product:attrgroup:save')"
type="primary"
@click="addOrUpdateHandle()"
>新增</el-button
>
<el-button
v-if="isAuth('product:attrgroup:delete')"
type="danger"
@click="deleteHandle()"
:disabled="dataListSelections.length <= 0"
>批量删除</el-button
>
</el-form-item>
</el-form>
<el-table
:data="dataList"
border
v-loading="dataListLoading"
@selection-change="selectionChangeHandle"
style="width: 100%"
>
<el-table-column
type="selection"
header-align="center"
align="center"
width="50"
>
</el-table-column>
<el-table-column
prop="attrGroupId"
header-align="center"
align="center"
label="分组id"
>
</el-table-column>
<el-table-column
prop="attrGroupName"
header-align="center"
align="center"
label="组名"
>
</el-table-column>
<el-table-column
prop="sort"
header-align="center"
align="center"
label="排序"
>
</el-table-column>
<el-table-column
prop="descript"
header-align="center"
align="center"
label="描述"
>
</el-table-column>
<el-table-column
prop="icon"
header-align="center"
align="center"
label="组图标"
>
</el-table-column>
<el-table-column
prop="catelogId"
header-align="center"
align="center"
label="所属分类id"
>
</el-table-column>
<el-table-column
fixed="right"
header-align="center"
align="center"
width="150"
label="操作"
>
<template slot-scope="scope">
<el-button
type="text"
size="small"
@click="addOrUpdateHandle(scope.row.attrGroupId)"
>修改</el-button
>
<el-button
type="text"
size="small"
@click="deleteHandle(scope.row.attrGroupId)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="sizeChangeHandle"
@current-change="currentChangeHandle"
:current-page="pageIndex"
:page-sizes="[10, 20, 50, 100]"
:page-size="pageSize"
:total="totalPage"
layout="total, sizes, prev, pager, next, jumper"
>
</el-pagination>
<!-- 弹窗, 新增 / 修改 -->
<add-or-update
v-if="addOrUpdateVisible"
ref="addOrUpdate"
@refreshDataList="getDataList"
></add-or-update></div
></el-col>
</el-row>
</template>
<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';
import Category from "../common/category.vue";
import AddOrUpdate from "./attrgroup-add-or-update.vue";
export default {
//import引入的组件需要注入到对象中才能使用
components: { Category, AddOrUpdate},
data() {
return {
dataForm: {
key: "",
},
dataList: [],
pageIndex: 1,
pageSize: 10,
totalPage: 0,
dataListLoading: false,
dataListSelections: [],
addOrUpdateVisible: false,
};
},
activated() {
this.getDataList();
},
methods: {
// 获取数据列表
getDataList() {
this.dataListLoading = true;
this.$http({
url: this.$http.adornUrl("/product/attrgroup/list"),
method: "get",
params: this.$http.adornParams({
page: this.pageIndex,
limit: this.pageSize,
key: this.dataForm.key,
}),
}).then(({ data }) => {
if (data && data.code === 0) {
this.dataList = data.page.list;
this.totalPage = data.page.totalCount;
} else {
this.dataList = [];
this.totalPage = 0;
}
this.dataListLoading = false;
});
},
// 每页数
sizeChangeHandle(val) {
this.pageSize = val;
this.pageIndex = 1;
this.getDataList();
},
// 当前页
currentChangeHandle(val) {
this.pageIndex = val;
this.getDataList();
},
// 多选
selectionChangeHandle(val) {
this.dataListSelections = val;
},
// 新增 / 修改
addOrUpdateHandle(id) {
this.addOrUpdateVisible = true;
this.$nextTick(() => {
this.$refs.addOrUpdate.init(id);
});
},
// 删除
deleteHandle(id) {
var ids = id
? [id]
: this.dataListSelections.map((item) => {
return item.attrGroupId;
});
this.$confirm(
`确定对[id=${ids.join(",")}]进行[${id ? "删除" : "批量删除"}]操作?`,
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
).then(() => {
this.$http({
url: this.$http.adornUrl("/product/attrgroup/delete"),
method: "post",
data: this.$http.adornData(ids, false),
}).then(({ data }) => {
if (data && data.code === 0) {
this.$message({
message: "操作成功",
type: "success",
duration: 1500,
onClose: () => {
this.getDataList();
},
});
} else {
this.$message.error(data.msg);
}
});
});
},
},
};
</script>
<style scoped>
</style>
踩坑:
Can't resolve './attrgroup-add-or-update' in 'C:\Users\hxld\Desktop\renren-fast-vue\src\views\modules\product'
解决办法:
原来是绝对路径,后面改为相对路径即可。错误原因是因为版本问题可能。
2、父子组件传递数据
我们要实现的功能是点击左侧,右侧表格对应显示。
父子组件传递数据:category.vue
点击时,引用它的attgroup.vue
能感知到, 然后通知到add-or-update。
- 子组件发送事件
-
在category.vue中的树形控件绑定点击事件@node-click=“nodeclick”
-
node-click方法中有三个参数(data, node, component),data表示当前数据,node为elementui封装的数据
-
点击之后向父组件发送事件:this.$emit(“tree-node-click”,…) …为参数
//组件绑定事件
<el-tree :data="menus" :props="defaultProps" node-key="catId" ref="menuTree" @node-click="nodeclick">
//methods中新增方法
nodeclick(data, node, component){
console.log("子组件categroy的节点被点击:", data,node,component);
this.$emit("tree-node-click", data,node,component); //向父组件发送tree-node-click事件
}
- 父组件接收事件
//引用的组件,可能会发散tree-node-click事件,当接收到时,触发父组件的treenodeclick方法
<category @tree-node-click="treenodeclick"></category>
//methods中新增treenodeclick方法,验证父组件是否接收到
treenodeclick(data, node, component){
console.log("attrgroup感知到category的节点被点击:",data, node, component);
console.log("刚才被点击的菜单Id", data.catId);
},
3、启动测试
6.3.4 获取分类属性分组
接口在线文档地址:https://easydoc.net/s/78237135/ZUqEdvA4/OXTgKobR
接口地址:/product/attrgroup/list/{catelogId}
@RequestParam:获取请求参数的值,和方法形参绑定,并自动赋值
@PathVariable:获取路径参数中的值,和方法形参绑定,并自动赋值
1、修改product下的controller
@RequestMapping("/list/{catelogId}")
public R list(@RequestParam Map<String, Object> params, @PathVariable Long catelogId){
//PageUtils page = attrGroupService.queryPage(params);
PageUtils page = attrGroupService.queryPage(params, catelogId);
return R.ok().put("page", page);
}
2、service新增接口,实现类新增方法
@Override
public PageUtils queryPage(Map<String, Object> params, Long catelogId) {
if (catelogId == 0){
//如果传过来的id是0,则查询所有属性
//this.page两个参数,第一个参数是查询页码信息,其中Query.getPage方法传入一个map,会自动封装成IPage
//第二个参数是查询条件,空的wapper就是查询全部
IPage<AttrGroupEntity> page = this.page(new Query<AttrGroupEntity>().getPage(params),
new QueryWrapper<AttrGroupEntity>());
return new PageUtils(page);
}else{
String key = (String) params.get("key");
QueryWrapper<AttrGroupEntity> wapper = new QueryWrapper<AttrGroupEntity>().eq("catelog_id", catelogId);
if (!StringUtils.isEmpty(key)){
wapper.and((obj)->{
obj.like("attr_group_name", key).or().eq("attr_group_id", key);
});
}
IPage<AttrGroupEntity> page = this.page(new Query<AttrGroupEntity>().getPage(params),
wapper);
return new PageUtils(page);
}
}
3、细节完善
我们不让一级和二级分类下,点击的时候也出现表格,只让三级分类的时候才出现相应的表格,所以我们可以设置一个判断。
修改前端代码
- 修改getDataList()中的请求路径
- data中新增
catId
,设置默认为0 - methods中修改点击方法
treenodeclick(data, node, component) {
//必须是三级分类,才显示属性
if (data.catLevel == 3){
this.catId = data.catId;
this.getDataList();
}
},
4、数据库中新增数据,进行测试。
6.3.5 属性分组新增功能
新增时,父id改换为选择框
1、新增选择框,添加菜单数据
-
我们发现可以选择分类,但是分类显示的是空白,这个是因为 显示的属性是label,通过props属性进行绑定
<!--v-model 绑定要提交的数据,options绑定选择菜单, props绑定选择框的参数--> <el-form-item label="所属分类id" prop="catelogId"> <el-cascader v-model="dataForm.catelogIds" :options="categroys" :props="props"></el-cascader> </el-form-item>
//data中新增属性,props用来绑定选择框的参数,categorys用来保存菜单 props:{ value:"catId", label:"name", children:"children" }, categroys:[], //方法中新增getCategorys(),用来获取选择菜单的值 getCategorys() { this.$http({ url: this.$http.adornUrl("/product/category/list/tree"), method: "get", }).then(({ data }) => { console.log("成功了获取到菜单数据....", data.data); this.categroys = data.data; }); }, //组件创建的时候就要获取菜单的值 created(){ this.getCategorys(); }
2、发现返回的数据,三级菜单下面也有children(为空)
- 解决方法:在CategoryEntity中设置相应的属性不为空既可。当children为空时,不返回children字段
在children字段上添加注解:当值为空时,不返回当前字段
3、修改之后仍然报错
原因是:el-cascader绑定的dataForm.catelogId
是一个数组,其中包含选择框的父节点id和自己的id。而我们要提交的只是他自己的id。
//修改data中的dataFrom
dataForm: {
attrGroupId: 0,
attrGroupName: "",
sort: "",
descript: "",
icon: "",
catelogIds: [], //保存父节点和子节点的id
catelogId: 0 //保存要提交的子节点的id
},
//修改表单提交方法,要传送的数据,只传最后一个子id
catelogId: this.dataForm.catelogIds[this.dataForm.catelogIds.length - 1],
6.3.6 修改回显分类功能
我们要设置选择进行修改的时候将原来本属于这个原信息回显出来。
1、前端 attrgroup-add-or-update.vue新增完整路径
init(id) {
this.dataForm.attrGroupId = id || 0;
this.visible = true;
this.$nextTick(() => {
this.$refs["dataForm"].resetFields();
if (this.dataForm.attrGroupId) {
this.$http({
url: this.$http.adornUrl(
`/product/attrgroup/info/${this.dataForm.attrGroupId}`
),
method: "get",
params: this.$http.adornParams(),
}).then(({ data }) => {
if (data && data.code === 0) {
this.dataForm.attrGroupName = data.attrGroup.attrGroupName;
this.dataForm.sort = data.attrGroup.sort;
this.dataForm.descript = data.attrGroup.descript;
this.dataForm.icon = data.attrGroup.icon;
this.dataForm.catelogId = data.attrGroup.catelogId;
//查出catelogId的完整路径
this.dataForm.catelogPath = data.attrGroup.catelogPath;
}
});
}
});
},
2、后端AttrGroupEntity
新增完整路径属性
@TableField(exist = false)
private Long[] catelogPath;
3、修改AttrGroupController
@Autowired
private CategoryService categoryService;
/**
* 信息
*/
@RequestMapping("/info/{attrGroupId}")
public R info(@PathVariable("attrGroupId") Long attrGroupId){
AttrGroupEntity attrGroup = attrGroupService.getById(attrGroupId);
Long catelogId = attrGroup.getCatelogId();
//根据id查询完整路径
Long[] path = categoryService.findCatelogPath(catelogId);
// 查询到的传入回去
attrGroup.setCatelogPath(path);
//返回
return R.ok().put("attrGroup", attrGroup);
}
4、修改categoryService以及categoryServiceImpl的方法,新增接口,实现方法
//categoryService接口
/*
*找到catelogId的完整路径
*/
Long[] findCatelogPath(Long catelogId);
//categoryServiceImpl实现方法
//查找完整路径方法
@Override
public Long[] findCatelogPath(Long catelogId) {
List<Long> paths = new ArrayList<>();
List<Long> parentPath = findParentPath(catelogId, paths);
// list.toArray list对象转换为数组对象
return parentPath.toArray(new Long[parentPath.size()]);
}
//递归查找父节点id
public List<Long> findParentPath(Long catelogId,List<Long> paths){
//1、收集当前节点id
CategoryEntity byId = this.getById(catelogId);
if (byId.getParentCid() != 0){
findParentPath(byId.getParentCid(), paths);
}
paths.add(catelogId);
return paths;
}
5、 attrgroup-add-or-update.vue 当对话框关闭时,清空数据,防止不合理回显
<el-dialog
:title="!dataForm.attrGroupId ? '新增' : '修改'"
:close-on-click-modal="false"
:visible.sync="visible"
@closed="dialogClose" //关闭时,绑定方法dialogClose
>
//新增方法
dialogClose(){
this.dataForm.catelogPath = [];
},
6、选择框加上搜索功能:filterable
, 显示提示信息placeholder="试试搜索:手机"
<el-cascader
placeholder="试试搜索:手机"
filterable
v-model="dataForm.catelogPath"
:options="categroys"
:props="props"
></el-cascader>
6.3.7 实现分页-引入插件
发现自动生成的分页条不好使,原因是没有引入mybatis-plus的分页插件。新建配置类,引入如下配置
1、新建mybatisplus配置文件,引入并配置分页插件
@Configuration
public class MybatisPlusConfig {
// 最新版
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
}
上面这个是最新版本的分页插件的配置信息。
下面这个是老师课件上的配置信息
@Configuration
@EnableTransactionManagement //开启事务
@MapperScan("com.atguigu.gulimall.product.dao")
public class MyBatisConfig {
//引入分页插件 显示页码
@Bean
public PaginationInterceptor paginationInterceptor(){
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
//设置请求的页面大于最大页后操作,true调回到首页,false继续请求,默认false
paginationInterceptor.setOverflow(true);
//设置最大单页限制数量,默认500条,-1不受限制
paginationInterceptor.setLimit(1000);
return paginationInterceptor;
}
}
6.3.8 关联分类
1、前端代码拷贝
这一部分前端代码我们直接将老师发的课件的全部复制到我们自己的renren-fast-vue文件夹下.
- 一个手机品牌下可能包含手机、电器等分类,同理手机分类下可能包含小米、华为等多个品牌,即品牌与分类之间是多对多的关系,表
pms_category_brand_relation
保存品牌与分类的多对多关系。
2、获取品牌关联的分类
根据传过来的brandId,查找所有的分类信息
CategoryBrandRelationController
/**
* 获取品牌关联的分类
*/
@GetMapping("/catelog/list")
public R catelogList(@RequestParam("brandId") Long brandId){
List<CategoryBrandRelationEntity> data = categoryBrandRelationService.list(
new QueryWrapper<CategoryBrandRelationEntity>().eq("brand_id", brandId)
);
return R.ok().put("data",data);
}
3、新增品牌与分类关联关系:
保存的时候,前端传过来brandid和categoryid,存储的时候还要存brandName和categoryName,所以在保存之前进行查找.
- CategoryBrandRelationController
/**
* 保存
*/
@RequestMapping("/save")
public R save(@RequestBody CategoryBrandRelationEntity categoryBrandRelation){
categoryBrandRelationService.saveDetail(categoryBrandRelation);
return R.ok();
}
- CategoryBrandRelationService
void saveDetail(CategoryBrandRelationEntity categoryBrandRelation);
- CategoryBrandRelationServiceImpl
@Override
public void saveDetail(CategoryBrandRelationEntity categoryBrandRelation) {
Long brandId = categoryBrandRelation.getBrandId();
Long catelogId = categoryBrandRelation.getCatelogId();
//查询详细名字和分类名字
BrandEntity brandEntity = brandDao.selectById(brandId);
CategoryEntity categoryEntity = categoryDao.selectById(catelogId);
categoryBrandRelation.setBrandName(brandEntity.getName());
categoryBrandRelation.setCatelogName(categoryEntity.getName());
this.save(categoryBrandRelation);
}
4、要对品牌(分类)名字进行修改时,品牌分类关系表之中的名字也要进行修改
- 品牌名字修改同时修改关系表数据
BrandController
@RequestMapping("/update")
//@RequiresPermissions("product:brand:update")
public R update(@Validated(value = {
UpdateGroup.class})@RequestBody BrandEntity brand){
brandService.updateByIdDetail(brand);
return R.ok();
}
brandServiceImpl
@Autowired
CategoryBrandRelationService categoryBrandRelationService;
@Transactional
@Override
public void updateByIdDetail(BrandEntity brand) {
//保证冗余字段的数据一致
this.updateById(brand);
if (!StringUtils.isEmpty(brand.getName())){
//如果修改了名字,则品牌分类关系表之中的名字也要修改
categoryBrandRelationService.updateBrand(brand.getBrandId(), brand.getName());
//TODO 更新其他关联
}
}
CategoryBrandRelationServiceImpl
@Override
public void updateBrand(Long brandId, String name) {
CategoryBrandRelationEntity categoryBrandRelationEntity = new CategoryBrandRelationEntity();
categoryBrandRelationEntity.setBrandName(name);
categoryBrandRelationEntity.setBrandId(brandId);
this.update(categoryBrandRelationEntity, new QueryWrapper<CategoryBrandRelationEntity>().eq("brand_id", brandId));
}
- 分类名字修改同时修改关系表数据
CategoryController
/**
* 修改
*/
@RequestMapping("/update")
//@RequiresPermissions("product:category:update")
public R update(@RequestBody CategoryEntity category){
categoryService.updateCascade(category);
return R.ok();
}
CategroyServiceImpl
@Autowired
CategoryBrandRelationService categoryBrandRelationService;
@Transactional
@Override
public void updateCascade(CategoryEntity category) {
this.updateById(category);
categoryBrandRelationService.updateCategory(category.getCatId(), category.getName());
}
CategoryBrandRelationDao
void updateCategroy(@Param("catId") Long catId,@Param("name") String name);
CateBrandRelationDao.xml
<update id="updateCategroy">
UPDATE `pms_category_brand_relation` SET catelog_name=#{name} WHERE catelog_id=#{catId}
</update>
6.4 规格参数
模糊查询全部
6.4.1 规格参数新增
1、流程梳理
-
规格参数新增时,请求的URL:Request URL:/product/attr/save 现在的情况是,它在保存的时候,只是保存了attr,并没有保存attrgroup,为了解决这个问题,我们新建了一个vo/AttrVo,在原AttrEntity基础上增加了attrGroupId字段,使得保存新增数据的时候,也保存了它们之间的关系。
通过" BeanUtils.copyProperties(attr,attrEntity);"能够实现在两个Bean之间拷贝数据,但是两个Bean的字段要相同
-
当有新增字段时,我们往往会在entity实体类中新建一个字段,并标注数据库中不存在该字段,然而这种方式并不规范。比较规范的做法是,新建一个vo文件夹,将每种不同的对象,按照它的功能进行了划分。
-
查看前端返回的数据,发现比数据库中的attr多了attrGroupId字段, 所以新建AttrVo
上面的保存的save方法只是逆向生成代码中最简单的,没有任何附加作用,所以我们进行修改。
2、创建Vo 包
@Data
public class AttrVo extends AttrEntity {
private Long attrGroupId;
}
3、修改AttrController
@RequestMapping("/save")
public R save(@RequestBody AttrVo attr){
attrService.saveAttr(attr);
return R.ok();
}
4、AttrServiceImpl
@Autowired
private AttrAttrgroupRelationDao attrAttrgroupRelationDao;
@Override
public void saveAttr(AttrVo attr) {
AttrEntity attrEntity = new AttrEntity();
//1.保存基本数据 保存attrEntity
//利用attr的属性给attrEntity的属性赋值,前提是他俩的属性名一致
BeanUtils.copyProperties(attr,attrEntity); //因为一个一个属性设置太麻烦了
this.save(attrEntity);
//2.保存关联关系 保存AttrGroupId信息
AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
relationEntity.setAttrGroupId(attr.getAttrGroupId());
relationEntity.setAttrId(attr.getAttrId());
attrAttrgroupRelationDao.insert(relationEntity);
}
5、知识点补充:
6.4.2 获取分类规格参数
1、新建AttrRespVo
@Data
public class AttrRespVo extends AttrVo {
private String catelogName;
private String groupName;
}
2、AttrController
@RequestMapping("/base/list/{catelogId}")
public R baseList(@RequestParam Map<String, Object> params, @PathVariable("catelogId") Long catelogId){
PageUtils page = attrService.queryBaseAttrPage(params, catelogId);
return R.ok().put("page", page);
}
3、AttrServiceImpl
@Autowired
private CategoryDao categoryDao;
@Autowired
private AttrGroupDao attrGroupDao;
@Override
public PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId) {
QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<>();
//模糊查询
if (catelogId != 0){
queryWrapper.eq("catelog_id", catelogId);
}
String key = (String) params.get("key");
if (!StringUtils.isEmpty(key)){
//attr_id attr_name
queryWrapper.and((wrapper) -> {
wrapper.eq("attr_id", key).or().like("attr_name", key);
});
}
IPage<AttrEntity> page = this.page(
new Query<AttrEntity>().getPage(params),
queryWrapper
);
//封装分页数据
PageUtils pageUtils = new PageUtils(page);
//查出新增的属性
List<AttrEntity> records = page.getRecords();
List<AttrRespVo> respVos = records.stream().map((attrEntity) -> {
AttrRespVo attrRespVo = new AttrRespVo();
BeanUtils.copyProperties(attrEntity, attrRespVo);
CategoryEntity categoryEntity = categoryDao.selectOne(new QueryWrapper<CategoryEntity>().eq("cat_id", attrEntity.getCatelogId()));
if (categoryEntity != null) {
attrRespVo.setCatelogName(categoryEntity.getName());
}
AttrAttrgroupRelationEntity attrgroupRelationEntity = attrAttrgroupRelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrEntity.getAttrId()));
if (attrgroupRelationEntity != null) {
AttrGroupEntity attrGroupEntity = attrGroupDao.selectOne(new QueryWrapper<AttrGroupEntity>().eq("attr_group_id", attrgroupRelationEntity.getAttrGroupId()));
attrRespVo.setGroupName(attrGroupEntity.getAttrGroupName());
}
return attrRespVo;
}).collect(Collectors.toList());
// 把新的数据传送过去
pageUtils.setList(respVos);
return pageUtils;
}
6.4.3 查询属性详情
1、修改AttrRespVo
@Data
public class AttrRespVo extends AttrVo {
private String catelogName;
private String groupName;
private Long[] catelogPath;
}
2、AttrController
@RequestMapping("/info/{attrId}")
public R info(@PathVariable("attrId") Long attrId){
AttrRespVo attrRespVo = attrService.getAttrInfo(attrId);
return R.ok().put("attr", attrRespVo);
}
3、AttrServiceImpl
@Override
public AttrRespVo getAttrInfo(Long attrId) {
AttrRespVo respVo = new AttrRespVo();
AttrEntity attrEntity = this.getById(attrId);
BeanUtils.copyProperties(attrEntity,respVo);
//1.设置分组信息
AttrAttrgroupRelationEntity attrAttrgroupRelation = attrAttrgroupRelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>()
.eq("attr_id", attrId));
if(attrAttrgroupRelation != null){
respVo.setAttrGroupId(attrAttrgroupRelation.getAttrGroupId());
AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrAttrgroupRelation.getAttrId());
if(attrGroupEntity!= null){
respVo.setGroupName(attrGroupEntity.getAttrGroupName());
}
}
//2.设置分类信息
Long catelogId = attrEntity.getCatelogId();
Long[] catelogPath = categoryService.findCatelogPath(catelogId);
respVo.setCatelogPath(catelogPath);
CategoryEntity categoryEntity = categoryDao.selectById(catelogId);
if(categoryEntity!=null){
respVo.setCatelogName(categoryEntity.getName());
}
return respVo;
}
4、未解决问题:
规格参数处不显示所属分组。数据库中已经修改。如下图:
所属分组修改成功,数据库中已经成功,但是页面不显示的问题?
目前暂时解决办法是在:规格参数那新增的时候选择到销售属性。在规格参数中新增的时候选择到销售属性即可。
6.4.4 修改属性
1、在AttrController中我们进行新增相应的方法
@RequestMapping("/update")
public R update(@RequestBody AttrVo attr){
attrService.updateAttr(attr);
return R.ok();
}
2、AttrServiceImpl
//保存时,要修改两张表 attr这张表和attrattrgroupRelationEntity这两个表
@Transactional
@Override
public void updateAttr(AttrVo attr) {
AttrEntity attrEntity = new AttrEntity();
BeanUtils.copyProperties(attr, attrEntity);
this.updateById(attrEntity);
AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
relationEntity.setAttrGroupId(attr.getAttrGroupId());
relationEntity.setAttrId(attr.getAttrId());
//判断是新增还是删除
Integer count = attrAttrgroupRelationDao.selectCount(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attr.getAttrId()));
if (count > 0){
attrAttrgroupRelationDao.update(relationEntity, new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attr.getAttrId()));
}else{
attrAttrgroupRelationDao.insert(relationEntity);
}
}
6.5 平台属性
6.5.1 获取分类销售属性
我们不难发现获取销售属性和规格参数的差别就是sale和base的区别,其他后面的都是差不多的,所以我们可以在路径变量中添加{attrType},使得同时用一个方法查询销售属性和规格参数。
**注意点:**销售属性,没有分组信息,所以我们在复用方法的时候要进行判断到底是销售属性还是规格参数。
1、AttrController
@RequestMapping("/{attrType}/list/{catelogId}")
public R baseList(@RequestParam Map<String, Object> params, @PathVariable("catelogId") Long catelogId,
@PathVariable("attrType") String attrType){
PageUtils page = attrService.queryBaseAttrPage(params, catelogId, attrType);
return R.ok().put("page", page);
}
2、AttrServiceImpl
@Override
public PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId, String attrType) {
QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>().eq("attr_type", "base".equalsIgnoreCase(attrType)?1:0);
if (catelogId != 0){
queryWrapper.eq("catelog_id", catelogId);
}
String key = (String) params.get("key");
if (!StringUtils.isEmpty(key)){
//attr_id attr_name
queryWrapper.and