学习来源:视频p6
书接上文
目录
- 数据修改功能
-
- 修改对话框
- 视频教程的做法
- 后端提供接口
- 前端调用接口
- 修改完成后提交
- 数据删除功能
-
- 后端开设接口
- 前端调用
- 最终成果展示
数据修改功能
将之前的 BookManage 页面的按钮改为想要的功能
可以注意到修改按钮的标签以及绑定了事件 handleClick
点击之后其可以在控制台打印出当前行对象的内容
观看视频时,关于修改数据,弹幕分为了两派
一派认为因该直接从页面中获取现有的数据信息加以修改,再提交给后端并存储到数据库,此流程业务简单,减轻服务器负荷。
还有一派认为因该依据关键信息或唯一标识,从后台请求这一系列数据,在此基础上进行修改,再提交给后端并存储到数据库,此流程数据安全。
我认为确实应该从后端拿数据,毕竟前端显示的数据不一定是完整信息,最全最新的内容肯定是在数据库当中,所有从后端拿数据重新修订再保存到数据库更加安全严谨。
相较于视频中新增一个页面的方式,我选择以弹出框来展示修改页面,这样我认为更切合实际场景
修改对话框
其核心内容就是 dialogFormVisible 这个属性在点击关键字时改为 true(默认是false)
所以运用到原来的页面上,当点击“修改”时,把这个属性置为 true 即可
弹出的表单用原来的新增页面进行代码结合复用
将一下代码拆分放入对应位置即可
<template>
<div>
<el-button type="text" @click="dialogFormVisible = true">修改 Dialog</el-button>
<el-dialog title="修改" :visible.sync="dialogFormVisible">
<el-form style="width: 80%" :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="书名" prop="name">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="作者" prop="author">
<el-input v-model="ruleForm.author"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">立即创建</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogFormVisible = false">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
dialogFormVisible: false,
formLabelWidth: '120px',
ruleForm: {
name: '',
author: ''
},
rules: {
name: [
{ required: true, message: '书名不能为空', trigger: 'blur' }
],
author: [
{ required: true, message: '作者不能为空', trigger: 'blur' }
],
}
};
},
methods: {
submitForm(formName) {
const _this = this;
this.$refs[formName].validate((valid) => {
if (valid) {
axios.post("http://localhost:8181/book/save",this.ruleForm).then(function (resp) {
if (resp.data == "success"){
_this.$alert("《"+_this.ruleForm.name+"》添加成功", '成功', {
confirmButtonText: '确定',
callback: action => {
_this.$router.push("/BookMange");
}
});
}else{
_this.$message.error("添加失败");
}
})
} else {
console.log('添加失败');
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
},
}
}
</script>
最终效果如下
视频教程的做法
创建额外的页面,当点击修改按钮时,进行页面跳转,并用 query 传递操作的 id 信息
handleClick(row) {
this.$router.push({
path: '/update',
query:{
id: row.id
}
})
},
在新的页面初始化地方进行接收参数,请求后端数据
需要跳转用 $router ,需要接收参数用 $route
拓展阅读
route 和 router的区别
params 和 query 传递参数的区别
后端提供接口
之前 bookRepository 继承的 JPA 接口中,也已经写好了 findById() 函数,对我们来说相当方便,只是这个接口返回的对象是 Optional 的对象,其可以把空的对象也能正常包装并返回,避免出现空指针异常导致程序崩溃,Optional讲解
再调用 get() 方法以获取到对象,结果也是能正确输出的
则下一步写入handler接口供外部调用
@GetMapping("/findById/{id}")
public Book findById(@PathVariable("id") Integer id){
return bookRepository.findById(id).get();
}
经测试也是可以使用的,故在前端调用
前端调用接口
当点击 修改 操作时,对调用函数 handleClick 进行修改
handleClick(row) {
const _this = this;
this.dialogFormVisible = true;
axios.get("http://localhost:8181/book/findById/"+row.id).then(function (resp) {
_this.ruleForm = resp.data;
})
},
即可实现点击后出现弹窗+载入修改的目录信息
修改完成后提交
将之前的立即创建改成符合业务逻辑的“修改完成”
然后对函数 submitForm 改装一下即可
其实目前实际使用看来,不改装也能满足业务逻辑需求,JPA 的save函数自动帮我们把对象存进去了
JPA是判定了当前参数是否携带主键,如果没有就存入,如果有就修改内容
但为了业务严谨,并且以后可能遇到更复杂的业务逻辑,针对修改功能还是有必要专门开辟接口的
且根据 REST 规范,更新应该使用 PUT 请求
所以直接在 handler 里面新增接口
@PutMapping("/update")
public String update(@RequestBody Book book){
Book result = bookRepository.save(book);
if (result != null){
return "success";
}
else {
return "fail";
}
}
将此处的 post 改为 put ,接口网址改成 update
即可实现修改功能
数据删除功能
后端开设接口
@DeleteMapping("/deleteById/{id}")
public void delete(@PathVariable("id") Integer id){
bookRepository.deleteById(id);
}
前端调用
按钮组件绑定函数
deleteBook(row){
const _this = this;
axios.delete("http://localhost:8181/book/deleteById/"+row.id).then(function (resp) {
if (resp.status == 200){
_this.$alert("《"+row.name+"》删除成功", '成功', {
confirmButtonText: '确定并刷新',
callback: action => {
_this.$router.go(0);
}
});
}else{
_this.$message.error("删除失败");
}
})
},
最终成果展示
主页面js代码
<script>
export default {
methods: {
handleClick(row) {
const _this = this;
this.dialogFormVisible = true;
axios.get("http://localhost:8181/book/findById/"+row.id).then(function (resp) {
_this.ruleForm = resp.data;
})
},
deleteBook(row){
const _this = this;
axios.delete("http://localhost:8181/book/deleteById/"+row.id).then(function (resp) {
if (resp.status == 200){
_this.$alert("《"+row.name+"》删除成功", '成功', {
confirmButtonText: '确定并刷新',
callback: action => {
_this.$router.go(0);
}
});
}else{
_this.$message.error("删除失败");
}
})
},
page(currentPage){
const _this = this;
axios.get("http://localhost:8181/book/findPart/"+currentPage+"/3").then(function (resp) {
_this.tableData = resp.data.content;
_this.total = resp.data.totalElements;
})
},
submitForm(formName) {
const _this = this;
this.$refs[formName].validate((valid) => {
if (valid) {
axios.put("http://localhost:8181/book/update",this.ruleForm).then(function (resp) {
if (resp.data == "success"){
_this.$alert("《"+_this.ruleForm.name+"》修改成功", '成功', {
confirmButtonText: '确定',
callback: action => {
_this.$router.go(0);
}
});
}else{
_this.$message.error("修改失败");
}
})
} else {
console.log('添加失败');
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
},
},
created(){
const _this = this;
axios.get("http://localhost:8181/book/findPart/1/3").then(function (resp) {
_this.tableData = resp.data.content;
_this.total = resp.data.totalElements;
})
},
data() {
return {
total: null,
tableData: null,
dialogFormVisible: false,
dialogFormVisible: false,
formLabelWidth: '120px',
ruleForm: {
name: '',
author: ''
},
rules: {
name: [
{ required: true, message: '书名不能为空', trigger: 'blur' }
],
author: [
{ required: true, message: '作者不能为空', trigger: 'blur' }
],
}
}
}
}
</script>