【基础篇】六、基于SpringBoot来整合SSM的案例(下)

news2024/12/24 7:47:23

文章目录

  • 1、前后端调用:axios发送异步请求
  • 2、添加功能
  • 3、删除功能
  • 4、修改功能
  • 5、异常消息处理
  • 6、分页功能
  • 7、分页Bug处理
  • 8、条件查询

接下来加入前端页面,使用axios发送异步请求调用上篇的接口。调前端代码时,发现还挺有趣,刷新、隐藏、调用、以及一些交互逻辑的代码翻译,等框架学完看看前端的东西。
在这里插入图片描述

1、前后端调用:axios发送异步请求

关于前端资源文件的位置:

  • 前后端分离结构设计中页面归属前端服务器
  • 单体工程中页面放置在resources目录下的static目录中(建议执行clean)

调用下上篇的getAll接口,并将结果打印到console控制台来先调试下。前端发送异步请求,调用后端接口:

//列表
getAll() {
	axios.get("/books").then((res)=>{
		console.log(res.data);
	});
},

created钩子函数用于初始化页面时发起调用,如页面加载完后要调接口查全部图书:

//钩子函数,VUE对象初始化完成后自动执行
created() {
	//查全部
	this.getAll();
}

将查询数据返回到页面,利用前端数据双向绑定进行数据展示:

//列表
getAll() {
	axios.get("/books").then((res)=>{
		this.dataList = res.data.data;
	});
},

重启服务,刷新页面,列表功能实现。

在这里插入图片描述

2、添加功能

弹出添加窗口:

//弹出添加窗口
handleCreate() {
	this.dialogFormVisible = true;  //true即弹出
},

这样写,弹窗的窗口带有上次添加时的数据,需要在每次弹出前清除旧数据,即重置表单:

//重置表单
resetForm() {
	this.formData = {};
},

因此,弹出窗口应该是:

//弹出添加窗口
handleCreate() {
	this.dialogFormVisible = true;
	this.resetForm();
},

弹出添加窗口后,写数据,然后提交给后端:

//添加
handleAdd () {
	//发送异步请求
	axios.post("/books",this.formData).then((res)=>{
		//如果操作成功,关闭弹层,显示数据
		if(res.data.flag){
			this.dialogFormVisible = false;
			this.$message.success("添加成功");
		}else {
			this.$message.error("添加失败");
		}
	}).finally(()=>{
		this.getAll();
	});
},

以上即添加成功,则关闭弹层并给用户一个message添加成功。添加失败时不关闭弹层,方便用户修改后继续添加。不管成功与否,最后finally都刷新下列表。最后,当点弹窗的取消时,给用户一个取消成功的提示:

//取消
cancel(){
	this.dialogFormVisible = false;  //关闭弹窗
	this.$message.info("当前操作取消");
},

在这里插入图片描述

3、删除功能

基本逻辑和添加类似:删除接口返回成功时弹窗给用户提示删除成功,接口失败则返回删除失败。

// 删除
handleDelete(row) {
	axios.delete("/books/"+row.id).then((res)=>{
		if(res.data.flag){
			this.$message.success("删除成功");
		}else{
			this.$message.error("删除失败");
		}
	}).finally(()=>{
		this.getAll();
	});
}

这样一点删除按钮,就会调用删除接口,为了防止用户误操作,加$confirm,catch后面就是取消删除的逻辑:

// 删除
handleDelete(row) {
	//1.弹出提示框
	this.$confirm("确认要删除这条数据吗?","Tip",{type:'info'}).then(()=>{
		//2.做删除业务
		axios.delete("/books/"+row.id).then((res)=>{
		……
		}).finally(()=>{
		this.getAll();
		});
	}).catch(()=>{
		//3.取消删除
		this.$message.info("取消删除操作");
	});
}

删除这块,注意三点:

  • row对象,删除操作需要传递当前行数据对应的id值到后台,row.id(row的数据可以log.console看下)
  • 删除操作结束后动态刷新页面加载数据
  • 删除操作前弹出提示框避免误操作

在这里插入图片描述

4、修改功能

首先是弹出修改窗口,里面包含当前这条数据的信息:

//弹出编辑窗口
handleUpdate(row) {
	axios.get("/books/"+row.id).then((res)=>{
		if(res.data.flag){
			//展示弹层,加载数据
			this.formData = res.data.data;
			this.dialogFormVisible4Edit = true;
		}else{
			this.$message.error("数据不存在,已自动刷新页面");
		}
	});
},

