Svelte框架实现表格协同文档

首先,从框架搭建上,本篇示例采用当下流行的前后端分离的开发方式,前端使用npm作为脚手架搭建Svelte框架。 后端使用Java的SpringBoot作为后端框架。
首先,介绍下在前端Svelte框架下搭建在线表格编辑器。
1、在pageage.json文件中引入相关资源

   "@grapecity/spread-excelio": "15.2.5",
    "@grapecity/spread-sheets": "15.2.5",
    "@grapecity/spread-sheets-barcode": "15.2.5",
    "@grapecity/spread-sheets-charts": "15.2.5",
    "@grapecity/spread-sheets-designer": "15.2.5",
    "@grapecity/spread-sheets-designer-resources-cn": "15.2.5",
    "@grapecity/spread-sheets-languagepackages": "15.2.5",
    "@grapecity/spread-sheets-pdf": "15.2.5",
    "@grapecity/spread-sheets-pivot-addon": "15.2.5",
    "@grapecity/spread-sheets-pivots": "^14.0.0",
    "@grapecity/spread-sheets-print": "15.2.5",
    "@grapecity/spread-sheets-resources-zh": "15.2.5",
    "@grapecity/spread-sheets-shapes": "15.2.5",
    "@grapecity/spread-sheets-tablesheet": "15.2.5",

2、然后,集成在线表格编辑器Svelte组件版。在上一篇文章中,我们介绍了如何在Svelte框架中实现在线表格编辑器。
我们按照此思路新建一个SpreadSheet.svelte文件,写入基础在线表格编辑器。

<script>
import {onMount} from 'svelte';
import '@grapecity/spread-sheets-print';
import "@grapecity/spread-sheets-charts";
import '@grapecity/spread-sheets-shapes';
import '@grapecity/spread-sheets-pivot-addon';
import '@grapecity/spread-sheets-tablesheet';
import '@grapecity/spread-sheets-designer-resources-cn';
import '@grapecity/spread-sheets-designer';
import * as GC from '@grapecity/spread-sheets';
import * as GCDesigner from '@grapecity/spread-sheets-designer';

let designer = null;
onMount(async () => {
designer = new GCDesigner.Spread.Sheets.Designer.Designer(document.getElementById("designerHost"));
let spread = designer.getWorkbook();
});

</script>
<div id="designerHost" class="designer-host"></div>

<style scoped>
@import "@grapecity/spread-sheets-designer/styles/gc.spread.sheets.designer.min.css";
@import '@grapecity/spread-sheets/styles/gc.spread.sheets.excel2013white.css';

.designer-host {
width: 100%;
height: 100vh;
}

</style>

3、协同文档可能不止一个,我们需要在页面上创建一个文档列表,来允许用户选择编辑哪个文档,所以我们需要创建一个文档列表页面OnlineSheets.svelte。在此页面中,我们要实现路由跳转,和加载文档数据。
这里我们用了svelte-spa-router进行路由跳转 与isomorphic-fetch进行前后端数据传输。

<script>
    import {onMount} from 'svelte';
    import { link } from "svelte-spa-router";
    import {Utility} from "../utility.js";

    let docList = [];
    onMount(async () => {
        Utility.getDocList().then(result => {
            docList  = result.map((item,index)=>{
                return {
                    path:'/Spreadsheet/' + item.substring(0, item.lastIndexOf('.')),
                    index,
                    fileName:item
                }
            })
        });
    });
