【wiki知识库】04.SpringBoot后端实现电子书的增删改查以及前端界面的展示
📝个人主页:哈__
期待您的关注
目录
一、🔥今日内容
二、🌏前端页面的改造
2.1新增电子书管理页面
2.2新增路由规则
2.3修改the-header代码
三、🚗SpringBoot后端Ebook模块改造
3.1增加电子书增/改接口
3.1.1新增EbookSaveParam
3.1.2添加Controller代码
3.1.3在Ebook实体类上增加一个注解
3.2 增加电子书删除接口
四、🔨测试
4.1添加功能测试
4.2修改功能测试。
4.3删除功能测试
一、🔥今日内容
【wiki知识库】03.前后端的初步交互(展现所有的电子书)-CSDN博客
上一次带领大家把前端的首页部分实现了一下,成功的从数据库当中取出了我们的信息并且展示在前端页面,到了下图的部分。
今天主要是把这个网页的界面初步优化一下,修改一下导航栏以及增加电子书管理模块。包含电子书的查询功能、新增功能、编辑功能和删除功能(不包括文档管理)。
二、🌏前端页面的改造
2.1新增电子书管理页面
我在src下新建了admin文件夹,这个文件夹中的内容是给网站管理员看到的,所以放到了admin目录,名字为admin-ebook.vue。
admin-ebook.vue的具体内容如下。这个文件里我注释掉了一些信息,而且这个文件中的内容包含了页面需要的功能很多,有的一些并不是今天要讲解的内容,所以并没有使用到。今天主要就是想带着大家做出一个电子书管理的模块来。
<template><a-layout><a-layout-content:style="{ background: '#fff', padding: '24px', margin: 0, minHeight: '280px' }"><p><a-form layout="inline" :model="param"><a-form-item><a-input v-model:value="param.name" placeholder="名称"></a-input></a-form-item><a-form-item><a-button type="primary" @click="handleQuery({page: 1, size: pagination.pageSize})">查询</a-button></a-form-item><a-form-item><a-button type="primary" @click="add()">新增</a-button></a-form-item></a-form></p><a-table:columns="columns":row-key="record => record.id":data-source="ebooks":pagination="pagination":loading="loading"@change="handleTableChange"><template #cover="{ text: cover }"><img v-if="cover" :src="cover" alt="avatar" /></template><template v-slot:category="{ text, record }"><!-- <span>{{ getCategoryName(record.category1Id) }} / {{ getCategoryName(record.category2Id) }}</span> --></template><template v-slot:action="{ text, record }"><a-space size="small"><!-- <router-link :to="'/admin/doc?ebookId=' + record.id"> --><a-button type="primary">文档管理</a-button><!-- </router-link> --><a-button type="primary" @click="edit(record)">编辑</a-button><a-popconfirmtitle="删除后不可恢复,确认删除?"ok-text="是"cancel-text="否"@confirm="handleDelete(record.id)"><a-button type="danger">删除</a-button></a-popconfirm></a-space></template></a-table></a-layout-content></a-layout><a-modaltitle="电子书表单"v-model:visible="modalVisible":confirm-loading="modalLoading"@ok="handleModalOk"><a-form :model="ebook" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }"><a-form-item label="封面"><a-input v-model:value="ebook.cover" /></a-form-item><a-form-item label="名称"><a-input v-model:value="ebook.name" /></a-form-item><a-form-item label="分类"><a-cascaderv-model:value="categoryIds":field-names="{ label: 'name', value: 'id', children: 'children' }":options="level1"/></a-form-item><a-form-item label="描述"><a-input v-model:value="ebook.description" type="textarea" /></a-form-item></a-form></a-modal> </template><script lang="ts">import { defineComponent, onMounted, ref } from 'vue';import axios from 'axios';import { message } from 'ant-design-vue';import {Tool} from "@/util/tool";export default defineComponent({name: 'AdminEbook',setup() {const param = ref();param.value = {};const ebooks = ref();const pagination = ref({current: 1,pageSize: 10,total: 0});const loading = ref(false);const columns = [{title: '封面',dataIndex: 'cover',slots: { customRender: 'cover' }},{title: '名称',dataIndex: 'name'},{title: '分类',slots: { customRender: 'category' }},{title: '文档数',dataIndex: 'docCount'},{title: '阅读数',dataIndex: 'viewCount'},{title: '点赞数',dataIndex: 'voteCount'},{title: 'Action',key: 'action',slots: { customRender: 'action' }}];/*** 数据查询**/const handleQuery = (params: any) => {loading.value = true;// 如果不清空现有数据,则编辑保存重新加载数据后,再点编辑,则列表显示的还是编辑前的数据ebooks.value = [];axios.get("/ebook/list", {params: {page: params.page,size: params.size,name: param.value.name}}).then((response) => {loading.value = false;const data = response.data;if (data.success) {ebooks.value = data.content.list;// 重置分页按钮pagination.value.current = params.page;pagination.value.total = data.content.total;} else {message.error(data.message);}});};/*** 表格点击页码时触发*/const handleTableChange = (pagination: any) => {console.log("看看自带的分页参数都有啥:" + pagination);handleQuery({page: pagination.current,size: pagination.pageSize});};// -------- 表单 ---------/*** 数组,[100, 101]对应:前端开发 / Vue*/const categoryIds = ref();const ebook = ref();const modalVisible = ref(false);const modalLoading = ref(false);const handleModalOk = () => {modalLoading.value = true;ebook.value.category1Id = categoryIds.value[0];ebook.value.category2Id = categoryIds.value[1];axios.post("/ebook/save", ebook.value).then((response) => {modalLoading.value = false;const data = response.data; // data = commonRespif (data.success) {modalVisible.value = false;// 重新加载列表handleQuery({page: pagination.value.current,size: pagination.value.pageSize,});} else {message.error(data.message);}});};/*** 编辑*/const edit = (record: any) => {modalVisible.value = true;ebook.value = Tool.copy(record);categoryIds.value = [ebook.value.category1Id, ebook.value.category2Id]};/*** 新增*/const add = () => {modalVisible.value = true;ebook.value = {};};const handleDelete = (id: number) => {axios.delete("/ebook/delete/" + id).then((response) => {const data = response.data; // data = commonRespif (data.success) {// 重新加载列表handleQuery({page: pagination.value.current,size: pagination.value.pageSize,});} else {message.error(data.message);}});};const level1 = ref();let categorys: any;/*** 查询所有分类**/const handleQueryCategory = () => {loading.value = true;axios.get("/category/all").then((response) => {loading.value = false;const data = response.data;if (data.success) {categorys = data.content;console.log("原始数组:", categorys);level1.value = [];level1.value = Tool.array2Tree(categorys, 0);console.log("树形结构:", level1.value);// 加载完分类后,再加载电子书,否则如果分类树加载很慢,则电子书渲染会报错handleQuery({page: 1,size: pagination.value.pageSize,});} else {message.error(data.message);}});};const getCategoryName = (cid: number) => {// console.log(cid)let result = "";categorys.forEach((item: any) => {if (item.id === cid) {// return item.name; // 注意,这里直接return不起作用result = item.name;}});return result;};onMounted(() => {handleQuery({page: pagination.value.current,size: pagination.value.pageSize,});});return {param,ebooks,pagination,columns,loading,handleTableChange,handleQuery,getCategoryName,edit,add,ebook,modalVisible,modalLoading,handleModalOk,categoryIds,level1,handleDelete}}}); </script><style scoped>img {width: 50px;height: 50px;} </style>
上边的内容很多,但我们今天核心的前端调用部分是下边的代码。
const handleQuery = (params: any) => {loading.value = true;// 如果不清空现有数据,则编辑保存重新加载数据后,再点编辑,则列表显示的还是编辑前的数据ebooks.value = [];axios.get("/ebook/list", {params: {page: params.page,size: params.size,name: param.value.name}}).then((response) => {loading.value = false;const data = response.data;if (data.success) {ebooks.value = data.content.list;// 重置分页按钮pagination.value.current = params.page;pagination.value.total = data.content.total;} else {message.error(data.message);}});};
当我们进去这个页面的时候,首先就会调用下方代码,请求路径也恰好是我们后端之前写过的list接口,用来分页查询电子书信息。
onMounted(() => {handleQuery({page: pagination.value.current,size: pagination.value.pageSize,});});
2.2新增路由规则
既然都要新增一个电子书的管理页面了,那我们也要为这个页面分配一个能够匹配到的路由路径。
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router' import HomeView from '../views/HomeView.vue' import AdminEbook from '@/views/admin/admin-ebook.vue' import AboutView from '../views/AboutView.vue' const routes: Array<RouteRecordRaw> = [{path: '/',name: 'home',component: HomeView},{path: '/about',name: 'about',component:AboutView},{path: '/admin/ebook',name: 'AdminEbook',component: AdminEbook}, ]const router = createRouter({history: createWebHistory(process.env.BASE_URL),routes })export default router
2.3修改the-header代码
我们新增的组件是通过点击the-header组件中的按钮实现跳转的,这里要修改一些代码。我在这个页面添加了一些路由用于跳转我们的组件。
<template><a-layout-header class="header"><div class="logo" ></div><a-menutheme="dark"mode="horizontal"v-model:selectedKeys="sselectedKeys1":style="{ lineHeight: '64px' }"><a-menu-item key="/"><router-link to="/">首页</router-link></a-menu-item><a-menu-item key="/admin/ebook"><router-link to="/admin/ebook">电子书管理</router-link></a-menu-item><a-menu-item key="/about"><router-link to="/about">关于我们</router-link></a-menu-item></a-menu></a-layout-header> </template>
至此我们前端改造成功,接下来就是后端了。
三、🚗SpringBoot后端Ebook模块改造
3.1增加电子书增/改接口
在我们点击新增按钮或者编辑按钮的时候,会弹出一个窗口来添加或者修改电子书的信息,当我们点击确定之后会向后端发送请求。请求接口是/ebook/save,注意,这里的save指代两个功能,第一个是新增,第二个是修改。
3.1.1新增EbookSaveParam
这个实体类用于封装我们前端传过来的电子书的信息。
@Data public class EbookSaveParam {private Long id;@NotNull(message = "【名称】不能为空")private String name;private Long category1Id;private Long category2Id;private String description;private String cover;private Integer docCount;private Integer viewCount;private Integer voteCount; }
3.1.2添加Controller代码
这里我直接使用的MybatisPlus封装好的函数
/*** 保存/修改电子书* @param ebookQueryParam* @return*/@PostMapping("/save")public CommonResp save(@Validated @RequestBody EbookSaveParam ebookQueryParam){boolean res = ebookService.saveOrUpdate(CopyUtil.copy(ebookQueryParam,Ebook.class));String message = Boolean.TRUE.equals(res) ? "操作成功":"操作失败";return new CommonResp<>(true,message,null);}
3.1.3在Ebook实体类上增加一个注解
我们要使用雪花算法生成的id存储在数据库当中。
/*** id*/@TableId(type = IdType.ASSIGN_UUID)private Long id;
当然除了雪花id还有其他的id可供选择。这里就不一一给大家说了。
3.2 增加电子书删除接口
删除功能的接口是下边图中所示。采用的是Restful风格的请求。
对应Controller代码。
/*** 删除电子书* @param id 电子书id* @return*/@DeleteMapping("/delete/{id}")public CommonResp delete(@PathVariable("id") Long id){boolean res = ebookService.removeById(id);String message = Boolean.TRUE.equals(res) ? "删除成功":"删除失败";return new CommonResp<>(true,message,null);}
四、🔨测试
4.1添加功能测试
测试之前还要注释两行代码。因为我们的分类模块还没写,这里不能传值。
随便加一个电子书上去。
结果还是没问题的。
4.2修改功能测试。
不在截图展示了,点击编辑按钮之后哦修改数据我这里是正确的。
4.3删除功能测试
这时就有问题了,我删除怎么成功不了?那么你是否会分析原因呢?先看看前端的打印。
仔细看看我们传过去的id是什么,再看看你的数据库里是否有这个id? 显然是没有的。
这里就要说一下前后端传输数据的数据精度丢失问题了,因为我们传的数据是一个整形,而且数值很大,在传输的过程总是有精度问题得,想要解决就需要在后端加一个配置类。
package com.my.hawiki.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;/*** 统一注解,解决前后端交互Long类型精度丢失的问题*/ @Configuration public class JacksonConfig {@Beanpublic 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;} }
之后在运行代码试试。大功告成。
电子书管理页面的基本几个功能差不多就这么多了。
相关文章:

