牛掰!我是這麼把我的博客粉絲轉到公衆號的

0一、前言

純潔的微笑推薦了一篇文章,題目沒有任何特點,叫作《我是怎麼把博客粉絲轉到公衆號的》,但讀完後,我震驚了——原來還有這種騷操做啊!css

驚歎於做者的思路和動手能力,我也決定試一把。畢竟在這個互聯網時代,擁有流量就彷彿擁有了一切html

沒想到的是,我這一把試了整整一個星期(有好幾天都是折騰到半夜兩三點,眼皮一直打架),今天才終於搞定。期間踩了無數次的坑,感慨頗多。因而就想從技術的角度,來回顧一下此次的歷程,給你們一些參照。前端

《我是怎麼把博客粉絲轉到公衆號的》的做者叫崔慶才,加了好友聊了幾句,感受很是的有才。藉此機會,咱們再來一塊兒回顧一下他的思路。java

1)讀者經過谷歌或者 Robin 李的搜索引擎檢索到了博客。nginx

2)博客的部份內容是隱藏的,須要讀者關注公衆號並回復口令解鎖。git

3)解鎖後,讀者就能夠無礙地瀏覽全站全部文章了。github

你們看到這可能會產生一個疑問:做者的思路是很是清晰的,但讀者的用戶體驗怎麼保證呢?web

首先,讀者只須要解鎖一次,全站的全部文章就全都解鎖了。其次,操做起來很是簡便,掃一下二維碼,發送一個口令就完事了。最後,讀者關注公衆號的動做,在必定程度上爲做者注入了源源不斷的寫做動力,這樣的話,讀者就能夠看到更多更優質的文章了。ajax

真的是一箭雙鵰啊!sql

既然方案大佬已經提供了,那咱們就動手開幹吧!人嘛,你能夠缺乏想法,但不能缺乏執行力啊——幹就對了

接下來,咱們就從前端到後端,細細緻致地過一遍。前端是經過 HTML + CSS + JavaScript 實現的,後端是經過 JFinal + 微信 SDK + MySql 實現的。用到的技術棧還包括 jQuery、Nginx、Maven 等等。

0二、前端

前端主要完成的工做包括隱藏文章、提醒用戶掃碼關注公衆號併發送口令,還有解鎖文章。怎麼實現的呢?咱們一步步來看。

1)找到文章所在的容器

怎麼找到文章所在的容器呢?很簡單,F12 打開谷歌瀏覽器的開發者模式,經過【Elements】面板的選擇器進行定位。

好比說,小白學堂這個博客的文章容器是 article.article-content。截圖以下。

2)把文章所在容器的高度縮小

怎麼縮小文章所在容器的高度呢?使用 jQuery 是最快捷的方法,好比說 $seletor.css('height', '100px'); 能夠將容器的高度設置爲 100 像素。

具體的代碼的以下所示。

// DOM 徹底就緒時執行
$(function() {
// 找到文章所在的容器
var $article = $("article.article-content");
if ($article.length > 0) {
// 文章的實際高度
var article = $article[0], height = article.clientHeight;
// 文章隱藏後的高度
var halfHeight = height * 0.3;

$article.css('height', halfHeight + 'px');
$article.addClass('lock');
}
});

執行完這段代碼後,文章呈現出來的樣子以下圖所示。

頁面有點亂,對不對?這是由於文章的容器高度縮小了,但文章的內容由於容納不下躲在了其餘頁面元素的下方。

3)真正地隱藏起來

上圖中呈現出來的頁面效果讀者確定是接受不了的,怎麼辦呢?一行 CSS 代碼就能搞定。

.lock {
position: relative;
overflow: hidden;
padding-bottom: 30px;
}

不知道你注意到了沒以前的 JavaScript 代碼,裏面有一行是:

$article.addClass('lock');

這行代碼能夠在文章容器上額外加上一個 CSS 樣式,因而文章的部份內容就真的隱藏了起來,就像下面這樣。

4)增長點漸變效果

部分文章雖然被隱藏了,但缺乏點漸變效果,給讀者的感覺就像是一刀兩斷——這種感受太過唐突,應該緩衝一下,因而咱們再來點 CSS 修飾一下。

.asb-post-01 {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
display: block;
z-index: 10000;
margin-bottom: 0;
}

