实现分类管理功能

分类表的设计
drop table if exists `category`;
create table `category`
(
    `id`     bigint      not null comment 'id',
    `parent` bigint      not null default 0 comment '父id',
    `name`   varchar(50) not null comment '名称',
    `sort`   int comment '顺序',
    primary key (`id`)
) engine=innodb default charset=utf8mb4 comment='分类';

insert into category values(100,000,'前端开发',100),(101,100,'Vue',101),(102,100,'HTML&CSS',102);
insert into category values(200,000,'Java',200),(201,200,'基础应用',201),(202,200,'框架应用',202);
insert into category values(300,000,'Python',300),(301,300,'基础应用',301),(302,300,'进阶方向应用',302);
insert into category values(400,000,'数据库',400),(401,400,'MySQL',401);
insert into category values(500,000,'其他',500),(501,500,'服务器',501),(502,500,'开发工具',502),(503,500,'热门服务器语言',503);
后端代码实现
MyBatis生成Model实体类文件、Mapper接口文件和Mapper XML配置文件

generatorConfig.xml如下,

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>

    <context id="Mysql" targetRuntime="MyBatis3">
        <commentGenerator>
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/test-database"
                        userId="test-user"
                        password="test@123">
        </jdbcConnection>

        <javaModelGenerator targetPackage="com.jepcc.test.model" targetProject="src\main\java">
        </javaModelGenerator>

        <sqlMapGenerator targetPackage="mapper"  targetProject="src\main\resources">
        </sqlMapGenerator>

        <javaClientGenerator type="XMLMAPPER" targetPackage="com.jepcc.test.mapper"  targetProject="src\main\java">
        </javaClientGenerator>

<!--        <table tableName="ebook" domainObjectName="Ebook" ></table>-->
        <table tableName="category" domainObjectName="Category" ></table>

    </context>
</generatorConfiguration>

执行命令mybatis-generator:generate -e,生成如下文件:

  • Model实体类文件: com.jepcc.test.model.Categorycom.jepcc.test.model.CategoryExample
  • Mapper接口文件:com.jepcc.test.mapper.CategoryMapper
  • Mapper XML配置文件:src/main/resources/mapper/CategoryMapper.xml
添加controller层和service层代码
//com.jepcc.test.controller.CategoryController
package com.jepcc.test.controller;

import com.jepcc.test.req.CategoryReq;
import com.jepcc.test.req.CategorySaveReq;
import com.jepcc.test.resp.CategoryResp;
import com.jepcc.test.resp.CommonResp;
import com.jepcc.test.resp.PageResp;
import com.jepcc.test.service.CategoryService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

@RestController
@RequestMapping("/category")
public class CategoryController {
    private final static Logger LOG = LoggerFactory.getLogger(CategoryController.class);
    @Resource
    private CategoryService categoryService;

    @GetMapping("/all")
    public CommonResp all(){
        CommonResp resp = new CommonResp();
        List<CategoryResp> list = categoryService.all();
        resp.setContent(list);
        return resp;
    }
    @GetMapping("/list")
    public CommonResp list(CategoryReq req){
        CommonResp resp = new CommonResp();
        PageResp<CategoryResp> list = categoryService.list(req);
        resp.setContent(list);
        return resp;
    }

    @PostMapping("/save")
    public CommonResp save(@RequestBody CategorySaveReq req){
        CommonResp resp = new CommonResp();
        categoryService.save(req);
        return resp;
    }

    @DeleteMapping("/delete/{id}")
    public CommonResp delete(@PathVariable long id){
        CommonResp resp = new CommonResp();
        categoryService.delete(id);
        return resp;
    }
}
//com.jepcc.test.service.CategoryService
package com.jepcc.test.service;


import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jepcc.test.mapper.CategoryMapper;
import com.jepcc.test.model.Category;
import com.jepcc.test.model.CategoryExample;
import com.jepcc.test.req.CategoryReq;
import com.jepcc.test.req.CategorySaveReq;
import com.jepcc.test.resp.CategoryResp;
import com.jepcc.test.resp.PageResp;
import com.jepcc.test.util.CopyUtil;
import com.jepcc.test.util.SnowFlake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.List;