【wiki知识库】04.SpringBoot后端实现电子书的增删改查以及前端界面的展示
📝个人主页:哈__ 期待您的关注 目录 一、🔥今日内容 二、🌏前端页面的改造 2.1新增电子书管理页面 2.2新增路由规则 2.3修改the-header代码 三、🚗SpringBoot后端Ebook模块改造 3.1增加电子书增/改接口 3.1.…...

NTLM Relay Gat:自动化NTLM中继安全检测工具
关于NTLM Relay Gat NTLM Relay Gat是一款功能强大的NTLM中继威胁检测工具,该工具旨在利用Impacket工具套件中的ntlmrelayx.py脚本在目标环境中实现NTLM中继攻击风险检测,以帮助研究人员确定目标环境是否能够抵御NTLM中继攻击。 功能介绍 1、多线程支持…...

摸鱼大数据——Hive函数14
14、开窗(开列)函数 官网链接:Window Functions - Apache AsterixDB - Apache Software Foundation 14.1 基础使用 开窗函数格式: 开窗函数 over(partition by 分组字段名 [order by 排序字段名 asc|desc] [rows between 开窗开始 and 开窗结束]) partition b…...

elasticsearch的常规操作--增删改查和批量处理
1、_cat 查询 GET /_cat/nodes: 查看所有节点 GET /_cat/health: 查看es 健康状况 GET /_cat/master: 查看主节点 GET /_cat/indices:查看所有索引show databases; 2、索引一个文档(保存) 保存一个数据&…...

