前后端分离的一个小demo

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 }
/src/restful/api.js
  1 <template>
  2     <div id="book">
  3         <h2>{{ msg }}</h2>
  4         <el-table
  5           :data="tableData"
  6           style=" 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>
/src/components/Book.vue

后端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)
app.py

3、经验总结

简单的练习下前后端分离的项目模式,感觉restful的风格也不是必须的,最后只要前后端接口能统一就Ok了、、

原文地址:https://www.cnblogs.com/cx59244405/p/11402992.html