首页 文章 精选 留言 我的

精选列表

搜索[增删改查],共8405篇文章
优秀的个人博客,低调大师

降本笑?割韭菜?

本月,滴滴崩溃事件闹得轰轰烈烈,各种离谱派单层出不穷,而造成这一混乱的,则是底层出故障的云。尴尬的是,这已经不是第一次云崩溃事件了,距离上一次阿里云事件,还不到一个月。 一时之间,各种有关“云”的讨论纷纷扬扬:有人眼馋马斯克的 X 下云省钱,觉得反正都有风险,还不如自己弄,这样更可掌控,也更清楚;有人则认为上云才是未来的趋势,想要发挥出软件的最大优势,上云更合适。 那么,实际操作中,到底是自建云更安全,还是公有云更有保障?对普通的厂商而言,该怎么选择呢?对此,开源中国邀请了前滴滴软件开发工程师李鹤、AutoMQ 联合创始人 & CTO 周新宇、前淘宝 DBA 蒋明、磐吉云数 CEO 冯若航、公众号《瑞典马工》主理人马工,一起来讨论。 上云到底有没有必要?云是不是在割韭菜? 正方:周新宇 speaking —— 我个人大概是在16年就加入阿里巴巴巴的中间件团队了,服务了很多客户。从我个人的经验来讲: 第一,没有云之前,硬件出了问题,解决的门槛很高。阿里内部上云之前,因为消息中间件集群规模很大,硬件它总是在出问题,比如说因为网卡问题导致了 TCD 重视率很高,硬盘出现局部的不可写;比如服务器某个硬件温度过高,导致一些局部的节点不可用。好在阿里有专业的团队帮忙解决,但这在小企业就很难负担了。 第二,公有云比专有云效率高。像我们专门做交付,交付完才是第一步,后面有很多的运维工作,这些运维工作,如果我们远程去做的话,效率比较低,如果去驻厂的话,成本又比较高。公有云的模式,通过聚集算力和统一标准,带来了很多效率上的提升。 第三,云计算能加速业务的创新,提高社会运转效率。像在线教育行业,几年前,基本上都利用了公有云的优势来快速进行业务的创新。如果没有云计算,如果不上云,这些完全不可能发生。还有疫情期间的远程会议,一定程度上保障了社会各方面的正常运转。背后的钉钉这些企业软件,也都是云计算在提供算力。 过去,大部分企业还是以云托管的方式上云为主,基本上就是传统的软件架构,通过这个方式进行上云。但不管怎么样,一定程度上解决了效率和创新问题。今天在降本增效的浪潮下,企业用云,可能不能暴力地照搬以前的架构了,架构需要面向云的能力去设计、去优化,把云原生的能力发挥出来。 反方:冯若航 speaking —— 我比较喜欢用实打实的数据来定量分析云。我的观点是:在降本增效成为主旋律的大背景下,对于有一定规模的云上企业来说,下云自建是一个非常经济务实的选项。我认为公有云它是有适用光谱的,绝对不是他们宣称的数字化万金油。不在这个光谱范围内的业务,如果选择上云,或者是留在云上,那就是被割韭菜了。 我这有歪诗一首:世人常道云上好,托管服务烦恼少。我言云乃杀猪盘,溢价百倍实厚颜。赛博地主搞垄断,坐地起价剥血汗。运维外包嫖开源,租赁电脑炒概念。 公有云的商业模式概括起来就是一个事儿:租——租服务器租带宽租磁盘租运维,这跟租房没有什么本质的区别,自建我们就可以类比为买房。那么租房还是买房的决定性因素是什么?我认为是租售比。房子的租售比一般在几百一个月,那大家买房可能要掂量。那么,服务器的租售比、云算力的租售比一般在半年左右使用费=购买价格。云磁盘的租售比就更离谱了,只有十几天到一个月。你用一块云盘十几天就能买下来,你用一台云服务器,六个月就能把它买下来,那么你为什么要把一个业务跑在这租的东西上,而不是直接把它买下来?如果你的业务生命周期超过六个月,你可以考虑把它买下来,而不是租。 为什么云的价格这么贵?我认为根本原因在硬件上。硬件遵循着摩尔定律在指数增长,成本在指数下降,而这个指数变化并没有在公有云的价格上反映出来,所以公有云从最开始的普惠基础设施,发展到今天变成了一个杀猪盘。它的资源租赁价格已经达到了自建单价的几十倍上百倍,堪称终极的成本刺客。 这也引发了一些新的变化,比如说马斯克的 X(Twitter)、DHH 的 37Signals,算了账单之后,明智地选择了从云上搬迁下来,节约了每年上千万甚至上亿的成本。我认为,这些案例对于整个行业,都是非常具有借鉴意义的里程碑标志。 所以,我认为云的适用光谱就是三件事——小规模,高弹性,全球化。不在这三个场景之内的业务,你选择留在云上,就是在为几倍几十倍的溢价交智商税、被割韭菜。 正方:周新宇 speaking —— 我觉得这里面有一个误区,不能拿这个硬件的成本去跟软件、甚至跟云服务对比。比如说冯总以前写过一篇文章,就是拿本地盘跟 EBS 价格做对比。实际上我认为 EBS 它本身是一个软件服务,它背后是一整套的完整的分布式系统,云服务已经提供了至少三个九的可用性。但本地盘它是硬件,它的故障概率是比较高的,不同的厂商,年化的故障率可能都有差异,有些可能甚至高达5%左右。任何硬件坏了都可能导致无法访问这个本地盘的数据,但在云上,ECS 也好 EBS 也好,它们都是软件,你可以理解为它们就是存算分离的。从应用角度来看,ECS、EBS 都是无状态的,EBS 还解决了一个多副本问题。 如果今天要用本地盘,肯定得主副本,那数据的复制带来的网络带宽消耗、计算资源消耗、存储空间消耗,都需要考虑到成本里面。另外,EBS 它后面是一个大规模的存储节点区域,是能够应对大量磁盘故障的,也能够解决这个数据完整性问题。如果真的要拿 EBS 跟本地盘去对比的话,我觉得至少得让用户去自建一套分布式存储系统,跟使用 EBS 做对比,还得把运维的人力成本也考虑进去。这些在自建、规模比较小的情况下,是很难算清楚的。 反方:冯若航 speaking —— 上云的成本比自建要高得多。我自己15年的时候在淘宝的 CNZZ,友盟+这个部门算是第一波被推上阿里云的内部 BU。在上云之前,我们有一个自己的机房,几百台服务器,一年所有成本算进去1000万。后来上了阿里云大数据全家桶数据库 ODPS 这些东西,每年计算3000万存储4000万。从1000万变成7000万这件事直接给了我对云的第一印象,因为阿里云是手把手出工程师加入我们团队帮我们改造业务搬上云的,从原来的每年1000万搬到了后来的每年7000万,而干的事情,本质上却还是一模一样的,都是统计和计算规模,也没有出现特别的变化。在上完云之后,我们的效能并没有出现变化,但是成本却是实打实地翻了七倍。 这是我自己亲身经历的一个案例。如果说更有共性的一件事,我觉得可以参考一下 Amazon。AWS 在2013年提出的公有云价值,他举了六个点:弹性、敏捷、全球化出海、将资本支出转变为运营支出,以及更低的成本、消除重复建设。 但是,这些公有云价值主张在2023年很多已经不成立了,甚至说很多已经没有价值了。我认为还有价值的点就是弹性、agility 和全球化出海,但是这里面覆盖的光谱其实并不多,特别是在高价值用户群体里面并没有覆盖那么多,更多是小微初创小规模业务会用到这些点。 比如这个 CAPEX 转为 OPEX,将资本支出转为运营支出。这一点,我认为除了对于那种连六个月都活不过的小业务有价值之外,凡是超过六个月,买肯定比租合算了。lower cost 是 AWS 当初相对于这些企业级解决方案来说的,它更便宜。比如说 Oracle 一盒1月你要付一万块钱,那么 AWS 上的 RDS 每个月只要1000块钱,是不是很便宜?但是那个时候,你可以说只有我这一家有云,所以我可以用这个价值定价,但现在谁家没有一个 RDS ?开源的 RDS 管控都出来了。那么这就变成了成本定价。既然是成本定价,我用云数据库加硬件,用这种开源的方案加上硬件20块钱一盒,1月不比这1000块钱或者400块钱的 RDS 要香吗?lower cost 这个事儿已经完全变味儿了,现在不是 lower cost 是 higher cost。 至于消除重复建设这个事,我认为现在开源干得已经比这好了,各家都有自己的 EC2 VPS,但是 K8s 很明显一统了这些无状态服务调度天下,所以我认为在2023年公有云的价值就剩下了全球化合规出海,它的适用光谱已经缩小到了小规模业务和高弹性业务和出海业务这三样。以前我们业界大概有一个规模估算,你在云上的年消费在100到300万这个区间,你就应该考虑下云了。我认为,随着资源云和开源平替的出现,100万-300万的阈值将会被进一步拉低至10万-30万或者1万-3万。我认为这件事很有可能会发生,而且正在发生。 如今上云还安全吗?稳定性有多强? 反方:马工 speaking —— 对于安全,我有很多话说。作为一个软件工程师最基本的是,你不能把密码直接写死、hard code 就编码到你的代码里面,更不能把它提交到 Github 上,这属于初级的实习生犯的错误对不对? 但是我看了一下,国内的腾讯云阿里云和华为云什么的,全都教用户把那个 Access ID,编码到代码里面。阿里云和腾讯云去年已经改正了,因为我写文章揭露他们。但是至今为止,华为云和火山引擎上面的范例里面还是页编码,Access key,这是非常不负责任的一个做法。 我为什么说他们是一个草台班子,因为这就相当于修了一座桥,然后把桥的地基给抽掉了,或者说做了一个保险库,但是把钥匙给插在那个锁上了。就这样还谈安全? 我们可以看一下更近的例子,滴滴出了事故影响了上千万的出行,它连具体的技术原因都没提出来,只说我们会改进、我们是一个内部系统。但这个内部系统是什么?你怎么改进这个系统?基础系统是外购的,还是自研的?什么都没说,但是北京那个地铁追尾,人家就成立调查组了,调查组就会有调查结论,就会有限期改正通知书,你得复盘,你得汇报,监管部门会过来检查,然后发通知给其他的地铁公司,让别人吸取他的教训。这才是一个真正的工程行业。 我赞同周新宇说的“云厂商的故障比自建机房的故障更令人瞩目”,但是,我的机房出故障,我可以得到最全面的信息,云厂商出故障,我得不到所有的信息,甚至他不给我信息。比如阿里云至今也没有披露技术细节。甚至有一些厂商,他是隐瞒故障,他不会跟你通知,而是想着偷偷修复了你就不知道了。这是一个非常让我们担心的问题:没有透明度。这样你也无法从业务上规避它,只能求它别出事了。这是非常危险的。 正方:周新宇 speaking —— 今天云厂商确实做得不够好,但这也是会改进的。云厂商在安全和数据完成这块都有很大的投入,我们以前做一个架构,要经过很多层的安全架构评审,并不是说啥都不做。当然,云计算这个技术也好,云计算这种商业模式也好,它肯定是有进步空间的,不能因为当前云厂商某些地方还不够成熟,就完全否定上云的优势或者是云计算的优势。 正方:蒋明 speaking —— 尤其是大规模的数据库用户,还是上云才能解决需求。像肯德基,阿里云出事以后,他们就把业务迁到了抖音建的云上,并没有迁到自己的机房里。 根据我的经验,自建机房的话,如果只是一两台机器托管一下的话,还是比较简单的。但是当机器达到四五千台的时候,那你就会遇到 CPU 的故障、内存的故障和磁盘的故障,这时候,你就会很依赖监控系统。我有过大概4000多台物理机的这种机房托管经验,当时用的是南京的管理系统,也是腾讯的开源软件,实时监控用的是阿里的监控软件 SLS,哪个磁盘出故障了,就发给线下的运维,让他去换。如果全部都是自建的话,根本就做不到。 像我们现在的政务云、水电煤背后的技术支持,全部都是在云上的,政府的政务处理系统,银行的交易系统也全部都在云上,如果云真的一无是处,那我们生活当中,支付宝就没办法扫了,钱也付不出去。 反方:冯若航 speaking —— 我觉得你说的问题非常严峻,就是所谓的云集中的问题。Gartner 最近发布的2023年三季度新兴风险报告里面,云集中风险已经连续第二年进入“五大新兴风险”综合榜单,在中国排第三位。云集中说的就是云厂商已成为了新的单点,爆炸半径极大。阿里云这一挂,有多少服务宕机了?如果政务云金融云这些都跑在阿里云,那挂了怎么办? 去年阿里云香港区域故障就导致香港政府很多单位的网站和电子政务不能用。 所以,这就是一个下云的重要 argument ——为了安全性和自主可控。上云其实就是放弃了自主可控,放弃了一部分的安全性。你没有办法对机密性、完整性去进行任何的验证,甚至是追索。 我是搞信息安全的,安全里面有三个点:CIA ——机密性,数据完整性和可用性。就是不丢,不坏,不宕。但是云厂商它不给你兜机密性和完整性,它只给你兜可用性,而且是非常逊色的可用性。 比如说云 RDS for PostgreSQL,这个云数据库的基础版甚至都没有望归档,也就是说它没有数据库 PITR 时间点恢复的能力,一个数据库服务竟然没有基础的时间点恢复能力,我认为这对于一个数据库用户来说是完全不可接受的。至于机密性,那就更没法保证了,你甚至没有办法去验证发现任何数据丢失。但要是自建机房,就不会存在这样的风险。 中小企业该怎么选? 正方:周新宇 speaking —— 如果是一家初创企业,那肯定是毫无疑问要上云,第一天就应该把你的 IT 设施构建在云上,这样未来的业务创新或试错成本都非常低。这是,如果你的企业已经在重度用云,今天因为成本的问题在考虑是否下云,那我觉得是要慎重的,因为不管是上云还是下云,折腾一次代价是比较大的。所以说更好的方式是去分析云上的账单,这里相对于自建有很大的优势:在云上你的一切价格账单都是透明的,到底贵在哪里,可以针对性地去降本。 正方:蒋明 speaking —— 可以用阿里云、腾讯云、AWS 的基础建设能力,比如 ECS 或 OSS,加上第三方的开源软件,比如 TiDB、AutoMQ,这些软件,它价格便宜,又能用云厂商最便宜的基础能力构建一个企业的自动化 DevOps 系统,让你用最低的成本,在云上创业。至于后面企业大了,像马斯克的 X 公司,那自建云是最佳的选择,毕竟成本会更低。 反方:冯若航 speaking —— 从务实的角度来讲,小企业其实是适合云的,但是你也不要把所有的东西都深度依赖云。 第一,你有自建能力,这是你跟云厂商谈价格折扣的最大筹码! 第二,优先使用资源云。什么是资源云?像租用它的虚拟机,尽可能的避免使用它的专有服务、被供应商锁定。 第三,如果你在云上非要用这些服务,请避免使用 AKSKIAM 这些让你陷入供应商锁定的东西。这些不仅会让你陷入云单点故障中,更是会把你绑在一个你下不来的账单下。 反方:马工 speaking —— 我觉得云是一个操作系统,你用云就相当于从 Windows 系统切换到 Linux,这需要非常大的努力,需要一个范式转移。这个转移路上,你必须要有人带着你走。但我目前看云自己也不知道怎么走。这有一个大胆的估测: 90%的云厂商的员工,没有自己的云账号; 90%的云厂商的员工,没有考过云的认证; 90%的云厂商的员工,从来没有在云上维护过或者部署过一个生产系统。 我觉得大家还是谨慎一点,除非云厂商能够证明云计算的价值点,然后给出一个很明确的路径,不然的话你就不要那么急躁地为了云而云。另外,腾讯会议或者钉钉那不是云,跟微信一样,只是一个很普通的 Saas 系统,这个跟你要负责任的企业 IT 系统是完全不一样的。 大家对此怎么看呢?快留言说说你的经验吧~ 直播回放如下,错过的赶紧扫码看看回放吧↓↓↓