@Service
public class CategoryService {
    @Resource
    private CategoryMapper categoryMapper;
    @Resource
    private SnowFlake snowFlake;
    private static final Logger LOG = LoggerFactory.getLogger(CategoryService.class);
    public List<CategoryResp> all(){
        CategoryExample categoryExample = new CategoryExample();
        //按照sort字段asc排序
        categoryExample.setOrderByClause("sort asc");

        List<Category> list = categoryMapper.selectByExample(categoryExample);
        List<CategoryResp> result = CopyUtil.copyList(list,CategoryResp.class);

        return result;
    }

    public PageResp<CategoryResp> list(CategoryReq req){

        CategoryExample categoryExample = new CategoryExample();
        CategoryExample.Criteria criteria = categoryExample.or();
        if(!ObjectUtils.isEmpty(req.getName())){
            criteria.andNameLike("%"+req.getName()+"%");
        }
        PageHelper.startPage(req.getPage(),req.getSize());

        List<Category> list = categoryMapper.selectByExample(categoryExample);

        PageInfo<Category> pageInfo = new PageInfo<>(list);

        List<CategoryResp> result = CopyUtil.copyList(list,CategoryResp.class);

        PageResp<CategoryResp> pageResp = new PageResp<>();
        pageResp.setTotal(pageInfo.getTotal());
        pageResp.setList(result);
        return pageResp;

    }

    public void save(CategorySaveReq req){
        Category category = CopyUtil.copy(req,Category.class);
        if(!ObjectUtils.isEmpty(category.getId())){
//            更新
            categoryMapper.updateByPrimaryKey(category);
        }else{
//            插入
            category.setId(snowFlake.nextId());
            categoryMapper.insert(category);
        }

    }

    public void delete(long id){
        categoryMapper.deleteByPrimaryKey(id);
    }
}

还新添加了一些请求类和响应类。

//com.jepcc.test.req.CategoryReq
package com.jepcc.test.req;

public class CategoryReq extends PageReq{
    private Long id;

    private Long parent;

    private String name;

    private Integer sort;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    public Long getParent() {
        return parent;
    }

    public void setParent(Long parent) {
        this.parent = parent;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getSort() {
        return sort;
    }

    public void setSort(Integer sort) {
        this.sort = sort;
    }
}
//com.jepcc.test.req.CategorySaveReq
package com.jepcc.test.req;

public class CategorySaveReq {
    private Long id;

    private Long parent;

    private String name;

    private Integer sort;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    public Long getParent() {
        return parent;
    }

    public void setParent(Long parent) {
        this.parent = parent;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getSort() {
        return sort;
    }

    public void setSort(Integer sort) {
        this.sort = sort;
    }
}
//com.jepcc.test.resp.CategoryResp
package com.jepcc.test.resp;

public class CategoryResp {
    private Long id;

    private Long parent;

    private String name;

    private Integer sort;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    public Long getParent() {
        return parent;
    }

