使用Python开发轻量级的Web框架以及基于WSGI的服务器来实现一个网站页面

news/2024/5/11 0:58:52/文章来源:https://cdtaogang.blog.csdn.net/article/details/88730705

说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!

目录

一丶项目说明

二丶数据准备 

三丶使用网络TCP开发一个基于WSGI协议的Web服务器

四丶使用python3开发一个轻量级的Web框架

五丶在框架中实现添加股票功能

六丶在框架中实现删除股票功能

七丶在框架中实现修改股票功能


一丶项目说明

1.实现过程

用户通过浏览器向Web服务器请求资源,Web服务器基于WSGI协议调用Web框架中application接口函数,在application函数中根据用户请求地址,匹配路由规则,匹配成功后调用请求地址对应的视图函数,在视图函数中主要操作为对MySQL数据库的增删改查以及读取html页面模板内容,然后将模板中需要填充的数据与MySQL返回的数据进行字符串拼接,然后返回给Web服务器,最终Web服务器将拿到的数据当作响应体数据,并与状态码和响应头进行拼接后返回给浏览器,在浏览器上呈现用户想要看到的资源数据

2.最终效果展示

  • 股票信息(index.html)
  • 逻辑说明:当用户访问该网页,将数据库中的info股票信息表的数据进行分页查询后显示在网页上,每页显示12条数据;当点击不同的页数时,那么就要求显示其对应页数的正确数据;当前页数为第一页或者最后一页时,则不显示上一页和下一页功能按钮;每条数据都会有一个添加功能按钮,当用户点击添加并且成功后,那么这条股票数据就不会出现添加功能按钮了

  •  个人中心(center.html)
  • 逻辑说明:在个人中心页面显示出用户添加成功后的股票信息,每只股票都有修改和删除功能按钮;当用户点击删除功能后则该支股票不显示在个人中心页面中,那么此时这支被删除的股票在回到股票信息页面中则出现添加功能按钮;当用户点击修改功能按钮,则成功跳转到修改页面进行修改

  • 修改界面(update.html) 
  • 逻辑说明:在修改页面中显示两个股票信息字段,一个是股票代码另一个是备注信息,修改或添加备注信息后,当即修改功能按钮,修改成功后则跳转到个人中心页面,并正确显示出该支股票修改添加后的信息

 3.效果动图

二丶数据准备 

1.在MySQL中创建stock_db数据库

create database stock_db charset=utf8;

2.在stock_db数据库下创建股票信息表info

3.在stock_db数据库下创建关注信息表focus

4.向focus表中的info_id字段添加info表的id外键

5.插入表数据