优秀的个人博客,低调大师

2020年工控系统漏洞数量暴

根据Claroty最新发布的报告,2020年下半年披露的ICS漏洞同比增加了25%,比2020年上半年增加了33%。71%的已披露工业控制系统(ICS)漏洞可通过网络攻击媒介远程利用。 2020年上半年,共披露了59个供应商的449个ICS产品漏洞,其中70%的漏洞CVSS评分为高或“关键”,76%的漏洞不需要身份验证即可被利用。 Claroty研究副总裁Amir Preminger表示:“由于数字化转型,IT和OT网络的加速融合提高了ICS流程的效率,但也增加了对手可用的攻击面。” “国家黑客在研究工控系统网络外围的诸多方面,而网络犯罪分子也特别关注ICS流程,这强调了对安全技术的需求,例如在工业环境中基于网络的检测和安全的远程访问。令人振奋的是,网络安全行业对ICS的兴趣日益增长,研究者们希望更加清楚地了解这些漏洞,以便帮助企业远离威胁。” 关键基础设施行业中,制造业、能源、水处理和商业设施部门受2020年上半年披露的漏洞的影响最大,并且比前两年全面增加: 关键制造业比2019年上半年增长15%,比2018年上半年增长66%; 能源比2019年上半年增长8%,比2018年上半年增长74%; 自2019年上半年起,供水和废水处理漏洞增加了54%,与2018年上半年相比增加了63%; 商业设施较2019年上半年增加14%,较2018年上半年增加140%。 2020年披露的ICS漏洞数量与2018年相比增加了30%以上,与2019年相比增加了近25%。近年来,ICS漏洞数量飙升主要有两个因素,对ICS漏洞风险意识的增强,以及研究人员和供应商更加努力地识别和修复安全漏洞。这种增长同时也表明针对CS产品的安全研究逐渐成熟。 第三方研究人员贡献了61%的漏洞发现,其中许多是网络安全公司。这标志着重点已发生变化,将ICS与IT安全研究结合起来,进一步证明了IT与OT之间加速融合。在所有第三方发现中,有22家公司首次披露信息,这是ICS漏洞研究市场增长的积极信号。 【本文是51CTO专栏作者“安全牛”的原创文章,转载请通过安全牛(微信公众号id:gooann-sectv)获取授权】 戳这里,看该作者更多好文 【责任编辑:赵宁宁 TEL:(010)68476606】 点赞 0