    public void setParent(Long parent) {
        this.parent = parent;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getSort() {
        return sort;
    }

    public void setSort(Integer sort) {
        this.sort = sort;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("CategoryResp{");
        sb.append("id=").append(id);
        sb.append(", parent=").append(parent);
        sb.append(", name='").append(name).append('\'');
        sb.append(", sort=").append(sort);
        sb.append('}');
        return sb.toString();
    }
}
关于雪花算法前后端交互Long型精度丢失问题

这里提供了解决方案。本例使用第二种方法:统一配置。
所以在config目录下添加JacksonConfig类。

package com.jepcc.test.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

@Configuration
public class JacksonConfig {
    @Bean
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder){
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }
}
前端代码实现
<template>
  <a-layout>
    <a-layout-content :style="{ background: '#fff', padding: '24px', margin: 0, minHeight: '280px' }">
      <p>
        <a-button type="primary" @click="handleAdd">新增</a-button>
      </p>
      <a-table :columns="columns" :data-source="categorys"
               :loading="loading" :pagination="false" @change="handleChange">
        <template #action="{text,record}">
          <a-space>
            <a-button type="primary" @click="edit(record)">编辑</a-button>
            <a-popconfirm
                title="删除后不可恢复,确认删除?"
                ok-text="确定"
                cancel-text="取消"
                @confirm="confirm(record)"
            >
              <a-button type="danger">删除</a-button>
            </a-popconfirm>
          </a-space>
        </template>
      </a-table>
    </a-layout-content>
  </a-layout>
    <a-modal :visible="visible" title="分类管理" @ok="handleOk" @cancel="handleCancel">
      <a-form :model="category" :label-col="{ span: 4 }" :wrapper-col="{ span: 16 }">
        <a-form-item label="名称">
          <a-input v-model:value="category.name" />
        </a-form-item>
        <a-form-item label="父分类">
          <a-input v-model:value="category.parent" />
          <a-select
              v-model:value="category.parent"
              ref="select"
          >
            <a-select-option value="0"></a-select-option>
            <a-select-option v-for="item in categorys" :key="item.id" :value="item.id" :disabled="category.id === item.id">
              {{item.name}}
            </a-select-option>
          </a-select>
        </a-form-item>
        <a-form-item label="排序">
          <a-input v-model:value="category.sort" />
        </a-form-item>
      </a-form>
    </a-modal>
</template>


<script lang="ts">
import {defineComponent, onMounted, ref} from 'vue';
import axios from "axios";
interface DataItem {
  id:number,
  name:string,
  parent:number,
  children?:DataItem[]
}
const arrayToTree = (arr:DataItem[],rootId:number) => {
  let res:DataItem[] = [];
  let len = arr.length;
  if(len === 0) return res;

  for(let i=0;i<len;i++){
    const item = arr[i];
    if(Number(item.parent) === Number(rootId)){
      res.push(item);
      const children = arrayToTree(arr,item.id);
      if(children.length!==0){
        item.children = children;
      }
    }
  }
  return res;
}
export default defineComponent({
  name:"AdminCategory",
  setup() {
    const columns = [
      {
        dataIndex: 'name',
        key: 'name',
        title:"名称"
      },
      {
        dataIndex: 'parent',
        key: 'parent',
        title:"父分类"
      },
      {
        dataIndex: 'sort',
        key: 'sort',
        title:"排序"
      },
      {
        title: 'Action',
        key: 'action',
        slots: { customRender: 'action' },
      },
    ];
    const loading = ref(false);
    const categorys = ref();
    const visible = ref(false);
    const category = ref({
      id:"",
      parent:"",
      name:"",
      sort:""
    });
    const handleQuery = () => {
      loading.value = true;
      axios.get("/category/all").then(response => {
        loading.value = false;
        const data = response.data;
        if(data.success){
          var result = arrayToTree(data.content,0);
          console.log("result of arrayToTree:",result);
          categorys.value = result;
        }
      })
    }
    const handleSave = (params:any) => {
      axios.post("/category/save",params).then(response => {
        visible.value = false;
        const data = response.data;
        if(data.success){
          handleQuery();
        }else{
          console.log("save failed");
        }
      })
    }
    const handleDelete = (record:any) => {
      axios.delete("/category/delete/"+record.id).then(response => {
        const data = response.data;
        if(data.success){
          handleQuery();
        }else{
          console.log("delete failed");
        }
      })
    }

    const handleChange = (p:any) => {
      handleQuery();
    }
    const edit = (record:any) => {
      visible.value = true;
      category.value = JSON.parse(JSON.stringify(record));
    }
    const handleOk = () => {
      handleSave(category.value);
    }
    const handleCancel = () => {
      visible.value = false;
    }
    const confirm = (record:any) => {
      handleDelete(record)
    }
    const handleSearch = () => {
      handleQuery();
    }
    const handleAdd = () => {
      category.value = {
        id:"",
        parent:"",
        name:"",
        sort:""
      }
      visible.value = true;
    }
    onMounted(() => {
      handleQuery();
    })

    return {
      categorys,
      columns,
      loading,
      visible,
      category,
      handleQuery,
      handleChange,
      edit,
      handleOk,
      handleCancel,
      confirm,
      handleSearch,
      handleAdd
    };

  }

});
</script>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值