(以下这个场景复现:复制页面,在一个页面后删除后,另一个页面未刷新,在这个页面点编辑,即编辑一条不存在的数据。PS:前面的删除应该也有这个场景,需要加个else)
在这里插入图片描述
以上:

  • 加载要修改数据通过传递当前行数据对应的id值到后台查询数据
  • 利用前端数据双向绑定将查询到的数据进行回显

写修改的逻辑:

//修改
handleEdit() {
	axios.put("/books",this.formData).then((res)=>{
		//如果操作成功,关闭弹层并刷新页面
		if(res.data.flag){
			this.dialogFormVisible4Edit = false;
			this.$message.success("修改成功");
		}else {
			this.$message.error("修改失败,请重试");
		}
	}).finally(()=>{
		this.getAll();
	});
},

取消编辑:

//和之前的取消复用一个函数
cancel(){
	this.dialogFormVisible = false;    //关闭新增弹窗窗口
	this.dialogFormVisible4Edit = false;  //关闭编辑弹窗窗口
	this.$message.info("操作取消");
},

到此,基本的增删改查的接口与页面完成。

5、异常消息处理

当接口请求出现异常时,返回体如下,和统一结果类R不一样,影响前端取值:

{
"timestamp": "2021-09-15T03:27:31.038+00:00",
"status": 500,
"error": "Internal Server Error",
"path": "/books"
}

鉴于此,加统一异常处理器,将异常处理成统一结果类返回给前端。修改R类,加msg字段:

@Data
public class R{
	private Boolean flag;
	private Object data;
	private String msg;
	public R(Boolean flag,Object data){
		this.flag = flag;
		this.data = data;
	}
	public R(Boolean flag,String msg){
		this.flag = flag;
		this.msg = msg;
	}
	//也可以定义个静态方法,里面封装构造方法
	public static R success(Object data){
		return new R(ture,data)
	}
	public static R error (String msg){
		return new R(false,msg);
	}

	
}

定义全局异常处理器

@RestControllerAdvice
public class ProjectExceptionAdvice {
	@ExceptionHandler(Exception.class)
	public R doException(Exception ex){
		//记录日志
		//发送消息给运维
		//发送邮件给开发人员,ex对象发送给开发人员
		ex.printStackTrace();
		return R.error("服务异常,请稍后重试!");
	}
}

此时,前端的msg就别写死了,从响应里拿res.data.msg

//添加
handleAdd () {
	//发送异步请求
	axios.post("/books",this.formData).then((res)=>{
		//如果操作成功,关闭弹层,显示数据
		if(res.data.flag){
			this.dialogFormVisible = false;
			this.$message.success("添加成功");
		}else {
			this.$message.error(res.data.msg);
		}
	}).finally(()=>{
		this.getAll();
	});
},

当然,响应成功的提示也可以改为res.data.msg,后端返回结果加msg:

@PostMapping
public R save(@RequestBody Book book) throws IOException {
	Boolean flag = bookService.insert(book);
	return new R(flag , flag ? "添加成功^_^" : "添加失败-_-!");
}

在这里插入图片描述
最后,小总结:

  • 使用注解@RestControllerAdvice定义SpringMVC异常处理器用来处理异常的
  • 异常处理器必须被扫描加载,否则无法生效(当然@RestControllerAdvice注解里面包含了@Component,你注意扫描范围就好)
  • 表现层返回结果的模型类中添加消息属性msg用来传递消息到页面

6、分页功能

页面使用el分页组件添加分页功能:

<!--分页组件-->
<div class="pagination-container">
	<el-pagination
		class="pagiantion"
		@current-change="handleCurrentChange"
		:current-page="pagination.currentPage"
		:page-size="pagination.pageSize"
		layout="total, prev, pager, next, jumper"
		:total="pagination.total">
	</el-pagination>
</div>

定义分页组件需要使用的数据并将数据绑定到分页组件:

data:{
	pagination: { //分页相关模型数据
		currentPage: 1, //当前页码
		pageSize:10, //每页显示的记录数
		total:0, //总记录数
	}
},

将之前的查全部接口改为调用分页功能的接口,传入上面定义的currentPage、pageSize

