目录
[1.1 前端思路](#1.1 前端思路)
[1.2 后端思路](#1.2 后端思路)
[2.1 在网页中建好目录及菜单](#2.1 在网页中建好目录及菜单)
[2.1.1 建好商品目录](#2.1.1 建好商品目录)
[2.1.2 建好分类管理菜单](#2.1.2 建好分类管理菜单)
[2.2 编写组件](#2.2 编写组件)
[2.2.1 先完成组件文件的创建](#2.2.1 先完成组件文件的创建)
[2.2.2 编写组件](#2.2.2 编写组件)
[2.2.2.1 显示三级分类树形列表](#2.2.2.1 显示三级分类树形列表)
[3.1 编写商品分类的相关接口](#3.1 编写商品分类的相关接口)
[3.1.1 获取树形三级分类列表](#3.1.1 获取树形三级分类列表)
一、总述
就是在前端编写好相应的组件,展示内容,绑定好相关的事件,然后向后端发送请求,在后端编写好想要的接口,执行操作或者是返回前端想要的数据。
具体细节:
1.1 前端思路
前端组件的编写就参考elementUI进行编写,只需稍作修改即可。
前端组件的写法按照那三部分即可,模板、脚本、样式
发的请求依靠请求对象,在api文件夹中写好相应的api对象向后端发好请求,然后在组件中进行引入,发送请求即可
1.2 后端思路
基本上直接使用若依提供好的逆向代码,只需稍作修改即可。
编写好各层代码。
二、前端部分
2.1 在网页中建好目录及菜单
这个比较简单在页面中找到菜单管理新建一个目录即可,首先还不是着急创建菜单,而是创建好目录,一个目录即代表一个一个大的类别,其实也就是对应着后端的一个微服务。比如说商品服务,优惠卷服务啥的,为什么说是一个大的类别,因为商品中就有类别管理,品牌管理啥的,一些细的管理,这就作为前端的一个菜单出现了,而菜单其实就对应后端的一个控制器。一个菜单里面实际上就是对一张表或者是多张表做增删改查的。
说了总体的,其实就是新建一个目录代表商品服务。建的步骤如下:
2.1.1 建好商品目录
不会写的,就参考之前已经存在了的目录,就比如这个路由地址,有点模糊,就参考之前的,比如是之前的系统工具这个目录的路由地址写的就是tool,可以知道其实也就是目录的英文简写,那这个就叫product就行了,其他按钮部分基本上默认就行了。
2.1.2 建好分类管理菜单
同样也是参考之前写好的,创建好分类管理菜单
到目前为止页面的基本框架就有了,但是这个分类菜单缺少实际的内容。接下来就是到前端项目里面按照刚刚的路径创建好组件,并进行编写 1.2 在前端项目中编写前端组件
2.2 编写组件
2.2.1 先完成组件文件的创建
2.2.2 编写组件
2.2.2.1 显示三级分类树形列表
这里直接使用elementUI的树形组件
在elementUI官网中到组件中找到树形控件,在data一栏中可以找到
这里因为不单单的只是展示节点,还涉及到节点的新增以及删除,因此得在节点的后面自定义上内容,定义上新增和删除按钮,所以直接使用上
这个组件,这里我们使用scoped slot这个。
复制下面的样例代码,注意别复制多了,只复制需要的,然后打开运行前端项目就能有官网的那种效果了,当然还是需要作一些优化的,比如说复制下来的某些东西不需要,就比如说这里的
模板就保留这里:
XML
<el-tree
:data="data"
show-checkbox
node-key="id"
default-expand-all
:expand-on-click-node="false">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
<span>
<el-button
type="text"
size="mini"
@click="() => append(data)">
Append
</el-button>
<el-button
type="text"
size="mini"
@click="() => remove(node, data)">
Delete
</el-button>
</span>
</span>
</el-tree>
可能有人会问,为什么不用div盖着,其实这个并不是必要的,只是有个时候可能需要,需要的时候我们在添上即可。
脚本部分:
XML
<script>
let id = 1000;
export default {
data() {
const data = [{
id: 1,
label: '一级 1',
children: [{
id: 4,
label: '二级 1-1',
children: [{
id: 9,
label: '三级 1-1-1'
}, {
id: 10,
label: '三级 1-1-2'
}]
}]
}, {
id: 2,
label: '一级 2',
children: [{
id: 5,
label: '二级 2-1'
}, {
id: 6,
label: '二级 2-2'
}]
}, {
id: 3,
label: '一级 3',
children: [{
id: 7,
label: '二级 3-1'
}, {
id: 8,
label: '二级 3-2'
}]
}];
return {
data: JSON.parse(JSON.stringify(data)),
data: JSON.parse(JSON.stringify(data))
}
},
methods: {
append(data) {
const newChild = { id: id++, label: 'testtest', children: [] };
if (!data.children) {
this.$set(data, 'children', []);
}
data.children.push(newChild);
},
remove(node, data) {
const parent = node.parent;
const children = parent.data.children || parent.data;
const index = children.findIndex(d => d.id === data.id);
children.splice(index, 1);
}
}
};
</script>
这里的数据先留着,方便初看效果,下面的renderContent方法可以删掉,这是
样式部分一般不要动,保留即可:
XML
<style>
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
}
</style>
注意:这里除了对原有的内容进行删减之后,还需要优化一些内容,就比如说:
-
就结构而言,我是需要点击箭头才展开子节点。
-
就内容:append和delete按钮来说,append因为最多只有三级分类,所以如果当前分类的层级已经是三层了,不能添加这个append,对于delete,如果当前分类下面还有子分类的话,也不能添加delete。
具体实现如下:
其实完成这些操作,注意参考element的官方文档,对于它给我的这些数据,有什么可以使用控制台打印查看,对于一些你想要的操作这里比如说想点击箭头再展开这样的特殊操作,就需要查看文档下面的属性配置
所以:
经过上面的两处优化,基本上三级分类也就是这个样子了,现在只是数据不是我们的真实数据罢了。
接下来的工作就是:在前端工程中写好请求对象,用来请求后端获得三级分类的树形列表,然后在组件中引入,然后使用,得到数据,然后再参考文档,将数据正确显示出来即可。
- 在api文件夹中编写好请求对象
XML
export function treeListCategory() {
return request({
url: '/product/category/treeList',
method: 'get'
})
}
2, 在组件中引入并使用
现在是创建了一个方法,调用接口
其实很简单,就是前端写好树形控件基本的架子先搭起来,然后将数据换成经由调用后端接口返回的数据。步骤也是很简单。到这里网页已经是可以显示三级分类的分类列表了。
三、后端部分
3.1 编写商品分类的相关接口
3.1.1 获取树形三级分类列表
无论是前台页面还是后台管理页面都得将分类列表以子父的树形三级列表体现出来。
所以就得写一个接口获取到树形三级分类列表。
树形子父关系如何体现呢?貌似有点抽象,其实很简单,就是一个分类下面有许多的子分类,在面向对象的思想中就是分类的这个类中有一个类型为集合,集合元素为分类的子分类属性。
如下图所示:
注意: 非表的字段一定得加上@TabelField(exist = false)注解,来标明此字段是非表字段,如果不加这个注解,MyBatis字段映射的时候就会出问题,就比如说sql查了记录的所有字段,但是却找不到该字段,就会报错
好,现在字段是有了,最终肯定是需要为这个字段赋上值的,所有的子分类是计算出来的,那到底如何计算呢?其核心业务实现如何写?请看下面我写的:
其实很简单,就两步,其实获取子分类的关键就是 依靠表中的父类别字段。有了这一个就很容易得到一个类别的下的子类别。
第一步:编写获取子分类的方法(不带真正实现)。
遍历所有分类,为每个分类赋上子分类
第二步:编写获取子分类的具体实现
也就是根据当前分类的id,然后遍历所有的分类,找到它的子分类,其实也就是分类的父id为当前分类的id,那么这个分类就为当前分类的子分类
最关键的业务实现思路就有了,最关键最重要的一步其实已经想明白了,接下来就是常规的写好各个层的代码。我现在已经习惯逆向编写了,也就是从控制层开始写,一直写到dao层。话不多说,直接贴代码:
controller:
java
@ApiOperation("获取商品分类的树形结构")
@GetMapping("/treeList")
public AjaxResult treeList(){
List<Category> treeList = categoryService.treeList();
return AjaxResult.success(treeList);
}
service:
service接口:
service实现:
java
@Override
public List<Category> treeList() {
//获取到所有分类
List<Category> list = list();
//为每个分类添加上子分类
list.stream().forEach(category -> category.setChildren(getChildren(category,list)));
//为根父类排序
list.stream().sorted((c1,c2)->
c1 == null ? 0 : c1.getSort().intValue() - (c2 == null ? 0 : c2.getSort().intValue()));
return list;
}
java
private List<Category> getChildren(Category root, List<Category> all) {
//从所有类别中找到子分类,并排好序
List<Category> childrenCategory = all.stream().filter(c -> c.getParentCid().equals(root.getCatId())).sorted((c1,c2)->
c1 == null ? 0 : c1.getSort().intValue() - (c2 == null ? 0 : c2.getSort().intValue())
).collect(Collectors.toList());
//针对所有的子分类也递归找其对应的子分类
childrenCategory.stream().forEach(category -> category.setChildren(getChildren(category,childrenCategory)));
return childrenCategory;
}
这里由于是直接使用的MP,并且没有复杂查询,也就不需要直接显式的写dao层了
四、总结
其实从后端编写好接口,到前端编写好组件,整个过程还是比较简单的
在这里前端相较于后端而言反而要繁琐一点,后端主要把真正的获取逻辑写明白就好了
而前端就根据elememtUI的组件库选好组件,然后将参数写好,使得能正确的将数据渲染出来,还有一些其他的修改,优化一下就行了。
另外写好api,使得可以正确的访问后端,其实不难,但是繁琐,之后的功能实现大体都是这些步骤,主要就是核心组件不同,后端无非还是CURD。
这次相当于是Vue+Boot的开发,这是比较主流的开发方式,利用若依框架开发也是公司中常用的,因此需要熟练掌握。