INSERT INTO `info` VALUES (1,'000007','全新好','10.01%','4.40%',16.05,14.60,'2019-03-18'),(2,'000036','华联控股','10.04%','10.80%',11.29,10.26,'2019-03-20'),(3,'000039','中集集团','1.35%','1.78%',18.07,18.06,'2019-02-28'),(4,'000050','深天马A','4.38%','4.65%',22.86,22.02,'2019-03-19'),(5,'000056','皇庭国际','0.39%','0.65%',12.96,12.91,'2019-03-20'),(6,'000059','华锦股份','3.37%','7.16%',12.26,12.24,'2018-12-11'),(7,'000060','中金岭南','1.34%','3.39%',12.08,11.92,'2019-03-20'),(8,'000426','兴业矿业','0.41%','2.17%',9.71,9.67,'2019-03-20'),(9,'000488','晨鸣纸业','6.30%','5.50%',16.37,15.59,'2019-03-10'),(10,'000528','柳工','1.84%','3.03%',9.42,9.33,'2019-03-19'),(11,'000540','中天金融','0.37%','5.46%',8.11,8.08,'2019-03-20'),(12,'000581','威孚高科','3.49%','3.72%',27.00,26.86,'2019-02-26'),(13,'000627','天茂集团','5.81%','12.51%',10.93,10.33,'2019-03-20'),(14,'000683','远兴能源','6.42%','21.27%',3.48,3.29,'2019-03-19'),(15,'000703','恒逸石化','0.24%','1.65%',16.92,16.88,'2019-03-20'),(16,'000822','山东海化','6.60%','8.54%',9.05,8.75,'2019-03-06'),(17,'000830','鲁西化工','1.38%','4.80%',7.36,7.26,'2019-03-20'),(18,'000878','云南铜业','1.26%','3.23%',14.50,14.47,'2019-03-19'),(19,'000905','厦门港务','5.44%','10.85%',15.90,15.60,'2018-12-20'),(20,'000990','诚志股份','0.53%','1.00%',16.99,16.90,'2019-03-20'),(21,'002019','亿帆医药','1.19%','2.81%',17.05,16.85,'2019-03-20'),(22,'002078','太阳纸业','2.05%','1.90%',8.45,8.29,'2019-03-19'),(23,'002092','中泰化学','7.25%','6.20%',15.53,14.48,'2019-03-20'),(24,'002145','中核钛白','2.43%','7.68%',6.75,6.61,'2019-03-19'),(25,'002285','世联行','8.59%','5.66%',9.23,8.50,'2019-03-20'),(26,'002311','海大集团','1.13%','0.24%',18.81,18.63,'2019-03-19'),(27,'002460','赣锋锂业','9.41%','9.00%',63.70,58.22,'2019-03-20'),(28,'002466','天齐锂业','3.62%','3.66%',68.44,66.05,'2019-03-20'),(29,'002470','金正大','2.30%','0.99%',8.00,7.82,'2019-03-20'),(30,'002496','辉丰股份','3.15%','4.29%',5.24,5.08,'2018-12-10'),(31,'002497','雅化集团','0.38%','12.36%',13.10,13.05,'2019-03-20'),(32,'002500','山西证券','0.44%','3.70%',11.49,11.44,'2019-03-20'),(33,'002636','金安国纪','2.70%','11.59%',19.80,19.42,'2019-03-19'),(34,'300032','金龙机电','0.66%','0.72%',15.28,15.18,'2019-03-20'),(35,'300115','长盈精密','0.60%','0.59%',33.50,33.41,'2019-03-19'),(36,'300268','万福生科','-10.00%','0.27%',31.77,13.57,'2018-12-10'),(37,'300280','南通锻压','3.31%','0.66%',32.20,32.00,'2018-12-11'),(38,'300320','海达股份','0.28%','0.82%',18.26,18.21,'2019-03-20'),(39,'300408','三环集团','1.69%','0.81%',23.42,23.17,'2019-03-19'),(40,'300477','合纵科技','2.84%','5.12%',22.10,22.00,'2019-03-12'),(41,'600020','中原高速','5.46%','4.48%',5.60,5.31,'2019-03-20'),(42,'600033','福建高速','1.01%','1.77%',4.00,3.99,'2019-02-26'),(43,'600066','宇通客车','4.15%','1.49%',23.08,23.05,'2019-02-13'),(44,'600067','冠城大通','0.40%','2.97%',7.56,7.53,'2019-03-20'),(45,'600110','诺德股份','2.08%','4.26%',16.16,15.83,'2019-03-20'),(46,'600133','东湖高新','9.65%','21.74%',13.64,12.44,'2019-03-20'),(47,'600153','建发股份','3.65%','2.03%',13.35,13.21,'2019-03-10'),(48,'600180','瑞茂通','2.20%','1.07%',14.86,14.54,'2019-03-20'),(49,'600183','生益科技','6.94%','4.06%',14.94,14.12,'2019-03-19'),(50,'600188','兖州煤业','1.53%','0.99%',14.56,14.43,'2019-03-19'),(51,'600191','华资实业','10.03%','11.72%',15.80,14.36,'2019-03-20'),(52,'600210','紫江企业','6.03%','10.90%',6.68,6.30,'2019-03-20'),(53,'600212','江泉实业','1.39%','1.78%',10.20,10.15,'2019-03-19'),(54,'600225','*ST松江','4.96%','2.47%',5.71,5.61,'2018-12-13'),(55,'600230','沧州大化','5.74%','13.54%',43.26,40.91,'2019-03-20'),(56,'600231','凌钢股份','2.79%','3.77%',3.68,3.60,'2019-03-19'),(57,'600291','西水股份','10.02%','9.23%',34.71,31.55,'2019-03-20'),(58,'600295','鄂尔多斯','4.96%','12.62%',16.51,15.73,'2019-03-20'),(59,'600303','曙光股份','8.37%','14.53%',11.53,10.64,'2019-03-20'),(60,'600308','华泰股份','1.12%','2.66%',6.30,6.26,'2019-03-19'),(61,'600309','万华化学','0.03%','1.78%',31.81,31.80,'2019-03-20'),(62,'600352','浙江龙盛','0.39%','1.85%',10.32,10.28,'2019-03-20'),(63,'600354','敦煌种业','7.89%','18.74%',9.44,8.75,'2019-03-20'),(64,'600408','安泰集团','1.98%','3.38%',4.13,4.12,'2018-12-13'),(65,'600409','三友化工','0.62%','3.78%',11.36,11.29,'2019-03-20'),(66,'600499','科达洁能','0.46%','3.94%',8.84,8.80,'2019-03-20'),(67,'600508','上海能源','3.26%','2.99%',13.32,13.01,'2019-03-19'),(68,'600563','法拉电子','0.32%','1.36%',53.67,53.50,'2019-03-20'),(69,'600567','山鹰纸业','0.76%','2.85%',3.98,3.96,'2019-03-19'),(70,'600585','海螺水泥','0.45%','0.61%',24.51,24.44,'2019-03-19'),(71,'600668','尖峰集团','4.35%','6.43%',18.70,18.36,'2018-12-13'),(72,'600688','上海石化','2.72%','0.91%',6.80,6.74,'2019-02-01'),(73,'600729','重庆百货','5.70%','3.34%',27.45,27.13,'2019-02-28'),(74,'600739','辽宁成大','3.30%','3.50%',19.74,19.11,'2019-03-20'),(75,'600779','水井坊','3.85%','2.77%',29.39,28.30,'2019-03-20'),(76,'600781','辅仁药业','8.61%','4.16%',23.46,21.89,'2019-01-02'),(77,'600801','华新水泥','4.00%','10.15%',12.99,12.49,'2019-03-20'),(78,'600846','同济科技','2.06%','17.41%',9.39,9.26,'2018-12-13'),(79,'600884','杉杉股份','1.08%','3.53%',20.67,20.45,'2019-03-20'),(80,'600966','博汇纸业','2.89%','5.54%',6.41,6.28,'2019-03-19'),(81,'600971','恒源煤电','2.36%','8.81%',12.16,11.88,'2019-03-20'),(82,'601012','隆基股份','0.76%','1.30%',19.93,19.78,'2019-03-20'),(83,'601100','恒立液压','4.78%','0.92%',19.31,18.97,'2019-03-13'),(84,'601101','昊华能源','4.03%','6.06%',11.10,10.80,'2019-03-19'),(85,'601216','君正集团','2.16%','2.26%',5.20,5.10,'2018-12-17'),(86,'601666','平煤股份','2.81%','6.14%',6.96,6.77,'2019-03-20'),(87,'601668','中国建筑','2.39%','1.42%',10.70,10.45,'2019-03-20'),(88,'601678','滨化股份','0.13%','2.47%',7.92,7.91,'2019-03-20'),(89,'601918','新集能源','1.23%','3.11%',4.93,4.92,'2019-03-19'),(90,'603167','渤海轮渡','2.77%','3.34%',11.87,11.61,'2018-12-13'),(91,'603369','今世缘','3.34%','2.13%',14.24,13.78,'2019-03-20'),(92,'603589','口子窖','3.99%','1.84%',39.37,39.04,'2019-02-26'),(93,'603799','华友钴业','2.38%','7.19%',67.46,65.89,'2019-03-20'),(94,'603993','洛阳钼业','2.94%','2.50%',7.36,7.16,'2019-03-19');
INSERT INTO `focus` VALUES (1,'先试一试',30),(2,'非常稳',38),(3,'一般般',78),(12,'不咋地',80),(17,'',23);

 6.查询表数据

  

三丶使用网络TCP开发一个基于WSGI协议的Web服务器

1.创建工程目录以及文件

说明:dynamic目录----存放动态资源,static目录----存放静态资源,templates目录----存放模板文件

server.conf----服务器配置文件,web_server.py----服务器启动文件

2.服务器文件web_server.py代码实现

  • step1  代码三大步,定义一个WSGIServer类,一个main主函数,脚本运行方式
import socket
import multiprocessingclass WSGIServer(object):def __init__(self):passdef main():passif __name__ == '__main__':main()
  • step2 在__init__方法中创建TCP套接字绑定端口以及转换为被动套接字
self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)self.tcp_server_socket.bind(("", 7979))self.tcp_server_socket.listen(128)
  • step3 因为这里是作为TCP服务器所以需要使用进程中的子线程来完成客户端的连接处理,所以在main函数中进行截堵塞操作
