最近聽人說如今的項目的都是先後端分離了,原來那種後端渲染模板的方式已然過期。前端
並且最近本身作項目發現,先後端維護一個包裏的代碼確實痛苦不堪、、、vue
爲了讓本身跟上時代的尾巴,增強開發的體驗,就學習了vue.js和restful規範。mysql
發現果真是好東西,那就先攢出來一個小demo,後期再上大項目。webpack
HTTP方法ios |
資源操做web |
URLsql |
描述數據庫 |
GETjson |
SELECTflask |
/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> |
刪除單個資源 |
前端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)
簡單的練習下先後端分離的項目模式,感受restful的風格也不是必須的,最後只要先後端接口能統一就Ok了、、