add mongodb & bokehjs
parent
bf4290ecbb
commit
939058411e
|
@ -16,6 +16,13 @@
|
||||||
|
|
||||||
# 更新日志
|
# 更新日志
|
||||||
|
|
||||||
|
* 2021年1月22日,进一步完善服务器基本框架。
|
||||||
|
* 基本尝试使用了BokehJS库的使用,计划用JS替代Python版本的Bokeh功能控件。
|
||||||
|
* 尝试Plotly的使用,计划作为Bokeh的备选。
|
||||||
|
* 尝试使用Javascript的Jquery库,利用ajax向服务器发送post请求传递信息。
|
||||||
|
* 发现Python版本的Bokeh功能控件部署在服务器上存在的一些问题,包括后台终端无后台信息等,暂时将该功能控件禁用。
|
||||||
|
* 新增Mongo数据库的使用,计划用来记录用户的行为数据;该数据库的部署已经完成;该数据库的python封装已完成雏形,但尚不完善,需要后续根据采集节点的设计进一步完善。
|
||||||
|
* 后续需要在项目管理方面进行梳理,当前代码库已经存在一定的混乱。
|
||||||
* 2021年1月20日,完成了服务器基本框架的搭建。实现的功能有:
|
* 2021年1月20日,完成了服务器基本框架的搭建。实现的功能有:
|
||||||
* 用户登录、认证、退出系统,新用户注册新账户
|
* 用户登录、认证、退出系统,新用户注册新账户
|
||||||
* 在mysql数据库中存储、更新用户基本信息
|
* 在mysql数据库中存储、更新用户基本信息
|
||||||
|
|
|
@ -2,9 +2,9 @@ import tornado.ioloop #开启循环,让服务一直等待请求的到来
|
||||||
import tornado.web #web服务基本功能都封装在此模块中
|
import tornado.web #web服务基本功能都封装在此模块中
|
||||||
import tornado.options #从命令行中读取设置
|
import tornado.options #从命令行中读取设置
|
||||||
from tornado.options import define,options #导入包
|
from tornado.options import define,options #导入包
|
||||||
from handler import main, auth
|
from handler import main, auth, spice
|
||||||
# import _thread,threading
|
# import _thread,threading
|
||||||
from spice import app_spice
|
# from spice import app_spice
|
||||||
|
|
||||||
define('port',default='8000',help='Listening port',type=int) #定义如何接受传进来的东西
|
define('port',default='8000',help='Listening port',type=int) #定义如何接受传进来的东西
|
||||||
|
|
||||||
|
@ -16,7 +16,11 @@ class Application(tornado.web.Application): #引入Application类,重写方
|
||||||
(r'/login',auth.LoginHandler),
|
(r'/login',auth.LoginHandler),
|
||||||
(r'/logout',auth.LogoutHandler),
|
(r'/logout',auth.LogoutHandler),
|
||||||
(r'/register',auth.RegisterHandler),
|
(r'/register',auth.RegisterHandler),
|
||||||
(r'/spice',main.Spice_Xyce_Handler),
|
# (r'/spice',spice.Spice_1_Handler),
|
||||||
|
(r'/spice2',spice.Spice_2_Handler),
|
||||||
|
(r'/spice3',spice.Spice_3_Handler),
|
||||||
|
(r'/spice4',spice.Spice_4_Handler),
|
||||||
|
(r'/test',main.TestHandler),
|
||||||
]
|
]
|
||||||
settings = dict(
|
settings = dict(
|
||||||
debug = False, #调试模式,修改后自动重启服务,不需要自动重启,生产情况下切勿开启,安全性
|
debug = False, #调试模式,修改后自动重启服务,不需要自动重启,生产情况下切勿开启,安全性
|
||||||
|
@ -50,7 +54,7 @@ app = Application() #实例化
|
||||||
if __name__ == '__main__': #当.py文件被直接运行时,代码块将被运行;当.py文件以模块形式被导入时,代码块不被运行。
|
if __name__ == '__main__': #当.py文件被直接运行时,代码块将被运行;当.py文件以模块形式被导入时,代码块不被运行。
|
||||||
|
|
||||||
# 开启 bokeh 服务
|
# 开启 bokeh 服务
|
||||||
app_spice.app_spice_begin()
|
# app_spice.app_spice_begin()
|
||||||
|
|
||||||
tornado.options.parse_command_line()
|
tornado.options.parse_command_line()
|
||||||
app.listen(options.port) ##如果一个与define语句中同名的设置在命令行中被给出,那么它将成为全局的options的一个属性 即 options.port 相当于define的url的port
|
app.listen(options.port) ##如果一个与define语句中同名的设置在命令行中被给出,那么它将成为全局的options的一个属性 即 options.port 相当于define的url的port
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
from pymongo import MongoClient
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
|
class Mongo_DB():
|
||||||
|
|
||||||
|
def __init__(self, Mongo_URL = 'mongodb://localhost:27017/'):
|
||||||
|
self.Client = MongoClient(Mongo_URL)
|
||||||
|
|
||||||
|
def connect(self,DataBase = 'default', Collection = 'default'):
|
||||||
|
self.DataBase = self.Client[DataBase]
|
||||||
|
self.Collection = self.DataBase[Collection]
|
||||||
|
|
||||||
|
def __insert(self, contents ):
|
||||||
|
if type(contents) == list:
|
||||||
|
self.Collection.insert_many(contents)
|
||||||
|
elif type(contents) == dict:
|
||||||
|
self.Collection.insert_one(contents)
|
||||||
|
else:
|
||||||
|
print("Data's format error !!!")
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, behavior = '' , spice = '', tags = ''):
|
||||||
|
message = {}
|
||||||
|
message['behavior'] = behavior
|
||||||
|
message['spice'] = spice
|
||||||
|
message['tags'] = tags
|
||||||
|
message['date'] = datetime.datetime.utcnow()
|
||||||
|
self.__insert(message)
|
||||||
|
|
||||||
|
Mongo = Mongo_DB()
|
|
@ -10,7 +10,7 @@ table_name = "user_info"
|
||||||
|
|
||||||
# 打开数据库连接
|
# 打开数据库连接
|
||||||
db = pymysql.connect( database_ip, database_user, database_passwd, database_name )
|
db = pymysql.connect( database_ip, database_user, database_passwd, database_name )
|
||||||
|
print('open mysql success !!!')
|
||||||
# 使用cursor()方法获取操作游标
|
# 使用cursor()方法获取操作游标
|
||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,6 +1,5 @@
|
||||||
import datetime
|
import datetime
|
||||||
from .database import *
|
from .MysqlDB import *
|
||||||
|
|
||||||
|
|
||||||
#用户密码匹配判断函数
|
#用户密码匹配判断函数
|
||||||
def authenticate(username,password):
|
def authenticate(username,password):
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
from .main import AuthBaseHandler
|
from .main import AuthBaseHandler
|
||||||
from .account import authenticate, add_user
|
from .account import authenticate, add_user
|
||||||
|
from .MongoDB import *
|
||||||
|
|
||||||
class LoginHandler(AuthBaseHandler):
|
class LoginHandler(AuthBaseHandler):
|
||||||
def get(self,*args,**kwargs):
|
def get(self,*args,**kwargs):
|
||||||
self.render('login.html')
|
self.render('auth/login.html')
|
||||||
|
|
||||||
def post(self,*args,**kwargs):
|
def post(self,*args,**kwargs):
|
||||||
username = self.get_argument('username',None)
|
username = self.get_argument('username',None)
|
||||||
|
@ -15,11 +16,15 @@ class LoginHandler(AuthBaseHandler):
|
||||||
if passed:
|
if passed:
|
||||||
# 保存cookie信息到redis数据库
|
# 保存cookie信息到redis数据库
|
||||||
self.session.set('username',username) #将前面设置的cookie设置为username,保存用户登录信息
|
self.session.set('username',username) #将前面设置的cookie设置为username,保存用户登录信息
|
||||||
print(self.session.get('username'))
|
print(self.session.get('username')+' login success !!!')
|
||||||
next_url = self.get_argument('next', '') # 获取之前页面的路由
|
next_url = self.get_argument('next', '') # 获取之前页面的路由
|
||||||
if next_url:
|
if next_url:
|
||||||
|
Mongo.connect(DataBase='example',Collection=username)
|
||||||
|
Mongo.update(behavior='login',tags='auth')
|
||||||
self.redirect(next_url) #跳转主页路由
|
self.redirect(next_url) #跳转主页路由
|
||||||
else:
|
else:
|
||||||
|
Mongo.connect(DataBase='example',Collection=username)
|
||||||
|
Mongo.update(behavior='login',tags='auth')
|
||||||
self.redirect('/')
|
self.redirect('/')
|
||||||
else:
|
else:
|
||||||
self.write({'msg':'login fail'}) #不通过,有问题
|
self.write({'msg':'login fail'}) #不通过,有问题
|
||||||
|
@ -28,6 +33,8 @@ class LoginHandler(AuthBaseHandler):
|
||||||
|
|
||||||
class LogoutHandler(AuthBaseHandler):
|
class LogoutHandler(AuthBaseHandler):
|
||||||
def get(self, *args, **kwargs):
|
def get(self, *args, **kwargs):
|
||||||
|
Mongo.connect(DataBase='example',Collection=self.get_current_user())
|
||||||
|
Mongo.update(behavior='logout',tags='auth')
|
||||||
#self.session.set('username','') #将用户的cookie清除
|
#self.session.set('username','') #将用户的cookie清除
|
||||||
self.session.delete('username')
|
self.session.delete('username')
|
||||||
self.redirect('/login')
|
self.redirect('/login')
|
||||||
|
@ -39,7 +46,7 @@ class LogoutHandler(AuthBaseHandler):
|
||||||
class RegisterHandler(AuthBaseHandler):
|
class RegisterHandler(AuthBaseHandler):
|
||||||
def get(self, *args, **kwargs):
|
def get(self, *args, **kwargs):
|
||||||
print('register')
|
print('register')
|
||||||
self.render('register.html')
|
self.render('auth/register.html')
|
||||||
|
|
||||||
def post(self, *args, **kwargs):
|
def post(self, *args, **kwargs):
|
||||||
print('registerpost')
|
print('registerpost')
|
||||||
|
@ -51,9 +58,11 @@ class RegisterHandler(AuthBaseHandler):
|
||||||
if username and password1 and (password1 == password2):
|
if username and password1 and (password1 == password2):
|
||||||
success = add_user(username,password1)
|
success = add_user(username,password1)
|
||||||
if success:
|
if success:
|
||||||
|
Mongo.connect(DataBase='example',Collection=username)
|
||||||
|
Mongo.update(behavior='register',tags='auth')
|
||||||
self.redirect('/login')
|
self.redirect('/login')
|
||||||
else:
|
else:
|
||||||
self.write({'msg':'register fail'})
|
self.write({'msg':'register fail'})
|
||||||
else:
|
else:
|
||||||
print('register again')
|
print('register again')
|
||||||
self.render('register.html')
|
self.render('auth/register.html')
|
|
@ -1,9 +1,7 @@
|
||||||
import tornado.web
|
import tornado.web
|
||||||
from pycket.session import SessionMixin
|
from pycket.session import SessionMixin
|
||||||
from bokeh.embed import server_document
|
from .MongoDB import *
|
||||||
from jinja2 import Environment, FileSystemLoader
|
|
||||||
|
|
||||||
env = Environment(loader=FileSystemLoader('template'))
|
|
||||||
|
|
||||||
class AuthBaseHandler(tornado.web.RequestHandler,SessionMixin):
|
class AuthBaseHandler(tornado.web.RequestHandler,SessionMixin):
|
||||||
def get_current_user(self): #重写get_current_user()方法
|
def get_current_user(self): #重写get_current_user()方法
|
||||||
|
@ -14,17 +12,19 @@ class IndexHandler(AuthBaseHandler):
|
||||||
|
|
||||||
@tornado.web.authenticated #@tornado.web.authenticated装饰器包裹get方法时,表示这个方法只有在用户合法时才会调用,authenticated装饰器会调用get_current_user()方法获取current_user的值,若值为False,则重定向到登录url装饰器判断有没有登录,如果没有则跳转到配置的路由下去,但是要在app.py里面设置login_url
|
@tornado.web.authenticated #@tornado.web.authenticated装饰器包裹get方法时,表示这个方法只有在用户合法时才会调用,authenticated装饰器会调用get_current_user()方法获取current_user的值,若值为False,则重定向到登录url装饰器判断有没有登录,如果没有则跳转到配置的路由下去,但是要在app.py里面设置login_url
|
||||||
def get(self,*args,**kwargs):
|
def get(self,*args,**kwargs):
|
||||||
user = self.get_current_user()
|
username = self.get_current_user()
|
||||||
self.render('index.html',user=user)
|
self.render('index.html',user=username)
|
||||||
|
|
||||||
|
class TestHandler(AuthBaseHandler):
|
||||||
|
|
||||||
class Spice_Xyce_Handler(AuthBaseHandler):
|
@tornado.web.authenticated #@tornado.web.authenticated装饰器包裹get方法时,表示这个方法只有在用户合法时才会调用,authenticated装饰器会调用get_current_user()方法获取current_user的值,若值为False,则重定向到登录url装饰器判断有没有登录,如果没有则跳转到配置的路由下去,但是要在app.py里面设置login_url
|
||||||
|
def post(self,*args,**kwargs):
|
||||||
|
username = self.get_current_user()
|
||||||
|
message = self.get_argument('message')
|
||||||
|
|
||||||
@tornado.web.authenticated
|
print('TestHandler: '+username+' '+message)
|
||||||
def get(self,*args,**kwargs):
|
Mongo.connect(DataBase='example',Collection=username)
|
||||||
template = env.get_template('spice.html')
|
Mongo.update(behavior=message,tags='test')
|
||||||
script = server_document('http://localhost:5006/bkapp')
|
|
||||||
self.write(template.render(script=script))
|
self.write("success")
|
||||||
|
|
||||||
# script = server_document('http://localhost:5006/bkapp')
|
|
||||||
# self.render('spice.html',script=script)
|
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
from .main import AuthBaseHandler
|
||||||
|
import tornado.web
|
||||||
|
from bokeh.embed import server_document
|
||||||
|
# from jinja2 import Environment, FileSystemLoader
|
||||||
|
|
||||||
|
class Spice_1_Handler(AuthBaseHandler):
|
||||||
|
|
||||||
|
@tornado.web.authenticated
|
||||||
|
def get(self,*args,**kwargs):
|
||||||
|
# env = Environment(loader=FileSystemLoader('template'))
|
||||||
|
# template = env.get_template('spice.html')
|
||||||
|
# script = server_document('http://localhost:5006/bkapp')
|
||||||
|
# self.write(template.render(script=script))
|
||||||
|
|
||||||
|
script = server_document('http://localhost:5006/bkapp')
|
||||||
|
self.render('spice/spice1.html',script=script)
|
||||||
|
|
||||||
|
class Spice_2_Handler(AuthBaseHandler):
|
||||||
|
|
||||||
|
@tornado.web.authenticated
|
||||||
|
def get(self,*args,**kwargs):
|
||||||
|
js_import = """
|
||||||
|
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.2.3.min.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.2.3.min.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.2.3.min.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-api-2.2.3.min.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-api-2.2.3.min.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
|
||||||
|
"""
|
||||||
|
js_code = """
|
||||||
|
<script>
|
||||||
|
// create a data source to hold data
|
||||||
|
var source = new Bokeh.ColumnDataSource({
|
||||||
|
data: { x: [], y: [] }
|
||||||
|
});
|
||||||
|
|
||||||
|
// make a plot with some tools
|
||||||
|
var plot = Bokeh.Plotting.figure({
|
||||||
|
title:'Example of Random data',
|
||||||
|
tools: "pan,wheel_zoom,box_zoom,reset,save",
|
||||||
|
height: 300,
|
||||||
|
width: 300
|
||||||
|
});
|
||||||
|
|
||||||
|
// add a line with data from the source
|
||||||
|
plot.line({ field: "x" }, { field: "y" }, {
|
||||||
|
source: source,
|
||||||
|
line_width: 2
|
||||||
|
});
|
||||||
|
|
||||||
|
// show the plot, appending it to the end of the current section
|
||||||
|
Bokeh.Plotting.show(plot);
|
||||||
|
|
||||||
|
function addPoint() {
|
||||||
|
// add data --- all fields must be the same length.
|
||||||
|
source.data.x.push(Math.random())
|
||||||
|
source.data.y.push(Math.random())
|
||||||
|
|
||||||
|
// notify the DataSource of "in-place" changes
|
||||||
|
source.change.emit()
|
||||||
|
}
|
||||||
|
|
||||||
|
function Callback_Button() {
|
||||||
|
addPoint();
|
||||||
|
var data = new Object();
|
||||||
|
data["name"] = "XerCis";
|
||||||
|
data["message"] = "This is the message from ajax(spice2) !";
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: "/test",
|
||||||
|
data: data,
|
||||||
|
success: function (response) {
|
||||||
|
alert(response);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
var addDataButton = document.createElement("Button");
|
||||||
|
addDataButton.appendChild(document.createTextNode("Add Some Data!!!"));
|
||||||
|
document.currentScript.parentElement.appendChild(addDataButton);
|
||||||
|
addDataButton.addEventListener("click", Callback_Button);
|
||||||
|
|
||||||
|
addPoint();
|
||||||
|
addPoint();
|
||||||
|
</script>
|
||||||
|
"""
|
||||||
|
self.render('spice/spice2.html',js_import=js_import,js_code=js_code)
|
||||||
|
|
||||||
|
|
||||||
|
class Spice_3_Handler(AuthBaseHandler):
|
||||||
|
@tornado.web.authenticated
|
||||||
|
def get(self,*args,**kwargs):
|
||||||
|
self.render('spice/spice3.html')
|
||||||
|
|
||||||
|
|
||||||
|
class Spice_4_Handler(AuthBaseHandler):
|
||||||
|
@tornado.web.authenticated
|
||||||
|
def get(self,*args,**kwargs):
|
||||||
|
self.render('spice/spice4.html')
|
Binary file not shown.
|
@ -11,6 +11,15 @@
|
||||||
<form action="/spice" method="get">
|
<form action="/spice" method="get">
|
||||||
<div><input type="submit" value="spice"></div>
|
<div><input type="submit" value="spice"></div>
|
||||||
</form>
|
</form>
|
||||||
|
<form action="/spice2" method="get">
|
||||||
|
<div><input type="submit" value="spice2"></div>
|
||||||
|
</form>
|
||||||
|
<form action="/spice3" method="get">
|
||||||
|
<div><input type="submit" value="spice3"></div>
|
||||||
|
</form>
|
||||||
|
<form action="/spice4" method="get">
|
||||||
|
<div><input type="submit" value="spice4"></div>
|
||||||
|
</form>
|
||||||
<form action="/logout" method="get">
|
<form action="/logout" method="get">
|
||||||
<div><input type="submit" value="退出"></div>
|
<div><input type="submit" value="退出"></div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!doctype html>
|
||||||
|
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Embedding a Bokeh Server With </title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
This Bokeh app below served by a Bokeh server that has been embedded
|
||||||
|
in another web app framework. For more information see the section
|
||||||
|
<a target="_blank" href="https://docs.bokeh.org/en/latest/docs/user_guide/server.html#embedding-bokeh-server-as-a-library">Embedding Bokeh Server as a Library</a>
|
||||||
|
in the User's Guide.
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{% raw script %}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Complete Example</title>
|
||||||
|
|
||||||
|
{% raw js_import %}
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
{% raw js_code %}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,95 @@
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Complete Example</title>
|
||||||
|
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.2.3.min.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.2.3.min.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.2.3.min.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-api-2.2.3.min.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-api-2.2.3.min.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<button id="foo">点击</button>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$("#foo").click(function(){
|
||||||
|
var data = new Object();
|
||||||
|
data["name"] = "XerCis";
|
||||||
|
data["message"] = "This is the message from ajax(spice2) !";
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: "/test",
|
||||||
|
data: data,
|
||||||
|
success: function (response) {
|
||||||
|
alert(response);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<script>
|
||||||
|
// create a data source to hold data
|
||||||
|
var source = new Bokeh.ColumnDataSource({
|
||||||
|
data: { x: [], y: [] }
|
||||||
|
});
|
||||||
|
|
||||||
|
// make a plot with some tools
|
||||||
|
var plot = Bokeh.Plotting.figure({
|
||||||
|
title:'Example of Random data',
|
||||||
|
tools: "pan,wheel_zoom,box_zoom,reset,save",
|
||||||
|
height: 300,
|
||||||
|
width: 300
|
||||||
|
});
|
||||||
|
|
||||||
|
// add a line with data from the source
|
||||||
|
plot.line({ field: "x" }, { field: "y" }, {
|
||||||
|
source: source,
|
||||||
|
line_width: 2
|
||||||
|
});
|
||||||
|
|
||||||
|
// show the plot, appending it to the end of the current section
|
||||||
|
Bokeh.Plotting.show(plot);
|
||||||
|
|
||||||
|
function addPoint() {
|
||||||
|
// add data --- all fields must be the same length.
|
||||||
|
source.data.x.push(Math.random())
|
||||||
|
source.data.y.push(Math.random())
|
||||||
|
|
||||||
|
// notify the DataSource of "in-place" changes
|
||||||
|
source.change.emit()
|
||||||
|
}
|
||||||
|
|
||||||
|
function Callback_Button() {
|
||||||
|
addPoint();
|
||||||
|
var data = new Object();
|
||||||
|
data["name"] = "XerCis";
|
||||||
|
data["message"] = "This is the message from ajax(spice2) !";
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: "/test",
|
||||||
|
data: data,
|
||||||
|
success: function (response) {
|
||||||
|
alert(response);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var addDataButton = document.createElement("Button");
|
||||||
|
addDataButton.appendChild(document.createTextNode("Add Some Data!!!"));
|
||||||
|
document.currentScript.parentElement.appendChild(addDataButton);
|
||||||
|
addDataButton.addEventListener("click", Callback_Button);
|
||||||
|
|
||||||
|
addPoint();
|
||||||
|
addPoint();
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,31 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<button id="send">发送复杂数据</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var data = new Object();
|
||||||
|
data["name"] = "XerCis";
|
||||||
|
data["message"] = "This is the message from ajax(spice4) !";
|
||||||
|
data["number"] = "2015012755";
|
||||||
|
data["grade"] = new Array();
|
||||||
|
data["grade"].push({"Chinese": 70});
|
||||||
|
data["grade"].push({"Math": 80});
|
||||||
|
data["grade"].push({"English": 90});
|
||||||
|
$("#send").click(function () {
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: "/test",
|
||||||
|
data: data,
|
||||||
|
success: function (response) {
|
||||||
|
alert(response);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue