后台管理系统——新页面开发 Book

1、后端方面

1.1 创建一个book表

在这里插入图片描述

1.2 创建实体类Book

在entity文件夹下创建实体类 Book,里面的内容与数据库对应。

package com.example.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.math.BigDecimal;
import java.util.Date;

//表名记得改
@TableName("book")
// 自动进行生成getter setter 方法
@Data

public class Book {
    @TableId(type = IdType.AUTO)
    private Integer id;
    private String name;
    private BigDecimal price;
    private String author;
    //数据库中有下划线的,自动转换为驼峰写法
    private Date createTime;

}

1.3 创建BookMapper类

package com.example.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.entity.Book;


public interface BookMapper extends BaseMapper<Book> {

}

1.4 创建 BookController类

package com.example.controller;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.common.Result;
import com.example.entity.Book;
import com.example.mapper.BookMapper;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;


@RequestMapping("/book")
@RestController
public class BookController {
    // 引入mapper中的内容
    @Resource
    BookMapper bookMapper;


    // 新增
    @PostMapping
    // Result<?>表示接收任何类型的数据
    public Result<?> save(@RequestBody Book book){
        // 插入数据库,在里面进行使用
        bookMapper.insert(book);
        return Result.success();
    }

    // 查询,使用的是分页查询
    // 在进行网页查询的时候,需要必须传入三个参数pageNum pageSize search
    @GetMapping
    // 当前页pageNum 默认从 1 开始,,每页条数 pageSize 默认从 10 开始,,查询关键字 默认为空
    public Result<?> findPage(@RequestParam(defaultValue = "1") Integer pageNum,@RequestParam(defaultValue = "10") Integer pageSize,@RequestParam(defaultValue = "") String search){
        // Page对象是由mybatisplus进行提供的
        // Page<Object> page =  new Page<>(pageNum,pageSize);

        // 里面需要传入两个参数 一个是分页的对象,另一个wrappers对象,也是由mybatisplus提供的类
        // eq含义是 = ,ne 含义是不等于, gt 是大于,like 模糊查询
        // 根据用户昵称进行模糊搜索,Book::getName中间四个点的意思是直接进行访问Book的属性,
        //当 Name 和search 类似的时候,就进行显示
        /**
         * 此时原先直接将Wrappers.<Book>lambdaQuery().like(Book::getNickName,search);写在 BookPage中,在进行查询数据库的时候,nickName为空的字段
         * 是查询不到的,所以在like之前进行一下判断
         * 使用的是 hutool工具,StrUtil.isNotBlank(search) 判断 search 不是空的时候执行,此时就能将 nickName为空的数据查询出来
         */
        LambdaQueryWrapper<Book> wrapper = Wrappers.<Book>lambdaQuery();
        if(StrUtil.isNotBlank(search)){
            wrapper.like(Book::getName,search);
        }
        Page<Book> bookPage =  bookMapper.selectPage(new Page<>(pageNum,pageSize),wrapper);
        return Result.success(bookPage);
    }

    // 更新 使用PutMapping接口
    @PutMapping
    // Result<?>表示接收任何类型的数据
    public Result<?> update(@RequestBody Book book){
        // 根据id进行更新
        bookMapper.updateById(book);
        return Result.success();
    }

    // 删除 使用DeleteMapping接口
    @DeleteMapping("/{id}")
    // "/{id}" 占位符是方式 需要通过PathVariable注解进行获取参数
    public Result<?> delete(@PathVariable Long id){
        // 根据id进行删除
        bookMapper.deleteById(id);
        return Result.success();
    }


}

2、前端方面

图书页面与用户管理页面几乎一致,稍微改动一下即可。

2.1 路由方面

首先将原来的Home.vue组件重命名为 User.vue组件,所以在路由中需要进行更新,同时在views文件夹下创建一个Book.vue组件,在文件夹router下的index.js修改如下:
在这里插入图片描述

const routes = [
  // 默认路由页面,主体区域
  {
    // 头部加上侧边栏
    path: '/',
    name: 'Layout',
    // 重定向功能,当访问 / 时,会自动的访问 /home 的页面
    redirect: '/user',
    component: Layout,
    // 进行路由的嵌套 主体区域
    children:[
      {
        path: '/user',
        name: 'User',
        component: ()=>import("@/views/User"),
      },
      {
        path: '/person',
        name: 'Person',
        component: ()=>import("@/views/Person"),
      },
      {
        path: '/book',
        name: 'Book',
        component: ()=>import("@/views/Book"),
      }
    ]
  },
  {
    path: '/login',
    name: 'Login',
    component: ()=>import("@/views/Login")
  },
  {
    path: '/register',
    name: 'Register',
    component: ()=>import("@/views/Register")
  },
  
]

2.2 页面设计

代码几乎没有改变,只是将发送请求的 /user改为 /book,以及与数据库内容相对应。
(1)html

