- 一、商品服务-API-三级分类
- 1、三级分类
- 2、查出所有分类以及子分类
- 2、配置网关路由与路径重写
- 3、网关统一配置跨域
- 4、查询-树形展示三级分类数据
- 5、删除
- 6、新增
- 7、修改
- 8、修改拖拽效果
- 9、批量删除
一、商品服务-API-三级分类 1、三级分类商品服务-三级分类
- pms_category 表代表商品的分类
cat_id:分类id,cat代表分类,bigint(20) name:分类名称 parent_cid:在哪个父目录下 cat_level:分类层级 show_status:是否显示,用于逻辑删除 sort:同层级同父目录下显示顺序 ico图标,product_unit商品计量单位, InnoDB表,自增大小1437,utf编码,动态行格式2、查出所有分类以及子分类
1.在product服务的package com.ljn.gulimall.product.controller中打开CategoryController,添加方法:
@RestController
@RequestMapping("product/category")
public class CategoryController {
@Autowired
private CategoryService categoryService;
@RequestMapping("/list/tree")
public R list(){
List entities = categoryService.listWithTree();
return R.ok().put("data", entities);
}
2…在product服务的package com.ljn.gulimall.product.service;中打开CategoryService,添加方法:
public interface CategoryService extends IService{ PageUtils queryPage(Map params); List listWithTree(); }
3.在product服务的package com.ljn.gulimall.product.service.impl;中打开CategoryServiceImpl实现方法:
package com.ljn.gulimall.product.service.impl;
@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl implements CategoryService {
// 注入CategoryDao
@Autowired
CategoryDao categoryDao;
@Override
public PageUtils queryPage(Map params) {
IPage page = this.page(
new Query().getPage(params),
new QueryWrapper()
);
return new PageUtils(page);
}
// 实现方法
@Override
public List listWithTree() {
// 1.查出所有分类
List entities = categoryDao.selectList(null);
// 2.组装成父子的树形结构
// 2.1 找到所有一级分类,一级分类父id=0,并返回为一个集合
List Level1Menus = entities.stream().filter(categoryEntity -> {
// 一级分类
return categoryEntity.getParentCid() == 0;
}).map((menu) -> {
// 将查找到的子菜单放入
menu.setChildren(getChildrens(menu, entities));
return menu;
}).sorted((menu1, menu2) -> {
// 排序
return (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort());
}).collect(Collectors.toList());
return Level1Menus;
}
// 递归查找所有菜单的子菜单,root:当前菜单 all:所有菜单
private List getChildrens(CategoryEntity root, List all) {
// 从所有菜单中过滤出子菜单
List children = all.stream().filter(categoryEntity -> {
// 当前菜单的父ID=指定菜单的id 也就是判断在哪个父目录下
return categoryEntity.getParentCid().equals(root.getCatId());
}).map(categoryEntity -> {
// 当前菜单还可能有子菜单
categoryEntity.setChildren(getChildrens(categoryEntity, all));
return categoryEntity;
}).sorted((menu1, menu2) -> {
// 排序
return (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort());
}).collect(Collectors.toList());
return children;
}
}
4.结果
启动renren-fast 前后端项目:
-
点击系统管理,菜单管理,新增
刷新,看到左侧多了商品系统,添加的这个菜单其实是添加到了guli-admin.sys_menu表里. -
继续新增:分类维护菜单
在左侧点击【分类维护】,希望在此展示3级分类
注意地址栏http://localhost:8001/#/product-category 可以注意到product-category我们的/被替换为了-
比如sys-role具体的视图在renren-fast-vue/views/modules/sys/role.vue
- 所以要自定义我们的product/category视图的话,就是创建mudules/product/category.vue
网关88配置
- 在登录管理后台的时候,我们会发现,他要请求localhost:8080/renren-fast/product/category/list/tree这个url
- 他要给8080发请求读取数据,但是数据是在10000端口上,如果找到了这个请求改端口那改起来很麻烦。
- 方法1是改vue项目里的全局配置.
- 方法2是搭建个网关,让网关路由到10000(即将vue项目里的请求都给网关,网关经过url处理后,去nacos里找到管理后台的微服务,就可以找到对应的端口了,这样我们就无需管理端口,统一交给网关管理端口接口)
1.在vue项目的 static/config/index.js里修改
window.SITE_CONFIG['baseUrl'] = 'http://localhost:88/api'; // 意思是说本vue项目中要请求的资源url都发给88/api,那么我们就让网关端口为88,然后匹配到/api请求即可, // 网关可以通过过滤器处理url后指定给某个微服务 // renren-fast服务已经注册到了nacos中
刷新后需要重新登录,此时验证码不显示,因为此时验证码是请求88的,所以不显示。而验证码是来源于fast后台即8080端口的的。
解决:将renren-fast 注册到nacos注册中心,这样请求88网关转发到8080fast。
2.让fast里加入注册中心的依赖:
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
2.1.0.RELEASE
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
2.1.0.RELEASE
3.在renren-fast项目的application.yml中添加:
spring:
application:
name: renren-fast # 意思是把renren-fast项目也注册到nacos中,这样网关才能转发给
cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos
4.开启服务注册与发现
@EnableDiscoveryClient
@SpringBootApplication
public class RenrenApplication {
public static void main(String[] args) {
SpringApplication.run(RenrenApplication.class, args);
}
}
5.在gateway服务中按格式加入
- id: admin_route
# lb 代表负载均衡
uri: lb://renren-fast # 路由给renren-fast
predicates: # 什么情况下路由给它
- Path=/api*.xml
global-config:
db-config:
id-type: auto
logic-delete-value: 1
logic-not-delete-value: 0
- 修改product.entity.CategoryEntity实体类,添加上@TableLogic,表明使用逻辑删除
@TableLogic(value = "1",delval = "0") private Integer showStatus;
3、apifox测试请求
4、前端请求处理
发送的请求:delete
发送的数据:this.$http.adornData(ids, false)
util/httpRequest.js中,封装了一些拦截器
http.adornParams是封装get请求的数据
http.adornData封装post请求的数据
ajax的get请求会被缓存,就不会请求服务器了。
所以我们在url后面拼接个date时间戳,让他每次都请求服务器
- 发送请求
// 2. 删除分类的方法
remove(node, data) {
// 1. 获取当前节点id
var ids = [data.catId]
// 2. 发送请求前弹框提示
this.$confirm(`是否删除${data.name}菜单?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 3. 确认删除,发送post请求
this.$http({
url: this.$http.adornUrl('/product/category/delete'),
method: 'post',
data: this.$http.adornData(ids, false)
}).then(({ data }) => {
// 4. 删除成功提示消息
this.$message({
type: "success",
message: "菜单删除成功!",
});
// 5. 删除成功后重新请求菜单
this.getMenus();
// 6. 设置默认展开菜单
this.expandedKey=[node.parent.data.catId]
})
}).catch(() => {
});
console.log("delete", node, data)
},
- 删除后展开标准
6、新增data() { return { expandedKey: [], // 展开基准 }; },
- 点击append按钮的时候打开对话框
- 用到属性 visible.sync,动态绑定,:visible.sync="dialogVisible"
取 消
确 定
data() {
return {
dialogVisible: false, // 是否打开对话框,默认为false
};
},
methods: {
append(data) {
// 1. 点击append 按钮打开对话框
this.dialogVisible = true;
console.log("append", data)
},
- 对话框中添加表单
- 属性
取 消
确 定
- 定义添加菜单的方法addCategory,并在append方法中设置默认值
// 4. 添加三级分类的方法
addCategory() {
console.log("提交的三级分类数据", this.category)
// 1. 发送保存请求,提交
this.$http({
url: this.$http.adornUrl('/product/category/save'),
method: 'post',
data: this.$http.adornData(this.category, false) // 要发送的数据
}).then(({ data }) => {
// 2. 保存成功提示消息
this.$message({
type: "success",
message: "菜单保存成功!",
});
// 3. 保存成功后关闭对话框
this.dialogVisible = false;
// 4. 刷新出新菜单
this.getMenus();
// 5. 设置默认展示的菜单
this.expandedKey = [this.category.parentCid];
})
},
append(data) {
console.log("append", data)
// 1. 点击append 按钮打开对话框
this.dialogVisible = true;
// 2. 点击按钮为category获取默认值
// 2.1 父id,当前点击append的catId
this.category.parentCid = data.catId;
// 2.2 层级catLevel 当前点击append 的层级+1
this.category.catLevel = data.catLevel * 1 + 1;
},
7、修改
- 增加修改按钮edit
edit(node, data)">
Edit
methods: {
// 5. 点击修改分类按钮
edit(node, data){
// 显示对话框
this.dialogVisible=true;
// 回显数据
this.category.name=data.name;
console.log(node,data)
},
}
- 复用对话框
- 定义对话框类型:dialogType
- 修改对话框确认按钮绑定的事件:submitDate (提交数据)
- 根据对话框类型动态提交数据
- 修改完后,在append中清除回显信息
取 消
确 定