.asb-post-01 .mask {
height: 240px;
width: 100%;
background: -webkit-gradient(linear, 0 top, 0 bottom, from(rgba(255, 255, 255, 0)), to(#fff));
}

.asb-post-01.mask 從哪裏跑出來的?在這裏呢,看下圖。

上面的 CSS 代碼稍微解釋一下。position: absolute; 是絕對定位,bottom: 0; 可使 .asb-post-01 定位在文章容器的最底部。.asb-post-01 .mask 就像一張幕布,呈現出了隱隱約約的漸變效果,效果圖以下所示。

5)提醒讀者關注公衆號

好了,文章已經隱藏了起來,而且漸變效果也有了,是時候提醒讀者關注公衆號了。在 <div class="mask"></div> 元素的下方加入如下代碼。

<div class="info">
<div>掃碼或搜索:<span style="color: #E9405A; font-weight: bold;">沉默王二</span></div>
<div>
<span>發送 </span><span class="token" style="color: #e9415a; font-weight: bold; font-size: 17px; margin-bottom: 45px;">290992</span>
</div>
<div>
便可<span style="color: #e9415a; font-weight: bold;">當即永久</span>解鎖本站所有文章
</div>
<div>
<img class="code-img" style="width: 300px;display:unset" src="http://www.itmind.net/wp-content/uploads/2019/09/cmower.jpg">
</div>
</div>

再來兩行 CSS 代碼,設置掃碼區域的高度和背景。

.asb-post-01 .info {
background: white;
height: 370px;
}

呈現出來的頁面效果圖以下所示,是否是感受很完美了?簡直完美無缺好很差,忍不住給本身點個贊。

6)生成口令

頁面效果已經搞定了。接下來就很關鍵了,怎麼肯定讀者的身份標識呢?

固然是 Cookies,Cookies 裏面保存了瀏覽網頁時自動生成的 Session ID,並且每個用戶都是不同的,這樣不就能夠來惟一標識一臺瀏覽設備了嗎?

這是崔慶才大佬給出的解決方案,我舉雙手贊同。怎麼獲取呢?代碼以下所示。

function getCookie(name) {
var value = "; " + document.cookie;
var parts = value.split("; " + name + "=");
if (parts.length == 2)
return parts.pop().split(";").shift();
}

function getToken() {
let value = getCookie('UM_distinctid');
if (!value) {
return defaultToken;
}
return value.substring(value.length - 6).toUpperCase();
}

7)輪循監聽解鎖或者隱藏文章

前端還有最後一個工做要作,就是輪循監聽,每隔一段時間向後端發送一個查詢,查詢讀者的口令是否已經保存到數據庫,若是保存過了,隱藏的文章就要重現江湖了;若是沒有保存,文章固然要繼續隱藏着。

具體的代碼以下所示。

var _lock = function() {
$article.css('height', halfHeight + 'px');
$article.addClass('lock');
$('.asb-post-01').css('display', 'block');
}

var _unlock = function() {
$article.css('height', 'initial');
$article.removeClass('lock');
$('.asb-post-01').css('display', 'none');
}

// 查詢後端的結果
var _detect = function() {
console.log('Detecting Token', token);
$.ajax({
url : 'http://qingmiaokeji.cn/jfinal/wx/',
method : 'GET',
data : {
token : token
},
success : function(data) {
console.log('locked', data.locked);

if (data.locked === true) {
_lock();
} else {
_unlock();
}
},
error : function(data) {
_unlock();
}
})
}

_detect();
setInterval(function() {
_detect();
}, 5000);

①、_lock 方法的做用是隱藏文章。

②、_unlock 方法的做用是顯示文章。

③、_detect 方法的做用是查詢口令有沒有保存,若是保存就解鎖文章,若是沒有就隱藏文章。

④、setInterval 是一個定時器,每隔 5 秒執行一次 _detect 方法。

0三、後端

前端的工做已經完成了。那後端的工做都包括哪一些呢?

1)將讀者發送的口令保存到數據庫。

2)響應前端的定時查詢,把要解鎖仍是繼續鎖定的結果返回。

這兩個工做看起來平淡無奇,但若是從零開發的話,仍是很是耗時耗力的。咱們應該珍惜站在巨人肩膀上的機會,不是嗎?

此次我採用的後端框架是 JFinal,配合其微信開發 SDK,省時省力省心。簡單介紹一下 JFinal,它是基於 Java 語言的極速 WEB + ORM 框架,其核心設計目標是開發迅速、代碼量少、學習簡單、功能強大、輕量級、易擴展、Restful——很是適合咱們此次的開發任務。

爲了減輕你們的開發成本,我已經將項目開源到了 GitHub 上,地址以下所示:

https://github.com/qinggee/jfinal_weixin_demo_for_maven

你們能夠直接將項目導出到 IDE 中,只須要把數據庫連接地址、用戶名和密碼,以及微信訂閱號相關配置修改一下就好了。截個圖你們參照一下。

爲了方便你們的實操,我把關鍵的內容詳細地說明一下。

1)建立數據庫和表

建立數據庫就再也不贅述了,就說建立表吧,SQL 以下所示。

DROP TABLE IF EXISTS `weixin`;
CREATE TABLE `weixin` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`openid` varchar(255) NOT NULL,
`token` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

weixin 表有三個字段:

①、id 爲主鍵;

