前后端分离项目学习笔记
该项目为一个基于Springboot+vue实现前后端分离的图书管理项目。
1.首先新建一个springboottest工程,负责完成后端的业务逻辑操作,不需要写页面。
1)先定义实体类Book,然后定义一个数据库层的接口BookRepository,该接口继承了JpaRepository,spring data jpa 默认预先生成了一些基本的CURD的方法,例如:增、删、改等等。最后定义控制层BookHandler,负责和前端页面交互(接收前端增删改查请求)。配置类中CroConfig负责解决跨域问题。代码写好后在idea中启动该项目,随后开始写前端代码。
其中BookHandler代码如下:
1 package com.southwind.springboottest.controller; 2 3 import com.southwind.springboottest.entity.Book; 4 import com.southwind.springboottest.repository.BookRepository; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.data.domain.Page; 7 import org.springframework.data.domain.PageRequest; 8 import org.springframework.web.bind.annotation.*; 9 10 @RestController 11 @RequestMapping("/book") 12 public class BookHandler { 13 @Autowired 14 private BookRepository bookRepository; 15 16 @GetMapping("/findAll/{page}/{size}") 17 public Page<Book> findAll(@PathVariable("page") Integer page, @PathVariable("size") Integer size){ 18 PageRequest request = PageRequest.of(page,size); 19 return bookRepository.findAll(request); 20 } 21 22 @PostMapping("/save") 23 public String save(@RequestBody Book book){ 24 Book result = bookRepository.save(book); 25 if(result != null){ 26 return "success"; 27 }else{ 28 return "error"; 29 } 30 } 31 32 @GetMapping("/findById/{id}") 33 public Book findById(@PathVariable("id") Integer id){ 34 return bookRepository.findById(id).get(); 35 } 36 37 @PutMapping("/update") 38 public String update(@RequestBody Book book){ 39 Book result = bookRepository.save(book); 40 if(result != null){ 41 return "success"; 42 }else{ 43 return "error"; 44 } 45 } 46 47 @DeleteMapping("/deleteById/{id}") 48 public void deleteById(@PathVariable("id") Integer id){ 49 bookRepository.deleteById(id); 50 } 51 }
2.前端部分
首先安装nodejs和vue。
cmd窗口输入vue ui
命令以图形化界面创建和管理项目,输入http://localhost:8000/project/select创建一个Vue项目。创建完后在idea中打开该项目进行开发。
在idea中打开该vue项目,通过router目录下index.js编写页面路由routes。如下图所示:
router/index.js如下:
1 import Vue from 'vue' 2 import VueRouter from 'vue-router' 3 import BookManage from '../views/BookManage' 4 import AddBook from '../views/AddBook' 5 import Index from '../views/Index' 6 import BookUpdate from '../views/BookUpdate' 7 8 Vue.use(VueRouter) 9 10 const routes = [ 11 { 12 path:"/", 13 name:"图书管理", 14 component:Index, 15 show:true, 16 redirect:"/BookManage", 17 children:[ 18 { 19 path:"/BookManage", 20 name:"查询图书", 21 component:BookManage 22 }, 23 { 24 path:"/AddBook", 25 name:"添加图书", 26 component:AddBook 27 } 28 ] 29 }, 30 { 31 path:'/update', 32 component:BookUpdate, 33 show:false 34 } 35 ] 36 37 const router = new VueRouter({ 38 mode: 'history', 39 base: process.env.BASE_URL, 40 routes 41 }) 42 43 export default router
配置好路由后,编写前端页面:
BookManage.vue
<template> <div> <el-table :data="tableData" border style="width: 70%"> <el-table-column fixed prop="id" label="编号" width="150"> </el-table-column> <el-table-column prop="name" label="图书名" width="120"> </el-table-column> <el-table-column prop="author" label="作者" width="120"> </el-table-column> <el-table-column fixed="right" label="操作" width="100"> <template slot-scope="scope"> <el-button @click="edit(scope.row)" type="text" size="small">修改</el-button> <el-button @click="deleteBook(scope.row)" type="text" size="small">删除</el-button> </template> </el-table-column> </el-table> <el-pagination background layout="prev, pager, next" :page-size="pageSize" :total="total" @current-change="page"> </el-pagination> </div> </template> <script> export default { methods: { deleteBook(row){ const _this = this axios.delete('http://localhost:8181/book/deleteById/'+row.id).then(function(resp){ _this.$alert('《'+row.name+'》删除成功!', '消息', { confirmButtonText: '确定', callback: action => { window.location.reload() } }) }) }, edit(row) { this.$router.push({ path: '/update', query:{ id:row.id } }) }, page(currentPage){ const _this = this axios.get('http://localhost:8181/book/findAll/'+(currentPage-1)+'/6').then(function(resp){ console.log(resp) _this.tableData = resp.data.content _this.pageSize = resp.data.size _this.total = resp.data.totalElements }) } }, data() { return { pageSize:'1', total:'11', tableData: [{ id: 1, name: '解忧杂货店', author: '东野圭吾' }, { id: 2, name: '追风筝的人', author: '卡勒德·胡赛尼' }, { id: 3, name: '人间失格', author: '太宰治' }] } }, created() { const _this = this axios.get('http://localhost:8181/book/findAll/0/6').then(function(resp){ console.log(resp) _this.tableData = resp.data.content _this.pageSize = resp.data.size _this.total = resp.data.totalElements }) } } </script>
AddBook.vue:
1 <template> 2 <el-form style="width: 60%" :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm"> 3 4 <el-form-item label="图书名称" prop="name"> 5 <el-input v-model="ruleForm.name"></el-input> 6 </el-form-item> 7 8 <el-form-item label="作者" prop="author"> 9 <el-input v-model="ruleForm.author"></el-input> 10 </el-form-item> 11 12 <el-form-item> 13 <el-button type="primary" @click="submitForm('ruleForm')">提交</el-button> 14 <el-button @click="resetForm('ruleForm')">重置</el-button> 15 </el-form-item> 16 17 </el-form> 18 </template> 19 20 <script> 21 export default { 22 data() { 23 return { 24 ruleForm: { 25 name: '', 26 author: '' 27 }, 28 rules: { 29 name: [ 30 { required: true, message: '图书名称不能为空', trigger: 'blur' } 31 ], 32 author:[ 33 { required: true, message: '作者不能为空', trigger: 'blur' } 34 ] 35 } 36 }; 37 }, 38 methods: { 39 submitForm(formName) { 40 const _this = this 41 this.$refs[formName].validate((valid) => { 42 if (valid) { 43 axios.post('http://localhost:8181/book/save',this.ruleForm).then(function(resp){ 44 if(resp.data == 'success'){ 45 _this.$alert('《'+_this.ruleForm.name+'》添加成功!', '消息', { 46 confirmButtonText: '确定', 47 callback: action => { 48 _this.$router.push('/BookManage') 49 } 50 }) 51 } 52 }) 53 } else { 54 return false; 55 } 56 }); 57 }, 58 resetForm(formName) { 59 this.$refs[formName].resetFields(); 60 } 61 } 62 } 63 </script>
BookUpdate.vue
1 <template> 2 <el-form style="width: 60%" :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm"> 3 4 <el-form-item label="图书编号"> 5 <el-input v-model="ruleForm.id" readOnly></el-input> 6 </el-form-item> 7 8 <el-form-item label="图书名称" prop="name"> 9 <el-input v-model="ruleForm.name"></el-input> 10 </el-form-item> 11 12 <el-form-item label="作者" prop="author"> 13 <el-input v-model="ruleForm.author"></el-input> 14 </el-form-item> 15 16 <el-form-item> 17 <el-button type="primary" @click="submitForm('ruleForm')">修改</el-button> 18 <el-button @click="resetForm('ruleForm')">重置</el-button> 19 </el-form-item> 20 21 </el-form> 22 </template> 23 24 <script> 25 export default { 26 data() { 27 return { 28 ruleForm: { 29 id: '', 30 name: '', 31 author: '' 32 }, 33 rules: { 34 name: [ 35 { required: true, message: '图书名称不能为空', trigger: 'blur' } 36 ], 37 author:[ 38 { required: true, message: '作者不能为空', trigger: 'blur' } 39 ] 40 } 41 }; 42 }, 43 methods: { 44 submitForm(formName) { 45 const _this = this 46 this.$refs[formName].validate((valid) => { 47 if (valid) { 48 axios.put('http://localhost:8181/book/update',this.ruleForm).then(function(resp){ 49 if(resp.data == 'success'){ 50 _this.$alert('《'+_this.ruleForm.name+'》修改成功!', '消息', { 51 confirmButtonText: '确定', 52 callback: action => { 53 _this.$router.push('/BookManage') 54 } 55 }) 56 } 57 }) 58 } else { 59 return false; 60 } 61 }); 62 }, 63 resetForm(formName) { 64 this.$refs[formName].resetFields(); 65 } 66 }, 67 created() { 68 const _this = this 69 axios.get('http://localhost:8181/book/findById/'+this.$route.query.id).then(function(resp){ 70 _this.ruleForm = resp.data 71 }) 72 } 73 } 74 </script>
至此前端页面写完,然后在终端Terminal输入npm run serve 运行该vue项目,点击http://localhost:8080/页面如下所示:(注意后端中为避免端口号冲突改成了8181,前端是8080)
mysql数据库:
rebuild project