<template>
  <div style="flex: 1; padding: 10px">
    <div class="content">
      <!-- 功能区域———新增按钮 -->
      <div style="margin: 10px 0" class="content_left">
        <el-button type="primary" @click="add">增加</el-button>
        <el-button type="primary">导入</el-button>
        <el-button type="primary">导出</el-button>
      </div>

      <!-- 搜索区域 -->
      <div style="margin: 10px 0" class="content_right">
        <el-input
          v-model="search"
          placeholder="请输入关键字"
          style="width: 200px"
          clearable
        />
        <el-button type="primary" style="margin-left: 5px" @click="load"
          >查询</el-button
        >
      </div>
    </div>
    <el-table :data="tableData" border style="width: 100%" stripe>
      <!-- 在进行数据显示的时候,给日期加上排序 -->
      <el-table-column prop="id" label="ID" sortable />
      <el-table-column prop="name" label="书名" />
      <el-table-column prop="price" label="单价" />
      <el-table-column prop="author" label="作者" />
      <el-table-column prop="createTime" label="出版时间" />
      <el-table-column fixed="right" label="操作" width="150">
        <template #default="scope">
          <el-button size="small" @click="handleEdit(scope.row)"
            >编辑</el-button
          >
          <el-popconfirm
            title="确认删除吗?"
            @confirm="handleDelete(scope.row.id)"
          >
            <template #reference>
              <el-button type="danger" size="small">删除</el-button>
            </template>
          </el-popconfirm>
        </template>
      </el-table-column>
    </el-table>

    <div style="margin: 10px 0">
      <el-pagination
        v-model:current-page="currentPage"
        v-model:page-size="pageSize"
        :page-sizes="[5, 10, 20]"
        layout="total, sizes, prev, pager, next, jumper"
        :total="total"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      />
      <!-- 对话弹出框 -->
      <el-dialog v-model="dialogVisible" title="提示" width="30%">
        <!-- 定义一个表单,将要进行添加的信息显示在此位置 -->
        <!-- <span>这是一段信息</span> -->
        <!-- 此时需要进行绑定一个变量form -->
        <el-form :model="form" label-width="120px">
          <el-form-item label="书名" style="width: 80%">
            <el-input v-model="form.name" />
          </el-form-item>
          <el-form-item label="单价" style="width: 80%">
            <el-input v-model="form.price" />
          </el-form-item>
          <el-form-item label="作者" style="width: 80%">
            <el-input v-model="form.author" />
          </el-form-item>
          <el-form-item label="出版时间" style="width: 80%">
            <el-date-picker
              v-model="form.createTime"
              type="date"
              clearable
              value-format="YYYY-MM-DD"
            />
          </el-form-item>
          <!-- <el-form-item label="出版时间" style="width: 80%">
            <el-date-picker
              v-model="form.createTime"
              value-format="YYYY-MM-DD"
              type="date"
              clearable
            ></el-date-picker>
          </el-form-item> -->
        </el-form>
        <template #footer>
          <span class="dialog-footer">
            <el-button @click="dialogVisible = false">取消</el-button>
            <!-- 点击之后,将数据保存到后台,显示在页面上面 -->
            <el-button type="primary" @click="save"> 确定 </el-button>
          </span>
        </template>
      </el-dialog>
    </div>
  </div>
</template>

(2)js