getAll() {
	axios.get("/books/"+this.pagination.currentPage+"/"+this.pagination.pageSize).then((res) => {
	});
},

之前的分页接口:

@GetMapping("/{currentPage}/{pageSize}")
public R getAll(@PathVariable Integer currentPage,@PathVariable Integer pageSize){

	IPage<Book> pageBook = bookService.getPage(currentPage, pageSize);
	return new R(null != pageBook ,pageBook);
	
}

加载分页数据,并给组件的页码和pageSize赋值,否则页码显示不对:

getAll() {
	axios.get("/books/"+this.pagination.currentPage+"/"+this.pagination.pageSize).then((res) => {
		this.pagination.total = res.data.data.total;
		this.pagination.currentPage = res.data.data.current;
		this.pagination.pagesize = res.data.data.size;
		this.dataList = res.data.data.records;
	});
},

从第一页切换到第二页,即切换页码的实现,就改下currentPage,并调用getAll:

//切换页码
handleCurrentChange(currentPage) {
	this.pagination.currentPage = currentPage;
	this.getAll();
},

效果:

在这里插入图片描述
分页功能的实现流程:

  • 使用el分页组件
  • 定义分页组件绑定的数据模型
  • 异步调用获取分页数据
  • 分页数据页面回显

7、分页Bug处理

场景:

一共两页数据,第二页仅有一条数据,删除这条数据后,实际只有一页数据,但前端页面仍停留在第二页。以下是查询接口的返回结果:

在这里插入图片描述

F12看到此时前端传参currentPage为2,后端接口修改下:对查询结果进行校验,当当前页码值大于总页码值时,就重新查询,使用最大页码值当作currentPage来查。IPage对象中就有数据总共能有几页的数据pages

@GetMapping("{currentPage}/{pageSize}")
public R getPage(@PathVariable int currentPage,@PathVariable int pageSize){

	//先按传的查,拿到IPage对象
	IPage<Book> page = bookService.getPage(currentPage, pageSize);
	
	//如果当前页码值大于了总页码值,那么重新执行查询操作,使用最大页码值作为当前页码值
	if( currentPage > page.getPages()){
		page = bookService.getPage((int)page.getPages(), pageSize);
	}
	return new R(true, page);
}

8、条件查询

查询条件数据封装,可单独封装,也可和之前的分页一起封装:

pagination: { //分页相关模型数据
	currentPage: 1, //当前页码
	pageSize:10, //每页显示的记录数
	total:0, //总记录数
	name: "",
	type: "",
	description: ""
}

页面数据模型绑定:

<div class="filter-container">
	<el-input placeholder="图书类别" v-model="pagination.type" class="filter-item"/>
	<el-input placeholder="图书名称" v-model="pagination.name" class="filter-item"/>
	<el-input placeholder="图书描述" v-model="pagination.description" class="filter-item"/>
	<el-button @click="getAll()" class="dalfBut">查询</el-button>
	<el-button type="primary" class="butT" @click="handleCreate()">新建</el-button>
</div>

组织数据成为get请求发送的数据,拼出一个请求路径,log.console看下param拼接是否正常:

getAll() {
	//1.获取查询条件,拼接查询条件
	param = "?name="+this.pagination.name;
	param += "&type="+this.pagination.type;
	param += "&description="+this.pagination.description;
	console.log("-----------------"+ param);
	axios.get("/books/"+this.pagination.currentPage+"/"+this.pagination.pageSize+param)
		.then((res) => {
		this.pagination.total = res.data.data.total;
		this.pagination.currentPage = res.data.data.current;
		this.pagination.pagesize = res.data.data.size;
		this.dataList = res.data.data.records;
	});
},


修改Controller,接收条件查询的参数,GET下接收对象,不加@RequestBody:

@GetMapping("{currentPage}/{pageSize}")
public R getAll(@PathVariable int currentPage,@PathVariable int pageSize,Book book) {

	IPage<Book> pageBook = bookService.getPage(currentPage,pageSize);
	return new R(null != pageBook ,pageBook);
	
}

修改Service层,使用LamdbaQueryWrapper对象拼接查询条件:

