官方社群在线客服官方频道防骗查询货币工具

系统设计:社交网络服务

2025-01-16 05:54:48
news.like.tgnews.like.tgnews.like.tgnews.like.tg

LIKE.TG 成立于2020年,总部位于马来西亚,是首家汇集全球互联网产品,提供一站式软件产品解决方案的综合性品牌。唯一官方网站:www.like.tg

需求

让我们设计一个类似Twitter的社交网络服务。该服务的用户将能够发布推文、关注他人以及喜爱的推文。

难度:中等

1.什么是Twitter?

Twitter是一种在线社交网络服务,用户可以发布和阅读140个字符的短消息,称为“推文”。注册用户可以发布和阅读推文,但未注册的用户只能阅读推文。用户通过其网站界面、短信或移动应用程序访问Twitter。

2.系统的要求和目标

我们将设计一个更简单的Twitter版本,并满足以下要求:

功能要求

1.用户应该能够发布新的推文。

2.用户应该能够跟随其他用户。

3.用户应该能够将推文标记为收藏夹。

4.该服务应该能够创建和显示用户的时间线,包括来自用户跟随的所有人。

5.推文可以包含照片和视频。

非功能性需求

1.我们的服务需要高度可用。

2.系统可接受的时间线生成延迟为200ms。

3.一致性可能会受到影响(为了可用性);如果用户没有看到某个用户的tweet,但是,它本身应该是可用的。

扩展要求

1.搜索推文。

2.回复推特。

3.趋势主题–当前热门主题/搜索。

4.标记其他用户。

5.推特通知。

6.跟随谁?建议?

7.什么时刻,时间点。

3.容量估计和限制

假设我们有10亿用户,每天有2亿活跃用户(DAU)。还假设我们每天有1亿条新推,平均每个用户跟踪200人。

  • 每天有多少人喜欢?

如果每个用户平均每天收藏5条推文,我们将拥有:

2亿(=200M) DAU * 5条收藏夹=>1GB条收藏夹

  • 我们的系统将生成多少条推文?

让我们假设一个用户平均每天访问他们的时间轴两次,并访问其他五个人的页面。在每个页面上,如果用户看到20条推文,那么我们的系统将生成28GB/天的推文总浏览量:

2亿(=200M) DAU *((2+5)*20条推文)=>28B/天

  • 存储量估计?

假设每条tweet有140个字符,我们需要两个字节来存储一个字符而无需压缩。假设我们需要30个字节来存储每条tweet的元数据(比如ID、时间戳、用户ID等等)。我们需要的总存储空间:

1亿(=100M)DAU *(280+30)字节=>30GB/天

  • 我们五年的存储需求是什么?我们需要多少存储空间来存储用户的数据、信息、收藏夹?

1亿(=100M)DAU *(280+30)字节 * (5 * 365天) => 54.75TB/天

并非所有推文都有媒体,让我们假设平均每五条推文有一张照片,每十条推文有一段视频。我们还假设平均一张照片是200KB,一段视频是2MB。这将使我们每天拥有24TB的新媒体。

(100M/5照片*200KB)+(100M/10视频*2MB)~=24TB/天

  • 带宽估计由于总入口数为24TB/天,这将转化为290MB/秒。

记住,我们每天有28B条推特。我们必须显示每条推文的照片(如果有照片的话),但我们假设用户在他们的时间线中每看三次视频。因此,总出口将为:

(28B * 280 bytes) / 86400s of text => 93MB/s + (28B/5 * 200KB ) / 86400s of photos => 13GB/S + (28B/10/3 * 2MB ) / 86400s of Videos => 22GB/s

Total ~= 35GB/s

4.系统API设计

一旦我们确定了需求,定义系统API总是一个好主意。这应该明确说明系统的期望值。

我们可以使用SOAP或RESTAPI来公开服务的功能。以下可能是发布新tweet的API的定义:

代码语言:javascript
复制
tweet(api_dev_key, tweet_data, tweet_location, user_location, media_ids,
maximum_results_to_return)

参数设计

代码语言:javascript
复制
api_dev_key(string):注册帐户的api开发者密钥。除其他外,这将用于根据分配的配额限制用户。
tweet_dat(string):tweet的文本,通常最多140个字符。
tweet_location(string):此tweet所指的可选位置(经度、纬度)。用户位置(字符串):添加tweet的用户的可选位置(经度、纬度)。
media_ids(number []):与推特关联的媒体ID的可选列表。(所有媒体照片、视频等需要单独上传)。

Returns: (string)

成功的帖子将返回访问该推文的URL。否则,将返回相应的HTTP错误。

5.高级系统设计

我们需要一个能够高效存储所有新推文的系统,100M/86400s=>1150条推文/秒,读取28B/86400s=>325K条推文/秒。从需求中可以清楚地看出,这将是一个重读系统。

在较高的层次上,我们需要多个应用程序服务器来为所有这些请求提供服务,前面有负载平衡器用于流量分布。在后端,我们需要一个高效的数据库来存储所有新的推文,并支持大量的读取。我们还需要一些文件存储来存储照片和视频。

尽管我们预计每天的写负载为1亿,读负载为280亿推特。这意味着我们的系统平均每秒将收到约1160条新推文和325K读取请求。这种流量在一天中的分布将是不均匀的,但在高峰时间,我们预计每秒至少有几千个写请求和大约一百万个读请求。在设计系统架构时,我们应该牢记这一点。

6.数据库模式

我们需要存储关于用户、他们的推文、他们最喜欢的推文以及他们关注的人的数据。

要在SQL和NoSQL数据库之间选择以存储上述模式,请参阅设计Instagram下的“数据库模式”。

7.数据分片

由于我们每天都有大量的新tweet,而且我们的读取负载也非常高,因此我们需要将数据分发到多台机器上,以便我们能够高效地读取/写入数据。我们有很多选择来分享我们的数据;让我们一个接一个地看一下:

基于UserID的分片:

我们可以尝试将用户的所有数据存储在一台服务器上。在存储时,我们可以将用户ID传递给哈希函数,该函数将用户映射到数据库服务器,在那里我们将存储用户的所有推文、收藏夹、关注等。在查询用户的推文/关注/收藏夹时,我们可以问哈希函数在哪里可以找到用户的数据,然后从那里读取数据。这种方法有两个问题:

1.如果用户变热怎么办?服务器上可能会有很多查询容纳用户。这种高负载将影响我们服务的性能。

2.随着时间的推移,与其他用户相比,一些用户最终可能会存储大量tweet或拥有大量的关注。保持不断增长的用户数据的均匀分布是相当困难的。

要从这些情况中恢复,我们必须重新分区/重新分发数据或使用一致的哈希。

基于TweetID的切分:

我们的散列函数将把每个TweetID映射到一个随机服务器,我们将在那里存储该Tweet。要搜索tweets,我们必须查询所有服务器,每个服务器将返回一组tweets。集中式服务器将聚合这些结果以将其返回给用户。让我们看看时间线生成示例;以下是我们的系统生成用户时间线必须执行的步骤数:

