#!/usr/bin/env python3 # -*- coding:utf-8 -*- # create by lonelylizard 2020-05-09 from bottle import Bottle,run,get,post,request,error,response,template import pymysql import re import json import collections from copy import deepcopy import argparse from DBUtils.PooledDB import PooledDB description = ''' 通用帮助: 前端请求步骤示例: 1、[POST] http://sumver.cn:8999/ymyql?id=sumver 2、Body选择raw格式,直接填写sql语句,无需任何额外符号修饰 正确示例:select id,user,pwd from user where id between 1 AND 5 ============================================================== ''' epilog = ''' ymysql [参数] =================================================== 参数列表: -u user 数据库用户名(必填) -p password 数据库密码(必填) -d database 指定数据库名(必填) -s sercet 鉴权参数(必填),该参数将要求在请求时携带 示例:ymysql -u root -p 1234 -d zulin -s sumver =================================================== ''' #args,参数列表 parser = argparse.ArgumentParser(description,epilog) parser.add_argument("-u","-uname",required=True) parser.add_argument("-p","-password",required=True) parser.add_argument("-d","-database",required=True) parser.add_argument("-id",required=True) args = parser.parse_args() #数据库连接配置 __config = { "host":"localhost", "port":3306, "user":args.u, "password":args.p, "database":args.d, "charset":'utf8' } #配置连接池,加快查询速度 POOL = PooledDB( creator=pymysql, # 使用链接数据库的模块 maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数 mincached=2, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建 maxcached=5, # 链接池中最多闲置的链接,0和None不限制 maxshared=3, # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。 blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错 maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制 setsession=[], # 开始会话前执行的命令列表。 **__config ) # conn = pymysql.connect(host='localhost',user='root',password='root',database='zulin',charset='utf8',) # class xmysql: app = Bottle() nameArr = []#存放需要返回的字段数组 #获取到select语句中的每个字段,返回数组 def getNames(sql): nameArr.clear() rule = re.compile("select ([\\s\\S]*) from") namesArr = rule.findall(sql)[0] for a in namesArr.split(","): nameArr.append(a.strip()) # nameArr.append(a) # print(nameArr) # print("id数组:",nameArr) # print("id数组长度",len(nameArr)) def query(sql): try: getNames(sql) except Exception as e: return '

前端传输的参数不正确!
为了安全起见,仅支持select操作
前端请求步骤示例:
1、[POST] http://sumver.cn:8999/ymsql?id=sumver
2、Body选择raw格式,直接填写sql语句,无需任何额外符号修饰
正确示例:select id,user,pwd from user where id between 1 AND 5

' else: if nameArr[0]=="*": return "请不要使用select *,你应当明确你要取的字段" else: all_data = collections.OrderedDict() mdata = collections.OrderedDict() num = 1 # conn = getConnect() conn = POOL.connection() cursor = conn.cursor() try: cursor.execute(sql) except Exception as e: print("连接数据库或查询语句出现错误:",e) cursor.close() conn.close() result = cursor.fetchall()#取出结果集 all_data["count"]=len(result) #读取数据库返回结果,拼接成字典返回 for item in result: mdata.clear()#每次都清空mdata i = 0 for item2 in item: mdata[nameArr[i]]=item2 # print(mdata[nameArr[i]]) i+=1 all_data[str(num)]=mdata.copy() #这里是坑,如果不是深拷贝,输出的结果会被最后一个mdata覆盖 # print("all_data:",all_data) num+=1 # print("mdata:",mdata) return all_data @app.route("/",method="GET") def hello(): return "请使用post请求!" @app.route("/",method="POST") def do_hello(): if request.params.get("id") != args.id : return "鉴权参数不对" else: sql = request.body.read().decode('utf-8')#read读到的是字节流,转化为Str才处理 st = query(sql) if type(st).__name__=="OrderedDict": return json.dumps(st,sort_keys=False)#返回json,不要排序,否则json里的键值对会根据类型、大小进行排序 else: return st run(app,host='0.0.0.0',port=8999,debug=True,reloader=False)