while True:client_socket, client_addr = self.tcp_server_socket.accept()# 使用进程中的子线程来完成客户端的连接处理p = multiprocessing.Process(target=self.handle_client, args=(client_socket,))p.start()client_socket.close()tcp_server_socket.close()
  • step4 紧接着在类中定义handle_client方法,用于客户端的处理,获取客户端的请求数据,从客户端的请求数据中通过正则匹配获取用户请求地址,如果匹配成功,则获取用户请求的静态文件名;通过文件读写方式,打开本地html目录下的静态文件,读取静态文件的内容,成功则组织服务器正确响应数据(响应头响应体),返回给浏览器;例如用户在浏览器中向http://127.0.0.1:7979/index.html地址发送请求则在handle_client函数中通过splitlines方法进行分割,获取第一行数据GET /index.html HTTP/1.1,通过正则匹配到(/index.html)文件名,打开并读取本地的静态目录html下的此文件的数据,返回给浏览器,最后呈现到页面给用户看
def handle_client(client_socket):request_data = client_socket.recv(1024).decode("utf-8")print(request_data)request_lines = request_data.splitlines()# print(request_lines)result = re.match(r"[^/]+([^ ]*)", request_lines[0])if result:# print(result.group(1)+"*"*10)file_name = result.group(1)try:with open("./html"+file_name, "rb") as f:server_response_body = f.read()except:server_response = "HTTP/1.1 404 NOT FOUND \r\n"server_response += "\r\n"server_response += "-----File Not Found-----"client_socket.send(server_response.encode("utf-8"))else:server_response_header = "HTTP/1.1 200 OK \r\n"server_response_header += "\r\n"client_socket.send(server_response_header.encode("utf-8"))client_socket.send(server_response_body)client_socket.close()

3.让该TCP服务器遵循WSGI协议

  • step1 在dynamic目录下创建__init__.py文件,让该目录成为一个python包,然后在这个包下创建web_frame.py框架文件,在这个文件中定义application方法,遵循WSGI服务器协议
def index():return "this is index page!"def login():return "this is login page!"def application(environ, start_response):pass
  • step2 回到web_server.py服务器文件中,首先进行判断,判断用户请求的是静态资源还是动态资源,这里请求资源文件名为.py结尾的为动态资源进行判断,当用户请求的文件名不是以.py结尾的则在本地html静态目录中读取文件内容直接返回给浏览器,如果用户请求的是.py结尾的文件,则遵循WSGI协议,首先导入web_frame框架文件,调用其application方法,这个方法需要传递两个参数,第一个参数environ是字典类型用作于服务器与框架之间需要的属性,第二个参数start_response则为函数引用用作于服务器响应客户端的参数(header和body)
# 以.py为结尾表示请求动态资源否则为静态资源
if not file_name.endswith(".py"):try:with open("../html"+file_name, "rb") as f:server_response_body = f.read()except:server_response = "HTTP/1.1 404 NOT FOUND \r\n"server_response += "\r\n"server_response += "-----File Not Found-----"client_socket.send(server_response.encode("utf-8"))else:server_response_header = "HTTP/1.1 200 OK \r\n"server_response_header += "\r\n"client_socket.send(server_response_header.encode("utf-8"))client_socket.send(server_response_body)
else:"""遵循WSGI协议"""# 1.导入定义的web_frame框架,模拟WSGI调用过程import web_frame# 2.调用框架中的application方法env = dict()# print(file_name) /index.pyenv["PATH_INFO"] = file_name #{'PATH_INFO':'/index.py'}body = web_frame.application(env, self.start_response)# print(body, env)server_response_header = "HTTP/1.1 %s \r\n" % self.statusfor temp in self.header:server_response_header += '%s:%s\r\n' %(temp[0], temp[1])server_response_header += "\r\n"# server_response_body = "<h1 style='color:red;text-align:center'>这是动态资源 %s </h1>" % time.ctime()server_response_data = server_response_header + bodyclient_socket.send(server_response_data.encode("utf-8"))client_socket.close()
  • step3 在web_server.py服务器文件中在调用mini_frame框架中的application方法时,传递的第二个参数为函数start_response的引用,所以在WSGIServer类中就需要定义start_response函数,这个函数需要接收两个参数,一个是响应码另一是响应头,博主在响应头中添加了一个属性为server也就是服务器,为web_frame/1.0,像百度等其他大型网站的server都是有说明的,所以博主在这里也给自己开发的服务器定义了一个版本名
# 3.定义start_response函数
def start_response(self, status, header):self.status = statusself.header = [("server"," web_frame/1.0")]self.header += header

  • step4 在web_server.py服务器中将start_response函数的引用传递给application函数,所以在application函数中,需要调用服务器传递过来的start_response方法,并传递正确的响应码和响应体
def application(environ, start_response):file_name = environ['PATH_INFO']start_response('200 OK', [('Content-Type', ' text/html;charset=utf-8')])if file_name == "/index.py":return index()elif file_name == "/login.py":return login()else:return '<h1 style="color:red;text-align:center">Hello World! 你好 中国!<h1>'

4.在浏览器中渲染出网页模板文件

  •  step1 在templates模板目录下创建一个index.html文件,其中{%content%}为预留空间,用于之后数据替换
<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>首页 - 个人选股系统 V5.87</title><link href="/css/bootstrap.min.css" rel="stylesheet"></head><body>
<div class="navbar navbar-inverse navbar-static-top "><div class="container"><div class="navbar-header"><button class="navbar-toggle" data-toggle="collapse" data-target="#mymenu"><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a href="#" class="navbar-brand">选股系统</a></div><div class="collapse navbar-collapse" id="mymenu"><ul class="nav navbar-nav"><li class="active"><a href="/index.html">股票信息</a></li><li><a href="/center.html">个人中心</a></li></ul></div></div>
</div><div class="container"><div class="container-fluid"><table class="table table-hover" style="background-color: #f1fde1"><tr style="background-color:#a6e22b;"><th>序号</th><th>股票代码</th><th>股票简称</th><th>涨跌幅</th><th>换手率</th><th>最新价(元)</th><th>前期高点</th><th>前期高点日期</th><th>添加自选</th></tr>          </table>{%content%}</div></div><script src="/js/bootstrap.min.js"></script></body>
</html>            
  • step2 在templates模板目录下创建一个center.html文件
