写在前面
昨晚又失眠了,四点半才睡着,还做了两个很糟心的梦,八点半就醒了,感觉好累,好想一醉方休呀,不行呀,害怕酒驾,哈哈哈。
今年要做的事依旧很多,必须行动起来,自己尽管努力就好,剩下就看天意了。
任务拆解
上篇文章已经把前端页面画好,那么现在就是写后端逻辑的过程了,也就是编辑后的保存功能,拆解如下:
- 增加后端保存接口
- 点击保存时,调用保存接口
- 保存成功刷新列表
编辑功能实现
1、增加后端保存接口
同样还是两步走,第一,先在controller
中调用,第二,在service
中实现。
首先,需要在controller
中加入调用保存方法,示例代码如下:
/**
* 保存或更新操作
*
* @param eBookSaveReq
* @return
*/
@PostMapping("/save")
public CommonResp save(@RequestBody EBookSaveReq eBookSaveReq) {
CommonResp resp = new CommonResp<>();
eBookService.save(eBookSaveReq);
return resp;
}
同样, 我们在service
中实现,示例代码如下:
/**
* 保存或更新操作
* @param eBookSaveReq
*/
public void save(EBookSaveReq eBookSaveReq) {
EBook eBook = copy(eBookSaveReq, EBook.class);
if(ObjectUtils.isEmpty(eBook.getId())){
//数据库中没查到,走新增方法
eBookMapper.insert(eBook);
}else{
//数据库中查到,有该条信息,走编辑操作
eBookMapper.updateByPrimaryKey(eBook);
}
}
知识点:
EBookSaveReq
是拷贝domain
中的实体Ebook
,早期代码中的EBookReq
让我改为EBookQueryReq
,仅为查询时候所用,这样做的好处就是专类专用,可能有的人会说,这不是代码冗余吗,真的是个人习惯。
EBook eBook = copy(eBookSaveReq, EBook.class);
,这段代码是单体拷贝,不懂得同学可以参考《寻找写代码感觉(七)之封装请求参数和返回参数 》这篇文章。
2、点击保存时,调用保存方法,保存成功并刷新列表
后端逻辑写完了,这时候我们可以用PostMan本地测试下,该接口是否可用,这里我就直接在页面里调用测试了。
这时我们需要对点击保存时候的方法进行修改,示例代码如下:
<template>
<a-layout class="layout">
<a-layout-content
:style="{ background: '#fff', padding: '24px', minHeight: '280px' }">
<a-table :columns="columns"
:row-key="record => record.id"
:data-source="ebooks1"
:pagination="pagination"
:loading="loading"
@change="handleTableChange"
>
<template #cover="{ text: cover }">
<img v-if="cover" :src="cover" alt="avatar"/>
</template>
<template #name="{ text: name }">
<a>{{ text }}</a>
</template>
<template #customTitle>
<span>
<smile-outlined/>
Name
</span>
</template>
<template #action="{ record }">
<span>
<a-space size="small">
<a-button type="primary" @click="edit(record)">
编辑
</a-button>
<a-modal
v-model:visible="modalVisible"
cancelText="取消"
okText="保存"
title="编辑电子书"
:confirm-loading="modalLoading"
@ok="handleModalOk"
>
<a-form
:model="ebooks_data"
name="basic"
:label-col="{ span: 4 }"
:wrapper-col="{ span: 16 }"
>
<a-form-item label="封面">
<a-input v-model:value="ebooks_data.cover"/>
</a-form-item>
<a-form-item label="名称">
<a-input v-model:value="ebooks_data.name"/>
</a-form-item>
<a-form-item label="分类一">
<a-input v-model:value="ebooks_data.category1Id"/>
</a-form-item>
<a-form-item label="分类二">
<a-input v-model:value="ebooks_data.category2Id"/>
</a-form-item>
<a-form-item label="描述">
<a-input v-model:value="ebooks_data.description"/>
</a-form-item>
<a-form-item label="文档数">
<a-input v-model:value="ebooks_data.docCount"/>
</a-form-item>
<a-form-item label="阅读数">
<a-input v-model:value="ebooks_data.viewCount"/>
</a-form-item>
<a-form-item label="点赞数">
<a-input v-model:value="ebooks_data.voteCount"/>
</a-form-item>
</a-form>
</a-modal>
<a-button type="danger">
删除
</a-button>
</a-space>
</span>
</template>
</a-table>
</a-layout-content>
</a-layout>
</template>
<script lang="ts">
import {DownOutlined, SmileOutlined} from '@ant-design/icons-vue';
import {defineComponent, onMounted, reactive, ref, toRef} from 'vue';
import axios from 'axios';
import {message} from 'ant-design-vue';
export default defineComponent({
name: 'AdminEbook',
setup() {
//使用ref进行数据绑定
const ebooks = ref();
// 使用reactive进行数据绑定
const ebooks1 = reactive({books: []})
const pagination = ref({
current: 1,
pageSize: 2,
total: 0
});
const loading = ref(false);
const columns = [
{
title: '封面',
dataIndex: 'cover',
120,
height: 120,
slots: {customRender: 'cover'}
},
{
title: '名称',
dataIndex: 'name'
},
{
title: '分类一',
dataIndex: 'category1Id',
key: 'category1Id',
},
{
title: '分类二',
dataIndex: 'category2Id',
key: 'category2Id',
},
{
title: '描述',
dataIndex: 'description',
key: 'description',
},
{
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: params.name
}
}).then((response) => {
loading.value = false;
const data = response.data;
if (data.success) {
const data = response.data;
ebooks.value = data.content.list;
ebooks1.books = 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
});
};
const ebooks_data = ref();
const modalVisible = ref<boolean>(false);
const modalLoading = ref<boolean>(false);
/**
* 编辑/保存
*/
const handleModalOk = () => {
modalLoading.value = true;
axios.post("/ebook/save", ebooks_data.value).then(response => {
const data = response.data;
if (data.success) {
modalVisible.value = false;
modalLoading.value = false;
//重新加载列表
handleQuery({
page: 1,
size: pagination.value.pageSize,
});
}
})
};
const edit = (record: any) => {
modalVisible.value = true;
ebooks_data.value = record;
};
onMounted(() => {
handleQuery({
page: 1,
size: pagination.value.pageSize,
});
})
return {
modalVisible,
modalLoading,
handleModalOk,
pagination,
handleTableChange,
loading,
columns,
edit,
ebooks_data,
ebooks1: ebooks,
ebooks2: toRef(ebooks1, "books")
}
},
components: {
SmileOutlined,
DownOutlined,
},
});
</script>
<style scoped>
img {
50px;
height: 50px;
}
</style>
知识点:
- 响应式变量声明,贯穿始终,需要慢慢使用;
- 入参是
json
对象,所以在controller
中需要加入@RequestBody
- 在table组件使用时需要加上
@change="handleTableChange"
,handleTableChange
为方法实现分页跳转 - 前端代码也需要好好处理下,让人看起来不那么难受至少,惭愧呀,因为我的变量声明和使用扔的哪都是,尴尬
3、编译运行,查看效果
写在最后
如果你闲着无聊没什么事做,建议去学习或者做自己不擅长的事,这样时间会过得很快,不做情绪的奴隶,只做快乐的小跟班
。
到此编辑功能开发完毕,有兴趣的同学,请自行尝试!
坚持下去,其实你就是大神!