这个教程6p学完了~总结一下这个图书增删改查的demo
https://www.bilibili.com/video/av85793766
工程创建 略 数据库部分略
后端 项目结构
Book 实体类
BookRepository 继承JpaRepository,提供数据库增删改查接口
BookHandler 相应请求
BookRepositoryTest 测试BookRepository的方法
Book 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.coconutnut.bookstore_server.entity;import lombok.Data;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;@Entity @Data public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String name; private String author; }
BookRepository 1 2 3 4 5 6 7 8 package com.coconutnut.bookstore_server.repository;import com.coconutnut.bookstore_server.entity.Book;import org.springframework.data.jpa.repository.JpaRepository;public interface BookRepository extends JpaRepository <Book ,Integer > { }
JpaRepository中有常用的增删改查方法,可以直接调用
& 通常流程:先在Test中测试方法,没问题在Controller中写对外接口,浏览器看一下返回值对不对,最后写前端
Spring工程自带一个测试类BookstoreServerApplicationTests 自己创建可在接口名上右键->Go To->Test->Create New Test 生成的测试类加@SpringBootTest,要测试的类@Autowired自动注入,写的方法加@Test即可
BookHandler 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 package com.coconutnut.bookstore_server.controller;import com.coconutnut.bookstore_server.entity.Book;import com.coconutnut.bookstore_server.repository.BookRepository;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.domain.Page;import org.springframework.data.domain.PageRequest;import org.springframework.web.bind.annotation.*;import java.util.List;@RestController @RequestMapping("/book") public class BookHandler { @Autowired private BookRepository bookRepository; @GetMapping("/findAll") public List<Book> findAll () { return bookRepository.findAll(); } @GetMapping("/findAll/{page}/{size}") public Page<Book> findAll (@PathVariable("page") Integer page,@PathVariable("size") Integer size) { PageRequest pageRequest = PageRequest.of(page,size); return bookRepository.findAll(pageRequest); } @PostMapping("/save") public String save (@RequestBody Book book) { Book result = bookRepository.save(book); if (result != null ){ return "success" ; }else { return "error" ; } } @GetMapping("/findById/{id}") public Book findById (@PathVariable("id") Integer id) { return bookRepository.findById(id).get(); } @PutMapping("/update") public String update (@RequestBody Book book) { Book result = bookRepository.save(book); if (result != null ){ return "success" ; }else { return "error" ; } } @DeleteMapping("/deleteById/{id}") public void deleteById (@PathVariable("id") Integer id) { bookRepository.deleteById(id); } }
前端 项目结构
Index.js 配路由
App.vue 常驻的页面
其它vue 嵌入的页面
index.js 配置页面的从属关系与路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import Vue from 'vue' import VueRouter from 'vue-router' import Index from "../views/Index" ;import BookManage from '../views/BookManage' import AddBook from '../views/AddBook' import BookUpdate from '../views/BookUpdate' Vue.use(VueRouter) const routes = [ { path : '/' , name : '图书管理' , show : true , component :Index, redirect :'book-manage' , children :[ { path : '/book-manage' , name : '查询图书' , component : BookManage }, { path : '/add-book' , name : '添加图书' , component : AddBook }, ] }, { path : '/book-update' , name : '修改' , show : false , component : BookUpdate }, ] const router = new VueRouter({ mode : 'history' , base : process.env.BASE_URL, routes }) export default router
页面嵌套与跳转 App.vue中template结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <template > <div id ="app" > <el-container > <el-aside > <el-menu > </el-menu > </el-aside > <el-main > <router-view > </router-view > </el-main > </el-container > </div > </template >
1 2 3 4 5 6 7 8 9 +------------------------------------+ | App | | +------+-------------------------+ | | | menu | main | | | | | +---------------------+ | | | | | | router-view | | | | | | +---------------------+ | | | +------+-------------------------+ | +------------------------------------+
左侧aside区域中放menu,右侧main中由router动态加载
Index.vue中template结构
1 2 3 <template > <router-view > </router-view > </template >
Index.vue中其它都是默认的
根据index.js中的配置,’/‘就加载Index.vue到App.vue的router-view区域,再’/book-manage’加载Index.vue的router-view区域。而Index重定向到book-manage,于是’http:localhost:4000/‘默认就显示了book-manage
而’/book-update’加载Update.vue到App.vue的router-view区域
故显示所有子页面的时候都可以看到菜单
根据routes配置动态加载菜单栏 -> App.vue 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <template > <div id ="app" > <el-container style ="height: 500px; border: 1px solid #eee" > <el-aside width ="200px" style ="background-color: rgb(238, 241, 246)" > <el-menu router :default-openeds ="['0','1']" > <el-submenu v-for ="(item,index) in $router.options.routes" :index ="index+''" v-if ="item.show" > <template slot ="title" > <i class ="el-icon-setting" > </i > {{item.name}}</template > <el-menu-item v-for ="item2 in item.children" :index ="item2.path" :class ="$route.path==item2.path ? 'is-active' : ''" > {{item2.name}}</el-menu-item > </el-submenu > </el-menu > </el-aside > <el-main > <router-view > </router-view > </el-main > </el-container > </div > </template > <script > export default { name : 'app' , } </script > <style > #app { font-family : 'Avenir' , Helvetica, Arial, sans-serif; -webkit-font-smoothing : antialiased; -moz-osx-font-smoothing : grayscale; text-align : center; color : #2c3e50 ; margin-top : 60px ; } </style >
表单显示所有书籍、翻页、删除 -> BookManage.vue 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 <template > <div > <el-table :data ="tableData" border style ="width: 100%" > <el-table-column fixed prop ="id" label ="编号" width ="150" > </el-table-column > <el-table-column prop ="name" label ="书名" width ="150" > </el-table-column > <el-table-column prop ="author" label ="作者" width ="150" > </el-table-column > <el-table-column > 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 ="clickPage" > </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 : '/book-update' , query : { id : row.id } }) }, clickPage (index ) { const _this = this axios.get('http://localhost:8181/book/findAll/' +(index-1 )+'/6' ).then(function (resp ) { _this.tableData = resp.data.content _this.pageSize = resp.data.size _this.total = resp.data.totalElements }) }, }, data ( ) { return { pageSize :'6' , total :'' , tableData :'' } }, created ( ) { const _this = this axios.get('http://localhost:8181/book/findAll/0/6' ).then(function (resp ) { _this.tableData = resp.data.content _this.pageSize = resp.data.size _this.total = resp.data.totalElements }) } } </script > <style scoped > </style >
新增 -> AddBook.vue 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 <template > <el-form style ="width: 60%" :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 > </template > <script > export default { data ( ) { return { 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.$message({ message : '《' +_this.ruleForm.name+'》' +'添加成功' , type : 'success' }) _this.$router.push('/book-manage' ) } }) } }); }, resetForm (formName ) { this .$refs[formName].resetFields(); } } } </script >
修改 -> BookUpdate.vue 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 <template > <el-form style ="width: 60%" :model ="ruleForm" :rules ="rules" ref ="ruleForm" label-width ="100px" class ="demo-ruleForm" > <el-form-item label ="编号" > <el-input v-model ="ruleForm.id" readonly > </el-input > </el-form-item > <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 ="submitForm('ruleForm')" > 重置</el-button > </el-form-item > </el-form > </template > <script > export default { data ( ) { return { ruleForm : { id : '' , 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.put('http://localhost:8181/book/update' ,this .ruleForm).then(function (resp ) { if (resp.data == 'success' ){ _this.$message({ message : '《' +_this.ruleForm.name+'》' +'修改成功' , type : 'success' }) _this.$router.push('/book-manage' ) } }) } }); }, resetForm (formName ) { this .$refs[formName].resetFields(); } }, created ( ) { const _this = this axios.get('http://localhost:8181/book/findById/' +this .$route.query.id).then(function (resp ) { _this.ruleForm = resp.data }) } } </script >
一点想法 Spring Boot + Vue 真是好方便
后端基本不用写什么,要用的方法都有
前端要什么模版直接在element ui里找来用
跟着敲这个demo的时候碰到的坑基本都是和路由有关的,router转来转去有点晕
但是 总之
我真的从来没有在哪个教程听见这么多“就行了”、“自动”、“不用管了”…极度舒适!有架子不用徒手爬墙真好