优秀的个人博客,低调大师

利用bootstrap模态框+ajax对数据进行增删改

接上篇:1.数据库改动,添加外键,多对多model.py from django.db import models # Create your models here. GENDER = { ('male', '男'), ('female', '女'), } class User(models.Model): username=models.CharField(max_length=32,null=False) password=models.CharField(max_length=32,null=False) email = models.EmailField(null=True) name = models.CharField(max_length=20, null=True) tel = models.CharField(max_length=20, null=True) gender = models.CharField(max_length=20, choices=GENDER) birthday = models.DateTimeField(null=True) class Proxy(models.Model): ng_name=models.CharField(max_length=20) class Domain(models.Model): domain=models.CharField(max_length=125,null=False) src=models.CharField(max_length=125,null=False) User=models.ForeignKey(User,on_delete=models.CASCADE) m=models.ManyToManyField(Proxy) 核心部分之view from django.core.exceptions import ValidationError from django.db import IntegrityError from django.shortcuts import redirect, render, HttpResponse from cdnpanel.models import User, Domain, Proxy import json def index(request): if request.COOKIES.get("is_login"): username = request.COOKIES.get('username') data = Domain.objects.filter(User__username=username) engine = Proxy.objects.all() user = User.objects.all() return render(request, 'index.html', {'data': data, "engine": engine, "user": user}) else: return redirect('/login') def login(request): if request.method == "POST": ajax_rep = {"status": "err", "msg": None} user = request.POST.get('username') pwd = request.POST.get('password') if not User.objects.filter(username=user).exists(): ajax_rep['msg'] = "用户不存在" elif not User.objects.filter(username=user, password=pwd).exists(): ajax_rep['msg'] = "密码错误" else: ajax_rep['status'] = 'ok' rep = HttpResponse(json.dumps(ajax_rep)) rep.set_cookie("is_login", True) rep.set_cookie("username", user) return rep return HttpResponse(json.dumps(ajax_rep)) return render(request, "login.html") def register(request): if request.method == "POST": ajax_rsp = {"status": "ok", "msg": None} try: if request.is_ajax(): username = request.POST.get('username') password = request.POST.get('password') name = request.POST.get('name') email = request.POST.get('email') tel = request.POST.get('tel') gender = request.POST.get('gender') birthday = request.POST.get('birthday') if User.objects.filter(username=username).exists(): ajax_rsp["status"] = "err" ajax_rsp["msg"] = "用户已存在" else: User.objects.create( username=username, password=password, email=email, name=name, tel=tel, gender=gender, birthday=birthday, ) except IntegrityError: ajax_rsp["status"] = "err" ajax_rsp['msg'] = "性别为必选项" except ValidationError: ajax_rsp["status"] = "err" ajax_rsp['msg'] = "日期为必选项" return HttpResponse(json.dumps(ajax_rsp)) else: return render(request, "register.html") def add_domain(request): if request.is_ajax(): print(request.POST) ajax_rsp = {'status': "err", "msg": None, "yourself": "yes"} try: domain = request.POST.get("domain") src = request.POST.get("src") user = request.POST.get("username") if not user == request.COOKIES.get('username'): ajax_rsp["yourself"] = "no" user_id = User.objects.get(username=user).id ng_id = [] ng = request.POST.getlist('ng_name') for n in ng: nid = Proxy.objects.get(ng_name=n).id ng_id.append(nid) Domain.objects.create(domain=domain, src=src, User_id=user_id) obj = Domain.objects.get(domain=domain) obj.m.set(ng_id) ajax_rsp['data_id'] = obj.id ajax_rsp['status'] = 'ok' except Exception as e: print(e) ajax_rsp['msg'] = str(e) return HttpResponse(json.dumps(ajax_rsp)) return redirect('/index') def del_domain(request): if request.is_ajax(): ajax_rsp = {'status': "err", "msg": None} try: del_data_id=request.POST.get("del_data_id") print(del_data_id) Domain.objects.get(id=del_data_id).delete() ajax_rsp['status'] = "ok" except Exception as e: print(e) ajax_rsp['msg'] = str(e) return HttpResponse(json.dumps(ajax_rsp)) def update_domain(request): if request.is_ajax(): if request.method == "GET": ajax_rsp = {"status": "err"} try: data_id=request.GET.get("data_id") domain=Domain.objects.filter(id=data_id).first() ajax_rsp["domain"]=domain.domain ajax_rsp["src"]=domain.src ajax_rsp["user"]=User.objects.get(domain__domain=domain.domain,domain__id=data_id).username engine_list=[] for item in Proxy.objects.filter(domain__domain=domain.domain): engine_list.append(item.ng_name) ajax_rsp["engine"]=engine_list ajax_rsp["status"]='ok' print(ajax_rsp) except Exception as e: print(e) ajax_rsp['msg'] = str(e) return HttpResponse(json.dumps(ajax_rsp)) elif request.method == "POST": print(request.POST) ajax_rsp = {'status': "err", "msg": None, "yourself": "yes"} try: old_id = request.POST.get("data_id") domain = request.POST.get("domain") src = request.POST.get("src") user = request.POST.get("username") if not user == request.COOKIES.get('username'): ajax_rsp["yourself"] = "no" user_id = User.objects.get(username=user).id ng_id = [] ng = request.POST.getlist('ng_name') for n in ng: nid = Proxy.objects.get(ng_name=n).id ng_id.append(nid) Domain.objects.filter(id=old_id).update(domain=domain, src=src, User_id=user_id) obj = Domain.objects.get(domain=domain,src=src) obj.m.set(ng_id, clear=True) ajax_rsp['status'] = 'ok' except Exception as e: ajax_rsp['msg'] = str(e) return HttpResponse(json.dumps(ajax_rsp)) def test(request): print(Domain.objects.get(domain="2343165sada4864sdsa.tw")) return render(request, 'test.html') 核心部分之index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> {% load static %} <link rel="stylesheet" href="{% static 'plugin/bootstrap/css/bootstrap.min.css' %}"> <link href="//netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"> <style> .table{ width: 300px; } </style> <body> <p></p> <div> <button type="button" class="btn btn-success" data-toggle="modal" data-target="#addModal">添加</button> </div> <p></p> <div> <table class="table table-bordered"> <thead> <tr> <th>域名</th> <th>源</th> <th>操作</th> </tr> </thead> <tbody> {% for item in data %} <tr data_id="{{ item.id }}"> <td>{{ item.domain }}</td> <td>{{ item.src }}</td> <td> <a data-toggle="modal" data-target="#delModal" id="del_icon" class="fa fa-trash-o fa-lg"></a> <a data-toggle="modal" data-target="#editModal" class="fa fa-pencil fa-fw"></a> </td> </tr> {% endfor %} </tbody> {# 添加模态对话框#} <div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-labelledby="addModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="addModalLabel">New message</h4> </div> <div class="modal-body"> <form action="add_domain" id="modal_form" method="post"> <div class="form-group"> <label for="inputEmail3" class="col-sm-2 control-label">域名:</label> <input type="text" name="domain" class="form-control" id="inputEmail3" placeholder="域名"> </div> <div class="form-group"> <label class="col-sm-2 control-label">源:</label> <input name="src" class="form-control" placeholder="1.1.1.1"> </div> <div class="form-group"> {% for ng in engine %} <input type="checkbox" name="ng_name" value="{{ ng.ng_name }}">{{ ng.ng_name }} {% endfor %} </div> <div class="form-group"> <select name="username" > {% for u in user %} <option value="{{ u.username }}">{{ u.username }}</option> {% endfor %} </select> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> <button type="button" class="btn btn-submit add_submit">提交</button> </div> </div> </div> </div> </table> </div> {#删除模态框#} <!-- Modal --> <div class="modal fade " id="delModal" tabindex="-1" role="dialog" aria-labelledby="delModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content "> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="delModalLabel" style="color: red" >危险!!</h4> </div> <div class="modal-body alert alert-danger" > 此操作不可以逆!是否删除? </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> <button type="button" class="btn btn-danger del_submit">确认删除</button> </div> </div> </div> </div> {#编辑模态框#} <div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="editModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="editModalLabel">update</h4> </div> <div class="modal-body"> <form action="update_domain" id="modal_form" method="post"> <div class="form-group"> <label for="inputEmail3" class="col-sm-2 control-label">域名:</label> <input type="text" name="domain" class="form-control" id="inputEmail3" > </div> <div class="form-group"> <label class="col-sm-2 control-label">源:</label> <input name="src" class="form-control" > </div> <div class="form-group"> {% for ng in engine %} <input type="checkbox" name="ng_name" value="{{ ng.ng_name }}">{{ ng.ng_name }} {% endfor %} </div> <div class="form-group"> <select name="username" > {% for u in user %} <option value="{{ u.username }}">{{ u.username }}</option> {% endfor %} </select> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> <button type="button" class="btn btn-submit edit_submit">提交</button> </div> </div> </div> </div> </table> </div> </body> <script src="/static/js/jquery-3.5.1.min.js"> </script> <script src="{% static 'plugin/bootstrap/js/bootstrap.min.js' %}"> </script> <script> $(".add_submit").click(function (){ var data=$("#addModal form").serialize() console.log(data) $.ajax({ data:data, dataType:"json", "type":"POST", "url":'/add_domain', "success":function (arg) { {#若添加的是自己的数据则在前端显示#} if(arg.yourself=="yes") { console.log(arg.msg) postdata = "{\"" + data.replace(RegExp("=", "g"), "\":\"").replace(RegExp("&", 'g'), "\",\"") + "\"}"; postdata = JSON.parse(postdata) console.log(postdata.domain) data_id=arg.data_id var tr_ele = $("<tr></tr>") tr_ele.attr("data_id",data_id) var dtd_ele = $("<td></td>").text(postdata.domain) var std_ele = $("<td></td>").text(postdata.src) var action_ele = '<td><a data-toggle="modal" data-target="#delModal" id="del_icon" class="fa fa-trash-o fa-lg"></a> <a data-toggle="modal" data-target="#editModal" class="fa fa-pencil fa-fw"></a></td>' tr_ele.append(dtd_ele) tr_ele.append(std_ele) tr_ele.append(action_ele) $("tbody").append(tr_ele) } $('#addModal').modal('hide') document.getElementById("modal_form").reset() } }) }) {# 删除函数 #} var data_id; {# 定义一个全局变量传递修改数据的id值 #} {#$(".fa-trash-o").click(function (){#} $(document).on("click",".fa-trash-o",function (){ data_id=$(this).parent().parent().attr("data_id") $(this).parent().parent().attr("id","del_targer"){# 因为没法通过data_id删除元素,给点击的tr标签加了个唯一id标识 #} $(".del_submit").click(function(){ var postdata={}; postdata['del_data_id']=data_id console.log(data_id) $.ajax({ data:postdata, dataType:"json", "type": "POST", "url":'/del_domain', "success":function (arg){ if(arg.status=="ok"){ $("#del_targer").remove() $('#delModal').modal('hide') } } }) }) }) {# 编辑函数 #} {# $(".fa-pencil").click(function (){#} $(document).on("click",".fa-pencil",function (){ data_id=data_id=$(this).parent().parent().attr("data_id") {# 直接从前端获取数据太麻烦,这里用ajax获取数据赋值#} $(this).parent().parent().attr("id","edit_targer") $.ajax({ type:"GET", data:{"data_id":data_id}, "url":'/update_domain', dataType:"json", "success":function (arg){ if(arg.status=="ok"){ $("#editModal input[name='domain']").val(arg.domain) $("#editModal input[name='src']").val(arg.src) $("#editModal option[value="+arg.user+"]").prop("selected",true) for (item in arg.engine) { ng_name=arg.engine[item] $("#editModal input[value="+ng_name+"]").prop("checked",true) } } } }) $(".edit_submit").click(function (){ var data=$("#editModal form").serialize() postdata = "{\"" + data.replace(RegExp("=", "g"), "\":\"").replace(RegExp("&", 'g'), "\",\"") + "\"}"; postdata = JSON.parse(postdata) postdata["data_id"]=data_id $.ajax({ data:postdata, dataType:"json", "type":"POST", "url":'/update_domain', "success":function (arg) { {#若修改的是自己的数据则在前端显示#} if (arg.status == 'ok') { if (arg.yourself == "yes") { var tr_ele = $("#edit_targer") tr_ele.empty() var dtd_ele = $("<td></td>").text(postdata.domain) var std_ele = $("<td></td>").text(postdata.src) var action_ele = '<td><a data-toggle="modal" data-target="#delModal" id="del_icon" class="fa fa-trash-o fa-lg"></a> <a data-toggle="modal" data-target="#editModal" class="fa fa-pencil fa-fw"></a></td>' tr_ele.append(dtd_ele) tr_ele.append(std_ele) tr_ele.append(action_ele) }else { var tr_ele = $("#edit_targer") tr_ele.empty() } $('#editModal').modal('hide') $("#edit_targer").attr("id","") } } }) }) }) $(".btn-default").click(function (){ document.getElementById("modal_form").reset() $(":checked").prop("checked",false) $(":selected").prop("selected",false) $("#del_targer").attr("id","") $("#edit_targer").attr("id","") }) </script> </html> url部分 urlpatterns = [ path('admin/', admin.site.urls), re_path('index', views.index), re_path('register', views.register), re_path('login', views.login), re_path('add_domain', views.add_domain), re_path('del_domain', views.del_domain), re_path('update_domain', views.update_domain), re_path('test', views.test), ] 思路历程简介: 1.登陆上篇的登陆没有设置cookie,所以每次都要重复登陆,操作其实很简单,当用户名和密码匹配成功了,在cookie中设置自定义字段is_login=true,然后在index函数中取得该值并判断,代码部分如下 def index(request): if request.COOKIES.get("is_login"): username = request.COOKIES.get('username') data = Domain.objects.filter(User__username=username) engine = Proxy.objects.all() user = User.objects.all() return render(request, 'index.html', {'data': data, "engine": engine, "user": user}) else: return redirect('/login') def login(request): if request.method == "POST": ajax_rep = {"status": "err", "msg": None} user = request.POST.get('username') pwd = request.POST.get('password') if not User.objects.filter(username=user).exists(): ajax_rep['msg'] = "用户不存在" elif not User.objects.filter(username=user, password=pwd).exists(): ajax_rep['msg'] = "密码错误" else: ajax_rep['status'] = 'ok' rep = HttpResponse(json.dumps(ajax_rep)) rep.set_cookie("is_login", True) rep.set_cookie("username", user) return rep return HttpResponse(json.dumps(ajax_rep)) return render(request, "login.html") 2.添加数据添加数据流程主要是:获取数据-->处理数据-->取得返回结果后展示 获取数据前还要先做填写数据的模态框,这里主要有个问题,因为涉及外键和多对多,所以要先有这些数据可以选,也就是模板里面必须传入外键表的值和多对多的值,我这里是render(request, 'index.html', {'data': data, "engine": engine, "user": user})然后用select元素作为多对多的选择项,checkbox为User的单选 <1>获取数据因为填数据用的是form表单,所以这里获取数据很简单用serialize()函数var data=$("#addModal form").serialize()<2>处理数据利用ajax传送,view函数处理即可<3>数据显示这里有个问题,serialize()函数处理出来的数据不是字典形式,而是类似get请求的形式:”username=linzb&password=123456“,所以要对其进行分割取值,才能对元素进行赋值(这里我还多赋值一个yourself字段,判断是否为当前登录用户,是才显示) 3.删除要删除,首先服务端要知道数据是什么,其次,服务端删除成功后,前端要删除对应元素,所以删除部分可以归结为一个问题:如何对原来的数据进行定位? 这里我利用了一个全局变量data_id(生成数据的时候在tr上赋值数据id),在点击删除按钮的时候,通过this关键字找到这个数据id并传递给data_id,并在id打了个del_tager标记,于是问题解决: <1>data_id通过ajax传递给服务端,服务端找到对应数据del <2>返回结果后,前端通过#del_tager找到标签并删除 (这里也许有人会问为什么不直接通过data_id,而要多此一举,这是因为我测试多次这方法行不通,才选择用del_targer) 4.编辑编辑比添加多了两步<1>打开模态框的时候要为模态框赋值(这里我采用ajax从服务端取值,这方法不推荐,从前端取值对服务端更友善)<2>成功执行后要在前端进行修改而不是添加 debug: 1.django 设置cookie需要用变量过渡,直接引用会报错 正确: rep=HttpResponse(json.dumps(ajax_rep)) rep.set_cookie("is_login",True) return rep 错误: return HttpResponse(json.dumps(ajax_rep)).set_cookie("is_login",True) 2. 给标签加 data-toggle="modal" data-target="#exampleModal"属性,点击没反应 测试发现是忘了加载bootstrap.min.js 3.ValueError: too many values to unpack (expected 2) 排查发现:Proxy.objects.get(ng_name=n).id写成了: Proxy.objects.get(n).id 少了字段名 4.添加时的元素位置和插入问题 想要的代码形式: <tbody> <tr> <td>已存在的数据</tr> </tr> <tr> <td>新增加的数据<td> </tr> </tbody> var tr_ele =$("<tr></tr>") var dtd_ele =$("<td></td>").text(新增加的数据) tr_ele.append(std_ele) $("tbody").append(tr_ele) 之前用:tr_ele.text(dtd_ele)和$("tbody tr").append(tr_ele)一直搞不定 错误原因在于没有意识到append是在内部添加,before()和after() 是在外部 5.Bootstrap 模态框使用 <1>以id为标识,内容标签包裹头部,body和尾部 <div class="modal fade" id="delModal" tabindex="-1" role="dialog" aria-labelledby="delModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> </div> <div class="modal-body " > </div> <div class="modal-footer"> </div> </div> </div> </div> <2>用data-target指向id引用 <a data-toggle="modal" data-target="#delModal" id="del_icon" class="fa fa-trash-o fa-lg"></a> 6.jquery attr()和prop()区别 <1>取自定义属性用attr() (下面摘抄自:https://www.jb51.net/article/140974.htm) 1.添加属性名称该属性就会生效应该使用prop(); 2.是有true,false两个属性使用prop();(如'checked','selected','disabled'等) 3.其他则使用attr(); 7.模态框退出,清空表单输入值的方法(利用form表单的reset) 由于jquery没有reset()方法,可以给表单赋予id,然后reset() document.getElementById("modal_form").reset() 选择按钮则需要去掉对应属性 $(":checked").prop("checked",false) $(":selected").prop("selected",false) 8.编辑模态框完成后发现添加数据时报错 后面print (POST数据)发现数据取了多行 原因:取数据时没有区分form表单 原来:var data=$("form").serialize() 修改:var data=$("#addModal form").serialize() 9.多对多表更新,加上clear=True就可以 obj.m.set(ng_id,clear=True) 意为先清空后添加 10.做删除的时候利用tr传递data_id,添加的时候也必须加上 11.事件委托on语法: $(document).on("click",".fa-trash-o",function (){}) on("事件","选择标签",函数(){}) 删除时的思路:点击模态按钮时必须获取当前的值,用全局变量传递 要删除整行,于是放在tr标签上 12.如果发现清空数据有问题用(找到对应位置即可,51编辑器不好用,懒得重复改): document.getElementById("modal_form").reset() $(":checked").prop("checked",false) $(":selected").prop("selected",false) $("#del_targer").attr("id","") $("#edit_targer").attr("id","")