1.我们的应用程序(app)服务器将找到用户跟踪的所有人。

2.App server将向所有数据库服务器发送查询,以查找这些人的推文。

3.每个数据库服务器将找到每个用户的tweet,按最近情况对它们进行排序,并返回顶部

推特。

4.App server将合并所有结果并再次对其排序,以将最重要的结果返回给用户。

这种方法解决了热用户的问题,但与按用户ID进行切分不同,我们必须查询所有数据库分区以查找用户的tweet,这可能会导致更高的延迟。

我们可以通过在数据库服务器前面引入缓存来存储热tweet,从而进一步提高性能。

基于Tweet创建时间的切分:

基于创建时间存储Tweet将使我们能够快速获取所有最热门的Tweet,并且我们只需要查询一小部分服务器。这里的问题是流量负载不会被分配,例如,在写的时候,所有新的tweet都将被发送到一个服务器,而其余的服务器将处于空闲状态。类似地,在读取时,与保存旧数据的服务器相比,保存最新数据的服务器将具有非常高的负载。

如果我们可以在tweed创建时间内结合切分和Tweet创建时间呢?

如果我们不单独存储tweet创建时间并使用TweetID来反映这一点,我们可以从这两种方法中获益。通过这种方式,可以很快找到最新的推文。为此,我们必须使每个TweetID在我们的系统中都是唯一的,并且每个TweetID也应该包含一个时间戳。

我们可以用大纪元来做这个。假设我们的TweetID将有两部分:第一部分将代表历元秒,第二部分将是一个自动递增序列。因此,要创建一个新的TweetID,我们可以使用当前的纪元时间并在其上附加一个自动递增的数字。我们可以从这个TweetID中找出碎片号并将其存储在那里。

我们的TweetID有多大?假设我们的大纪元时间从今天开始,我们需要多少位来存储未来50年的秒数?

86400 sec/day * 365 (days a year) * 50 (years) => 1.6B

我们需要31位来存储这个数字。因为我们平均预期每秒有1150条新推,我们可以分配17位来存储自动递增序列;这将使我们的TweetID长48位。因此,每秒钟我们都可以存储(2^17=>130K)条新推文。我们可以每秒重置自动递增序列。为了容错和更好的性能,我们可以有两个数据库服务器为我们生成自动递增密钥,一个生成偶数密钥,另一个生成奇数密钥。

如果我们假设当前的历元秒数为“1483228800”,我们的TweetID将如下所示:

1483228800 000001

1483228800 000002

1483228800 000003

1483228800 000004 ...

如果我们将TweetID设置为64位(8字节)长,我们可以轻松地将tweet存储100年,也可以将其存储为毫秒。

在上述方法中,我们仍然需要查询所有服务器以生成时间线,但我们的读取(和写入)速度将大大加快。

1.由于我们没有任何辅助索引(在创建时),这将减少写入延迟。

2.在阅读时,我们不需要过滤创建时间,因为我们的主键有纪元时间包括在内。

8.缓存

我们可以为数据库服务器引入缓存来缓存热门推文和用户。我们可以使用像Memcache这样的现成解决方案来存储整个tweet对象。在访问数据库之前,应用服务器可以快速检查缓存是否有所需的tweet。根据客户端的使用模式,我们可以确定需要多少缓存服务器。

  • 哪种缓存替换策略最适合我们的需要?

当缓存已满,并且我们希望用更新/更热的tweet替换tweet时,我们将如何选择?对于我们的系统来说,最近最少使用(LRU)是一个合理的策略。根据这项政策,我们首先放弃最近浏览次数最少的tweet。

  • 我们如何拥有更智能的缓存?

如果我们遵循80-20规则,即20%的推文产生80%的阅读流量,这意味着某些推文非常受欢迎,大多数人都会阅读它们。这意味着我们可以尝试缓存来自每个碎片的每日读取量的20%。

  • 如果我们缓存最新的数据呢?

我们的服务可以从这种方法中受益。比方说,如果80%的用户只看到过去三天的推文;我们可以尝试缓存过去三天的所有推文。假设我们有专门的缓存服务器,缓存过去三天所有用户的所有推文。如上所述,我们每天都会收到1亿条新推文或30GB的新数据(没有照片和视频)。如果我们想存储过去三天的所有推文,我们将需要少于100GB的内存。这些数据可以很容易地放入一台服务器,但我们应该将其复制到多台服务器上,以分配所有读取流量,从而减少缓存服务器上的负载。因此,每当我们生成一个用户的时间线时,我们都可以询问缓存服务器是否有该用户最近的所有推文。如果是,我们可以简单地从缓存返回所有数据。如果缓存中没有足够的tweet,我们必须查询后端服务器以获取数据。在类似的设计中,我们可以尝试缓存过去三天的照片和视频。

我们的缓存就像一个哈希表,其中“key”是“OwnerID”,而“value”是一个双链接列表,其中包含该用户在过去三天内发出的所有推文。因为我们想首先检索最新的数据,所以我们总是可以在链接列表的开头插入新的tweet,这意味着所有较旧的tweet都将位于链接列表的末尾附近。因此,我们可以从尾部删除tweet,为新tweet腾出空间。

9、时间轴生成

关于时间线生成的详细讨论,暂不做重要讨论

10、复制和容错

由于我们的系统是重读的,我们可以为每个DB分区提供多个辅助数据库服务器。辅助服务器将仅用于读取流量。所有写入操作将首先进入主服务器,然后复制到辅助服务器。此方案还将为我们提供容错能力,因为无论何时主服务器发生故障,我们都可以故障切换到辅助服务器。

11、负载平衡

我们可以在系统的三个位置添加负载平衡层:

1)客户端和应用服务器之间;

2)应用服务器和数据库复制服务器之间;

3)聚合服务器和缓存服务器之间。

最初,可以采用简单的循环方法;在服务器之间平均分配传入请求的。此LB易于实现,不会引入任何开销。这种方法的另一个好处是,如果服务器死机,LB将使其退出循环,并停止向其发送任何流量。循环LB的一个问题是它不会占用服务器,考虑到。如果服务器过载或速度较慢,LB不会停止向该服务器发送新请求。为了解决这个问题,可以放置一个更智能的LB解决方案,定期查询后端服务器的负载,并根据负载调整流量。

12、监控

拥有监控系统的能力至关重要。我们应该不断地收集数据,以便及时了解系统的运行情况。我们可以收集以下指标/计数器,以了解我们服务的性能:

1.每天/秒新增推文,每日峰值是多少?

2.Timeline delivery stats,我们的服务每天/每秒发送多少条推文。3.用户看到的刷新时间线的平均延迟。

通过监视这些计数器,我们将了解是否需要更多的复制、负载平衡或缓存。

13、扩展要求

我们如何提供物料?

