0、写在前面
最近听人说现在的项目的都是前后端分离了,原来那种后端渲染模板的方式已然过时。
而且最近自己做项目发现,前后端维护一个包里的代码确实痛苦不堪、、、
为了让自己跟上时代的尾巴,加强开发的体验,就学习了vue.js和restful规范。
发现果然是好东西,那就先攒出来一个小demo,后期再上大项目。
1、资源接口表
HTTP方法 | 资源操作 | URL | 描述 |
GET | SELECT | /book/api/v1.0/books | 查多个资源 |
POST | INSERT | /book/api/v1.0/books | 新增资源 |
GET | SELECT | /book/api/v1.0/books/<id> | 查单个资源 |
PUT | UPDATE | /book/api/v1.0/books/<id> | 更新单个资源 |
DELETE | DELETE | /book/api/v1.0/books/<id> | 删除单个资源 |
2、实现
前端vue.js+webpack模板+elemen-ui
1 import Axios from 'axios' 2 3 Axios.defaults.baseURL='http://localhost:5000' 4 5 const BookListURL = '/book/api/v1.0/books' 6 const BookURL = '/book/api/v1.0/books/' 7 8 export function getBookListAPI() { 9 return Axios.get(BookListURL).then(res=>res.data) 10 } 11 12 export function postBookListAPI(data) { 13 return Axios.post(BookListURL,data).then(res=>res.data) 14 } 15 16 export function getBookAPI(id) { 17 return Axios.get(BookListURL+'/'+id).then(res=>res.data) 18 } 19 20 export function putBookAPI(id,data) { 21 return Axios.put(BookListURL+'/'+id,data).then(res=>res.data) 22 } 23 24 export function deleteBookAPI(id) { 25 return Axios.delete(BookListURL+'/'+id).then(res=>res.data) 26 }
1 <template> 2 <div id="book"> 3 <h2>{{ msg }}</h2> 4 <el-table 5 :data="tableData" 6 style="width: 100%" 7 align="center" 8 > 9 <el-table-column 10 prop="id" 11 label="ID" 12 width="60"> 13 </el-table-column> 14 <el-table-column 15 prop="name" 16 label="书名" 17 width="180"> 18 </el-table-column> 19 <el-table-column 20 prop="price" 21 label="价格" 22 width="180"> 23 </el-table-column> 24 <el-table-column label="操作"> 25 <template slot-scope="scope"> 26 <el-button 27 size="mini" 28 @click="handleGet(scope.$index, scope.row)">查看</el-button> 29 <el-button 30 size="mini" 31 type="warning" 32 @click="handleEdit(scope.$index, scope.row)">编辑</el-button> 33 <el-button 34 size="mini" 35 type="danger" 36 @click="handleDelete(scope.$index, scope.row)">删除</el-button> 37 </template> 38 </el-table-column> 39 </el-table> 40 <br> 41 <div id="add-form"> 42 <el-form ref="form" :model="form" label-width="80px"> 43 <el-form-item label="书名"> 44 <el-input v-model="form.name"></el-input> 45 </el-form-item> 46 <el-form-item label="价格"> 47 <el-input v-model="form.price"></el-input> 48 </el-form-item> 49 <el-form-item> 50 <el-button type="primary" @click="addBook">新增</el-button> 51 <el-button type="warning" @click="editBook">修改</el-button> 52 </el-form-item> 53 </el-form> 54 </div> 55 </div> 56 </template> 57 58 <script> 59 export default { 60 name: "Book", 61 data() { 62 return { 63 msg: '图书管理系统', 64 bookList:[], 65 tableData: [], 66 form:{ 67 name:'', 68 price:'' 69 }, 70 current_id:'' 71 } 72 }, 73 methods:{ 74 addBook(){ 75 this.$http.postBookListAPI( 76 { 'name':this.form.name, 77 'price':this.form.price, 78 } 79 ).then( 80 res=>{ 81 this.tableData.push({ 82 id: res.data[0].id, 83 name: res.data[0].name, 84 price: res.data[0].price, 85 }) 86 } 87 ).catch( 88 err=>{ 89 console.log(err.data) 90 } 91 ) 92 }, 93 handleGet(index,row){ 94 this.$http.getBookAPI(row.id).then( 95 res=>{ 96 console.log(res.data) 97 } 98 ).catch( 99 err=>{ 100 console.log(err.data) 101 } 102 ) 103 }, 104 handleEdit(index,row){ 105 this.form.name = row.name 106 this.form.price = row.price 107 this.current_id = row.id 108 109 }, 110 handleDelete(index,row){ 111 this.$http.deleteBookAPI(row.id).then( 112 res=>{ 113 console.log(res.data) 114 this.tableData.splice(index,1) 115 } 116 ).catch( 117 err=>{ 118 console.log(err.data) 119 } 120 ) 121 }, 122 editBook(){ 123 this.$http.putBookAPI(this.current_id,{ 124 'name':this.form.price,'price':this.form.price 125 }).then( 126 res=>{ 127 console.log(res.data) 128 this.reloadData() 129 } 130 ).catch( 131 err=>{ 132 console.log(err.data) 133 } 134 ) 135 }, 136 reloadData(){ 137 this.$http.getBookListAPI().then( 138 res=>{ 139 this.bookList = res.data 140 this.tableData = [] 141 for (let i=0; i<this.bookList.length; i++){ 142 this.tableData.push({ 143 id: this.bookList[i].id, 144 name: this.bookList[i].name, 145 price: this.bookList[i].price, 146 }) 147 } 148 } 149 ).catch( 150 err=>{ 151 console.log(err.data) 152 } 153 ) 154 } 155 } 156 , 157 created() { 158 this.$http.getBookListAPI().then( 159 res=>{ 160 this.bookList = res.data 161 for (let i=0; i<this.bookList.length; i++){ 162 this.tableData.push({ 163 id: this.bookList[i].id, 164 name: this.bookList[i].name, 165 price: this.bookList[i].price, 166 }) 167 } 168 } 169 ).catch( 170 err=>{ 171 console.log(err.data) 172 } 173 ) 174 } 175 } 176 </script> 177 178 <style scoped> 179 180 </style>
后端flask+flask_restful
1 # -*- coding: UTF-8 -*- 2 3 from flask import Flask,jsonify,request 4 from flask_sqlalchemy import SQLAlchemy 5 from flask_restful import reqparse, abort, Api, Resource 6 7 8 9 app = Flask(__name__) 10 api = Api(app) 11 12 class Config: 13 SECRET_KEY = '1a1@z2' 14 SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:root@127.0.0.1/book?charset=utf8' 15 16 #SQLALCHEMY_TRACK_MODIFICATIONS = True 17 #解决返回无法显示汉字问题 18 JSON_AS_ASCII = False 19 RESTFUL_JSON = dict(ensure_ascii=False) 20 @staticmethod 21 def init_app(app): 22 pass 23 24 app.config.from_object(Config) 25 db=SQLAlchemy(app) 26 27 28 #数据库模型 29 class Book(db.Model): 30 __tablename__ = 'book' 31 id = db.Column(db.Integer, primary_key=True, index=True,autoincrement=True) 32 name = db.Column(db.String(64), unique=True, index=True) 33 price = db.Column(db.String(64)) 34 35 def __repr__(self): 36 return '<Book %r>'%(self.name) 37 38 39 40 def get_book(id): 41 book_obj = Book.query.filter_by(id=id).first() 42 if not book_obj: 43 abort(404, message="id(%s) is not found"%(id)) 44 return book_obj 45 46 #视图 47 #解决前端跨域访问的问题 48 @app.after_request 49 def after_request(response): 50 response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization,session_id') 51 response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS,HEAD') 52 # 这里不能使用add方法,否则会出现 The 'Access-Control-Allow-Origin' header contains multiple values 的问题 53 response.headers['Access-Control-Allow-Origin'] = '*' 54 return response 55 56 @app.route('/') 57 def hello_world(): 58 return 'Hello World!' 59 60 @app.route('/db_create') 61 def db_create(): 62 db.create_all() 63 return 'db create success!' 64 65 #资源组的增查,对应get,post 66 class BookListAPI(Resource): 67 def __init__(self): 68 self.reqparse = reqparse.RequestParser() 69 self.reqparse.add_argument('name',type=str, required = True, 70 help = "pleas send name", location = ['json','form']) 71 self.reqparse.add_argument('price',type=str, required = True, 72 help = "pleas send price", location = ['json','form']) 73 self.returnData = { 'state':1,'data':[],'url':'','items_url':'' } 74 super(BookListAPI, self).__init__() 75 76 def get(self): 77 self.returnData['url'] = '/book/api/v1.0/books' 78 self.returnData['items_url'] = '/book/api/v1.0/books/<id>' 79 books = Book.query.order_by(Book.id.asc()).all() 80 for book_obj in books: 81 book_info = { 'id': book_obj.id, 82 'name':book_obj.name, 83 'price':book_obj.price, 84 'url':'/book/api/v1.0/books/'+str(book_obj.id) 85 } 86 self.returnData['data'].append(book_info) 87 print self.returnData 88 return jsonify(self.returnData) 89 90 def post(self): 91 book_name = self.reqparse.parse_args()['name'] 92 book_price = self.reqparse.parse_args()['price'] 93 new_book = Book(name=book_name,price=book_price) 94 db.session.add(new_book) 95 db.session.commit() 96 book_info = {'id': new_book.id, 97 'name': new_book.name, 98 'price': new_book.price} 99 self.returnData['data'].append(book_info) 100 return jsonify(self.returnData) 101 102 #单个资源的查询,对应get,put,delete 103 class BookAPI(Resource): 104 def __init__(self): 105 self.reqparse = reqparse.RequestParser() 106 self.reqparse.add_argument('name',type=str, required = True, 107 help = "pleas send name", location = ['json','form']) 108 self.reqparse.add_argument('price',type=str, required = True, 109 help = "pleas send price", location = ['json','form']) 110 self.returnData = {'state': 1, 'data': []} 111 super(BookAPI, self).__init__() 112 113 def get(self,id): 114 book_obj = get_book(id) 115 book_info = {'id': book_obj.id, 116 'name': book_obj.name, 117 'price': book_obj.price} 118 self.returnData['data'].append(book_info) 119 return jsonify(self.returnData) 120 121 def put(self,id): 122 book_obj = get_book(id) 123 book_name = self.reqparse.parse_args()['name'] 124 book_price = self.reqparse.parse_args()['price'] 125 db.session.add(book_obj) 126 db.session.commit() 127 book_info = {'id': book_obj.id, 128 'name': book_obj.name, 129 'price': book_obj.price} 130 self.returnData['data'].append(book_info) 131 return jsonify(self.returnData) 132 133 def delete(self,id): 134 book_obj = get_book(id) 135 db.session.delete(book_obj) 136 db.session.commit() 137 return jsonify(self.returnData) 138 139 api.add_resource(BookListAPI, '/book/api/v1.0/books') 140 api.add_resource(BookAPI, '/book/api/v1.0/books/<id>') 141 142 if __name__ == '__main__': 143 app.run(debug=True)
3、经验总结
简单的练习下前后端分离的项目模式,感觉restful的风格也不是必须的,最后只要前后端接口能统一就Ok了、、