优秀的个人博客,低调大师

AIGC 应用爆发,相关岗位需求超 300%

央视财经《正点财经》报道称,随着人工智能应用的爆发,生成式人工智能的招聘市场也十分火爆。 在一家大型人工智能软件公司,团队负责人告诉记者,他们团队主要做基于大模型的办公协作类软件的研发,近期正在升级一款面向程序员的代码工具,产品已经在网页端取得不错的成绩,团队想拓展至移动端,却苦于人手不够。 记者从这家公司的人力资源部门了解到,多数人工智能业务团队长期都处于招人状态。招聘岗位涉及从底层算力、芯片设计,到模型训练、商业落地等多环节、全链条。招到一个生成式人工智能岗位的平均耗时是普通岗位的两倍。 不仅是科技类企业,生成式AI由于商业应用广泛,人才稀缺也蔓延到了其它行业。在一家连锁餐饮企业,技术部门负责人表示,企业的后台系统数据庞大,有千万量级的客户评价,而传统分析方式要么不够精准、要么耗费大量人力。企业急需利用生成式人工智能技术,来更精准地响应客户评价。 某餐饮连锁企业信息科技部高级产品经理 于文超:顾客给我们评价的时候语序、话术可能比较杂乱。经过AIGC(生成式人工智能)大模型的语义分析处理后的数据,我们可以从中识别到比如服务质量、菜品质量等,对后续经营管理的持续优化迭代产生非常大的指导。 某招聘平台数据显示,今年一季度,生成式人工智能相关职位需求同比增长超过三倍,投递该领域的求职人次同样水涨船高,同比增长更是超过9倍,呈现供需两旺的状态。 某招聘平台负责人 戴科彬:从全平台增长较好的职位类别来看,增长率达到60%已经算是非常突出的表现了,而AIGC(生成式人工智能)相关岗位的同比增长超过了320%,这样的增长速度是飞速的。