public interface IBookService extends IService<Book> {
	IPage<Book> getPage(Integer currentPage,Integer pageSize,Book queryBook);
}
@Service
public class BookServiceImpl2 extends ServiceImpl<BookDao,Book> implements IBookService {
	public IPage<Book> getPage(Integer currentPage,Integer pageSize,Book queryBook){
		IPage page = new Page(currentPage,pageSize);
		LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
		lqw.like(Strings.isNotEmpty(queryBook.getName()),Book::getName,queryBook.getName());
		lqw.like(Strings.isNotEmpty(queryBook.getType()),Book::getType,queryBook.getType());
		lqw.like(Strings.isNotEmpty(queryBook.getDescription()),
		Book::getDescription,queryBook.getDescription());
		return bookDao.selectPage(page,lqw);
	}
}

最终效果:

在这里插入图片描述

到此,基础篇结束。

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

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

相关文章

Learn Prompt-ChatGPT 精选案例:广告文案

ChatGPT 可以帮助我们生成广告文案和宣传图片&#xff0c;这对营销品牌建设很有帮助。通常&#xff0c;一个产品会有一个主要的广告词&#xff0c;传达设计理念或宣传产品的好处。我们可以尝试直接生成文案&#xff0c;看看 ChatGPT 有没有好的创意。假设我们的产品是一款登山鞋…

【css | linear-gradient】linear-gradient()的用法

linear-gradient() CSS函数创建一个由两种或多种颜色沿一条直线进行线性过渡的图像,其结果是<gradient>数据类型的对象,此对象是一种特殊的<image> 数据类型。 先看一个线上的示例 https://code.juejin.cn/pen/7277486410842996771 语法 /* 渐变轴为 45 度&…

Docker容器详解

值得看的原文地址

一根USB线,全新单片机开发体验!推荐WeCanStudio工具套件

我的需求 回想当初大学时代,学习单片机的开发最繁琐的事情就是,通过串口升级STC的MCU来调试编写的固件。不知到有多少个深夜都在重复以下步骤&#xff1a; Keil编译代码打开STC软件,选择对生成的新固件程序手动断电、上电MCU板子(USB转串口的驱动还经常让电脑蓝屏&#x1f6…

极智开发 | 制作u盘启动盘的几种方式

欢迎关注我的公众号 [极智视界],获取我的更多经验分享 大家好,我是极智视界,本文分享一下 制作u盘启动盘的几种方式。 邀您加入我的知识星球「极智视界」,星球内有超多好玩的项目实战源码和资源下载,链接:https://t.zsxq.com/0aiNxERDq 在平时的工作、生活中,经常会涉及…

Bigemap在市政工程设计给排水行业的应用场景?

去年单位采购的&#xff0c;今年11月份才分配给我使用。 使用场景&#xff1a; 现场定位&#xff1a; 通过我们电脑导入cad图纸数据&#xff0c;根据需求可以画一些简单的示意路线&#xff0c;发送到手机进行现场比对&#xff0c;最后会在cad里面加入管道设计方案。 去年单位采…

Windows Server 2012 R2系统远程桌面的数字证书算法SHA1升级到SHA256

问题描述&#xff1a; 最近项目进行密评的时候&#xff0c;Windows Server 2012 R2发现了以下证书问题&#xff1a; Windows Server 2012 R2系统远程桌面的TLS 1.2协议使用SHA1算法数字证书&#xff0c;且证书有效日期截止23年10月&#xff0c;建议注意证书到期时间&#xff…

极简解析!IP计费的s5爬虫IP

大家好&#xff01;今天我将为大家分享关于s5爬虫IP服务的知识。对于经常做爬虫的小伙伴来说&#xff0c;需要大量的爬虫IP支持爬虫业务&#xff0c;那么对于选择什么样的爬虫IP&#xff0c;我想我有很多发言权。 下面我们一起了解下IP计费的s5爬虫IP的知识&#xff0c;废话不…

Spring Boot + Vue3前后端分离实战wiki知识库系统<十三>--单点登录开发二

接着Spring Boot Vue3前后端分离实战wiki知识库系统<十二>--用户管理&单点登录开发一继续往下。 登录功能开发&#xff1a; 接下来则来开发用户的登录功能&#xff0c;先准备后端的接口。 后端增加登录接口&#xff1a; 1、UserLoginReq&#xff1a; 先来准备…

都在谈网关,Modbus网关到底是什么

