尚品甄选-学习-开发之分类管理

本文介绍了作者在学习开发尚品甄选项目时,如何进行分类管理的步骤。从创建数据库表,设置字段,到编写controller、service、mapper和前端代码,详细展示了学习过程。特别提到了admin用户的权限处理以及解决视频中出现的问题。文章旨在分享个人学习方法,帮助读者更好地理解和应用教程内容。

前言

上一篇文章是我写这一系列文章的心路历程。这一篇我准备给大家看一下具体我是如何进行学习-开发的。那么就直接开始吧》》

内容

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;
}

页面展示:

结尾

这就是我想具体跟大家展示我是如何学习-开发这个项目的一些方法吧,按照自己的逻辑,利用好视频中的资源,这样更能写出适合自己的代码,如果这篇文章能够对你有帮助,可以点点赞,给个关注,谢谢~

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值