新增电子书表单
主要是对admin-book.vue
进行修改。
- 点击编辑按钮,弹出对话框,这里使用Antd的Modal组件
<template>
<a-layout>
<a-layout-content
:style="{ background: '#fff', padding: '24px', margin: 0, minHeight: '280px' }"
>
<a-table :columns="columns"
:dataSource="ebooks"
:row-key="record=>record.id"
:pagination="pagination"
:loading="loading"
@change="handleTableChange">
<template #cover="{text:cover}">
<img v-if="cover" :src="cover" alt="avatar">
</template>
<template #action="{text,record}">
<a-space>
<a-button type="primary" @click="handleEdit">编辑</a-button>
<a-button type="danger">删除</a-button>
</a-space>
</template>
</a-table>
</a-layout-content>
</a-layout>
<a-modal
title="电子书表单"
v-model:visible="visible"
:confirm-loading="confirmLoading"
@ok="handleOk"
>
<p>{{ modalText }}</p>
</a-modal>
</template>
<script lang="ts">
import { defineComponent,ref,onMounted} from 'vue';
import axios from "axios";
export default defineComponent({
name:"AdminEbook",
setup() {
const ebooks = ref();
const pagination = ref({
current:1,
pageSize:4,
total:0
});
const loading = ref(false);
const columns = [
{
title:"封面",
dataIndex:"cover",
key:"cover",
slots:{customRender:'cover'}
},
{
title:"名称",
key:"name",
dataIndex:"name"
},
{
title:"分类一",
key:"category1Id",
dataIndex:"category1Id"
},
{
title:"分类二",
key:"category2Id",
dataIndex:"category2Id"
},
{
title:"文档数",
key:"docCount",
dataIndex:"docCount"
},
{
title:"阅读数",
key:"viewCount",
dataIndex:"viewCount"
},
{
title:"点赞数",
key:"vouteCount",
dataIndex:"voteCount"
},
{
title:"操作",
key:"action",
dataIndex:"action",
slots:{customRender:'action'}
}
];
const visible = ref(false);
const modalText = ref('test');
const confirmLoading = ref(false);
const handleQuery = (params:any) => {
loading.value = true;
axios.get("/ebook/list",{params:params}).then(response => {
loading.value = false;
const data = response.data.content;
ebooks.value = data.list;
pagination.value.total = data.total;
pagination.value.current = params.page;
})
};
const handleTableChange = (pagination:any) => {
handleQuery({
page:pagination.current,
size:pagination.pageSize
});
}
const handleEdit = (record:any) => {
visible.value = true;
}
const handleOk = () => {
modalText.value = 'The modal will be closed after two seconds';
confirmLoading.value = true;
setTimeout(() => {
visible.value = false;
confirmLoading.value = false;
}, 2000);
};
onMounted(() => {
handleQuery({
page:1,
size:pagination.value.pageSize
});
})
return {
columns,
ebooks,
loading,
pagination,
handleTableChange,
visible,
modalText,
confirmLoading,
handleEdit,
handleOk
}
}
})
</script>
<style scoped>
img{
width: 48px;
height: 48px;
}
</style>
- 弹出的对话框,框中内容是表单,所以使用Antd的Form组件
<template>
<a-layout>
<a-layout-content
:style="{ background: '#fff', padding: '24px', margin: 0, minHeight: '280px' }"
>
<a-table :columns="columns"
:dataSource="ebooks"
:row-key="record=>record.id"
:pagination="pagination"
:loading="loading"
@change="handleTableChange">
<template #cover="{text:cover}">
<img v-if="cover" :src="cover" alt="avatar">
</template>
<template #action="{text,record}">
<a-space>
<a-button type="primary" @click="handleEdit(record)">编辑</a-button>
<a-button type="danger">删除</a-button>
</a-space>
</template>
</a-table>
</a-layout-content>
</a-layout>
<a-modal
title="电子书表单"
v-model:visible="visible"
:confirm-loading="confirmLoading"
@ok="handleOk"
>
<a-form :model="ebook" :label-col="{span:4}" :wrapper-col="{span:16}">
<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-input v-model:value="ebook.category1Id" />
</a-form-item>
<a-form-item label="分类二">
<a-input v-model:value="ebook.category2Id" />
</a-form-item>
<a-form-item label="描述">
<a-input v-model:value="ebook.description" />
</a-form-item>
</a-form>
</a-modal>
</template>
<script lang="ts">
import { defineComponent,ref,onMounted} from 'vue';
import axios from "axios";
export default defineComponent({
name:"AdminEbook",
setup() {
const ebooks = ref();
const pagination = ref({
current:1,
pageSize:4,
total:0
});
const loading = ref(false);
const columns = [
{
title:"封面",
dataIndex:"cover",
key:"cover",
slots:{customRender:'cover'}
},
{
title:"名称",
key:"name",
dataIndex:"name"
},
{
title:"分类一",
key:"category1Id",
dataIndex:"category1Id"
},
{
title:"分类二",
key:"category2Id",
dataIndex:"category2Id"
},
{
title:"文档数",
key:"docCount",
dataIndex:"docCount"
},
{
title:"阅读数",
key:"viewCount",
dataIndex:"viewCount"
},
{
title:"点赞数",
key:"vouteCount",
dataIndex:"voteCount"
},
{
title:"操作",
key:"action",
dataIndex:"action",
slots:{customRender:'action'}
}
];
const visible = ref(false);
const modalText = ref('test');
const confirmLoading = ref(false);
const ebook= ref({});
const handleQuery = (params:any) => {
loading.value = true;
axios.get("/ebook/list",{params:params}).then(response => {
loading.value = false;
const data = response.data.content;
ebooks.value = data.list;
pagination.value.total = data.total;
pagination.value.current = params.page;
})
};
const handleTableChange = (pagination:any) => {
handleQuery({
page:pagination.current,
size:pagination.pageSize
});
}
const handleEdit = (record:any) => {
visible.value = true;
ebook.value = record;
}
const handleOk = () => {
modalText.value = 'The modal will be closed after two seconds';
confirmLoading.value = true;
setTimeout(() => {
visible.value = false;
confirmLoading.value = false;
}, 2000);
};
onMounted(() => {
handleQuery({
page:1,
size:pagination.value.pageSize
});
})
return {
columns,
ebooks,
loading,
pagination,
handleTableChange,
visible,
modalText,
confirmLoading,
handleEdit,
handleOk,
ebook
}
}
})
</script>
<style scoped>
img{
width: 48px;
height: 48px;
}
</style>
完成电子书编辑功能
新增并测试后端接口
修改电子书属性后,点击OK按钮,保存,对此,需要新增后端接口。
- 在
com.jepcc.test.req
包下新增类EbookSaveReq
,
package com.jepcc.test.req;
public class EbookSaveReq {
private Long id;
private String name;
private Long category1Id;
private Long category2Id;
private String description;
private String cover;
private Integer docCount;
private Integer viewCount;
private Integer voteCount;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getCategory1Id() {
return category1Id;
}
public void setCategory1Id(Long category1Id) {
this.category1Id = category1Id;
}
public Long getCategory2Id() {
return category2Id;
}
public void setCategory2Id(Long category2Id) {
this.category2Id = category2Id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getCover() {
return cover;
}
public void setCover(String cover) {
this.cover = cover;
}
public Integer getDocCount() {
return docCount;
}
public void setDocCount(Integer docCount) {
this.docCount = docCount;
}
public Integer getViewCount() {
return viewCount;
}
public void setViewCount(Integer viewCount) {
this.viewCount = viewCount;
}
public Integer getVoteCount() {
return voteCount;
}
public void setVoteCount(Integer voteCount) {
this.voteCount = voteCount;
}
}
- 在
com.jepcc.test.service.EbookService
中添加保存方法
package com.jepcc.test.service;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jepcc.test.mapper.EbookMapper;
import com.jepcc.test.model.Ebook;
import com.jepcc.test.model.EbookExample;
import com.jepcc.test.req.EbookReq;
import com.jepcc.test.req.EbookSaveReq;
import com.jepcc.test.resp.EbookResp;
import com.jepcc.test.resp.PageResp;
import com.jepcc.test.util.CopyUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import java.util.List;
@Service
public class EbookService {
private static final Logger LOG = LoggerFactory.getLogger(EbookService.class);
@Autowired
private EbookMapper ebookMapper;
public PageResp<EbookResp> list(EbookReq req){
EbookExample ebookExample = new EbookExample();
EbookExample.Criteria criteria = ebookExample.or();
if(!ObjectUtils.isEmpty(req.getName())){
criteria.andNameLike("%"+req.getName()+"%");
}
PageHelper.startPage(req.getPage(),req.getSize());
List<Ebook> ebookList = ebookMapper.selectByExample(ebookExample);
PageInfo<Ebook> pageinfo = new PageInfo<>(ebookList);
// LOG.info("总条数:{}",pageinfo.getTotal());
// LOG.info("总页数,{}",pageinfo.getPages());
List<EbookResp> list = CopyUtil.copyList(ebookList,EbookResp.class);
PageResp<EbookResp> pageResp = new PageResp<>();
pageResp.setTotal(pageinfo.getTotal());
pageResp.setList(list);
return pageResp;
}
public void save(EbookSaveReq req){
Ebook ebook = CopyUtil.copy(req,Ebook.class);
if(!ObjectUtils.isEmpty(ebook.getId())){
ebookMapper.updateByPrimaryKey(ebook);
}
}
}
- 在
com.jepcc.test.controller.EbookController
新增保存方法
package com.jepcc.test.controller;
import com.alibaba.fastjson.JSONObject;
import com.jepcc.test.req.EbookReq;
import com.jepcc.test.req.EbookSaveReq;
import com.jepcc.test.resp.CommonResp;
import com.jepcc.test.resp.EbookResp;
import com.jepcc.test.resp.PageResp;
import com.jepcc.test.service.EbookService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/ebook")
public class EbookController {
private static final Logger LOG = LoggerFactory.getLogger(EbookController.class);
@Autowired
private EbookService ebookService;
@GetMapping("/list")
public CommonResp list(EbookReq req){
CommonResp resp = new CommonResp();
PageResp<EbookResp> list = ebookService.list(req);
resp.setContent(list);
return resp;
}
@PostMapping("/save")
public CommonResp save(@RequestBody EbookSaveReq req){
LOG.info("----------------------------------------");
LOG.info("req:{}", JSONObject.toJSONString(req));
LOG.info("----------------------------------------");
CommonResp resp = new CommonResp();
ebookService.save(req);
return resp;
}
}
- 接口测试
POST http://localhost:8088/ebook/save
content-type: application/json
{
"id": 1,
"name": "SpringBoot入门教程",
"category1Id": 10,
"category2Id": 20,
"cover": "/image/cover1.png",
"description": "这是一项测试"
}
###
需要注意的是,如果http请求的Content-Type
是application/json
,则EbookController
中的接口方法save
,其参数前需要添加@RequestBody
注解;
如果http请求的Content-Type
是application/x-www-form-urlencoded
,则EbookController
中的接口方法save
中,其请求参数前不需要@RequestBody
。
后端使用@RequestBody
接收从前端传递过来的json字符串,通常是通过post请求发送过来的请求体数据。
前端调用接口
对admin-book.vue
进行修改。
<template>
<a-layout>
<a-layout-content
:style="{ background: '#fff', padding: '24px', margin: 0, minHeight: '280px' }"
>
<a-table :columns="columns"
:dataSource="ebooks"
:row-key="record=>record.id"
:pagination="pagination"
:loading="loading"
@change="handleTableChange">
<template #cover="{text:cover}">
<img v-if="cover" :src="cover" alt="avatar">
</template>
<template #action="{text,record}">
<a-space>
<a-button type="primary" @click="handleEdit(record)">编辑</a-button>
<a-button type="danger">删除</a-button>
</a-space>
</template>
</a-table>
</a-layout-content>
</a-layout>
<a-modal
title="电子书表单"
v-model:visible="visible"
:confirm-loading="confirmLoading"
@ok="handleOk"
>
<a-form :model="ebook" :label-col="{span:4}" :wrapper-col="{span:16}">
<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-input v-model:value="ebook.category1Id" />
</a-form-item>
<a-form-item label="分类二">
<a-input v-model:value="ebook.category2Id" />
</a-form-item>
<a-form-item label="描述">
<a-input v-model:value="ebook.description" />
</a-form-item>
</a-form>
</a-modal>
</template>
<script lang="ts">
import { defineComponent,ref,onMounted} from 'vue';
import axios from "axios";
export default defineComponent({
name:"AdminEbook",
setup() {
const ebooks = ref();
const pagination = ref({
current:1,
pageSize:4,
total:0
});
const loading = ref(false);
const columns = [
{
title:"封面",
dataIndex:"cover",
key:"cover",
slots:{customRender:'cover'}
},
{
title:"名称",
key:"name",
dataIndex:"name"
},
{
title:"分类一",
key:"category1Id",
dataIndex:"category1Id"
},
{
title:"分类二",
key:"category2Id",
dataIndex:"category2Id"
},
{
title:"文档数",
key:"docCount",
dataIndex:"docCount"
},
{
title:"阅读数",
key:"viewCount",
dataIndex:"viewCount"
},
{
title:"点赞数",
key:"vouteCount",
dataIndex:"voteCount"
},
{
title:"操作",
key:"action",
dataIndex:"action",
slots:{customRender:'action'}
}
];
const visible = ref(false);
const modalText = ref('test');
const confirmLoading = ref(false);
const ebook= ref({});
const handleQuery = (params:any) => {
loading.value = true;
axios.get("/ebook/list",{params:params}).then(response => {
loading.value = false;
const data = response.data.content;
ebooks.value = data.list;
pagination.value.total = data.total;
pagination.value.current = params.page;
})
};
const handleTableChange = (pagination:any) => {
handleQuery({
page:pagination.current,
size:pagination.pageSize
});
}
const handleEdit = (record:any) => {
visible.value = true;
ebook.value = record;
}
const handleOk = () => {
// modalText.value = 'The modal will be closed after two seconds';
// confirmLoading.value = true;
axios.post("/ebook/save",ebook.value).then(response => {
const data = response.data;
if(data.success){
visible.value = false;
confirmLoading.value = false;
handleQuery({
page:pagination.value.current,
size:pagination.value.pageSize
})
}
})
// setTimeout(() => {
// visible.value = false;
// confirmLoading.value = false;
// }, 2000);
};
onMounted(() => {
handleQuery({
page:1,
size:pagination.value.pageSize
});
})
return {
columns,
ebooks,
loading,
pagination,
handleTableChange,
visible,
modalText,
confirmLoading,
handleEdit,
handleOk,
ebook
}
}
})
</script>
<style scoped>
img{
width: 48px;
height: 48px;
}
</style>