随着工业自动化的不断发展&#xff0c;各种协议和标准在行业中变得越来越重要。其中&#xff0c;Modbus协议是一种在工业自动化领域非常流行的通信协议&#xff0c;而Modbus网关是实现Modbus协议转换的关键设备。本文将介绍HiWoo Box&#xff0c;作为Modbus网关的应用和发展趋势…

2023App测试必掌握的核心测试:UI、功能测试

一、UI测试 UI即User Interface (用户界面)的简称。UI 设计则是指对软件的人机交互、操作逻辑、界面美观的整体设计。好的UI设计不仅是让软件变得有个性有品味,还要让软件的操作变得舒适、简单、自由、充分体现软件的定位和特点。手机APP从启动界面开始, 到运行过程,直至退出,…

【校招VIP】测试方案之测试需求分析

考点介绍&#xff1a; 需求分析就是要弄清楚用户需要的是什么功能&#xff0c;用户会怎样使用系统。这样我们测试的时候才能更加清楚的知道系统该怎么样运行&#xff0c;才能更好的设计测试用例&#xff0c;才能更好的测试。 测试方案之测试需求分析-相关题目及解析内容可点击…

C/C++空格分开输出 2019年12月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C空格分开输出 一、题目要求 1、编程实现 2、输入输出 二、解题思路 1、案例分析 三、程序代码 四、程序说明 五、运行结果 六、考点分析 C/C空格分开输出 2019年12月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 读入一个字符&#xff0c;一个整…

Linux知识点 -- 网络基础(二)-- 应用层

Linux知识点 – 网络基础&#xff08;二&#xff09;-- 应用层 文章目录 Linux知识点 -- 网络基础&#xff08;二&#xff09;-- 应用层一、使用协议来实现一个网络版的计算器1.自定义协议2.守护进程3.使用json来完成序列化 二、HTTP协议1.概念2.HTTP协议请求和响应的报文格式3…

DB2 JDBC连接详解(附DEMO~超详细)

DB2 JDBC连接详解 DB2 JDBC连接详解摘要引言正文1. JDBC基础2. 配置DB2JDBC连接2.1 DB2连接JDBC2.2 DB2连接JDBC是否成功2.3 DB2连接JDBC获取表信息注释等2.4 DB2连接JDBC根据表名获取字段信息注释等2.5 执行 SQL 查询2.6 执行 SQL 查询2.7 插入数据2.8 执行存储过程2.9 批处理…

Vue3 封装 element-plus 图标选择器

一、实现效果 二、实现步骤 2.1. 全局注册 icon 组件 // main.ts import App from ./App.vue; import { createApp } from vue; import * as ElementPlusIconsVue from element-plus/icons-vueconst app createApp(App);// 全局挂载和注册 element-plus 的所有 icon app.con…

Android平台下奔溃Crash和无响应ANR日志抓取分析

一、使用AndroidStudio 在logcat中查看实时日志&#xff0c;需要选择连接的手机和应用包名 AS下载链接 二、使用adb shell dumpsys dropbox命令获取 #!/bin/bash # path"/data/system/dropbox" # 在手机这个目录下存储了崩溃日志 newest_time$(adb shell dumps…

JK405R-SOP16录音芯片ic方案的测试板使用说明以及咪头如何选择

目录 2.1芯片硬件说明 注意事项 1、供电最高5.2V&#xff0c;最低2.6V。芯片的11脚是唯一的电源输入&#xff0c;供电电压越低扬声器声音越小 2、注意音频地和数字地要在供电的入口处短接 3、USB引脚一定要留出测试&#xff0c;也可以升级固件 4、10脚为芯片输出的3.3V&am…

旭雅阁私人博物馆 钱币博物馆

一、旭雅阁博物馆简介 旭雅阁博物馆&#xff0c;成立于2018年&#xff0c;是一家以古钱币、老钱币、字画等为主的专题博物馆&#xff0c;主要从事钱币的收藏、研究和展示&#xff0c;肩负有指导和推动钱币收藏、研究及宣传钱币文化的任务。旭雅阁博物馆&#xff0c;坐落于湖南…

个人博客网站一揽子:Docker建站(Nginx、Wordpress、MySql)

前言 既然安装了Docker&#xff0c;那就不妨建立一个自己的博客网站。实现内外网隔离网站部署&#xff0c;更安全。 1.创建Docker子网络 首先创建一个Docker虚拟子网&#xff1a; sudo docker network create wpnt检查是否建立成功&#xff1a; sudo docker network ls最后…