从某人关注的人那里获取所有最新推文,并按时间对其进行合并/排序。使用分页来获取/显示推文。只从所有关注的人那里获取前N条推文。这取决于客户端的视口,因为在移动设备上,与Web客户端相比,我们显示的tweet更少。我们还可以缓存下一条热门推文以加快速度。或者,我们可以预生成进料以提高效率;

Retweet:对于数据库中的每个Tweet对象,我们可以存储原始Tweet的ID,而不存储此Retweet对象上的任何内容。

趋势主题:我们可以在最近N秒内缓存最频繁出现的hashtag或搜索查询,并在每M秒后不断更新它们。我们可以根据推特、搜索查询、转发或喜欢的频率对趋势主题进行排名。我们可以对展示给更多人的主题给予更多的重视。

跟随谁?如何提出建议?

此功能将提高用户参与度。我们可以推荐某人的朋友。我们可以下两到三层楼去找名人,征求他们的意见。我们可以优先考虑拥有更多追随者的人。

由于在任何时候都只能提出一些建议,所以使用机器学习(ML)来洗牌和重新排序。ML信号可能包括最近跟随人数增加的人、普通跟随者(如果其他人跟随该用户)、普通位置或兴趣等。

时刻:获取过去1或2小时内不同网站的头条新闻,找出相关推文,对它们进行优先级排序,使用ML–监督学习或聚类对它们进行分类(新闻、支持、金融、娱乐等)。然后我们可以在瞬间将这些文章显示为趋势主题。

搜索:搜索包括索引、排名和检索推文。

参考资料

grok_system_design_interview.pdf

现在关注【LIKE.TG出海指南频道】【LIKE.TG生态链-全球资源互联社区】,即可免费领取【WhatsApp、LINE、Telegram、Twitter、ZALO云控】等获客工具试用、【住宅IP、号段筛选】等免费资源,机会难得,快来解锁更多资源,助力您的业务飞速成长!点击【联系客服】

本文由LIKE.TG编辑部转载自互联网并编辑,如有侵权影响,请联系官方客服,将为您妥善处理。

This article is republished from public internet and edited by the LIKE.TG editorial department. If there is any infringement, please contact our official customer service for proper handling.