<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>个人中心 - 个人选股系统 V5.87</title><link href="/css/bootstrap.min.css" rel="stylesheet"></head><body>
<div class="navbar navbar-inverse navbar-static-top "><div class="container"><div class="navbar-header"><button class="navbar-toggle" data-toggle="collapse" data-target="#mymenu"><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a href="#" class="navbar-brand">选股系统</a></div><div class="collapse navbar-collapse" id="mymenu"><ul class="nav navbar-nav"><li ><a href="/index.html">股票信息</a></li><li class="active"><a href="/center.html">个人中心</a></li></ul></div></div>
</div><div class="container"><div class="container-fluid"><table class="table table-hover" style="background-color: #f1fde1"><tr style="background-color:#a6e22b;"><th>股票代码</th><th>股票简称</th><th>涨跌幅</th><th>换手率</th><th>最新价(元)</th><th>前期高点</th><th style="color:red">备注信息</th><th>修改备注</th><th>删除</th></tr>{%content%}                     </table></div></div><script src="/js/bootstrap.min.js"></script></body>
</html>            
  • step3 之前在web_server.py服务器文件中定义以.py为结尾的文件名表示动态资源,这样做的话,用户就知道我们的服务器是以什么代码进行编写的,就利于不怀好意者攻击网站服务器,所以需要改为以.html为结尾的请求资源名为动态资源
if not file_name.endswith(".html"):# print(self.static_path_+file_name)try:with open("./static" + file_name, "rb") as f:server_response_body = f.read()except:server_response = "HTTP/1.1 404 NOT FOUND \r\n"server_response += "\r\n"server_response += "-----File Not Found-----"client_socket.send(server_response.encode("utf-8"))else:server_response_header = "HTTP/1.1 200 OK \r\n"server_response_header += "\r\n"client_socket.send(server_response_header.encode("utf-8"))client_socket.send(server_response_body)
else:"""遵循WSGI协议"""# 1.导入定义的web_frame框架,模拟WSGI调用过程import web_frame# 2.调用框架中的application方法env = dict()# print(file_name) /index.htmlenv["PATH_INFO"] = file_name #{'PATH_INFO':'/index.html'}env["page_num"] = 1body = web_frame.application(env, self.start_response)# print(body, env)# print(body, "5555555555")server_response_header = "HTTP/1.1 %s \r\n" % self.statusfor temp in self.header:server_response_header += '%s:%s\r\n' %(temp[0], temp[1])server_response_header += "\r\n"# server_response_body = "<h1 style='color:red;text-align:center'>这是动态资源 %s </h1>" % time.ctime()server_response_data = server_response_header + bodyclient_socket.send(server_response_data.encode("utf-8"))client_socket.close()
  • step4 在大多网站中当用户输入 http://127.0.0.1:7979等价于输入http://127.0.0.1:7979/index.html,所以在代码中需进行编写,当请求名为/时表示用户请求的是index.html
if result:# print(result.group(1)+"*"*10)file_name = result.group(1)if file_name == "/":file_name = "/index.html"# print(file_name,"qwqwqwq")
  •  step5 在web_frame.py框架文件中进行如下修改,首先判断服务器传过来的文件名为哪个资源名,再调用对应的接口函数,读取对应的资源文件内容,返回给服务器
def index():with open("./templates/index.html",encoding="utf-8") as f:content = f.read()return contentdef center():with open("./templates/center.html") as f:return f.read()def application(env, start_response):start_response('200 OK', [('Content-Type', 'text/html;charset=utf-8')])file_name = env['PATH_INFO']# file_name = "/index.html"if file_name == "/index.html":return index()elif file_name == "/center.html":return center()else:return '<h1 style="color:red;text-align:center">Hello World! 你好 中国!<h1>'
  • step6 在WSGIServer类中定义一个run_forever方法,将main函数中的逻辑代码放在此函数中,在main函数中只需要创建实例对象调用run_forever方法,来控制整个程序
    def run_forever(self):while True:client_socket, client_addr = self.tcp_server_socket.accept()# 使用进程中的子线程来完成客户端的连接处理p = multiprocessing.Process(target=self.handle_client, args=(client_socket,))p.start()client_socket.close()# handle_client(client_socket)tcp_server_socket.close()
def main():WSGIServer().run_forever()
  • step7 运行web_server.py程序,在浏览器输入http://127.0.0.1:7979/index.html,成功渲染出对应的模板

5.以解释器 程序 端口号 框架名:方法,如python3 web_server.py 7979 web_frame:application运行此程序

  • step1 在server.conf文件中进行如下编写,静态文件路径以及动态文件路径,这样做的目的是降低项目的耦合性,方便以后对代码进行有效变更
{"static_path":"./static","dynamic_path":"./dynamic"
}
  • step2 获取配置文件中的内容
with open("./server.conf") as f:config = eval(f.read())
  • step3 获取端口号
port = int(sys.argv[1])
  • step4 获取框架名以及方法
frame_app = sys.argv[2].split(':')
frame_name = frame_app[0]
app_name = frame_app[1]
  • step5 导入web_frame框架下的application方法对象
sys.path.append(config["dynamic_path"])
frame = __import__(frame_name) #__import__方法以变量的值去导入模块 返回对象
app = getattr(frame, app_name) # getattr返回函数
  • step6  在创建WSGIServer实例对象时需要传递三个参数(端口号,application函数引用,静态文件路径)
WSGIServer(port, app, config['static_path']).run_forever()
  • step7 同时在WSGIServer类中需要接收这三个参数 ,在类中将./static以及mini_frame.application进行对应修改如下

在__init__方法中

def __init__(self, port, app, static_path):self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)self.tcp_server_socket.bind(("", port))self.tcp_server_socket.listen(128)self.application = appself.static_path = static_path

 在handle_client方法中

"""遵循WSGI协议"""# 2.调用框架中的application方法
env = dict()
# print(file_name) /index.py
env["PATH_INFO"] = file_name #{'PATH_INFO':'/index.py'}
env["page_num"] = 1
body = self.application(env, self.start_response)
# print(body, env)
# print(body, "5555555555")
server_response_header = "HTTP/1.1 %s \r\n" % self.status
for temp in self.header:server_response_header += '%s:%s\r\n' %(temp[0], temp[1])
server_response_header += "\r\n"
# server_response_body = "<h1 style='color:red;text-align:center'>这是动态资源 %s </h1>" % time.ctime()
server_response_data = server_response_header + body
client_socket.send(server_response_data.encode("utf-8"))
  • step8 在Terminal终端中输入:python3 web_server.py 7979 web_frame:application成功运行项目,在浏览器中访问http://127.0.0.1:7979/index.html成功

四丶使用python3开发一个轻量级的Web框架

1.在web_frame.py框架文件中,使用装饰器完成路由功能

  • step1 定义通用装饰器
URL_FUNC_DICT = dict()
def route(url):def set_func(func):# URL_FUNC_DICT["/index.html"] = indexURL_FUNC_DICT[url] = funcdef call_func(*args, **kwargs):return func(*args, **kwargs)return call_funcreturn set_func
  • step2 在index函数和center函数上添加装饰器
@route("/index.html")
def index():with open("./templates/index.html",encoding="utf-8") as f:content = f.read()return content@route("/center.html")
def center():with open("./templates/center.html") as f:return f.read()
  • step3 修改application方法中的代码
