前言
上一篇文章是我写这一系列文章的心路历程。这一篇我准备给大家看一下具体我是如何进行学习-开发的。那么就直接开始吧》》
内容
p53 视频 内容介绍
根据视频所讲,需要创建controller,service, mapper,映射文件,这些就需要自己按部就班的进行,因为我是依赖的mp,所以我需要先去创建数据库,再可以往下走流程,表的字段可以直接按照老师的来,我的流程是这样的,如下:
首先, 打开老师的资料数据库sql文件,这个网上都是有的,可以自己找一下。


根据以上字段可以自己参考,思考。
这里要注意id要选择自动递增,create_time默认CURRENT_TIMESTAMP,update_time默认CURRENT_TIMESTAMP,需要勾选根据当前时间戳更新,大家可以看下区别,这对之后写其他项目具有参考意义,页面显示如下:


完成以上表搭建之后,就可以insert数据了,这个数据同样在资料中,如下:

第二步, 准备写controller,service, mapper,映射文件,实体类,代码如下:
package com.atguigu.spzx.manager.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/admin/system/category")
public class CategoryController {
}
package com.atguigu.spzx.manager.service;
import com.atguigu.spzx.model.entity.system.Category;
import com.baomidou.mybatisplus.extension.service.IService;
public interface CategoryService extends IService<Category> {
}
package com.atguigu.spzx.manager.service.Impl;
import com.atguigu.spzx.manager.mapper.CategoryMapper;
import com.atguigu.spzx.manager.service.CategoryService;
import com.atguigu.spzx.model.entity.system.Category;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {
}
package com.atguigu.spzx.manager.mapper;
import com.atguigu.spzx.model.entity.system.Category;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface CategoryMapper extends BaseMapper<Category> {
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.spzx.manager.mapper.CategoryMapper">
</mapper>
第三步, 参照视频对前端代码进行处理,这里就按照视频走就可以了,这里不再过多进行解释。
有一个地方需要注意,就是我的admin用户是没有进行分配角色的,因为我在代码里面加了判断,如果是admin用户,就返回全菜单,相当于是超级管理员,有所有权限。代码如下:
@Override
public List<SysMenuDynamicVO> findMenusByUserId() {
SysUser sysUser = AuthContextUtil.get();
//判断是否是超级管理员
if (sysUser.getId().equals(1L)) {
//所有菜单显示
return buildMenus(findAllMenus());
}
List<SysRoleUser> sysRoleUsers = sysRoleUserMapper
.selectList(new LambdaQueryWrapper<SysRoleUser>()
.eq(SysRoleUser::getUserId, sysUser.getId())
.eq(SysRoleUser::getIsDeleted, 0));
if (CollectionUtils.isEmpty(sysRoleUsers)) {
throw new GuiguException(ResultCodeEnum.AUTH_FORBIDDEN_ROLE);
}
List<Long> roleIds = sysRoleUsers.stream().map(SysRoleUser::getRoleId).toList();
List<SysRoleMenu> sysRoleMenus = sysRoleMenuMapper
.selectList(new LambdaQueryWrapper<SysRoleMenu>()
.in(SysRoleMenu::getRoleId, roleIds)
.eq(SysRoleMenu::getIsDeleted, 0));
if (CollectionUtils.isEmpty(sysRoleMenus)) {
throw new GuiguException(ResultCodeEnum.AUTH_FORBIDDEN_MENU);
}
List<Long> menuIds = sysRoleMenus.stream().map(SysRoleMenu::getMenuId).distinct().toList();
List<SysMenu> sysMenus = sysMenuMapper.selectBatchIds(menuIds);
List<SysMenuVO> menuVOS = MenuHelper.buildTree(sysMenus);
return buildMenus(menuVOS);
}
/**
* 构建菜单
* @param menuVOS
* @return
*/
private List<SysMenuDynamicVO> buildMenus(List<SysMenuVO> menuVOS) {
List<SysMenuDynamicVO> list = new ArrayList<>();
for (SysMenuVO menuVO : menuVOS) {
SysMenuDynamicVO sysMenuDynamicVO = new SysMenuDynamicVO();
sysMenuDynamicVO.setTitle(menuVO.getTitle());
sysMenuDynamicVO.setName(menuVO.getComponent());
if (!CollectionUtils.isEmpty(menuVO.getChildren())) {
sysMenuDynamicVO.setChildren(buildMenus(menuVO.getChildren()));
}
list.add(sysMenuDynamicVO);
}
return list;
}
视频中的bug问题出现两个商品管理,此方法我的代码如上,与老师的不同,仅供参考。
页面最终显示:

p54 视频 内容介绍
一开始的表结构创建我因为创建过,可以直接跳过,进入前端页面的搭建,这个大致就是copy代码。
<template>
<div class="tools-div">
<el-button type="success" size="small" @click="exportData">导出</el-button>
<el-button type="primary" size="small" @click="importData">导入</el-button>
</div>
<el-dialog v-model="dialogImportVisible" title="导入" width="30%">
<el-form label-width="120px">
<el-form-item label="分类文件">
<el-upload
class="upload-demo"
action="http://localhost:8501/admin/product/category/importData"
:on-success="onUploadSuccess"
:headers="headers"
>
<el-button type="primary">上传</el-button>
</el-upload>
</el-form-item>
</el-form>
</el-dialog>
<!---懒加载的树形表格-->
<el-table
:data="list"
style="width: 100%"
row-key="id"
border
lazy
:load="fetchData"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<el-table-column prop="name" label="分类名称" />
<el-table-column prop="imageUrl" label="图标" #default="scope">
<img :src="scope.row.imageUrl" width="50" />
</el-table-column>
<el-table-column prop="orderNum" label="排序" />
<el-table-column prop="status" label="状态" #default="scope">
{{ scope.row.status == 1 ? '正常' : '停用' }}
</el-table-column>
<el-table-column prop="createTime" label="创建时间" />
</el-table>
</template>
<script setup>
import { ref , onMounted} from 'vue';
import { FindCategoryByParentId,ExportCategoryData } from '@/api/category.js'
import { ElMessage, ElMessageBox } from 'element-plus'
////////////////////////导入
import { useApp } from '@/pinia/modules/app'
// 文件上传相关变量以及方法定义
const dialogImportVisible = ref(false)
const headers = {
token: useApp().authorization.token // 从pinia中获取token,在进行文件上传的时候将token设置到请求头中
}
const importData = () => {
dialogImportVisible.value = true
}
// 上传文件成功以后要执行方法
const onUploadSuccess = async (response, file) => {
ElMessage.success('操作成功')
dialogImportVisible.value = false
const { data } = await FindCategoryByParentId(0)
list.value = data ;
}
///////////////////////////////////
// 定义list属性模型
const list = ref([])
// 页面初始化完毕以后请求后端接口查询数据
onMounted(async () => {
const {code , data , message} = await FindCategoryByParentId(0)
list.value = data ;
})
// 加载数据的方法
const fetchData = async (row, treeNode, resolve) => {
// 向后端发送请求获取数据
const {code , data , message} = await FindCategoryByParentId(row.id)
// 返回数据
resolve(data)
}
const exportData = () => {
// 调用 ExportCategoryData() 方法获取导出数据
ExportCategoryData().then(res => {
// 创建 Blob 对象,用于包含二进制数据
const blob = new Blob([res]);
// 创建 a 标签元素,并将 Blob 对象转换成 URL
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
// 设置下载文件的名称
link.download = '分类数据.xlsx';
// 模拟点击下载链接
link.click();
})
}
</script>
<style scoped>
.search-div {
margin-bottom: 10px;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
.tools-div {
margin: 10px 0;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
</style>
注意:这是资料里面已经完成的代码,在最初导入的时候,可能会有很多报错,因为很多方法等信息是没有的,可以暂时注释掉,我这里就不一步到位了,大家可以顺便自己理解下前端代码,把页面给完成。
页面呈现:

在写接口方法(根据父级id查询列表),我的方法跟老师的不一样,同时我用CategoryListVO对返回数据进行了封装,代码如下:
@Override
public List<CategoryListVO> findCategoryList(Long id) {
List<CategoryListVO> categoryListVOS = new ArrayList<>();
//根据id条件值进行查询,返回list集合
List<Category> categories = categoryMapper.selectList(new LambdaQueryWrapper<Category>()
.eq(id != null, Category::getParentId, id));
if (!CollectionUtils.isEmpty(categories)) {
//遍历返回list,判断是否为父节点,如果是,则设置hasChildren = true,如果不是,则返回false
categories.forEach(category -> {
CategoryListVO categoryListVO = new CategoryListVO();
BeanUtils.copyProperties(category, categoryListVO);
Integer count = categoryMapper.selectCount(new LambdaQueryWrapper<Category>()
.eq(Category::getParentId, category.getId()));
if (count > 0) {
categoryListVO.setHasChildren(true);
} else {
categoryListVO.setHasChildren(false);
}
categoryListVOS.add(categoryListVO);
});
}
return categoryListVOS;
}
//响应实体类
package com.atguigu.spzx.model.vo.product;
import com.atguigu.spzx.model.entity.product.Category;
import lombok.Data;
@Data
public class CategoryListVO extends Category {
private Boolean hasChildren;
}
页面展示:

结尾
这就是我想具体跟大家展示我是如何学习-开发这个项目的一些方法吧,按照自己的逻辑,利用好视频中的资源,这样更能写出适合自己的代码,如果这篇文章能够对你有帮助,可以点点赞,给个关注,谢谢~
本文介绍了作者在学习开发尚品甄选项目时,如何进行分类管理的步骤。从创建数据库表,设置字段,到编写controller、service、mapper和前端代码,详细展示了学习过程。特别提到了admin用户的权限处理以及解决视频中出现的问题。文章旨在分享个人学习方法,帮助读者更好地理解和应用教程内容。
1743