科技论坛互联网论坛虚拟币论坛技术论坛科技峰会互联网峰会虚拟币峰会技术峰会社交媒体论坛世界互联网Server deployment数据论坛数据峰会网络论坛网络峰会战略论坛开放论坛全球论坛全球峰会发展论坛人工智能论坛程序员论坛
加入like.tg生态圈,即可获利、结识全球供应商、拥抱全球软件生态圈加入like.tg生态圈,即可获利、结识全球供应商、拥抱全球软件生态圈加入like.tg生态圈,即可获利、结识全球供应商、拥抱全球软件生态圈
全球峰会
Flarum搭建论坛详细教程
Flarum搭建论坛详细教程
1、关于Flarum程序完美支持军哥lnmp环境/宝塔等,下载程序上传到网站根目录并需要伪静态+fileinfo扩展。程序本地下载:FlarumChina-beta7.zipGithub下载地址:https://github.com/skywalker512/FlarumChinafileinfo拓展 需要支持php扩展fileinfo。 1、对于lnmp1.3默认没有支持。修改include/upgrade_php.sh这个文件,把其中的:--disable-fileinfo,全部替换:--enable-fileinfo,再执行./upgrade.sh升级php就行了。 2、对于宝塔,安装后,找到你的PHP程序,里面有扩展可以选择安装。2、centos安装LNMP支持flarun2 | 1 数据库安装代码语言:javascript复制sudo wget https://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm yum -y install mysql57-community-release-el7-10.noarch.rpm yum -y install mysql-community-server systemctl start mysqld.service2 | 2 mysql5.7获取密码的方式代码语言:javascript复制sudo grep 'temporary password' /var/log/mysqld.log代码语言:javascript复制vi /etc/my.cnf代码语言:javascript复制#添加validate_password_policy配置 validate_password_policy=0 #关闭密码策略 validate_password = off修改root密码代码语言:javascript复制mysql -uroot -p密码代码语言:javascript复制set global validate_password_policy=0; set global validate_password_length=1; ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass4!'; grant all privileges on *.* to root@"%" identified by "new password"; flush privileges;代码语言:javascript复制systemctl restart mysql2 | 3 安装php7.2代码语言:javascript复制sudo rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm sudo rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm yum install php72w-fpm php72w-cli php72w-curl php72w-dom php72w-gd php72w-json php72w-mbstring php72w-openssl php72w-pdo_mysql php72w-tokenizer php72w-zip -y代码语言:javascript复制vim /etc/php-fpm.d/www.conf代码语言:javascript复制#找到以下两处共四行代码并修改如下: user = nginx group = nginx listen.owner = nginx listen.group = nginx3、安装Flarum方法一:下载=即使用整合包https://github.com/skywalker512/FlarumChina/releases/tag/v0.1.0-beta.12方法二:composer拉取 (比较建议后面装插件都是用的composer)3 | 1 安装composer下载composer.phar, 如果是网络原因失败,多试几次代码语言:javascript复制curl -sS https://getcomposer.org/installer | php把composer.phar移动到环境下让其变成可执行:代码语言:javascript复制mv composer.phar /usr/local/bin/composer测试代码语言:javascript复制composer -v修改镜像地址代码语言:javascript复制composer config repo.packagist composer https://mirrors.aliyun.com/composer/3 | 2 安装ningx代码语言:javascript复制yum -y install nginx unzip进入wwwroot目录中使用composer命令来安装flarum:代码语言:javascript复制mkdir /var/www/flarum/ cd /var/www/flarum/代码语言:javascript复制composer create-project flarum/flarum . --stability=beta #不用使用管理员权限命令sudo。完毕后修改nginx中的默认配置文件:代码语言:javascript复制sudo vim /etc/nginx/nginx.conf代码语言:javascript复制#将server代码段下的所有代码都用#注释掉 #server { # listen 80 default_server; # listen [::]:80 default_server; # server_name _; # root /usr/share/nginx/html; # # Load configuration files for the default server block. # include /etc/nginx/default.d/*.conf; # location / { # } # error_page 404 /404.html; # location = /40x.html { # } # error_page 500 502 503 504 /50x.html; # location = /50x.html { # } #} #然后修改 server { listen 80; server_name your.website.url; root /var/www/flarum/public; index index.php index.html; #include /home/flarum/wwwroot/.nginx.conf; location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } location / { try_files $uri $uri/ /index.php?$query_string; } # The following directives are based on best practices from H5BP Nginx Server Configs # https://github.com/h5bp/server-configs-nginx # Expire rules for static content location ~* \.(?:manifest|appcache|html?|xml|json)$ { add_header Cache-Control "max-age=0"; } location ~* \.(?:rss|atom)$ { add_header Cache-Control "max-age=3600"; } location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|mp4|ogg|ogv|webm|htc)$ { add_header Cache-Control "max-age=2592000"; access_log off; } location ~* \.(?:css|js)$ { add_header Cache-Control "max-age=31536000"; access_log off; } location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ { add_header Cache-Control "max-age=2592000"; access_log off; } # Gzip compression gzip on; gzip_comp_level 5; gzip_min_length 256; gzip_proxied any; gzip_vary on; gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; }注意:因为Flarum遵守了最新的安全规范,其程序的运行目录其实是在public文件夹内。4、插件安装https://bbs.csur.fun/d/84-flarum5、虚拟机搭建买个虚拟机做网页,诸多限制,虚拟机服务商的提供的服务确实就两字“操蛋”。 为什么没有买云服务器?就两字 “没钱”!哈哈。 虚拟机的购买途径自寻,但是很多服务商真的很坑爹。 虚拟机要求php支持7.2以上mysql支持5.7以上能够支持更改网站跟目录6、更改网站根目录层级将 public 目录(包括 .htaccess)中的所有文件移动到 Flarum 根目录。然后编辑 .htaccess 取消第 9-14 行的注释,以保护敏感资源。 然后编辑 index.php 文件,更改以下行:代码语言:javascript复制$site = require './site.php';最后,在 site.php 更新路径,以反映新的目录结构:代码语言:javascript复制'base' => __DIR__, 'public' => __DIR__, 'storage' => __DIR__.'/storage',config.php 更新 url 路径代码语言:javascript复制'url' => 'https://xxx.com/community',不更改网站层级目录请根据你的虚拟主机面板的不同,将网站运行目录指向public文件夹。 如果您使用的是虚拟主机无法更改目录,请按照一下的方法进行设置 在根目录下新建一个名为 .htaccess的文件代码语言:javascript复制RewriteEngine on RewriteCond %{REQUEST_URI} !^/public/ RewriteRule ^(.*)$ /public/$1 [L]7、其他底部加统计代码语言:javascript复制vendor/flarum/core/views/app.blade.php去掉网络字体代码语言:javascript复制vendor/flarum/core/src/Http/WebApp/WebAppView.php伪静态设置Nginx的话在站点配置文件处添加下面一段话。代码语言:javascript复制location / { try_files $uri $uri/ /index.php?$query_string; } location /api { try_files $uri $uri/ /api.php?$query_string; } location /admin { try_files $uri $uri/ /admin.php?$query_string; } location /flarum { deny all; return 404; } location ~ .php$ { fastcgi_split_path_info ^(.+.php)(/.+)$; fastcgi_pass unix:/tmp/php-cgi.sock; fastcgi_index index.php; include fastcgi.conf; }
一些关于网站推广问题合集。
一些关于网站推广问题合集。
网站怎么快速上权重?要让一个网站快速提高权重,需要实施以下一些有效的策略:提供高质量的内容:提供高质量、原创、有用的内容是最重要的。这可以吸引更多的用户访问,并增加用户留存时间,提高用户体验。同时,高质量的内容也会被其他网站引用和分享,这将有助于增加外部链接,提高网站的权重。内部链接优化:内部链接是指在网站内部不同页面之间的链接。通过优化内部链接结构,可以增加搜索引擎对网站的理解,提高网站权重。在内部链接时,要使用相关的关键字作为链接文本,而不是使用"点击这里"这样无意义的链接文本。外部链接建设:获取来自其他网站的高质量链接对于提高网站权重非常重要。可以通过主动进行友情链接、媒体报道、论坛发帖等方式增加外部链接。但是请注意,建立外部链接是需要花费时间和精力的,必须确保链接是高质量的、自然的,否则可能会适得其反。社交媒体推广:在社交媒体平台上建立专业的社交媒体账号,提供网站相关的信息、文章、图像、视频等,让更多的用户了解网站,增加网站的曝光度,进而增加网站权重。网站结构优化:优化网站结构可以帮助搜索引擎更好地抓取和理解网站内容,提高网站权重。可以通过优化网站的HTML代码结构、网站的目录结构、网站的图片和视频的优化等方式实现。需要注意的是,这些策略需要长期坚持和不断完善,才能够取得长期、稳定的效果。怎么养站?要养好一个网站,需要考虑以下几个方面:网站内容:一个网站需要有高质量、有价值的内容来吸引用户。内容可以是文字、图片、视频等形式,需要有足够的量和质量,同时需要及时更新。网站设计:网站的设计需要符合用户的视觉需求,界面简洁、易于操作、美观大方,同时需要考虑不同设备(如手机、平板、电脑)的适配。网站优化:通过搜索引擎优化(SEO)、网站性能优化(如减少页面加载时间)、提高用户体验(如减少广告干扰),来提高网站的流量和用户满意度。社交媒体:通过社交媒体来吸引用户,增加网站的曝光率和影响力,比如可以在微信公众号、微博、知乎等平台上发布内容,吸引用户关注。安全保护:确保网站的安全性,包括用户信息保护、反垃圾邮件、反病毒等安全措施。数据分析:通过数据分析工具,了解用户访问情况,优化网站的运营,提高用户满意度和转化率。综合考虑上述因素,不断更新和改进,就可以养好一个网站。网站怎么发外链有用?要使外链对你的网站有用,你需要遵循以下几个步骤:确定目标受众和内容:确定你要向哪些人推广内容,以及他们可能对哪些内容感兴趣。通过创建高质量的内容,吸引用户来阅读你的文章并点击你的链接。找到相关的网站:寻找与你的内容相关的网站,并联系网站所有者以获得一个外链。你可以通过搜索引擎、社交媒体、行业博客等方式来找到这些网站。站长百科网创建有价值的内容:创建有价值的内容可以吸引其他网站链接到你的网站。确保你的内容是高质量的,包含有用的信息,且易于阅读和分享。联系其他网站:直接联系其他网站的所有者,请求他们在他们的网站上添加你的链接。你可以通过电子邮件、社交媒体或其他渠道来联系他们。使用社交媒体:在社交媒体上分享你的内容,并鼓励其他用户分享你的文章。这样可以提高你的内容的曝光率,并吸引更多的用户来访问你的网站。需要注意的是,对于外链的数量和质量,搜索引擎有一定的要求,如果采用不当的方式获取外链,可能会对你的网站产生负面影响。因此,你需要遵守搜索引擎的规则,采用合法的方式获取外链,从而为你的网站带来更多的流量和排名提升。2023年建什么类型的网站有前景?2023年,移动端和云端应用程序将继续受到极大的关注,尤其是基于AI的应用程序。有预测认为,2023年将会出现大量的智能家居、自动驾驶、语音助手等应用,这些网站将具有更大的前景。收藏 | 0点赞 | 0打赏
红鲱鱼发布欧洲100佳创业企业名单
红鲱鱼发布欧洲100佳创业企业名单
红鲱鱼欧洲100佳创业企业评选活动上周在阿姆斯特丹结束,这次活动评出了欧洲100家最具潜力的创业企业。此次论坛讨论了2016年及未来几年欧洲创业者面临的前景。众多顶级投资人参与了讨论,指导创业企业如何吸引合适的投资机构。演讲嘉宾和听众都认为在欧洲融资仍然是主要挑战,这对于创业者来说尤其重要。论坛讨论结束,企业开始登台宣讲,评选标准和去年一样严格。参与评选的企业来自整个欧洲,从俄罗斯到法国到英国到德国。这100家最佳企业都是经过严格的层层筛选评出的,荣誉来之不易,也是众望所归。这些企业来自不同的领域,他们在欧洲以及全球市场的发展将备受瞩目,也会受到密切跟踪。 2016年欧洲100佳创业企业榜单公司行业国家12Return软件荷兰3megawatt GmbH清洁技术德国4th Office云技术英国6Tribes社交媒体英国Acast AB娱乐媒体瑞典Accellta Ltd生命科学/生物技术以色列Agiboo BV云技术荷兰agile42其他德国Anders Innovations网络/互联网芬兰Appentra Solutions软件西班牙arivis AG软件德国Beyond Sports虚拟技术荷兰Billage云技术西班牙Biovotion AG医疗设备瑞士BISEES INFORMATION SYSTEMS软件爱尔兰CARENITY社交媒体法国CloudEndure云技术以色列Compliance Risks专业服务爱尔兰Create Intelligence Ltd软件/分析英国Cree GmbH清洁技术奥地利CropX云技术以色列DCA (Data-Centric Alliance)大数据/存储俄罗斯Diviac AG互联网/网络瑞士EasyPark Group其他瑞典Educated Change Ltd娱乐媒体英国Enso Detego GmbH软件奥地利eSMART Technologies清洁技术瑞士EVRYTHNG云技术英国Fairsail云技术英国Featurespace其他英国FINALCAD软件法国GetIntent广告技术美国Grapeshot软件英国GuardSquare网络安全比利时HeadSense Medical医疗设备以色列HELLO STAGE娱乐媒体美国Herta Security网络安全西班牙High-Tech Bridge网络安全瑞士homePad Solutions互联网/网络瑞士ICS2大数据/存储以色列ID Finance银行/并购西班牙indoo.rs GmbH软件奥地利Kameleoon广告技术法国Keypasco网络安全瑞典KTH Event Agency清洁技术土耳其Lemon Way互联网/网络法国Leverate软件以色列LibraEsva Srl网络安全意大利MediSapiens Ltd生命科学/生物技术芬兰MeetApp AB移动技术瑞典Metafused Ltd广告技术英国moblin大数据/软件/广告技术以色列Mols Media BV软件荷兰MYMobile Security网络安全英国nestpick其他德国Nexthink软件瑞士OneSoon Limited软件英国Openhost, SL云技术西班牙Optimal Plus大数据/存储以色列OurCrowd风险资本/投资以色列Overleaf云技术英国P.I.Works电讯土耳其Padawan Ltd网络英国Parx Plastics BV清洁技术荷兰PleaseTech Ltd软件英国Polar OLED Ltd硬件英国Privatequity.biz互联网/网络以色列Productsup GmbH软件德国Pyreos Limited硬件英国Qosmos软件法国QUASARDB软件法国Radisens Diagnostics医疗设备爱尔兰rational motion清洁技术德国RedCloud Technologies软件英国Relay42云技术荷兰Roima Intelligence其他芬兰Securosys SA网络安全瑞士Sentiance软件比利时Shadow Technologies网络/互联网以色列Smoltek AB纳米技术瑞典Spideo软件法国Sportswik AB娱乐媒体dia瑞典Stratoscale虚拟技术以色列Takeaway.com B.V.网络/互联网荷兰Teamnet Group软件罗马尼亚The Nostrum Group Ltd软件英国TimeLog A/S软件丹麦Tinitell电讯瑞典TitanHQ网络安全爱尔兰Umbilical Design其他瑞典VATBOX云技术英国Venture Spirit云技术比利时VerseOne软件英国Visma Solutions Oy云技术芬兰Wax Digital Ltd云技术英国网络lib大数据/存储法国WeekCal BV移动技术荷兰Zapgocharger Ltd消费电子英国Zebra Medical Vision生命科学/生物技术以色列ZeroLight软件英国
科技论坛
Flarum搭建论坛详细教程
Flarum搭建论坛详细教程
1、关于Flarum程序完美支持军哥lnmp环境/宝塔等,下载程序上传到网站根目录并需要伪静态+fileinfo扩展。程序本地下载:FlarumChina-beta7.zipGithub下载地址:https://github.com/skywalker512/FlarumChinafileinfo拓展 需要支持php扩展fileinfo。 1、对于lnmp1.3默认没有支持。修改include/upgrade_php.sh这个文件,把其中的:--disable-fileinfo,全部替换:--enable-fileinfo,再执行./upgrade.sh升级php就行了。 2、对于宝塔,安装后,找到你的PHP程序,里面有扩展可以选择安装。2、centos安装LNMP支持flarun2 | 1 数据库安装代码语言:javascript复制sudo wget https://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm yum -y install mysql57-community-release-el7-10.noarch.rpm yum -y install mysql-community-server systemctl start mysqld.service2 | 2 mysql5.7获取密码的方式代码语言:javascript复制sudo grep 'temporary password' /var/log/mysqld.log代码语言:javascript复制vi /etc/my.cnf代码语言:javascript复制#添加validate_password_policy配置 validate_password_policy=0 #关闭密码策略 validate_password = off修改root密码代码语言:javascript复制mysql -uroot -p密码代码语言:javascript复制set global validate_password_policy=0; set global validate_password_length=1; ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass4!'; grant all privileges on *.* to root@"%" identified by "new password"; flush privileges;代码语言:javascript复制systemctl restart mysql2 | 3 安装php7.2代码语言:javascript复制sudo rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm sudo rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm yum install php72w-fpm php72w-cli php72w-curl php72w-dom php72w-gd php72w-json php72w-mbstring php72w-openssl php72w-pdo_mysql php72w-tokenizer php72w-zip -y代码语言:javascript复制vim /etc/php-fpm.d/www.conf代码语言:javascript复制#找到以下两处共四行代码并修改如下: user = nginx group = nginx listen.owner = nginx listen.group = nginx3、安装Flarum方法一:下载=即使用整合包https://github.com/skywalker512/FlarumChina/releases/tag/v0.1.0-beta.12方法二:composer拉取 (比较建议后面装插件都是用的composer)3 | 1 安装composer下载composer.phar, 如果是网络原因失败,多试几次代码语言:javascript复制curl -sS https://getcomposer.org/installer | php把composer.phar移动到环境下让其变成可执行:代码语言:javascript复制mv composer.phar /usr/local/bin/composer测试代码语言:javascript复制composer -v修改镜像地址代码语言:javascript复制composer config repo.packagist composer https://mirrors.aliyun.com/composer/3 | 2 安装ningx代码语言:javascript复制yum -y install nginx unzip进入wwwroot目录中使用composer命令来安装flarum:代码语言:javascript复制mkdir /var/www/flarum/ cd /var/www/flarum/代码语言:javascript复制composer create-project flarum/flarum . --stability=beta #不用使用管理员权限命令sudo。完毕后修改nginx中的默认配置文件:代码语言:javascript复制sudo vim /etc/nginx/nginx.conf代码语言:javascript复制#将server代码段下的所有代码都用#注释掉 #server { # listen 80 default_server; # listen [::]:80 default_server; # server_name _; # root /usr/share/nginx/html; # # Load configuration files for the default server block. # include /etc/nginx/default.d/*.conf; # location / { # } # error_page 404 /404.html; # location = /40x.html { # } # error_page 500 502 503 504 /50x.html; # location = /50x.html { # } #} #然后修改 server { listen 80; server_name your.website.url; root /var/www/flarum/public; index index.php index.html; #include /home/flarum/wwwroot/.nginx.conf; location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } location / { try_files $uri $uri/ /index.php?$query_string; } # The following directives are based on best practices from H5BP Nginx Server Configs # https://github.com/h5bp/server-configs-nginx # Expire rules for static content location ~* \.(?:manifest|appcache|html?|xml|json)$ { add_header Cache-Control "max-age=0"; } location ~* \.(?:rss|atom)$ { add_header Cache-Control "max-age=3600"; } location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|mp4|ogg|ogv|webm|htc)$ { add_header Cache-Control "max-age=2592000"; access_log off; } location ~* \.(?:css|js)$ { add_header Cache-Control "max-age=31536000"; access_log off; } location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ { add_header Cache-Control "max-age=2592000"; access_log off; } # Gzip compression gzip on; gzip_comp_level 5; gzip_min_length 256; gzip_proxied any; gzip_vary on; gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; }注意:因为Flarum遵守了最新的安全规范,其程序的运行目录其实是在public文件夹内。4、插件安装https://bbs.csur.fun/d/84-flarum5、虚拟机搭建买个虚拟机做网页,诸多限制,虚拟机服务商的提供的服务确实就两字“操蛋”。 为什么没有买云服务器?就两字 “没钱”!哈哈。 虚拟机的购买途径自寻,但是很多服务商真的很坑爹。 虚拟机要求php支持7.2以上mysql支持5.7以上能够支持更改网站跟目录6、更改网站根目录层级将 public 目录(包括 .htaccess)中的所有文件移动到 Flarum 根目录。然后编辑 .htaccess 取消第 9-14 行的注释,以保护敏感资源。 然后编辑 index.php 文件,更改以下行:代码语言:javascript复制$site = require './site.php';最后,在 site.php 更新路径,以反映新的目录结构:代码语言:javascript复制'base' => __DIR__, 'public' => __DIR__, 'storage' => __DIR__.'/storage',config.php 更新 url 路径代码语言:javascript复制'url' => 'https://xxx.com/community',不更改网站层级目录请根据你的虚拟主机面板的不同,将网站运行目录指向public文件夹。 如果您使用的是虚拟主机无法更改目录,请按照一下的方法进行设置 在根目录下新建一个名为 .htaccess的文件代码语言:javascript复制RewriteEngine on RewriteCond %{REQUEST_URI} !^/public/ RewriteRule ^(.*)$ /public/$1 [L]7、其他底部加统计代码语言:javascript复制vendor/flarum/core/views/app.blade.php去掉网络字体代码语言:javascript复制vendor/flarum/core/src/Http/WebApp/WebAppView.php伪静态设置Nginx的话在站点配置文件处添加下面一段话。代码语言:javascript复制location / { try_files $uri $uri/ /index.php?$query_string; } location /api { try_files $uri $uri/ /api.php?$query_string; } location /admin { try_files $uri $uri/ /admin.php?$query_string; } location /flarum { deny all; return 404; } location ~ .php$ { fastcgi_split_path_info ^(.+.php)(/.+)$; fastcgi_pass unix:/tmp/php-cgi.sock; fastcgi_index index.php; include fastcgi.conf; }
一些关于网站推广问题合集。
一些关于网站推广问题合集。
网站怎么快速上权重?要让一个网站快速提高权重,需要实施以下一些有效的策略:提供高质量的内容:提供高质量、原创、有用的内容是最重要的。这可以吸引更多的用户访问,并增加用户留存时间,提高用户体验。同时,高质量的内容也会被其他网站引用和分享,这将有助于增加外部链接,提高网站的权重。内部链接优化:内部链接是指在网站内部不同页面之间的链接。通过优化内部链接结构,可以增加搜索引擎对网站的理解,提高网站权重。在内部链接时,要使用相关的关键字作为链接文本,而不是使用"点击这里"这样无意义的链接文本。外部链接建设:获取来自其他网站的高质量链接对于提高网站权重非常重要。可以通过主动进行友情链接、媒体报道、论坛发帖等方式增加外部链接。但是请注意,建立外部链接是需要花费时间和精力的,必须确保链接是高质量的、自然的,否则可能会适得其反。社交媒体推广:在社交媒体平台上建立专业的社交媒体账号,提供网站相关的信息、文章、图像、视频等,让更多的用户了解网站,增加网站的曝光度,进而增加网站权重。网站结构优化:优化网站结构可以帮助搜索引擎更好地抓取和理解网站内容,提高网站权重。可以通过优化网站的HTML代码结构、网站的目录结构、网站的图片和视频的优化等方式实现。需要注意的是,这些策略需要长期坚持和不断完善,才能够取得长期、稳定的效果。怎么养站?要养好一个网站,需要考虑以下几个方面:网站内容:一个网站需要有高质量、有价值的内容来吸引用户。内容可以是文字、图片、视频等形式,需要有足够的量和质量,同时需要及时更新。网站设计:网站的设计需要符合用户的视觉需求,界面简洁、易于操作、美观大方,同时需要考虑不同设备(如手机、平板、电脑)的适配。网站优化:通过搜索引擎优化(SEO)、网站性能优化(如减少页面加载时间)、提高用户体验(如减少广告干扰),来提高网站的流量和用户满意度。社交媒体:通过社交媒体来吸引用户,增加网站的曝光率和影响力,比如可以在微信公众号、微博、知乎等平台上发布内容,吸引用户关注。安全保护:确保网站的安全性,包括用户信息保护、反垃圾邮件、反病毒等安全措施。数据分析:通过数据分析工具,了解用户访问情况,优化网站的运营,提高用户满意度和转化率。综合考虑上述因素,不断更新和改进,就可以养好一个网站。网站怎么发外链有用?要使外链对你的网站有用,你需要遵循以下几个步骤:确定目标受众和内容:确定你要向哪些人推广内容,以及他们可能对哪些内容感兴趣。通过创建高质量的内容,吸引用户来阅读你的文章并点击你的链接。找到相关的网站:寻找与你的内容相关的网站,并联系网站所有者以获得一个外链。你可以通过搜索引擎、社交媒体、行业博客等方式来找到这些网站。站长百科网创建有价值的内容:创建有价值的内容可以吸引其他网站链接到你的网站。确保你的内容是高质量的,包含有用的信息,且易于阅读和分享。联系其他网站:直接联系其他网站的所有者,请求他们在他们的网站上添加你的链接。你可以通过电子邮件、社交媒体或其他渠道来联系他们。使用社交媒体:在社交媒体上分享你的内容,并鼓励其他用户分享你的文章。这样可以提高你的内容的曝光率,并吸引更多的用户来访问你的网站。需要注意的是,对于外链的数量和质量,搜索引擎有一定的要求,如果采用不当的方式获取外链,可能会对你的网站产生负面影响。因此,你需要遵守搜索引擎的规则,采用合法的方式获取外链,从而为你的网站带来更多的流量和排名提升。2023年建什么类型的网站有前景?2023年,移动端和云端应用程序将继续受到极大的关注,尤其是基于AI的应用程序。有预测认为,2023年将会出现大量的智能家居、自动驾驶、语音助手等应用,这些网站将具有更大的前景。收藏 | 0点赞 | 0打赏
红鲱鱼发布欧洲100佳创业企业名单
红鲱鱼发布欧洲100佳创业企业名单
红鲱鱼欧洲100佳创业企业评选活动上周在阿姆斯特丹结束,这次活动评出了欧洲100家最具潜力的创业企业。此次论坛讨论了2016年及未来几年欧洲创业者面临的前景。众多顶级投资人参与了讨论,指导创业企业如何吸引合适的投资机构。演讲嘉宾和听众都认为在欧洲融资仍然是主要挑战,这对于创业者来说尤其重要。论坛讨论结束,企业开始登台宣讲,评选标准和去年一样严格。参与评选的企业来自整个欧洲,从俄罗斯到法国到英国到德国。这100家最佳企业都是经过严格的层层筛选评出的,荣誉来之不易,也是众望所归。这些企业来自不同的领域,他们在欧洲以及全球市场的发展将备受瞩目,也会受到密切跟踪。 2016年欧洲100佳创业企业榜单公司行业国家12Return软件荷兰3megawatt GmbH清洁技术德国4th Office云技术英国6Tribes社交媒体英国Acast AB娱乐媒体瑞典Accellta Ltd生命科学/生物技术以色列Agiboo BV云技术荷兰agile42其他德国Anders Innovations网络/互联网芬兰Appentra Solutions软件西班牙arivis AG软件德国Beyond Sports虚拟技术荷兰Billage云技术西班牙Biovotion AG医疗设备瑞士BISEES INFORMATION SYSTEMS软件爱尔兰CARENITY社交媒体法国CloudEndure云技术以色列Compliance Risks专业服务爱尔兰Create Intelligence Ltd软件/分析英国Cree GmbH清洁技术奥地利CropX云技术以色列DCA (Data-Centric Alliance)大数据/存储俄罗斯Diviac AG互联网/网络瑞士EasyPark Group其他瑞典Educated Change Ltd娱乐媒体英国Enso Detego GmbH软件奥地利eSMART Technologies清洁技术瑞士EVRYTHNG云技术英国Fairsail云技术英国Featurespace其他英国FINALCAD软件法国GetIntent广告技术美国Grapeshot软件英国GuardSquare网络安全比利时HeadSense Medical医疗设备以色列HELLO STAGE娱乐媒体美国Herta Security网络安全西班牙High-Tech Bridge网络安全瑞士homePad Solutions互联网/网络瑞士ICS2大数据/存储以色列ID Finance银行/并购西班牙indoo.rs GmbH软件奥地利Kameleoon广告技术法国Keypasco网络安全瑞典KTH Event Agency清洁技术土耳其Lemon Way互联网/网络法国Leverate软件以色列LibraEsva Srl网络安全意大利MediSapiens Ltd生命科学/生物技术芬兰MeetApp AB移动技术瑞典Metafused Ltd广告技术英国moblin大数据/软件/广告技术以色列Mols Media BV软件荷兰MYMobile Security网络安全英国nestpick其他德国Nexthink软件瑞士OneSoon Limited软件英国Openhost, SL云技术西班牙Optimal Plus大数据/存储以色列OurCrowd风险资本/投资以色列Overleaf云技术英国P.I.Works电讯土耳其Padawan Ltd网络英国Parx Plastics BV清洁技术荷兰PleaseTech Ltd软件英国Polar OLED Ltd硬件英国Privatequity.biz互联网/网络以色列Productsup GmbH软件德国Pyreos Limited硬件英国Qosmos软件法国QUASARDB软件法国Radisens Diagnostics医疗设备爱尔兰rational motion清洁技术德国RedCloud Technologies软件英国Relay42云技术荷兰Roima Intelligence其他芬兰Securosys SA网络安全瑞士Sentiance软件比利时Shadow Technologies网络/互联网以色列Smoltek AB纳米技术瑞典Spideo软件法国Sportswik AB娱乐媒体dia瑞典Stratoscale虚拟技术以色列Takeaway.com B.V.网络/互联网荷兰Teamnet Group软件罗马尼亚The Nostrum Group Ltd软件英国TimeLog A/S软件丹麦Tinitell电讯瑞典TitanHQ网络安全爱尔兰Umbilical Design其他瑞典VATBOX云技术英国Venture Spirit云技术比利时VerseOne软件英国Visma Solutions Oy云技术芬兰Wax Digital Ltd云技术英国网络lib大数据/存储法国WeekCal BV移动技术荷兰Zapgocharger Ltd消费电子英国Zebra Medical Vision生命科学/生物技术以色列ZeroLight软件英国
互联网论坛
BBS论坛(二十五)
BBS论坛(二十五)
25.1.发布帖子后台逻辑完成(1)apps/models.py代码语言:javascript复制class PostModel(db.Model): __tablename__ = 'post' id = db.Column(db.Integer, primary_key=True, autoincrement=True) title = db.Column(db.String(200), nullable=False) content = db.Column(db.Text, nullable=False) create_time = db.Column(db.DateTime, default=datetime.now) board_id = db.Column(db.Integer, db.ForeignKey('board.id')) board = db.relationship('BoardModel', backref='posts')(2)front/decorater.py代码语言:javascript复制from flask import session,redirect,url_for from functools import wraps import config def login_requried(func): @wraps(func) def wrapper(*args,**kwargs): if config.FRONT_USER_ID in session: return func(*args,**kwargs) else: return redirect(url_for('front.signin')) return wrapper(3)front/forms.py代码语言:javascript复制class AddPostForm(BaseForm): title=StringField(validators=[InputRequired(message='请输入标题')]) content=StringField(validators=[InputRequired(message='请输入内容')]) board_id=IntegerField(validators=[InputRequired(message='请选择版块')])(4)front/views.py代码语言:javascript复制@bp.route('/apost/', methods=['POST', 'GET']) @login_requried def apost(): if request.method == 'GET': boards = BoardModel.query.all() return render_template('front/front_apost.html', boards=boards) else: form = AddPostForm(request.form) if form.validate(): title = form.title.data content = form.content.data board_id = form.board_id.data board = BoardModel.query.get(board_id) if not board: return restful.params_error(message='没有这个版块') post = PostModel(title=title, content=content, board_id=board_id) post.board = board db.session.add(post) db.session.commit() return restful.success() else: return restful.params_error(message=form.get_error())25.2.发布帖子界面布局完成(1)把ueditor静态文件放到static目录下(2)apps目录下新建ueditor目录init.py代码语言:javascript复制from .ueditor import bpueditor.py代码语言:javascript复制#encoding: utf-8 from flask import ( Blueprint, request, jsonify, url_for, send_from_directory, current_app as app ) import json import re import string import time import hashlib import random import base64 import sys import os from urllib import parse # 更改工作目录。这么做的目的是七牛qiniu的sdk # 在设置缓存路径的时候默认会设置到C:/Windows/System32下面 # 会造成没有权限创建。 os.chdir(os.path.abspath(sys.path[0])) try: import qiniu except: pass from io import BytesIO bp = Blueprint('ueditor',__name__,url_prefix='/ueditor') UEDITOR_UPLOAD_PATH = "" UEDITOR_UPLOAD_TO_QINIU = False UEDITOR_QINIU_ACCESS_KEY = "" UEDITOR_QINIU_SECRET_KEY = "" UEDITOR_QINIU_BUCKET_NAME = "" UEDITOR_QINIU_DOMAIN = "" @bp.before_app_first_request def before_first_request(): global UEDITOR_UPLOAD_PATH global UEDITOR_UPLOAD_TO_QINIU global UEDITOR_QINIU_ACCESS_KEY global UEDITOR_QINIU_SECRET_KEY global UEDITOR_QINIU_BUCKET_NAME global UEDITOR_QINIU_DOMAIN UEDITOR_UPLOAD_PATH = app.config.get('UEDITOR_UPLOAD_PATH') if UEDITOR_UPLOAD_PATH and not os.path.exists(UEDITOR_UPLOAD_PATH): os.mkdir(UEDITOR_UPLOAD_PATH) UEDITOR_UPLOAD_TO_QINIU = app.config.get("UEDITOR_UPLOAD_TO_QINIU") if UEDITOR_UPLOAD_TO_QINIU: try: UEDITOR_QINIU_ACCESS_KEY = app.config["UEDITOR_QINIU_ACCESS_KEY"] UEDITOR_QINIU_SECRET_KEY = app.config["UEDITOR_QINIU_SECRET_KEY"] UEDITOR_QINIU_BUCKET_NAME = app.config["UEDITOR_QINIU_BUCKET_NAME"] UEDITOR_QINIU_DOMAIN = app.config["UEDITOR_QINIU_DOMAIN"] except Exception as e: option = e.args[0] raise RuntimeError('请在app.config中配置%s!'%option) csrf = app.extensions.get('csrf') if csrf: csrf.exempt(upload) def _random_filename(rawfilename): letters = string.ascii_letters random_filename = str(time.time()) + "".join(random.sample(letters,5)) filename = hashlib.md5(random_filename.encode('utf-8')).hexdigest() subffix = os.path.splitext(rawfilename)[-1] return filename + subffix @bp.route('/upload/',methods=['GET','POST']) def upload(): action = request.args.get('action') result = {} if action == 'config': config_path = os.path.join(bp.static_folder or app.static_folder,'ueditor','config.json') with open(config_path,'r',encoding='utf-8') as fp: result = json.loads(re.sub(r'\/\*.*\*\/','',fp.read())) elif action in ['uploadimage','uploadvideo','uploadfile']: image = request.files.get("upfile") filename = image.filename save_filename = _random_filename(filename) result = { 'state': '', 'url': '', 'title': '', 'original': '' } if UEDITOR_UPLOAD_TO_QINIU: if not sys.modules.get('qiniu'): raise RuntimeError('没有导入qiniu模块!') buffer = BytesIO() image.save(buffer) buffer.seek(0) q = qiniu.Auth(UEDITOR_QINIU_ACCESS_KEY, UEDITOR_QINIU_SECRET_KEY) token = q.upload_token(UEDITOR_QINIU_BUCKET_NAME) ret,info = qiniu.put_data(token,save_filename,buffer.read()) if info.ok: result['state'] = "SUCCESS" result['url'] = parse.urljoin(UEDITOR_QINIU_DOMAIN,ret['key']) result['title'] = ret['key'] result['original'] = ret['key'] else: image.save(os.path.join(UEDITOR_UPLOAD_PATH, save_filename)) result['state'] = "SUCCESS" result['url'] = url_for('ueditor.files',filename=save_filename) result['title'] = save_filename, result['original'] = image.filename elif action == 'uploadscrawl': base64data = request.form.get("upfile") img = base64.b64decode(base64data) filename = _random_filename('xx.png') filepath = os.path.join(UEDITOR_UPLOAD_PATH,filename) with open(filepath,'wb') as fp: fp.write(img) result = { "state": "SUCCESS", "url": url_for('files',filename=filename), "title": filename, "original": filename } return jsonify(result) @bp.route('/files/<filename>/') def files(filename): return send_from_directory(UEDITOR_UPLOAD_PATH,filename)(3)perfect_bbs.py代码语言:javascript复制from apps.ueditor import bp as ueditor_bp app.register_blueprint(ueditor_bp)(4)front/index.html代码语言:javascript复制<a class="btn btn-warning btn-block" href="{{ url_for('front.apost') }}" id="add-post-btn">发布帖子</a>(5)front/apost.html代码语言:javascript复制{% extends 'front/front_base.html' %} {% from 'common/_macros.html' import static %} {% block title %} 发布帖子 {% endblock %} {% block head %} <script src="{{ static('ueditor/ueditor.config.js') }}"></script> <script src="{{ static('ueditor/ueditor.all.min.js') }}"></script> <script src="{{ static('front/js/front_apost.js') }}"></script> {% endblock %} {% block body %} <form method="post"> <div class="form-group"> <div class="input-group"> <span class="input-group-addon">标题</span> <input type="text" name="title" class="form-control"> </div> </div> <div class="form-group"> <div class="input-group"> <span class="input-group-addon">版块</span> <select name="board_id" class="form-control"> {% for board in boards %} <option value="{{ board.id }}">{{ board.name }}</option> {% endfor %} </select> </div> </div> <div class="form-group"> <script id="ueditor" type="text/plain" style="height:500px;"></script> </div> <div class="form-group"> <button class="btn btn-danger" id="submit-btn">发布帖子</button> </div> </form> {% endblock %}(6)front/js/apost.js代码语言:javascript复制$(function () { var ue=UE.getEditor('ueditor',{'serverUrl':'/ueditor/upload/'}); });
加入like.tg生态圈,即可获利、结识全球供应商、拥抱全球软件生态圈加入like.tg生态圈,即可获利、结识全球供应商、拥抱全球软件生态圈加入like.tg生态圈,即可获利、结识全球供应商、拥抱全球软件生态圈