def application(env, start_response):start_response('200 OK', [('Content-Type', 'text/html;charset=utf-8')])file_name = env['PATH_INFO']try:return URL_FUNC_DICT[file_name]()except Exception as ret:return "产生了异常:%s" % str(ret)

2.让路由支持正则匹配规则

  • step1 修改application函数中的代码,通过遍历URL_FUNC_DICT常量,获取url地址以及对应的方法名,通过正则匹配服务器传过来的用户请求的文件名,匹配成功则将该调用此函数
for url, func in URL_FUNC_DICT.items():# {#   r"/index.html":index,#   r"/center.html":center,# }ret = re.match(url, file_name)if ret:return func()
else:return "请求的url(%s)没有对应的函数...." % file_name
  • step2 将对应的index和center函数装饰器修改为正则表达式
@route(r"/index.html")
def index():with open("./templates/index.html",encoding="utf-8") as f:content = f.read()return content@route(r"/center.html")
def center():with open("./templates/center.html") as f:return f.read()

3.将数据库中的数据显示到index.html以及center.html网页中

  • step1 因为需要从数据库中查询数据,所以需要连接数据库,博主这里定义一个connect_db方法,用作于连接数据操作,在这个方法进行判断,如果是对数据库的查询操作则不需要commit提交操作,其他的增删改都是需要提交
def connect_db(sql):conn = connect(host="localhost",port=3306,user="root",password="mysql",database="stock_db",charset="utf8")cs = conn.cursor()cs.execute(sql)info_data = cs.fetchall()if sql.startswith("select"):conn.close()cs.close()else:conn.commit()cs.close()return info_data
  • step2 在index函数中调用connect_db方法获取info股票信息表所有数据,定义一个info_data模板数据,通过遍历info表数据,向html_data空字符串中追加info_data模板所需要info表字段内容数据,最后通过正则匹配将index.html文件中{%content%}数据替换成拼接好的html_data数据,最终返回给服务器,服务器再将此body数据,与响应体和响应头进行拼接最后返回给浏览器,最终显示到页面上
with open("./templates/index.html", encoding="utf-8") as f:content = f.read()
info_data = connect_db("select * from info;")
info_template= """<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td><input type="button" value="添加" id="toAdd" name="toAdd" systemidvaule="%s"></td></tr>"""
html_data = ""
for temp in info_data:html_data += info_template % (temp[0],temp[1],temp[2],temp[3],temp[4],temp[5],temp[6],temp[7],temp[1])  #后面加的temp[1]股票代码是为了填充添加列systemidvaule得值
content = re.sub(r"\{%content%\}",html_data,content)
return content
  • step3 在center函数跟index函数大体一致,不同的就是查询语句不同以及定义的模板数据不同
with open("./templates/center.html", encoding="utf-8") as f:content = f.read()
info_data = connect_db("select i.code,i.short,i.chg,i.turnover,i.price,i.highs,f.not_info from info as i inner join focus as f on i.id = f.info_id;")
info_template = """<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td><a type="button" class="btn btn-default btn-xs" href="/update/%s.html"> <span aria-hidden="true">⇋</span> 修改 </a></td><td><input type="button" value="删除" id="toDel" name="toDel" systemidvaule="%s"></td></tr>"""
html_data = ""
for temp in info_data:html_data += info_template % (temp[0],temp[1],temp[2],temp[3],temp[4],temp[5],temp[6],temp[0],temp[0])
content = re.sub(r"\{%content%\}",html_data,content)
return content
  •  step4 启动程序后,在浏览器中输入http://127.0.0.1:7979/index.html或者是http://127.0.0.1:7890/后进入如下界面

  • step5 点击index页面中的个人中心或者输入http://127.0.0.1:7890/center.html进入个人中心页面

4.将主页index.html数据进行分页显示

  • step1 首先在index.html中给网页下方预留一个显示页码的位置{%page%}

  • step2 在框架index函数中定义一个页码模板
page_template = """<div class="pagenation"><a href="#" id="up">上一页</a><a href="/index.html" class="active">1</a><a href="/index.html?page=2">2</a><a href="/index.html?page=3">3</a><a href="/index.html?page=4">4</a><a href="/index.html?page=5">5</a><a href="/index.html?page=6">6</a><a href="/index.html?page=7">7</a><a href="/index.html?page=8">8</a><a href="/index.html?page=9">9</a><a href="#" id="next">下一页</a></div>"""
  • step3 替换index.html中的{%page%}
content = re.sub(r"\{%page%\}",page_template,content)
  • step4 编写页码CSS样式
