04 后端增删改查【小白入门SpringBoot + Vue3】

项目笔记,教学视频来源于B站青戈
https://www.bilibili.com/video/BV1H14y1S7YV

保证前面的都功能都实现后,接着往下走。

查 +分页

接下来,实现前端页面分页功能。

前端分页组件

打开elementplus官网,找到合适的分页组件,其对应代码如下

<template><el-pagination background layout="prev, pager, next" :total="1000" />
</template>

放到前端的表格组件下方,加个div包裹。

js加个变量,因为total总记录数量,应该是从数据库拿到的,是动态的。

<!--    分页组件--><div><el-pagination background layout="prev, pager, next" :total="total" /></div>const total = ref(0) //总记录数,初始为0

然后打开后端项目,实现分页查询,需要与SQL语句配合,而且浏览器的路由也可以修改后缀。

后端SQL语句修改

首先是数据库的SQL语句,复制上个SQL代码,稍加修改,让其实现分页,借助LIMIT这个分页函数后面的两个参数,第一个是开始序号,第二个是每页放置多少条记录。

select * from user where name like%%or date like%%or address like%%or user_no like%%LIMIT 1,2

接着尝试修改后端的SQL代码,

在UserMapper新增SQL代码;

注意@Param在导入包的时候,要选择有apache单词的包,选错会导致报错。

@Select("select * from user where name like concat('%',#{name},'%')  or date like concat('%',#{name},'%') or address like concat('%',#{name},'%') or user_no like concat('%',#{name},'%')  limit #{start}, #{pageSize}") 
List<User> selectPage(@Param("name") String name,@Param("start") Integer start,@Param("pageSize") Integer pageSize); //三个参数

在UserController这个文件添加以下代码

    @GetMapping("/page")    //表示访问到这个函数返回值,其路径是【localhost:9090/user/page】public Result selectPage(@RequestParam String name,@RequestParam Integer start,@RequestParam Integer pageSize){List<User> userList = userMapper.selectPage( name,start,pageSize);return Result.success(userList);}

前端SQL相关修改

后端配置得差不多,前端也进行相应修改,来到HomeView.vue ,把数据请求的路由更改成与后端SQL语句还参数一致的