优秀的个人博客,低调大师

隐私搜索引擎DuckDuckGo流量暴62%

隐私保护搜索引擎DuckDuckGo一月份搜索查询首次突破亿次大关,呈现爆发式增长。 DuckDuckGo是一个以隐私保护为卖点的搜索引擎,其搜索索引主要有三个来源:DuckDuckBot爬虫、WikiPedia索引以及Bing等搜索引擎合作伙伴,值得注意的是,DuckDuckGo搜索引擎不使用任何来自Google的数据。(编者:Google也是少数,如果不是唯一,对虚拟专用网极其不友好的搜索引擎) 使DuckDuckGo脱颖而出的原因在于,它们不会跟踪您的搜索痕迹来建立用户个人资料或与第三方公司(包括广告网络)共享任何个人或识别数据。 “每次在DuckDuckGo上进行搜索时,您的搜索历史记录都是一片空白,每一次,都像是第一次。”DuckDuckGo在其博客中解释道。 根据DuckDuckGo提供的数据,2020年DuckDuckGo的平均日搜索量增长了62%。截至2021年1月,DuckDuckGo平均每天收到9000万个搜索查询。 2021年1月11日,DuckDuckGo每天收到102,251,307条搜索查询请求,创下该搜索引擎的新记录。 DuckDuckGo的快速增长得益于互联网用户对隐私的关注度不断提高。随着越来越多的个人数据泄露事件曝光,以及海量隐私数据被用于政治目的或者商业巨头的垄断经营,越来越多的人开始转向以隐私为中心的搜索引擎。 DuckDuckGo表示:“虽然我们不追踪用户,但我们会通过全国调查来研究用户的采用情况。从这些调查中我们了解到,我们的整体增长是关注隐私的人们口口相传所推动的。” 最近一些备受关注的隐私新闻,例如有关WhatsApp和Facebook之间数据共享的担忧,以及社交应用Parler被硅谷巨头“社死”,导致人们对隐私保护为卖点的产品,例如DuckDuckGo和Signal的关注度飙升。 根据StatCounter的统计,这种爆发式的增长使DuckDuckGo成为美国、英国、加拿大和澳大利亚市场上移动设备上第二大最常用搜索引擎。 尽管Google在美国仍占有94%的市场份额,但DuckDuckGo现在以2.25%的市场份额排名第二,其次是Yahoo(1.94%)。 【本文是51CTO专栏作者“安全牛”的原创文章,转载请通过安全牛(微信公众号id:gooann-sectv)获取授权】 戳这里,看该作者更多好文