②、openid 爲微信用戶的關鍵標識。當用戶取消關注訂閱後,可根據該字段刪除記錄。

③、token 爲博客讀者的惟一標識。當用戶關注訂閱號後,可根據該字段斷定博客是否須要解鎖。

2)讀者關注訂閱號後,保存口令

WeixinMsgController 類的 processInTextMsg() 方法用來處理接收到的文本消息,咱們能夠在這個方法裏保存 openid 和 token,成功後提示讀者:恭喜您已經解鎖博客所有文章~

protected void processInTextMsg(InTextMsg inTextMsg) {
String msgContent = inTextMsg.getContent().trim();

if ("2048".equals(msgContent)) {

} else if (msgContent.length() == 6) {
Weixin param = new Weixin();
param.setOpenid(inTextMsg.getFromUserName());
param.setToken(msgContent);
param.save();

OutTextMsg outMsg = new OutTextMsg(inTextMsg);
outMsg.setContent("恭喜您已經解鎖博客所有文章~");
render(outMsg);
} else {
renderDefault();
}
}

3)響應前端的定時查詢

WeixinController 類的 index() 方法用來響應前端的定時查詢。

public void index() {
// 跨域
getResponse().addHeader("Access-Control-Allow-Origin", "*");

String token = getPara("token");
String openid = service.findByToken(token);
if (openid == null || "".equals(openid)) {
renderJson("locked", true);
} else {
renderJson("locked", false);
}
}

①、getResponse().addHeader("Access-Control-Allow-Origin", "*") 這行代碼能夠解決跨域的問題。

②、根據 token 查詢讀者是否已經關注了公衆號,關注過的話返回 false,不然返回 true。

4)讀者取消關注訂閱號後刪除記錄

WeixinMsgController 類的 processInFollowEvent() 方法用來處理接收到的關注/取消關注事件,若是取消關注的話,根據 openid 刪除記錄。

protected void processInFollowEvent(InFollowEvent inFollowEvent) {
if (InFollowEvent.EVENT_INFOLLOW_SUBSCRIBE.equals(inFollowEvent.getEvent())) {

else if (InFollowEvent.EVENT_INFOLLOW_UNSUBSCRIBE.equals(inFollowEvent.getEvent())) {
log.debug("取消關注:" + inFollowEvent.getFromUserName());
service.deleteByOpenid(inFollowEvent.getFromUserName());
}
}

0四、注意事項

後端的工做完成後,就須要將其打包運行到服務器上了。

1)打包項目

命令行進入項目根目錄,而後運行 mvn clean package 便可打包。

打包完成後,能夠在 target 目錄下看到如下內容。

tar.gz 文件爲 target/jfinal_weixin_demo_for_maven-release/jfinal_weixin_demo_for_maven 目錄的壓縮包,方便上傳至服務器。

2)將 tar.gz 文件上傳至服務器,並啓動服務

上傳工具可使用 FileZilla,上傳成功後能夠經過 tar -xzvf xxx.tar.gz 命令進行解壓。而後進入 jfinal_weixin_demo_for_maven 目錄下,輸入 ./jfinal.sh start 便可啓動服務。

3)配置 Nginx

因爲服務器上 80 端口已經被佔用,因此咱們須要 Nginx 反向代理一下。簡單介紹一下 Nginx(發音同 engine x),它是異步框架的網頁服務器,也能夠用做反向代理、負載平衡器和 HTTP 緩存。

打開 nginx.conf 文件,增長如下內容。

location ^~ /jfinal/ {
proxy_pass http://127.0.0.1:8089/;
rewrite http://127.0.0.1:8089/ last;
}

配置以前,假如域名是 itwanger.com,訪問該服務的地址爲:http://itwanger.com:8089。配置以後,訪問該服務的地址就能夠是:http://itwanger.com/jfinal。這樣請求的 URL 中就不須要指定端口了——有沒有感受到 Nginx 的一絲牛逼之處?

4)啓用微信訂閱號服務器配置

一切準備就緒後,就能夠進入微信訂閱號後臺,填寫服務器地址、令牌,而後啓用服務器配置了。

5)實際效果

可能你們想知道效果如何,這裏截幾張圖你們看看。這個功能已經在小白學堂(itmind.net)上線了,感興趣的能夠進去體驗一把,測到 bug 有獎勵喲。

首先進去文章是這個樣子的:

而後關注了訂閱號,發送了口令:

因而同時,博客上的文章也解鎖了!

牛掰!

0五、後記

一週時間,我幾乎把全部的事情都滯後了,但總算是把這個方案落地了!心裏仍是很是激動的。再次感謝崔慶才大佬的思路,也爲本身頑強的鬥志點個贊!

謝謝你們的閱讀,但願能給你在技術的實現上提供一些思路。

相關文章
相關標籤/搜索