const load = () =>{request.get('user/page?name=' + input.value + '&start=1&pageSize=2').then(res =>{ // request.get('user/all?name=' + input.value).then(res =>{ //name改成inputconsole.log(res)state.tableData = res.data})
}

然后数据库、前端、后端,都运行,打开前端项目生成的本地网址,若表格出现数据,则这一步成功。

但是上面的分页参数&start=1&pageSize=2,是静态的写死的,我们希望这个分页参数是可以根据用户手动选择的,于是要考虑运用分页组件的参数。

找到elementplus前端分页组件的代码,加上两个数据绑定

原来
<el-pagination  layout="prev, pager, next" :total="total"/>修改
<el-pagination  layout="prev, pager, next" v-model:current-page="pageNum" v-model:page-size="pageSize" :page-size="[1,2,5]" :total="total"/>

在js加上这两个变量,为了把页码的两个参数变成动态的,初步修改如下

const pageNum = ref(1) //页码。最小的是1
const pageSize = ref(1) //页码大小,实际上数据库无记录可以显示零条,但是理论上最起码显示一条const load = () => {let start = pageNum.value - 1  //数据库的记录序号从0开始,但是前端页面数据从1开始request.get('user/page?name=' + input.value + '&start='+ start +'&pageSize=' + pageSize.value).then(res => { //省略代码})
}

去看前端的分页,但是发现没反应。

首先因为组件的total 变量数值默认是 零,但数据库目前的总数量是2,故手动修改。

const total = ref(2) //总记录数

其次,分页没有触发load函数故,回到elementplus官网,找到分页切换触发的两个函数,所以修改如下

原来(其他属性省略没写)<el-pagination layout="prev, pager, next"  / >修改后<el-pagination  layout="sizes,prev, pager, next"  @size-change="load"  @current-change="load"/>

补充:

layout属性有多个属性值,它们有不同的功能,从左到右依次为

  1. total,表示后端数据的总条数,即页面上的 “ 共400条 ”
  2. sizes,表示每页能容纳多少条数据,即页面上的下拉选框 “ 100条/页 ”
  3. prev,表示向前翻一页,即页面上的 “ < ”
  4. pager,表示指定翻到哪一页,即页面上的 “ 1 2 3 4 ”
  5. next,表示向后翻一页,即页面上的 “ > ”
  6. jumper,表示直接跳去哪一页,即页面上的 “ 前往 3 页 ”

二个核心事件

  1. @size-change事件,当你使用下拉选框改变page-size属性时,它能监听到page-size属性的变化,并立刻将最新的值自动传给的事件处理函数,你甚至无需给它手动传参
  2. @current-change事件,当你改变current-page属性时,它能监听到current-page属性的变化,并立刻将最新的值自动传给相应的事件处理函数,你甚至无需给它手动传参

然后,发现,分页组件的文案都是英文,想改成中文,可以使用elementplus的国际化功能。来到前端项目的main.js ,添加下面的代码

import zhCn from 'element-plus/dist/locale/zh-cn.min'// app.use(ElementPlus)  //原来的
app.use(ElementPlus,{  //修改的locale: zhCn,
})

一个新的问题,随着数据库记录数量的增多,发现最后一条记录会被吞掉,原因是数据库页的起始序号计算有问题

原来
const load = () => {let start = pageNum.value - 1  //数据库的记录序号从0开始,但是前端页面数据从1开始//省略代码  
}修改
const load = () => {let start = (pageNum.value - 1)*pageSize.value //数据库的记录序号从0开始,但是前端页面数据从1开始,为了避免吞数据,需要乘每页的数量//省略代码  
}

动态total 修改

下一个问题,total的数值,目前还是静态写死的,为了改成动态的,需要从数据库中查出具体数值并显示到前端上。

第一步,后端项目,在UserMapper文件新增代码(复制粘贴上面的SQL语句,然后修改)如下

@Select("select count(id) from user where name like concat('%',#{name},'%')  or date like concat('%',#{name},'%') or address like concat('%',#{name},'%') or user_no like concat('%',#{name},'%')")  
Integer selectTotal(@Param("name") String name); //一个参数,函数返回值是integer类型

第二步,后端项目,UseController文件,新增代码,主要是增加total这个变量,把数值顺利传递到前端,修改如下

原来
@GetMapping("/page")    //表示访问到这个函数返回值,其路径是【localhost:9090/user/page】
public Result selectPage(@RequestParam String name,@RequestParam Integer start,@RequestParam Integer pageSize){List<User> userList = userMapper.selectPage( name,start,pageSize);return Result.success(userList);
}修改
@GetMapping("/page")    //表示访问到这个函数返回值,其路径是【localhost:9090/user/page】
public Result selectPage(@RequestParam String name,@RequestParam Integer start,@RequestParam Integer pageSize){List<User> userList = userMapper.selectPage( name,start,pageSize);Integer total = userMapper.selectTotal(name);Map<String,Object> map= new HashMap<>();map.put("list",userList);map.put("total",total);return Result.success(map);
}    

然后,重新访问前端页面,发现表格里面的数据没有显示出来。

为什么?因为刚才修改的Controller文件,把返回的数据包裹成map类型(key:value),里面有两个key,如下图,data里面有两个对象,需要进一步访问。
在这里插入图片描述

所以,前端访问data的代码要稍加修改,在前端项目,HomeView.vue修改

原来
<el-pagination layout="sizes,prev, pager, next"/>const load = () => {//省略代码({state.tableData = res.data})
}修改(layout加上total这个布局,展示一共有多少条数据)
<el-pagination layout="sizes,prev, pager, next,total"/>const load = () => {//省略代码({state.tableData = res.data.list  //修改这里total.value = res.data.total  //添加这个语句  })
}

补充说明:layout等号右边的单词,排序也有是有讲究的,会根据你排放的顺序调整哦



刚开始前端的增删改查,都是在前端单方面的简易模拟,接下来与数据库挂钩。

先做增加功能。

增加的数据中,有“日期”信息,之前为了简单,只用了字符串String类型,但是实际上是用专门的日期组件,更加方便美观。

在elementplus找到日期选择器组件,复制粘贴然后根据自身需求修改代码,如下

<el-date-picker v-model="state.form.data" type="date" placeholder="选择一个日期" />

来到后端,把数据库SQL语句写好,来到UseMapper,新增代码如下

@Insert("insert into user(name,date,address,user_no) values( #{name} , #{date} ,#{address},#{userNo}  )")
void insert(User user);

来到UseController,新增代码如下

    @PostMapping("/save")public Result save(@RequestBody User user){userMapper.insert(user);return Result.success();}

至此,后端代码ok,需要修改前端的相应代码。

来到前端项目HomeViews.vue ,修改save()函数

原来
const save = () => {if (globalIndex.value > -1) { //编辑数据state.tableData[globalIndex.value] = state.form;globalIndex = ref(-1)} else { //新增数据// 向表格添加数据state.tableData.push(state.form);}// 关闭弹窗dialogFormVisible.value = false;
}修改
const save = () => {console.log(state.form)//打印当前弹窗的数据内容request.post('/user/save',state.form).then(res=>{if (res.code === '200'){ElMessage.success("保存成功")// 关闭弹窗dialogFormVisible.value = false;}else {ElMessage.error(res.msg)}},err=>{console.log("发送post请求失败:",err)  //现在是后端返回错误})
}

但是运行的时候出现错误,如下

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.example.springboot.entity.User]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.example.springboot.entity.User` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 2]] with root cause

找了师兄才解决这个问题

在后端UseMapper添加三个注解,并且引入相关的包

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor

接着就可以在数据库中查看,数据是否被增加进去。

发现,虽然添加成功了,但是添加的时间格式有问题

在这里插入图片描述

故需要修改时间格式,解决很简单,elementplus有时间格式的属性,修改如下

原来<el-date-pickerv-model="state.form.date"type="date"placeholder="选择日期"/>修改<el-date-pickerv-model="state.form.date"type="date"placeholder="选择日期"value-format="YYYY-MM-DD"/>


下一个功能,修改数据

跟“增加数据”步骤相似

后端项目,修改SQL语句,打开UseMapper,新增下面的代码(一定不能写错变量的名字!!!)

@Update("update user set name = #{name}, date = #{date}, address = #{address} ,user_no = #{userNo} where id = #{id} ")
void update(User user);

然后打开UseController,新增代码如下

    @PutMapping("/update")public Result update(@RequestBody User user){  //函数名原来是saveuserMapper.update(user);return Result.success();}

相应地,前端网络请求也要进行相应修改,来到HomeView.vue

原来
const save = () => {console.log(state.form)request.post('/user/save',state.form).then(res=>{if (res.code === '200'){ElMessage.success("操作成功")// 关闭弹窗dialogFormVisible.value = false;}else {ElMessage.error(res.msg)}},err=>{console.log("发送post请求失败:",err)})
}    修改
const save = () => {console.log(state.form)request({url: state.form.id ? '/user/update':'/user/save',method: state.form.id ? 'PUT' :'POST',data: state.form}).then(res=>{if (res.code === '200'){ElMessage.success("操作成功")dialogFormVisible.value = false}else{ElMessage.error("操作失败", res.msg)}})
}

更新数据操作成功后,发现,虽然数据库的记录更新了,

但是前端页面还没有及时更新,所以调用load()

const save = () => {//省略代码if (res.code === '200'){ElMessage.success("操作成功")dialogFormVisible.value = falseload() //调用查询方法,及时更新数据  }//省略代码
}

补充一个细节,希望新增的记录能够显示在最前面,所以,SQL语句查询的时候,增加一个倒序排序

order by id desc

原来
@Select("select * from user where name like concat('%',#{name},'%')  or date like concat('%',#{name},'%') or address like concat('%',#{name},'%') or user_no like concat('%',#{name},'%') limit #{start}, #{pageSize}") 
List<User> selectPage(@Param("name") String name,@Param("start") Integer start,@Param("pageSize") Integer pageSize); //三个参数,注意相应类型修改
@Select("select * from user where name like concat('%',#{name},'%')  or date like concat('%',#{name},'%') or address like concat('%',#{name},'%') or user_no like concat('%',#{name},'%')  order by desc limit #{start}, #{pageSize}") 
List<User> selectPage(@Param("name") String name,@Param("start") Integer start,@Param("pageSize") Integer pageSize); //三个参数,注意相应类型

后端

UseMapper新增代码

    @Delete("delete from user where id = #{id}")void delete(Integer id);

UseController新增代码

    @DeleteMapping("/del")public Result delete(@RequestParam Integer id){userMapper.delete(id);return Result.success();}

前端HomeView.vue (多余的代码省略了)

原来
<el-button @click.prevent="remove(scope.$index)">删除</el-button>
// 删除数据
const remove = (index) => {// 从index的位置开始,删除一行state.tableData.splice(index, 1)
}修改
<el-button @click.prevent="remove(scope.row.id)">删除</el-button>
// 删除数据
const remove = (id) => {request.delete('user/del?id='+id).then(res=>{if (res.code === '200'){ElMessage.success("操作成功")load() //调用查询方法,及时更新数据}else{ElMessage.error("操作失败", res.msg)}})
}

以上就是小白入门增删改查的基础操作了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/148071.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何解决swagger-editor在线接口调试时的跨域问题

文章目录 一&#xff0c;序言二&#xff0c;问题重现1. 运行swagger-editor2. 运行接口服务3. 问题重现步骤 三&#xff0c;解决问题思路1. 去除浏览器安全限制2. 服务器接口统一处理3. 委托nginx转发 四&#xff0c;完整接口代码传送 一&#xff0c;序言 在 Docker 运行swagg…

光敏传感器模块(YH-LDR)

目录 1. YH-LDR模块说明 1.1 简介 1.2 YH-LDR 模块的引脚说明 1.3 LDR 传感器工作原理与输出特性 2. 使用单片机系统控制 YH-LDR 模块 2.1 通用控制说明 1. YH-LDR模块说明 1.1 简介 YH-LDR 是野火设计的光强传感器&#xff0c;使用一个光敏电阻作为采集源&#x…

【C++】多线程的学习笔记(3)——白话文版(bushi

目录 前一篇内容&#xff08;mutex锁&#xff09; 前言 Condition Variable的简介 Condition Variable的使用方法 wait方法 wait for函数与wait until函数 notify函数 notify_one notify_all 注意 前一篇内容&#xff08;mutex锁&#xff09; 【C】多线程的学习笔记&…

pythongui实时闹钟

# codinggbk import tkinter as tk from time import strftime# 创建一个主窗口 root tk.Tk() root.title("实时闹钟")# 设置窗口的大小不可变 root.resizable(False, False)# 设置窗口始终保持在最上层 root.attributes(-topmost, True)# 更新时间的函数 def time(…

java游戏制作-拼图游戏

一.制作主界面 首先创建一个Java项目命名为puzzlegame。 再在src中创建一个包&#xff0c;用来制作主界面 代码&#xff1a; 结果&#xff1a; 二.设置界面 代码&#xff1a; 三.初始化界面 代码&#xff1a; 优 化代码&#xff1a; 结果&#xff1a; 四.添加图片 先在Java项…

mysql查询json字符串内容

参考文章&#xff1a;mysql json 基础查询_mysql json查询-CSDN博客 mysql查询json字符串内容 &#xff08;多层数组嵌套&#xff09; select id,nameJSON_EXTRACT(JSON_UNQUOTE(JSON_EXTRACT(JSON_UNQUOTE(config_json), $.baseInfo)), $.template_list[*].sms_content) s…

03 前后端数据交互【小白入门SpringBoot + Vue3】

项目笔记&#xff0c;教学视频来源于B站青戈 https://www.bilibili.com/video/BV1H14y1S7YV 前两个笔记。是把前端页面大致做出来&#xff0c;接下来&#xff0c;把后端项目搞一下。 后端项目&#xff0c;使用IDEA软件、jdk1.8、springboot2.x 。基本上用的是稳定版。 还有My…

【C++】chono库:使用及源码分析

文章目录 0. 概述1. duration1.1 分析std::chrono::duration_cast() 1.2 使用案例std::chrono::duration::count() 1.3 部分源码 2. time_point2.1 分析std::chrono::time_point_cast() 2.2 使用举例std::chrono::time_point::time_since_epoch() 2.3 部分源码 0. 概述 本篇文…

python使用selenium webDriver时 报错

可能原因和解决&#xff1a; 1. python 解释器 ----> 设置 2. 浏览器版本 与 浏览器驱动版本不一致 ----> 安装同一版本的 (下载chromedriver | 谷歌驱动更高版本的测试版) 参考&#xff1a;Python使用Selenium WebDriver的入门介绍及安装教程-CSDN博客 Selenium安…

设计模式-行为型模式-策略模式

一、什么是策略模式 策略模式是一种行为设计模式&#xff0c;它允许在运行时选择算法或行为&#xff0c;并将其封装成独立的对象&#xff0c;使得这些算法或行为可以相互替换&#xff0c;而不影响使用它们的客户端。&#xff08;ChatGPT生成&#xff09; 主要组成部分&#xff…

基于django的在线教育系统

基于python的在线教育系统 摘要 基于Django的在线教育系统是一种利用Django框架开发的现代化教育平台。该系统旨在提供高效、灵活、易用的在线学习体验&#xff0c;满足学生、教师和管理员的需求。系统包括学生管理、课程管理、教师管理、视频课程、在线测验等核心功能。系统采…

在线 sha1 加密

ttmd5 http://www.ttmd5.com/hash.php?type5 qqxiuzi https://www.qqxiuzi.cn/bianma/sha-1.htm jb51 http://tools.jb51.net/password/sha_encode

23111707[含文档+PPT+源码等]计算机毕业设计基于javawebmysql的旅游网址前后台-全新项目

文章目录 **软件开发环境及开发工具&#xff1a;****功能介绍&#xff1a;****论文截图&#xff1a;****实现&#xff1a;****代码:** 编程技术交流、源码分享、模板分享、网课教程 &#x1f427;裙&#xff1a;776871563 软件开发环境及开发工具&#xff1a; 前端使用技术&a…

mock测试数据

1.下载一个jar 架包 地址&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1G5rVF5LlIYpyU-_KHsGjOA?pwdab12 提取码&#xff1a;ab12 2.配置当前电脑java环境变量 3.在同一文件目录下创建json 数据4.在终端切换到当前目录下启动服务&#xff0c; java -jar ./moco-r…

使用百度翻译API或腾讯翻译API做一个小翻译工具

前言 书到用时方恨少&#xff0c;只能临时抱佛脚。英文pdf看不懂&#xff0c;压根看不懂。正好有百度翻译API和腾讯翻译API&#xff0c;就利用两个API自己写一个简单的翻译工具&#xff0c;充分利用资源&#xff0c;用的也放心。 前期准备 关键肯定是两大厂的翻译API&#x…

IDEA 集成 Docker 插件一键部署 SpringBoot 应用

目录 前言IDEA 安装 Docker 插件配置 Docker 远程服务器编写 DockerFileSpringBoot 部署配置SpringBoot 项目部署结语 前言 随着容器化技术的崛起&#xff0c;Docker成为了现代软件开发的关键工具。在Java开发中&#xff0c;Spring Boot是一款备受青睐的框架&#xff0c;然而&…

kubenetes-服务发现和负载均衡

一、服务发布 kubenetes把服务发布至集群内部或者外部&#xff0c;服务的三种不同类型&#xff1a; ClusterlPNodePortLoadBalancer ClusterIP是发布至集群内部的一个虚拟IP,通过负载均衡技术转发到不同的pod中。 NodePort解决的是集群外部访问的问题&#xff0c;用户可能不…

debian 修改镜像源为阿里云【详细步骤】

文章目录 修改步骤第 1 步:安装 vim 软件第 2 步:备份源第 3 步:修改为阿里云镜像参考👉 背景:在 Docker 中安装了 jenkins 容器。查看系统,发现是 debian 11(bullseye)。 👉 目标:修改 debian bullseye 的镜像为阿里云镜像,加速软件安装。 修改步骤 第 1 步:…

限制Domain Admin登录非域控服务器和用户计算机

限制Domain Admin管理员使用敏感管理员帐户(域或林中管理员组、域管理员组和企业管理员组中的成员帐户)登录到信任度较低的服务器和用户端计算机。 此限制可防止管理员通过登录到信任度较低的计算机来无意中增加凭据被盗的风险。 建议采用的策略 建议使用以下策略限制对信任度…

SPASS-偏相关分析

基本概念 偏相关分析的任务就是在研究两个变量之间的线性相关关系时控制可能对其产生影响的变量,这种相关系数称为偏相关系数。偏相关系数的数值和简单相关系数的数值常常是不同的,在计算简单相关系数时,所有其他自变量不予考虑。 统计原理 控制一个变量和控制两个变量的偏…