优秀的个人博客,低调大师

加密通讯元年:Signal下载量暴4200%

在社交媒体应用Parler本周一被科技巨头们“集体处决”后,本周三WhatsSpp在新的隐私政策中宣布将与其母公司Facebook分享用户隐私数据后,这导致大批恐慌的用户纷纷涌向WhatsApp的竞争对手。 在新的隐私政策中,WhatsApp告诉用户,他们必须同意让Facebook及其子公司在2月8日之前收集WhatsApp数据(包括电话号码和位置),否则将无法继续使用WhatsApp应用。随后,面对舆论的一片哗然,WhatsApp澄清说,该政策仅影响欧盟和英国以外的用户(编者:因为惧怕GDPR),并表示此更改“不会以任何方式影响您与朋友或家人共享的消息的隐私”。 来自应用分析公司Sensor Tower的数据显示,在WhatsApp宣布之后,加密消息服务Signal的用户数量激增。从1月6日到1月10日,Signal在App Store和Google Play上的全球安装量约为750万,比前一周增长了4,200%。 WhatsApp的隐私政策发布后,Signal的曝光量也激增,包括马斯克和斯诺登在内的“科技公知”都纷纷为Signal点赞“带货”。在国会抗议活动第二天马斯克就曾在推特上发推号召粉丝“Use Signal”。 但这条推文产生了意想不到的副作用,与Signal一毛钱关系都没有的一家上市公司——Signal Advance的股票飙升了11700%。 加密消息服务Telegram也受益于最近的一系列事件,新用户数量快速增长。在同一时期,Telegram积累了900万新用户,比前一周增长了91%。 值得注意的是,Signal和Telegram增长最快的市场都是印度。Signal在印度的安装量为230万,占其新安装量的30%以上。Telegram在印度的安装量约150万,占总安装量的16%。 过去几年,Signal在网络安全业界赢得不错的口碑,但依然属于小众产品。但是去年在疫情引发的全球远程办公大潮中,以Signal为代表的,将安全性作为卖点的产品开始逆袭传统通讯和协作软件。根据美国国家安全局(NSA)去年二季度发布的流行视频会议、文本聊天和协作工具的安全评估报告,Signal在以下多项评测选项中综合表现优异: 是否提供“端到端加密”; 隐私政策; 多因素认证; 安全协议强度; 源代码是否开源; 应用开发和数据托管的合规性。 【本文是51CTO专栏作者“安全牛”的原创文章,转载请通过安全牛(微信公众号id:gooann-sectv)获取授权】 戳这里,看该作者更多好文 【责任编辑: 赵宁宁 TEL:(010)68476606】 点赞 0