盘点2024年还在活跃发版的开源私有网盘项目附源码链接
时不时的会有客户上门咨询,丰盘ECM是不是开源项目,源码在哪里可以下载;如果需要和内部其他系统做集成,购买商业版的话,能否提供源代码做二次开发呢,等等诸多问题。 这里做个统一回复,丰盘ECM产…...

MySQL 使用方法以及教程
一、引言 MySQL是一个流行的开源关系型数据库管理系统(RDBMS),广泛应用于Web开发、数据分析等领域。它提供了高效、稳定的数据存储和查询功能。同时,Python作为一种强大的编程语言,也提供了多种与MySQL交互的库&#…...

算法学习笔记——二进制
二进制 负数的十进制转二进制数(-2 -> 1110): 正数 - 1,再取反,得到负数的二进制。 例如:-2 :0010 -> 0010 - 1 -> 0001 -> 取反 -> 1110 负数的二进制转十进制(…...

计算机网络介绍
计算机网络介绍 概述网络概述相关硬件 链路层VLAN概念VLAN 特点VLAN 的划分帧格式端口类型原理 STP概念特点原理 Smart Link概念特点组网 网络层ARP概念原理 IP概念版本IP 地址 IPv4IP 地址数据报格式 IPv6特点IP 地址数据报格式 ICMP概念分类报文格式 VRRP概念原理报文格式 OS…...

解锁数据宝藏:高效查找算法揭秘
代码下载链接:https://gitee.com/flying-wolf-loves-learning/data-structure.git 目录 一、查找的原理 1.1 查找概念 1.2 查找方法 1.3平均查找长度 1.4顺序表的查找 1.5 顺序表的查找算法及分析 1.6 折半查找算法及分析 1.7 分块查找算法及分析 1.8 总结…...

利用EasyCVR视频智能监控技术,构建智慧化考场监管体系
随着科技的进步,视频监控在各个领域的应用越来越广泛,其中在考场中的应用尤为显著。视频监控不仅能够提高考场的监管水平,确保考试的公平、公正和公开,还能有效预防和打击作弊行为,为考生营造一个良好的考试环境。 传…...

深度解析:速卖通618风控下自养号测评的技术要点
速卖通每年的618大促活动平台的风控都会做升级,那相对的测评技术也需要进行相应的做升级,速卖通618风控升级后,自养号测评需要注意以下技术问题,以确保测评 的稳定性和安全性: 一、物理环境 1. 硬件参数伪装&#x…...

国产算力——沐曦GPU性能及应用
沐曦集成电路(上海)有限公司(简称“沐曦”)成立于2020年9月,专注于为异构计算提供全栈GPU芯片及解决方案,满足数据中心对“高性能”、“高能效”及“高通用性”的算力需求。 产品系列 沐曦构建了全栈高性…...

贪心算法拓展(反悔贪心)
相信大家对贪心算法已经见怪不怪了,但是一旦我们的决策条件会随着我们的步骤变化,我们该怎么办呢?有没有什么方法可以反悔呢? 今天就来讲可以后悔的贪心算法,反悔贪心。 https://www.luogu.com.cn/problem/CF865Dhttp…...

在spring框架的基础上自定义autowired注解
在Spring框架的基础上自定义Autowired注解是不可能的,因为注解本身是Java语言的一部分,并且Autowired是Spring框架提供的注解,用于实现自动装配。但是,你可以创建自己的注解,并结合Spring框架的扩展机制来实现类似的功…...

2005NOIP普及组真题 3. 采药
线上OJ: [05NOIP普及组] 采药 核心思想: 1、题与 2006 年普及组第2题《开心的金明》一样,考察的都是01背包。 2、直接套用01背包的一阶模板即可 a、限定时间看成背包总容量m b、每件物品的采药时间 v 看成占用背包的体积 c、每件物品的价格w作为该物品的…...

preventDefault()与stopPropagation()有什么区别?
1、event.preventDefault()方法 (1)可防止元素的默认行为 (2)如果在表单元素中使用,它将阻止其提交 (3)如果在锚元素中使用,它将阻止其导航 (4)如果在上下…...

AIGC 全面介绍
随着人工智能技术的不断进步,生成式人工智能(AI Generated Content, AIGC)成为了一个日益热门的话题。AIGC 指利用人工智能技术生成各类内容,包括文本、图像、音频、视频等。与传统的内容生成方法相比,AIGC 具有速度快…...

网站入门:Flask用法讲解
Flask是一个使用Python编写的轻量级Web服务框架,旨在帮助开发人员快速构建和部署Web应用程序。下面将对Flask进行更为详细的解释说明,并展示其使用示例与注意事项: 1.解释说明 定义及特点: Flask以其简洁和灵活著称,允许开发者以…...

头歌数据库备份与恢复
第1关:数据库的备份和恢复 mysql -uroot -p123123 -h127.0.0.1 < /data/workspace/myshixun/src/data.sqlmysqldump -u root -p studb student> /student_bk.sqlmysql -uroot -p123123 -h127.0.0.1 -e "create database studb2;"mysql -u root -p123123 studb…...

小程序项目创建与Vant-UI引入
一,创建小程序项目 AppID可先用测试号; 模板来源选择 ’全部来源‘ ,’基础‘ 。模板一定JS开头的; vant-weapp 官网 vant-Weapp 二,下载vant-weapp 组件 1,在新项目中打开 ’调试器‘; 2…...

xtrabackup 使用
官网 Percona XtraBackup Use APT repositories - Percona XtraBackup 一 安装 下载 wget https://repo.percona.com/apt/percona-release_latest.$(lsb_release -sc)_all.deb wget https://repo.percona.com/apt/percona-release_latest.zesty_all.deb 可下载列表 Perc…...

C++写一个简单的计算器程序案例
1. 编写C源代码 创建一个名为 advanced_calculator.cpp 的文件,并编写以下代码: // advanced_calculator.cpp #include <iostream> #include <limits>int main() {char operatorChoice;bool keepRunning true;while (keepRunning) {int nu…...

Spring Boot 开发 -- swagger3.0 集成
前言 随着微服务架构的普及和API数量的增长,API文档的管理和维护变得尤为重要。Swagger作为一款强大的API文档生成工具,能够帮助我们自动生成API文档,并提供在线测试功能,极大地提高了开发效率。本文将介绍如何在Spring Boot项目…...

探索安全之道 | 企业漏洞管理:从理念到行动
如今,网络安全已经成为了企业管理中不可或缺的一部分,而漏洞管理则是网络安全的重中之重。那么企业应该如何做好漏洞管理呢?不妨从业界标准到企业实践来一探究竟!通过对业界标准的深入了解,企业可以建立起完善的漏洞管…...

【记录贴:分布式系列文章】
分布式系列文章目录 文章目录 分布式系列文章目录前言一、Redisq1.怎么判断是否命中缓存1. MySQL数据库如何检查询查缓存是否命中链接2.如何判断redis是否命中缓存链接 q2.Redis缓存穿透、雪崩、击穿以及分布式锁和本地锁 二、分布式q1.分布式订单号生成策略q2.接口幂等性,防止…...

初识SDN(二)
初识SDN(二) SDN部分实现 REST API 是什么? REST API(Representational State Transfer Application Programming Interface,表述性状态传递应用程序接口)是一种基于HTTP协议的接口,广泛用于…...

某红书旋转滑块验证码分析与协议算法实现(高通过率)
文章目录 1. 写在前面2. 接口分析3. 验证轨迹4. 算法还原 【🏠作者主页】:吴秋霖 【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致…...

Gin的快速入门和搭建
文章目录 Go的工程工程架构技术选型 Gin入门 Go的工程 基于Go生态,构建一个支持内容管理,内容加工、内容分发的内容库系统。 内容管理:增删改查内容加工:例如内容审核、推荐等内容分发:将内容可以推到不同的业务线 …...

react-native运行程序 出现 Application XXX is waiting for the debugger
1.重启adb: adb kill-server、 adb start-server. 2、确定USB调试模式是否开启,如果已经开启了,关闭了重新打开一下 3.选择调试模式并关闭等待调试程序...

什么文档加密软件好用?迅软DSE加密软件你不会还不知道吧?
一、什么文档加密软件好用? 其中有迅软DSE文档加密软件等。 迅软DSE加密软件:让企业的创意成果、招投标文件、生产工艺、流程配方、研发成果、公司计划、员工信息等核心数据更安全。 多方面加密模式,有效防止数据泄密 透明无感知加密&…...