<script>
import request from "@/utils/request";
export default {
  name: "Book",
  components: {},
  data() {
    return {
      form: {},
      dialogVisible: false,
      currentPage: 1,
      pageSize: 10,
      total: 0,
      search: "",
      // 从后台进行获取数据
      tableData: [],
      flag: false,
    };
  },
  created() {
    this.load();
  },
  // updated() {
  //   this.load();
  // },
  methods: {
    // 编辑操作
    handleEdit(row) {
      // console.log(row);
      /** 此时可以拿到当前行的数据,然后将拿到的数据,传入到form中进行显示,为了避免v-model
       *  的影响,当在表格中进行修改数据的时候,会导致form中的数据,当点击取消之后,会影响原先的数据
       * 所以采用深拷贝的方式进行赋值
       */
      this.form = JSON.parse(JSON.stringify(row));
      //  打开弹窗
      this.dialogVisible = true;
    },
    // 改变页面个数触发函数
    handleSizeChange() {
      this.load();
    },
    // 改变当前页码
    handleCurrentChange() {
      this.load();
    },
    // 当点击添加按钮之后,会显示一个弹窗
    add() {
      // 打开弹窗
      this.dialogVisible = true;
      // 同时要进行清空表单里面的内容
      this.form = {};
    },
    //查询数据库中的数据,由于需要多次进行使用,所以先进行一下封装
    // 此时的方法并没有进行调用,所以可以再页面一进行加载,就调用
    load() {
      // 在进行后端设计的时候,get代表查询
      // get不能直接使用对象进行传参
      request
        .get("/book", {
          params: {
            // 需要进行传递参数
            pageNum: this.currentPage,
            pageSize: this.pageSize,
            search: this.search,
          },
        })
        .then((res) => {
          // console.log(res);
          this.tableData = res.data.records;
          // 总条数
          this.total = res.data.total;
        });
    },
    // 将数据保存到后台
    save() {
      // 通过 form表单中id进行判断,如果有id,表示为更新,否则为新增
      if (this.form.id) {
        // 更新 put
        request.put("/book", this.form).then((res) => {
          // console.log(res);
          if (res.code === "0") {
            this.$message({
              type: "success",
              message: "更新成功",
            });
          } else {
            this.$message({
              type: "error",
              message: "更新失败",
            });
          }
          // 判断之后,需要进行弹窗的关闭和页面的重新渲染
          this.load();
          this.dialogVisible = false;
        });
      } else {
        // 新增
        // 此时路径不能使用/api/book,要不然会自动拼接
        request.post("/book", this.form).then((res) => {
          // console.log(res);
          //成功之后的提示
          if (res.code === "0") {
            this.$message({
              type: "success",
              message: "新增成功",
            });
          } else {
            this.$message({
              type: "error",
              message: "新增失败",
            });
          } // 判断之后,需要进行弹窗的关闭和页面的重新渲染
          this.load();
          this.dialogVisible = false;
        });
      }
    },
    // 删除当前数据
    handleDelete(id) {
      // console.log(id);
      // 通过字符串拼接的方式,将id传给后端userMapper.deleteById(id);中进行删除
      request.delete("/book/" + id).then((res) => {
        if (res.code === "0") {
          this.$message({
            type: "success",
            message: "删除成功",
          });
        } else {
          this.$message({
            type: "error",
            message: "删除失败",
          });
        }
        this.load(); //重新进行表格数据的渲染
      });
    },
  },
};
</script>

页面效果如下:
在这里插入图片描述

2.3 在Aside组件中添加

<template>
  <div>
    <!-- el-menu 存在一个属性 router ,
        功能是,当进行点击里面的内容时,会自动进行跳转
        会根据index中的路由内容进行跳转
     -->
     <!-- default-active="user" 进行控制高亮 -->
    <el-menu
      default-active="user"
      class="el-menu-vertical-demo"
      router
      style="width: 200px; min-height: calc(100vh - 50px)"
    >
      <el-sub-menu index="1">
        <template #title>
          <span>系统管理</span>
        </template>
        <el-menu-item index="user">用户管理</el-menu-item>
      </el-sub-menu>
      <!-- index 中的值与路由名称相对应 -->
      <el-menu-item index="book">图书管理</el-menu-item>
      <!-- <el-menu-item index="date" :route="{ path: '/' }">数据管理</el-menu-item> -->
    </el-menu>
  </div>
</template>

3 问题

3.1 出版时间的显示

(1)第一种方法:在entity文件夹下的Book类下进行代码修改,加个格式化注解,改完记得重启后台,具体代码如下:
在这里插入图片描述

//表名记得改
@TableName("book")
// 自动进行生成getter setter 方法
@Data

public class Book {
    @TableId(type = IdType.AUTO)
    private Integer id;
    private String name;
    private BigDecimal price;
    private String author;
    @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
    //数据库中有下划线的,自动准换为驼峰写法
    private Date createTime;

}

(2)第二种方法: 在项目中统一进行设置。
在配置文件application.properties中,代码为

spring.jackson.date-format=yyyy-MM-dd

在配置文件application.yml中,代码为:

  jackson:
    date-format: yyyy-MM-dd

3.2 关于左侧高亮的显示问题

问题:用户管理页面进行**/book**,不能进行高亮的跳转
在这里插入图片描述
解决办法:
控制高亮是通过default-active属性进行控制的,所以让他动态的接收当前传来的数据,将获取到当前页面的路由赋值给当前的这个属性值,即可。具体代码如下:

<template>
  <div>
    <!-- el-menu 存在一个属性 router ,
        功能是,当进行点击里面的内容时,会自动进行跳转
        会根据index中的路由内容进行跳转
     -->
    <!-- default-active="user" 进行控制高亮 -->
    <el-menu
      :default-active="path"
      class="el-menu-vertical-demo"
      router
      style="width: 200px; min-height: calc(100vh - 50px)"
    >
      <el-sub-menu index="1">
        <template #title>
          <span>系统管理</span>
        </template>
        <el-menu-item index="/user">用户管理</el-menu-item>
      </el-sub-menu>
      <!-- index 中的值与路由名称相对应 -->
      <el-menu-item index="/book">图书管理</el-menu-item>
      <!-- <el-menu-item index="date" :route="{ path: '/' }">数据管理</el-menu-item> -->
    </el-menu>
  </div>
</template>

<script>
export default {
  name: "Aside",
  data() {
    return {
      path: this.$route.path, //设置默认高亮的菜单
    };
  },
  // created() {
  //   console.log(this.$route.path);
  //   // path: this.$route.path;
  // },
};
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值