优秀的个人博客,低调大师

android连接SQLite数据库-----增加改+分页

SQLite,是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源世界著名的数据库管理系统来讲,它的处理速度比他们都快。SQLite第一个Alpha版本诞生于2000年5月. 至今已经有10个年头,SQLite也迎来了一个版本 SQLite 3已经发布。 还有一件事,大家下载的时候,不要加数据库连接驱动包。本项目是不用的。 先让我们看一下图先。 业务类 package com.smart.dh; import java.util.Iterator; import java.util.List; import android.test.AndroidTestCase; import android.util.Log; import com.smart.domain.Person; import com.smart.service.PersonService; public class PersonServiceTest extends AndroidTestCase { private static final String TAG="PersonServiceTest"; //保存数据。 public void testSave() throws Exception{ PersonService personService=new PersonService(this.getContext()); //personService.save(new Person("老梁",(short)23)); for (int i = 0; i < 10; i++) { personService.save(new Person("llb"+i,(short)(i+1))); } } //查询 public void testFind() throws Exception{ PersonService personService=new PersonService(this.getContext()); Person person=personService.find(1); Log.i(TAG, person.toString()); //personService.save(new Person("老梁",(short)23)); } //更新语句 public void testUpdate() throws Exception{ PersonService personService=new PersonService(this.getContext()); Person person=personService.find(1); person.setName("smart"); personService.update(person); Log.i(TAG, person.toString()); } //获得所有的条数 public void testGetCount() throws Exception{ PersonService personService=new PersonService(this.getContext()); Log.i(TAG, String.valueOf(personService.getCount())); } //分页功能 public void testGetScrollData() throws Exception{ PersonService personService=new PersonService(this.getContext()); List<Person> persons=personService.getScrollData(0, 20);//从0条到20条的数据 for(Person person:persons){ Log.i(TAG, person.toString()); } } public void testDelete() throws Exception{ PersonService personService=new PersonService(this.getContext()); personService.delete(1,2,3);//删除1.2.3三条记录 } } javaBean类 package com.smart.domain; public class Person { @Override public String toString() { return "personid="+personid+",name="+name+",age="+age; } public int personid; public String name; public Short age; public int getPersonid() { return personid; } public void setPersonid(int personid) { this.personid = personid; } public String getName() { return name; } public void setName(String name) { this.name = name; } // 增加一个构造器 public Person(int personid, String name, Short age) { super(); this.personid = personid; this.name = name; this.age = age; } //创建构造器 public Person(String name, short age) { this.name = name; this.age = age; } public Short getAge() { return age; } public void setAge(Short age) { this.age = age; } } 数据库创建类 package com.smart.service; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; public class DataBaseOpenHelper extends SQLiteOpenHelper { // 数据名称, private static final String DBNAME = "smrtDataBase"; // 数据库版本 private static final int version = 1; // 构造方法参数, public DataBaseOpenHelper(Context context) { super(context, DBNAME, null, version); } // 数据库创建表的名子。 @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE person (personid integer primary key autoincrement,name varchar(20),age INTEGER)"); } // 更新方法 @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("EROP TABLE IF EXISTS person"); onCreate(db); } } 本文转自 llb988 51CTO博客,原文链接:http://blog.51cto.com/llb988/486373,如需转载请自行联系原作者

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Oracle

Oracle

Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小、微机环境。它是一种高效率、可靠性好的、适应高吞吐量的数据库方案。

Apache Tomcat

Apache Tomcat

Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。