牛掰!我是這麼把個人部落格粉絲轉到公眾號的
01、前言
純潔的微笑推薦了一篇文章,題目沒有任何特色,叫做《我是怎麼把部落格粉絲轉到公眾號的》,但讀完後,我震驚了——原來還有這種騷操作啊!
驚歎於作者的思路和動手能力,我也決定試一把。畢竟在這個網際網路時代,擁有流量就彷彿擁有了一切。
沒想到的是,我這一把試了整整一個星期(有好幾天都是折騰到半夜兩三點,眼皮一直打架),今天才終於搞定。期間踩了無數次的坑,感慨頗多。於是就想從技術的角度,來回顧一下這次的歷程,給大家一些參照。
《我是怎麼把部落格粉絲轉到公眾號的》的作者叫崔慶才,加了好友聊了幾句,感覺非常的有才。藉此機會,我們再來一起回顧一下他的思路。
1)讀者通過谷歌或者 Robin 李的搜尋引擎檢索到了部落格。
2)部落格的部分內容是隱藏的,需要讀者關注公眾號並回復口令解鎖。
3)解鎖後,讀者就可以無礙地瀏覽全站所有文章了。
大家看到這可能會產生一個疑問:作者的思路是非常清晰的,但讀者的使用者體驗怎麼保證呢?
首先,讀者只需要解鎖一次,全站的所有文章就全都解鎖了。其次,操作起來非常簡便,掃一下二維碼,傳送一個口令就完事了。最後,讀者關注公眾號的動作,在一定程度上為作者注入了源源不斷的寫作動力,這樣的話,讀者就可以看到更多更優質的文章了。
真的是兩全其美啊!
既然方案大佬已經提供了,那我們就動手開幹吧!人嘛,你可以缺少想法,但不能缺少執行力啊——幹就對了。
接下來,我們就從前端到後端,細細緻致地過一遍。前端是通過 HTML + CSS + JavaScript 實現的,後端是通過 JFinal + 微信 SDK + MySql 實現的。用到的技術棧還包括 jQuery、Nginx、Maven 等等。
02、前端
前端主要完成的工作包括隱藏文章、提醒使用者掃碼關注公眾號併發送口令,還有解鎖文章。怎麼實現的呢?我們一步步來看。
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 方法。
03、後端
前端的工作已經完成了。那後端的工作都包括哪一些呢?
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());
}
}
04、注意事項
後端的工作完成後,就需要將其打包執行到伺服器上了。
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 有獎勵喲。
首先進去文章是這個樣子的:
然後關注了訂閱號,傳送了口令:
於是同時,部落格上的文章也解鎖了!
牛掰!
05、後記
一週時間,我幾乎把所有的事情都滯後了,但總算是把這個方案落地了!內心還是非常激動的。再次感謝崔慶才大佬的思路,也為自己頑強的鬥志點個贊!
謝謝大家的閱讀,希望能給你在技術的實現上提供一些思路。