<style type="text/css">.pagenation{height:32px;text-align:center;font-size:0;margin:30px auto;}.pagenation a{display:inline-block;border:1px solid #d2d2d2;background-color:#f1e7f8;font-size:12px;padding:7px 10px;color:#666;margin:5px;text-decoration: none;}.pagenation .active{background-color:#fff;color:#43a200}.pagenation span{display: inline-block;font-size: 12px;}.pagenation a:hover{background-color: #9bb797}</style>
  • step5 刷新网页,查看页码显示样式

  • step6 回到web_server.py服务器文件中,匹配并获取页码连接地址中的数字,并保存到env字典中的page_num Key中
page_num = re.match(r".*page=(\d+)",request_lines[0])
if page_num:page_num = page_num.group(1)# print(type(page_num))if file_name.endswith("page=%s" % page_num):env = dict()# print(file_name) /index.pyenv["PATH_INFO"] = "/index.html"  # {'PATH_INFO':'/index.py'}env["page_num"] = page_numbody = self.application(env, self.start_response)
  • step7 在框架文件application方法中需要获取用户请求的页数,并传递给index函数,因为这里使用了路由正则,所以center函数也必须定义一个形参,用不用无所谓,不然程序会报错
def application(environ, start_response):file_name = environ['PATH_INFO']page_num = environ["page_num"]start_response('200 OK', [('Content-Type', ' text/html;charset=utf-8')])for url, func in URL_FUNC_DICT.items():ret = re.match(url, file_name)# print(ret,"wwwwwwwwwwwwww")if ret:# print(ret.group(1))return func(page_num)else:return "请求的url(%s)地址不存在..." % file_name
  • step8 在index函数中进行如下修改,获取info表总共有多少条数据,按照每页12条数据进行分页,设定当某一页数据大于总数据量时,则返回提示给用户
page_num = int(page_num)
with open("./templates/index.html", encoding="utf-8") as f:content = f.read()
total_page = connect_db("select count(*) from info;")if (page_num-1)*12 > total_page[0][0]:html_data = "<h1 style='color:red'>没有更多的数据了.....</h1>"content = re.sub(r"\{%content%\}", html_data, content)content = re.sub(r"\{%page%\}", "", content)return content
info_data = connect_db("select * from info limit %d,%d;" %((page_num-1)*12,12))
  • step9 在js中进行逻辑编写,当前页为第一页时不显示上一页,当前页为最后一页时不显示下一页,当点击某页时,此页面无法点击,并且该页码为激活状态,JS代码不予展示

  • step10 对比上图于数据库分页查询一致

五丶在框架中实现添加股票功能

1.在index.html中编写以下JS,点击添加按钮则向http://127.0.0.1:7979/add/code.html地址发送请求,其中code为股票代码,通过js中的attr方法获取模板中systemIdvalue的值也就是股票代码

<script type="text/javascript">$(document).ready(function(){$("input[name='toAdd']").each(function(){var currentAdd = $(this);var code = $(this).attr("systemIdVaule");          currentAdd.click(function(){code = $(this).attr("systemIdVaule");// alert("/add/" + code + ".html");$.get("/add/" + code + ".html", function(data, status){alert("数据: " + data + "\n状态: " + status);window.location.reload();});});});});

2.定义add_focus方法,用于数据库处理操作,在js中通过ajax方法向http://127.0.0.1:7979/add/code.html地址发送请求,所以在application函数中需要将正则匹配成功后的对象,传递到add_foucs函数中,因为之前在做分页时,传递了页码参数,所以该函数需要定义两个形参来接收

@route(r"/add/(\d+)\.html")
def add_focus(page_num, ret):pass

3.获取股票代码,并通过股票代码的值向数据库中focus表中添加此股票数据

# 1. 获取添加按钮触发的ajax请求地址中的股票代码
stock_code = ret.group(1)
# print(stock_code)
# 2.判断获取到的股票代码是否存在
res = connect_db("select * from info where code = '%s'" % stock_code)
if not res:return "非法请求<This stock does not exist>"
# 3.判断该股票是否已经关注
res = connect_db("select * from info as i inner join focus as f on i.id = f.info_id where i.code = '%s'" % stock_code)
if res:return "该股票已经关注过了,请勿重复关注...."
# 4.关注股票
connect_db("insert into focus(info_id) select id from info where code = '%s'" % stock_code)
return "关注股票成功"

4.测试点击第一支股票进行添加,显示关注成功,查看数据库focus表最后一条数据为info_id为1的,确定添加成功

5.博主这里觉得当某支股票添加成功后,在该股票信息上不应该出现添加的功能按钮,所以需要在数据库info表中添加一个字段is_add字段,默认为0(未添加)反之为1,添加成功后将focus表中的股票在info表中将is_add字段修改为1

6.在index函数中将input标签中的id字段的值修改为toAdd_%s,并在最后面添加isadd字段,之所以要将id字段的值修改为非相同的值,是因为id不允许重复

info_template= """<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td><input type="button" value="添加" id="toAdd_%s" name="toAdd" systemidvaule="%s" isadd=%s></td></tr>"""
html_data += info_template % (temp[0],temp[1],temp[2],temp[3],temp[4],temp[5],temp[6],temp[7],temp[1],temp[1],temp[8])

7.在add_focus函数中在添加股票信息到focus之后需要将该股票对应的info表的is_add字段的值修改为1

connect_db("update info set is_add = 1 where code = '%s'" % stock_code)

8.回到index.html文件中js中,获取模板中isadd的值,如果该值为1表示已经关注,所以设置添加按钮不显示

var is_add = $(this).attr("isadd");
if(is_add == 1){document.getElementById("toAdd_"+code).style.display = "none"
}

9.进行添加测试,当点击添加成功后,如不显示添加按钮表示成功

六丶在框架中实现删除股票功能

1.在index页面添加股票成功后,随后点击进入个人中心center页面,则显示所有关注的股票信息,包括刚才关注的股票

2.在个人中心页面中,每支股票都有一个删除按钮,当用户点击删除按钮后则在此页面中不再显示出该支股票,对应咋数据库focus表中该支股票也直接被物理删除

  • step1 在center.html文件中编写如下JS,这个跟添加功能中index.html文件中的JS几乎一模一样,当用户点击删除按钮后,则获取模板文件中systemIdValue的值,这个值就是在center函数中使用字符串替换的股票代码的值,然后向http://127.0.0.1:7979/del/000036.html地址发送请求,最终打印响应数据
<script>$(document).ready(function(){$("input[name='toDel']").each(function(){var currentAdd = $(this);currentAdd.click(function(){code = $(this).attr("systemIdVaule");// alert("/del/" + code + ".html");$.get("/del/" + code + ".html", function(data, status){alert("数据: " + data + "\n状态: " + status);window.location.reload()});});});});
</script>
  • step2 定义视图函数del_focus,用于完成数据库focus表物理删除操作,正则匹配获取股票请求地址中的股票代码
@route(r"/del/(\d+)\.html")
def del_focus(page_num, ret):pass
  • step3 获取股票代码,判断股票是否存在以及判断股票是否是关注的股票,最后根据股票代码删除数据库focus表数据,并且根据该股票代码修改对应info表中is_add的值为0,使这支股票被取消关注后显示在股票信息表上
# 1. 获取添加按钮触发的ajax请求地址中的股票代码
stock_code = ret.group(1)
# print(stock_code)
# 2.判断获取到的股票代码是否存在
res = connect_db("select * from info where code = '%s'" % stock_code)
if not res:return "非法请求<This stock does not exist>"
# 3.判断该股票是否已经关注,未关注表示非法删除请求
res = connect_db("select * from info as i inner join focus as f on i.id = f.info_id where i.code = '%s'" % stock_code)
if not res:return "该股票未关注...."
# 4.取关股票,并修改info表中is_add字段为0表示在页面显示添加按钮
connect_db("delete from focus where info_id = (select id from info where code = '%s')" % stock_code)
connect_db("update info set is_add = 0 where code = '%s'" % stock_code)
return "取关股票成功"

3.进行测试

  • step1 刷新网页,点击最后一个000050代码的股票进行删除测试

  • step2  回到股票信息页面,查看000050是否有添加功能,有表示逻辑正确

  • step3 查看数据focus表是否没有该只股票,以及info表该只股票is_add字段是否为0

 七丶在框架中实现修改股票功能

1.在templates模板目录下创建update.html文件,代码如下

<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>首页 - 个人选股系统 V5.87</title><link href="/css/bootstrap.min.css" rel="stylesheet"><script src="/js/jquery-1.12.4.min.js"></script><script src="/js/bootstrap.min.js"></script></head><body>
<div class="navbar navbar-inverse navbar-static-top "><div class="container"><div class="navbar-header"><button class="navbar-toggle" data-toggle="collapse" data-target="#mymenu"><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a href="#" class="navbar-brand">选股系统</a></div><div class="collapse navbar-collapse" id="mymenu"><ul class="nav navbar-nav"><li><a href="/index.html">股票信息</a></li><li><a href="/center.html">个人中心</a></li></ul></div></div>
</div><div class="container"><div class="container-fluid"><div class="input-group"><span class="input-group-addon">正在修改:</span><span class="input-group-addon">{%code%}</span><input id="note_info" type="text" class="form-control" aria-label="Amount (to the nearest dollar)" value="{%note_info%}"><span id="update" class="input-group-addon" style="cursor: pointer">修改</span></div></div></div></body>
</html>            

2.在update.html文件中编写如下js,当用户点击修改按钮,首先当用户在个人中心页面对股票点击修改时,向http://127.0.0.1:7979/update/300320.html地址发送请求进入到修改界面,然后在修改界面点击修改时,向http://127.0.0.1:7979/update/000581/备注信息.html地址发送请求,获取响应内容最后跳转到个人中心网页

<script>$(document).ready(function(){$("#update").click(function(){var item = $("#note_info").val();// alert("/update/{%code%}/" + item + ".html");$.get("/update/{%code%}/" + item + ".html", function(data, status){alert("数据: " + data + "\n状态: " + status);self.location='/center.html';});});});
</script>

3.在框架文件中创建show_update_page视图函数,用于显示修改备注信息页面

  • step1 在center函数中nfo_template模板文件中修改按钮使用超链接进行跳转,没有使用ajax方式发送请求
<a type="button" class="btn btn-default btn-xs" href="/update/%s.html"> <span aria-hidden="true">⇋</span> 修改 </a>
  • step2 在show_update_page视图函数中编写如下代码,从路由匹配成功后获取到要修改的股票代码,根据该股票代码获取focus表中的备注信息,然后将此备注信息替换update.html中的{%note_info%}字段,以及将获取的股票代码替换update.html文件中的{%code%}字段,最后返回给服务器
@route(r"/update/(\d+)\.html")
def show_update_page(page_num, ret):"""显示修改界面"""# 1.读取修改界面代码with open("./templates/update.html", encoding="utf-8") as f:content = f.read()# 2. 获取要修改的股票代码stock_code = ret.group(1)# 3. 获取该关注股票的备注信息res = connect_db("select f.not_info from info as i inner join focus as f on i.id = f.info_id where i.code = '%s'" % stock_code)not_info = res[0][0]# print(not_info, "wwwwwwwwwwwww")# 4. 替换html中的空缺两次依次替换content = re.sub(r"\{%note_info%\}", not_info, content)content = re.sub(r"\{%code%\}", stock_code, content)return content
  • step3 测试,在个人中心页面点击股票修改按钮,是否成功跳转到修改页面,并在修改页面显示正确的股票代码以及该只股票的备注信息

4.在框架文件中定义save_update_data视图函数用于保存股票修改后的备注信息

  • step1 在sava_update_data视图函数中进行如下编写,需要注意的是路由规则中第二个参数为用户修改的备注信息,所以这里需要使用(.*)来进行匹配
@route(r"/update/(\d+)/(.*)\.html")
def save_update_data(page_num, ret):"""将用户修改的备注信息保存到数据库"""# 1. 获取股票代码以及备注信息stock_code = ret.group(1)comment = ret.group(2)# 2. 因之前添加关注功能对股票信息进行了验证,所以在个人中心页面的已关注的股票信息为合法信息,所以直接写入数据库即可connect_db("update focus set not_info = '%s' where info_id = (select id from info where code = %s)" %(comment, stock_code))return """修改备注信息成功"""
  • step2 修改备注信息测试,在个人中心页面中点击最后一条股票002311,进行修改,在修改页面输入hahhahahhaha后,点击修改提示修改成功,并跳转显示到个人中心页面,说明代码逻辑正确

  • step3 查看focus表数据,已成功在数据库进行对应修改

  • step4 有个bug就是当用户输入中文时,则提示乱码,对刚才那支股票继续进行修改,输入(好好好 )这三个字,点击修改按钮后,提示修改成功,但跳转到个人中心页面则显示乱码,

  •  step5 以上出现乱码是因为当浏览器向服务器发送请求数据时,会对数据进行url编码,所以填完备注信息后直接保存到数据库的数据时进行url编码后的数据,那么此时就需要在数据保存到数据库之前,进行url解码操作,需要导入python库中urllib.parse模块,在save_update_data函数中添加以下代码
comment = urllib.parse.unquote(comment)
  • step6 再次进行测试,bug已解

5.这个项目有很多需要优化以及不足的地方,所有的Web项目大同小异都是这个流程,代码不重要,重要的是明白浏览器服务器以及程序框架之间数据是怎么传递的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_745179.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Django项目之Web端电商网站的实战开发(一)

说明&#xff1a;该篇博客是博主一字一码编写的&#xff0c;实属不易&#xff0c;请尊重原创&#xff0c;谢谢大家&#xff01; 项目源码下载 目录 一丶项目介绍 二丶电商项目开发流程 三丶项目需求 四丶项目架构概览 五丶项目数据库设计 六丶项目框架搭建 一丶项目介绍 …

Flask项目之个性化微电影网站的实战开发(一)

说明&#xff1a;该篇博客是博主一字一码编写的&#xff0c;实属不易&#xff0c;请尊重原创&#xff0c;谢谢大家&#xff01; 项目源码下载 目录 一丶叙述 二丶Windows环境搭建 三丶项目分析丶搭建目录以及模型设计 四丶搭建前台页面 一丶叙述 1.项目中使用到的知识点 …

Django项目于之在线教育平台网站的实战开发(一)

说明&#xff1a;该篇博客是博主一字一码编写的&#xff0c;实属不易&#xff0c;请尊重原创&#xff0c;谢谢大家&#xff01; 项目源码下载 目录 一丶叙述 二丶Windows环境搭建 三丶数据库模型设计 四丶搭建后台管理系统 五丶使用xadmin注册方式注册模型表 六丶xadmin后…

Django项目于之在线教育平台网站的实战开发(完结)

说明&#xff1a;该篇博客是博主一字一码编写的&#xff0c;实属不易&#xff0c;请尊重原创&#xff0c;谢谢大家&#xff01; 接着上一篇博客继续往下写 &#xff1a;https://blog.csdn.net/qq_41782425/article/details/90141577 项目源码下载 目录 一丶常见web攻击及防范…

Django与Elasticsearch交互打造搜索引擎网站(一)

说明&#xff1a;该篇博客是博主一字一码编写的&#xff0c;实属不易&#xff0c;请尊重原创&#xff0c;谢谢大家&#xff01; 项目源码下载 目录 一丶叙述 二丶elasticsearch-rtf的安装与测试 三丶elasticsearch-head插件以及kibana的安装 四丶elasticsearch搜索引擎的使…

2020 搭建一个属于自己的动态网站(WordPress+云服务器BCC)

说明&#xff1a;该篇博客是博主一字一码编写的&#xff0c;实属不易&#xff0c;请尊重原创&#xff0c;谢谢大家&#xff01; 文章目录前言一、WordPress是什么&#xff1f;二、建站准备1.准备服务器2.准备域名三、网站搭建1.安装宝塔面板2.宝塔面板搭建站点3.域名解析4.通过…

2021 搭建一个属于自己的静态网站(Hexo+GitHub Pages)

说明&#xff1a;该篇博客是博主一字一码编写的&#xff0c;实属不易&#xff0c;请尊重原创&#xff0c;谢谢大家&#xff01; 文章目录前言一、Hexo是什么&#xff1f;二、GitHub Pages是什么&#xff1f;三、建站准备1.准备Github账号2.准备域名四、网站搭建1. 安装 Node.js…

2021 WordPress 网站迁移(从百度云BCC 迁移到 阿里云ECS)

说明&#xff1a;该篇博客是博主一字一码编写的&#xff0c;实属不易&#xff0c;请尊重原创&#xff0c;谢谢大家&#xff01; 文章目录前言一、迁移准备1. 备份原网站2. 备份数据库3. 准备服务器4. 准备好域名5. ICP域名备案二、网站迁移1. ICP备案成功2. 安装宝塔面板3. 创建…

网站架构基础学习(详细)

网站架构基础学习(详细) 1.网站架构的发展经历: 初始阶段的网站(特点&#xff1a;没人)应用程序&#xff0c;数据库&#xff0c;文件都在一个服务器中 比如我们学的是开发&#xff0c;我们要写一个网站&#xff0c;因为这是一个项目&#xff0c; 所以我们要把它部署一下&#x…

云服务器怎么显示网站数据库名称,云服务器怎么显示网站数据库

云服务器怎么显示网站数据库 内容精选换一换本章节指导您使用MongoDB客户端&#xff0c;通过弹性云服务器内网方式连接GaussDB(for Mongo)集群实例。操作系统使用场景&#xff1a;弹性云服务器的操作系统以Linux为例&#xff0c;客户端本地使用的计算机系统以Windows为例。目标…

给自己的网站带来和平:实现自动开启Cloudflare的5秒盾和验证码

引言 梦也不分明&#xff0c;远山云乱横。 ——勿埋我心 你的网站有没有被攻击过&#xff1f;这个脚本虽然不能抵御那些恐怖的“洪流”&#xff0c;但是抵挡一下“小打小闹”应该问题不大。   原理&#xff1a;通过检测系统负载&#xff08;cpu或load&#xff09;自动开启clo…

过滤器的使用实现网站访问计数器

随时随地阅读更多技术实战干货&#xff0c;获取项目源码、学习资料&#xff0c;请关注源代码社区公众号(ydmsq666) 一、创建过滤器需要使用javax.servlet.Filter接口&#xff0c;同时实现Filter接口的3个方法。 CountFilter: package com.home.web;import java.io.IOException…

Nginx配置SSL证书部署HTTPS网站(颁发证书)

自行颁发不受浏览器信任的SSL证书 手动颁发 xshell登录服务器&#xff0c;使用openssl生成RSA密钥及证书 # 生成一个RSA密钥 $ openssl genrsa -des3 -out tfjybj.key 1024# 拷贝一个不需要输入密码的密钥文件 $ openssl rsa -in dmsdbj.key -out tfjybj_nopass.key# 生成一…

实战学习NodeJS建站(5)—nodejs 访问 redis

随时随地阅读更多技术实战干货&#xff0c;获取项目源码、学习资料&#xff0c;请关注源代码社区公众号(ydmsq666) from&#xff1a;http://blog.csdn.net/qidong7/article/details/52888211 前提是你已经安装了nodejs环境。 node_redis是nodejs访问redis的客户端安装包&…

excel修改列名_利用Excel分析招聘网站数据分析师岗位

Excel是进行数据分析用得最多、最基本的工具&#xff0c;下面内容是运用Excel2013对一份数据分析师招聘网站的数据进行分析。Excel数据分析的步骤&#xff1a;1、提出问题&#xff08;明确数据分析目的&#xff09;2、理解数据&#xff08;理解数据列名的意义&#xff09;3、数…

图片变色_『设计|分享』设计师的色彩网站推荐(一)—渐变色

整理&#xff1a;设计与设计师&#xff08;ID&#xff1a;Design-Designer&#xff09;作者&#xff1a;设计与设计师转载请注明出处。配色对一项设计的重要性&#xff0c;这边就不多加赘述。在色彩设计应用中&#xff0c;我们对颜色不同程度的理解&#xff0c;将影响到产品&am…

php写伪静态,php网站动态网站的伪静态写法

PHP网站是主要是以动态网页展示&#xff0c;有时候为了方便优化&#xff0c;也可以设置伪静态来进行网站的优化。主要是通过下面的方式进行伪静态的书写&#xff1a;首先我们先查看Apache是否支持mod_rewrite功能&#xff0c;可以通过PHP提供的phpinfo()函数查看是否支持重写功…

ab压力测试_使用ab命令对网站进行压力测试

概述这是apache自带的一个网站压力测试工具&#xff0c;是ApacheBench的缩写&#xff0c;我们可以使用这个工具来对我们的网站进行压力测试安装在ubuntu上要安装下面这个包sudo apt-get install apache2-utils在centos下是下面这个包sudo yum install httpd-tools -y使用可以直…

虾米音乐java_抓取虾米音乐网站音乐,搜索虾米音乐功能的java实现

可以实现和点点网音乐分享功能暂时还没做界面&#xff0c;先留下代码package com;/*** 歌曲实体* author hanfei**/public class Song {private String title;private String songUrl;private String flashUrl;private String image;public String getTitle() {return title;}p…

百度二级网页打不开_网站降权都是什么原因 - 百度蜘蛛池博客

原出处&#xff1a;蜘蛛池博客原文链接&#xff1a;网站降权都是什么原因&#xff1f; - 蜘蛛池博客我们要学会找出网站降权的原因&#xff0c;才能知道如何对症下药&#xff0c;解决问题。那么&#xff0c;网站降权都是什么原因&#xff1f;接下来蜘蛛池博客小编就跟大家介绍几…