</script>
<main class="main">
    <table className='table' aria-labelledby="tabelLabel">
        <thead>
        <tr>
            <th>Document</th>
            <th></th>
        </tr>
        </thead>
        <tbody>
        {#each docList as docItem}
            <tr>
                <td>{docItem.index}</td>
                <td>{docItem.fileName}</td>
                <td className='row'>
                    <a use:link={docItem.path}> Open</a>
                </td>
            </tr>
        {/each}
        </tbody>
    </table>
</main>

以上代码实现了文档列表查看与文档跳转,使用 Open将跳转至前面设计好的在线表格编辑器中。
至此,前端的相关内容就准备好了,接下来搭建下后端工作。
后端的准备工作,首先安装gradle作为包管理器。当然,这里也可以用其他工具来代替,例如maven,或者源生引入jar包的方式将需要用到的jar包引入进来。之后创建springboot工程配合搭建gradle引用GCExcel以及后面协同需要用到的websocket。

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.4.3</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.4.3</version>
</dependency>

<dependency>
<groupId>com.grapecity.documents</groupId>
<artifactId>gcexcel</artifactId>
<version>4.0.3</version>
</dependency>

<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>

<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>10.0.2</version>
</dependency>

<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.5.0</version>
</dependency>
</dependencies>

这样子,我们做了框架的基本环境搭建,接下来我们介绍下如何搭建webSocket。
在SpreadSheet.svelte文件中写入如下代码建立webSocket链接:

    function connectDocument(docName) {
        if (webSocket != null) {
            return;
        }
        var ws = new WebSocket(Utility.webSocketUrl);  //'ws://localhost:8090/spreadjs'
        ws.onopen = function () {
            var data = {
                cmd: "connect",
                docID: docName
            }
            ws.send(JSON.stringify(data));
        }
        ws.onmessage = onmessage;
        webSocket = ws;
    }

接下来我们访问下文档列表页,从文档列表页跳转进入文档,进行编辑。

接下来我们需要监听前端发出的操作。这里因为在线表格编辑器本身将所有用户可能做的操作全部做了封装,所以省下了很多的功夫。

   onMount(async () => {
        //初始化Designer
        designer = new GCDesigner.Spread.Sheets.Designer.Designer(document.getElementById("designerHost"));
        let spread = designer.getWorkbook();
        //fromJSON
        openDocument(docName);
        //建立webSocket
        connectDocument(docName);
        var cm = spread.commandManager();
        cm.addListener('myListener', onCommandExecute)
    });

根据cmd去判断并且对命令再做一些简单封装,之后将封装过的命令发到服务端,之后通过websocket发同步指令:

  function onCommandExecute(args) {
        console.log(args.command);
        var command = args.command;
        var ServerCommand = null;

        switch (command.cmd) {
            case Utility.ServerCommands.EditCell:
                ServerCommand = {
                    sheetName: command.sheetName,
                    row: command.row,
                    column: command.col,
                    newValue: command.newValue
                }
                break;
            case Utility.ServerCommands.ResizeRow:
                ServerCommand = {
                    sheetName: command.sheetName,
                    rows: command.rows,
                    size: command.size
                };
                break;
            case Utility.ServerCommands.ResizeColumn:
                ServerCommand = {
                    sheetName: command.sheetName,
                    columns: command.columns,
                    size: command.size
                };
                break;
            case 'Designer.' + Utility.ServerCommands.SetFontFamily:
            case 'Designer.' + Utility.ServerCommands.SetFontSize:
            case 'Designer.' + Utility.ServerCommands.SetBackColor:
            case 'Designer.' + Utility.ServerCommands.SetForeColor:
            case 'Designer.' + Utility.ServerCommands.SetFontWeight:
            case 'Designer.' + Utility.ServerCommands.SetFontStyle:
            case 'Designer.' + Utility.ServerCommands.SetUnderline:
            case 'Designer.' + Utility.ServerCommands.SetDoubleUnderline:
                if (command.value && command.value.indexOf('undefined') === -1) {
                    ServerCommand = {
                        sheetName: command.sheetName,
                        selections: command.selections,
                        value: command.value
                    }
                }
                break;
            case Utility.ServerCommands.MoveFloatingObjects:
                ServerCommand = {
                    sheetName: command.sheetName,
                    floatingObjects: command.floatingObjects,
                    offsetX: command.offsetX,
                    offsetY: command.offsetY
                };
                break;
            case Utility.ServerCommands.ResizeFloatingObjects:
                ServerCommand = {
                    sheetName: command.sheetName,
                    floatingObjects: command.floatingObjects,
                    offsetX: command.offsetX,
                    offsetY: command.offsetY,
                    offsetWidth: command.offsetWidth,
                    offsetHeight: command.offsetHeight
                };
                break;
            case Utility.ServerCommands.InsertColumns:
            case Utility.ServerCommands.InsertRows:
                ServerCommand = {
                    sheetName: command.sheetName,
                    selections: command.selections
                };
                break;
            default:
        }

        if (ServerCommand != null) {

            var cmd = command.cmd;
            var dotIndex = cmd.lastIndexOf('.');
            if (dotIndex !== -1) {
                cmd = cmd.substring(dotIndex + 1);
            }
            ServerCommand.cmd = cmd;
            ServerCommand.docID = params.fileName;

            Utility.ExecuteCommandAtServer(ServerCommand);

            command.docID = ServerCommand.docID;
            webSocket.send(JSON.stringify(command))
        }
    }

当协同端通过websocket接收到请求的时候,使用onmessage方法做同步命令。这里在协同端执行command之前需要先撤销之前的监听,避免再发送websocket导致死循环。在执行之后,再次添加监听。

  function onmessage(message) {
        var command = JSON.parse(message.data);
        command._styles = null;
        let spread = designer.getWorkbook()
        var cm = spread.commandManager();
        cm.removeListener('myListener');

        spread.commandManager().execute(command);

        cm.addListener('myListener', onCommandExecute);
    }

至此,协同基础内容搭建结束,我们来看看编辑单元格内容后,发生了什么吧。
如下图所示,修改E4单元格内容,同时打开控制台网络tab。
将E4单元格数值2500改为2000,此时触发了EditCell事件,同时发出了交互指令:

此时新建一个窗口,复制链接,查看文档内容已经变为了2000。
如下动图所示:

拓展阅读

React + Springboot + Quartz,从0实现Excel报表自动化

电子表格也能做购物车?简单三步就能实现

使用纯前端类Excel表格控件SpreadJS构建企业现金流量表



本文是由葡萄城技术开发团队发布,转载请注明出处:葡萄城官网


本文转载于网络 如有侵权请联系删除

相关文章

  • 设计模式的六大原则

    面向对象设计的6大原则:1.单一职责原则原则思想:一个方法只负责一件事情。 描述:单一职责原则很简单,一个方法一个类只负责一个职责,各个职责的程序改动,不影响其它程序。这是常识,几乎所有程序员都会遵循这个原则。 优点:降低类和类的耦合,提高可读性,增加可维护性和可拓展性,降低可变性的风险。2.里氏替换原则原则思想:使用的基类可以在任何地方使用继承的子类,完美的替换基类。 描述:子类可以扩展父类的功能,但不能改变父类原有的功能。子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法,子类中可以增加自己特有的方法。 优点:增加程序的健壮性,即使增加了子类,原有的子类还可以继续运行,互不影响。3.依赖倒置原则原则思想:高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象,抽象不应该依赖于具体实现,具体实现应该依赖于抽象。 描述:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。 优点:可以减少需求变化带来的工作量,做并行开发更加

  • 汉江大桥上的监控 AI,挽救自杀者的生命

    By超神经内容一览:首尔科学技术大学的研究人员与汉江大桥的救援部门合作,开发了一个通过摄像头捕捉和预警有自杀倾向的行人,从而提前干预与救援。关键词:机器视觉人文AI位于韩国的国立首尔科学技术大学,在2020年4月以来,与首尔的紧急服务部门合作,通过根据布控在汉江大桥上的监控,来分析和预测行人是否有自杀行为。救援队展示桥上的实时监控画面一旦AI预测危险情况或者可疑行为,将立即向救援队发出警报,救援队可以在三分钟内赶到现场,阻止悲剧的发生。 除了这项自杀行为预测以外,在KimJun-chul研究院领导下的研究小组,还通过摄像头、传感器和救援服务的调度记录,来让AI学习并理解紧急情况下的救援任务部署行为。AI将识别有自杀倾向的可疑行为,并及时标记和预警AI目前可以根据摄像头标记有自杀倾向的行人,并通过他们的运动行为来区分他们是否真的有自杀倾向,从而减少误报。汉江见证崛起,也送别生命贯穿首尔的汉江,在朝鲜战争后,创造了韩国经济崛起的「汉江奇迹」。 这条汉江记录了韩国战后从一片废墟,在资本与资源都极度匮乏的情况下,实现经济迅猛发展,跻身亚洲前列的惊人成果。汉江奇迹见证了韩国战后的经济快速腾飞 也

  • Digitalocean 旧金山机房 AMD VPS测评:1Gbps宽带 电信联通直连

    Digitalocean是一家成立于2012年的总部设置在纽约的云主机商家,采用KVM虚拟,配置高性能的SSD做储存,加上服务器配备的是1Gbps端口,以1G内存为起点,月付最低低至5美元!支持PayPal、Visa卡等。目前有纽约、旧金山、阿姆斯特丹、新加坡、伦敦、法兰克福、多伦多、班加罗尔等12个数据中心,支持按小时付款。Digitalocean要比热门的Vultr热度低不少,不支持支付宝、机房选择上也要少很多,IP被墙的概率也会低不少。现在新款还有AMD处理器和NVMESSD存储的服务器。官网:https://www.digitalocean.com/通过此链接注册充值25美元送100美元:https://m.do.co/c/9828226c9d48Digitalocean新加坡机房VPS测评:https://www.awsl9527.cn/archives/441.html温馨提示:注册账户时请关闭代理工具,使用正常的网络注册,否知会出现账户异常以及账户封停(需要联系客服提供有效身份证明)。为什么会出现这种情况呢?由于Digitalocean优惠力度大,新用户注册就给100美金

  • GitLab发布最新的13.8版本

    GitLab发布最新的13.8版本,更新重点在CI/CD上,不只新增了工作流程编辑器,让开发者能够以视觉化方法,来定义CI/CD的功能,另外,GitLab现在也提供4大指标DORA4之一的部署频率图表,让用户可以评估自身DevOps的成熟度。 过去GitLab用户都要以gitlab-ci.yml配置文件,来定义CI/CD的功能,官方提到,以代码配置工作流程,代表用户可以将用于应用程序代码的工具,拿来对工作流程进行版本控制,并和团队成员协作,而且GitLab所提供的进阶语法,也让用户可以高度定制化复杂的CI/CD功能。但是这些功能和灵活性,有着相当高复杂性,因此官方为了让用户能够更简单地配置CI/CD工作流程,因此提供内部视觉化工作流程编辑工具。从GitLab13.8开始,用户将可以使用CI/CD专用编辑器,这是该编辑器的第一个版本,提供灵活的选项,能够支持各种复杂的工作流程使用案例,用户不会再被冗长与复杂的语法困扰。该编辑器能够同时良好地支持新手和高手使用者,并且作为单一解决方案,在同一个地方提供所有现有的CI编辑功能。除了编辑功能之外,编辑器还会持续检查工作流程的配置,在使用者一边进

  • vector 和 list区别

    吃一堑,长一智,做学问就要研究的清楚,透彻,不要模模糊糊,稀里糊涂的用(某题为什么要用list而不用vector???这都不知道,题目怎么做的?CCF2018-12-3)首先,说一下它们两个的试用情况,如下:vector适用:对象数量变化少,简单对象,随机访问元素频繁list适用:对象数量变化大,对象复杂,插入和删除频繁stl提供了三个最基本的容器:vector,list,deque。 vector和built-in数组类似,它拥有一段连续的内存空间,并且起始地址不变,因此它能非常好的支持随即存取,即[]操作符,但由于它的内存空间是连续的,所以在中间进行插入和删除会造成内存块的拷贝,另外,当该数组后的内存空间不够时,需要重新申请一块足够大的内存并进行内存的拷贝。这些都大大影响了vector的效率。 list就是数据结构中的双向链表(根据sgistl源代码),因此它的内存空间可以是不连续的,通过指针来进行数据的访问,这个特点使得它的随即存取变的非常没有效率,因此它没有提供[]操作符的重载。但由于链表的特点,它可以以很好的效率支持任意地方的删除和插入。 deque是一个double-

  • 面试题-树状数组结构转化

    题目如下:这道题是我朋友发给我的,之前一开始看的时候,觉得很简单,但仔细往下看的时候,眉头一皱发现事情并不简单。传进去的数组:letoldArr=[ { '1_class':'工具', '2_class':'备忘录', '1_id':1, '2_id':2 }, { '1_class':'教育', '2_class':'学历教育', '3_class':'中等', '1_id':3, '2_id':4, '3_id':6 }, { '1_class':'教育', '2_class':'学历教育', '3_class':'高等', '1_id':3, &#

  • LeetCode 435. 无重叠区间(贪心/动态规划)

    1.题目给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。注意: 可以认为区间的终点总是大于它的起点。 区间[1,2]和[2,3]的边界相互“接触”,但没有相互重叠。示例1: 输入:[[1,2],[2,3],[3,4],[1,3]] 输出:1 解释:移除[1,3]后,剩下的区间没有重叠。 示例2: 输入:[[1,2],[1,2],[1,2]] 输出:2 解释:你需要移除两个[1,2]来使剩下的区间没有重叠。 示例3: 输入:[[1,2],[2,3]] 输出:0 解释:你不需要移除任何区间,因为它们已经是无重叠的了。复制来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/non-overlapping-intervals 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 2.解题2.1贪心按照结束位置升序排序找到满足prev[end]<=next[start]的下一个,更新prev为next寻找下一个next,这些找到的是无重叠的最长的区间长度classSolution{ public:

  • LeetCode 1238. 循环码排列(格雷编码+旋转数组)

    1.题目给你两个整数n和start。你的任务是返回任意(0,1,2,,...,2^n-1)的排列p,并且满足:p[0]=start p[i]和p[i+1]的二进制表示形式只有一位不同 p[0]和p[2^n-1]的二进制表示形式也只有一位不同复制示例1: 输入:n=2,start=3 输出:[3,2,0,1] 解释:这个排列的二进制表示是(11,10,00,01) 所有的相邻元素都有一位是不同的,另一个有效的排列是[3,1,0,2] 示例2: 输出:n=3,start=2 输出:[2,6,7,5,4,0,1,3] 解释:这个排列的二进制表示是(010,110,111,101,100,000,001,011) 提示: 1<=n<=16 0<=start<2^n复制来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/circular-permutation-in-binary-representation 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 2.解题生成格雷编码 找到start所

  • 用 Python 爬取 4332 条数据,揭秘甜咸肉粽的江湖!

    作者:朱小五 来源:凹凸数据端午节快要到了,甜咸粽子之争也快要拉开帷幕。本文准备用Python爬取淘宝上的粽子数据并进行分析,看看有什么发现。注:本文仅用于学习交流,禁止用于商业目的。爬虫爬取淘宝数据,本次采用的方法是:Selenium控制Chrome浏览器自动化操作[1]。其实我们还可以利用Ajax接口来构造链接,但是非常繁琐(包含加密秘钥等),直接使用Selenium来模拟浏览器会省去很多事情。最常见的问题是chromedriver驱动与谷歌浏览器的版本不匹配,很容易就可以解决。接下来,我们就开始利用selenium抓取淘宝商品,并使用Xpath解析得到商品名、价格、付款人数、店铺名、发货地址信息,最后将数据保存在本地。爬虫过程如下图:selenium自动化爬取(需要淘宝扫描登录一次)fromseleniumimportwebdriver #搜索商品,获取商品页码 defsearch_product(key_word): #定位输入框 browser.find_element_by_id("q").send_keys(key_word) #定义点击按钮,并点击

  • 分享 | C#编写的电影售票系统(附源码+数据库)

    最近疫情真的很可怕,大家要注意保护好自己,响应国家的号召。尽量不出门,可以利用这个时间好好充实自己。 也希望武汉和中国能尽快好起来,大家都健健康康,相安无事。01介绍这个是小编上学期的C#课程结课作业,是小组完成的。这次一并分享出来啦。嗯……为什么界面这么少女心呢,并不是小编有一颗少女心,而是因为UI部分是同组的女生负责设计的。 我们做的是一个有会员制的电影院购票系统。具有会员注册功能,可区分会员和散客两种身份,实现会员及折扣管理。购票具有挑选电影场次,选择座位和查看电影信息等功能:》查看电影详情、获取排片信息。》选择场次座位,完成支付,获取取票信息。》注册成为影院会员,享受优惠折扣。代码获取关注我们的公众号!在后台回复【CSTK】不包括【】即可获取。02设计思路 在功能设计上,一个电影院购票系统,首先需要具备最基础的功能:影片选择、场次选择和座位选择。在用户提交选择后,需要支付模块提示用户付款并完成出票。为了吸引用户,我们增加了会员的注册和登录模块,为会员用户提供折扣。注册与购票的支付我们的处理是预留一个接口,当做简单模拟,实际使用可以调用支付宝或微信的支付接口。在界面设计上,我们为

  • HashTable和HashMap的区别

    HashTable底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化 初始size为11,扩容:newsize=oldsize*2+1 计算index的方法:index=(hash&0x7FFFFFFF)%tab.lengthHashMap底层数组+链表实现,可以存储null键和null值,线程不安全 初始size为16,扩容:newsize=oldsize*2,size一定为2的n次幂 扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入 插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容) 当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀 计算index方法:index=hash&(tab.length–1)HashMap的初始值还要考虑加载因子:哈希冲突:若干Key的哈希值按数组大小取模后,如果落在同一个数组下标上,

  • DeepMind团队回顾2017年:想象、推理取得突破

    上周,百度搜索公布了一份年度搜索榜单,对2017年中文搜索热词进行了盘点。人工智能自然是年度科技事件中的热中之热,共计3项AI相关事件进入年度前十,其中“AlphaGo对战柯洁”一项排名科技榜第一。日前开发AlphaGo程序的谷歌旗下DeepMind团队在官方网站上撰文,回顾了2017年团队在新的AI技术研发方面取得的发展,以及在AI技术的社会影响方面的作为。以下为文章全文:今年7月,世界排名第一的围棋选手柯洁在20次连胜之后发表了讲话。此时距离他与AlphaGo在中国乌镇围棋峰会上的对弈刚刚过去两个月。他说:“在和AlphaGo的比赛之后,我从根本上重新审视了围棋游戏,现在看来这些思考对我的帮助很大。我希望所有的围棋选手都能思考AlphaGo对游戏的理解和思维方式,所有这些都是非常有意义的。虽然我输了,但我发现围棋的可能性是巨大的,而且它还在不停地进步。”围棋峰会是一个为期五天的围棋盛会。它包括多种多样的游戏形式——双人组队战,团队战,以及像柯洁那样的1:1对战。柯洁是围棋领域的顶级人物,他的话让DeepMind的研究人员们感到很荣幸。这同时也是对我们的激励,因为这预示着在未来,AI

  • 疯涨的比特币让黑客眼红,价值700亿美元的比特币被盗

    当比特币的价值飙升至1.5万美元时,价值近700亿美元的比特币从一个名为NiceHash挖矿平台服务中被盗。加密货币矿业服务公司NiceHash在出现安全漏洞之后,被迫关闭了24小时。NiceHash在Facebook上的一份声明中说:“很明显,这是一个非常值得关注的问题,我们在未来几天正努力纠正这一问题,我们将致力于尽早恢复NiceHash服务,并采取最高的安全措施。”在调查过程中,NiceHash建议用户更改密码。大约4700个比特币被盗,根据NiceHash的营销主管介绍,这是一次专业的恶意攻击。周三,比特币创下了新的纪录,比特币被盗时的价值突破了1.5万美元大关。随着比特币的价值继续飙升,金融专家正在努力解释快速升值的意义,而另一些人则表示,比特币的价值可能很快就会大幅下跌。“这是有史以来最大的卖空机会之一,”风险投资公司的合伙人卢·肯纳本周早些时候告诉彭博社。“有很多狂热分子,包括我在内的很多人认为这是人类历史上最伟大的事情;也有很多人认为这是一个泡沫和庞氏骗局。事实证明,这两种看法都是不对的。“摩根大通首席执行官杰米•戴蒙称比特币是一个骗局,最终将会破灭。比特币2017年初

  • 腾讯云主机安全查询资产管理内核模块列表api接口

    1.接口描述接口请求域名:cwp.tencentcloudapi.com。 查询资产管理内核模块列表 默认接口请求频率限制:20次/秒。 APIExplorer提供了在线调用、签名验证、SDK代码生成和快速检索接口等能力。您可查看每次调用的请求内容和返回结果以及自动生成SDK调用示例。 2.输入参数以下请求参数列表仅列出了接口请求参数和部分公共参数,完整公共参数列表见公共请求参数。 参数名称 必选 类型 描述 Action 是 String 公共参数,本接口取值:DescribeAssetCoreModuleList。 Version 是 String 公共参数,本接口取值:2018-02-28。 Region 是 String 公共参数,详见产品支持的地域列表。 Uuid 否 String 服务器Uuid Quuid 否 String 服务器Quuid Filters.N 否 ArrayofAssetFilters 过滤条件。IpOrAlias-String-是否必填:否-主机ip或别名筛选Name-string-是否必填:否-包名

  • 使用Python编写多线程爬虫抓取百度贴吧邮箱与手机号

    醒来的时候登QQ发现有人找我要一份贴吧爬虫的源代码,想起之前练手的时候写过一个抓取百度贴吧发帖记录中的邮箱与手机号的爬虫,于是开源分享给大家学习与参考。 需求分析: 本爬虫主要是对百度贴吧中各种帖子的内容进行抓取,并且分析帖子内容将其中的手机号和邮箱地址抓取出来。主要流程在代码注释中有详细解释。 测试环境: 代码在Windows764bit,python2.764bit(安装mysqldb扩展)以及centos6.5,python2.7(带mysqldb扩展)环境下测试通过 github:https://github.com/cw1997/get-email-by-tieba/blob/master/get-email-by-tieba-multithreading.py 环境准备: 工欲善其事必先利其器,大家可以从截图看出我的环境是Windows7+PyCharm。我的Python环境是Python2.764bit。这是比较适合新手使用的开发环境。然后我再建议大家安装一个easy_install,听名字就知道这是一个安装器,它是用来安装一些扩展包的,比如说在python中如果

  • 小城里的“明星”产业,有微信云托管保驾护航

    小城故事多,充满喜和乐。 地处河南省最南端的信阳市是一座拥有600多万常住人口的中小型城市,四季分明,气候适宜,有“江南北国、北国江南”之美誉。信阳当地拥有众多娱乐设施,但其中有一个比较特别,那就是属于当地人的“限定快乐”——信阳海岛风暴水上乐园(下称“水上乐园”)。 水上乐园于2016年6月16日正式开园,是信阳市最大的水上乐园,每年仅在夏季开放两个月时间,乐园设有大喇叭、大型互动水寨、海浪池、戏水小品等设施,高峰期可达到单日千人以上的规模,是当地不折不扣的“明星产业”。为了更好地服务游客,水上乐园也于2018年上线了专属小程序,由信阳长远科技担任开发商,让游客能更方便地完成购票、验票、退票甚至分销等操作,同时打通线上线下消费场景,提供园区整体的运营效率。 虽然每年只有两个月左右的营业期,但过于火爆的业务也给水上乐园运营方带来了挑战: 首先,信阳长远科技是小规模创业团队,研发人力不足,掌握的技术栈也非常有限;其次,业务营业时间较为集中,从全年来看,业务数据基本呈现出较为明显的正态分布,兼具了业务洪峰与业务低谷,因此对业务在大流量下的稳定性与闲时流量下的灵活性都带来了考验;最后,虽

  • 【学习笔记】Palindrome Series

    SoyTony近日每天给我讲字符串,我听的受不了了,所以我要来写字符串的博。 前情提要:全是感情,没有证明。 bikuhiku说我不应该使用“前情提要”这个词,我想了想感觉很对,那换一个词。 前情提要:全是感情,没有证明。 BorderSeries Border有一个性质:对于一个长为\(n\)的字符串,其所有长度大于等于\(\frac{n}{2}\)的Border构成等差数列。 感性理解下,如果大于\(\frac{n}{2}\),那么前后缀的交集就又是一个Border。 那么由此可以推出一个性质:一个字符串的Border可以划分为\(\logn\)段等差序列。 这就是BorderSeries。 不知道有啥用,如果有人有例题麻烦给我一个。 PalindromeSeries 众所周知,回文串有着与Border类似的性质,于是上面的性质可以直接搬过来用。 也就是,对于一个回文串,它的回文串后缀的长度也可以划分为\(\logn\)段等差序列。 然后它可以用来解决一些回文串DP的问题。 这类问题一般转移式子长这样: \[f_i=\mathop{\operatorname{OPT}}\limit

  • 基于EF6的快速开发Web框架——Swift.Net

    Swift.Net ThisIsALight-WeightAndFast-Develop.NetFramework. Usage STEP1CreateYourEntities publicclassDemoEntity:BaseEntity { publicintId{get;set;} publicstringName{get;set;} publicstringPhone{get;set;} publicstringNric{get;set;} publicintAge{get;set;} publicfloatHeight{get;set;} publicint?Sex{get;set;} } 复制 STEP2CreateTheMapper PutthisMappersintotheMapperDirectorywhichInEntityProject. publicclassDemoEnityMapper:BaseMap<DemoEntity> { publicoverridevoidInit() { ToTable("DemoEntity"); HasKey(m

  • C++第10课 STL容器 (九)

    1.map(映射) /* map:映射,一种对应关系 自带排序(按照键去排序) 键唯一,相同键采用最后一次插入的数据,覆盖的方式去处理 存储的数据是:数对类型(pair) */ voidtestMap() { map<int,string>str; //1.pair对象插入 str.insert(pair<int,string>(1,"小可爱")); //2.数组法插入 str[-1]="小甜心"; //3.间接通过make_pair构建一个pair类型 str.insert(make_pair<int,string>(2,"小宝贝")); str[-1]="小美女"; for(autov:str){ cout<<v.first<<"\t"<<v.second<<"\t"; } cout<<endl; map<int,string>::iteratoriter=str.begin(); while(iter!=str.end()){ cout<<(*iter).f

  • 四元数的实矩阵

  • 《人月神话》读书笔记 PB16110698 第七周(~4.19)

      每逢读书笔记上交作业时刻,班级blog页面上总能看到《人月神话》相关的读书笔记,本次软工课邓老师推荐的第一篇读书笔记也是写的《人月神话》,算是对它“耳濡目染”了。本周,我终于抽空读了这本书,感觉确实名不虚传。以下,我将从几方面谈谈我的感想。 一、焦油坑与银弹   书中将大型项目形象地比作焦油坑,开发者往往在巨大的项目里遇到纷繁复杂的问题,并在其中越陷越深,难以掌握全貌和本质。在我看来,软件的开发确实存在其固有问题,在一个开发团队开始挖坑时,由于思路的些许偏差、交流和认知水平的些许欠缺或分歧,都会为将来项目的混杂、纠结埋下伏笔。在本次结对作业和单人作业中,我仅仅写了数百行代码,就已经面临这样的“焦油坑”问题:陷于细节,难以掌握整体开发思路。在写某个具体功能的函数时,我时常需要上下拉动滑条,阅读之前写的更高层次或更低层次的函数,以尽量保证其功能符合预期。有时一疏忽,就会把已经在其他函数中实现的某功能在这一函数中添加,导致多次处理、结果血崩。而大型项目的开发中,代码量是我的简单工程的数千数万倍,通过浏览相关函数来保证不出bug显然是非常困难的,加上不同开发人员之间理解、思路的差异,隐含的

相关推荐

推荐阅读