我們組有一個優良傳統——借鑒於“冰桶挑戰賽”的形式,采取點名的方式,促進團隊成員每天利用一小段時間,不斷的完善團隊 wiki 的小游戲。
但有時候忙於業務,可能會忘記,所以我寫了一個小應用,提示大家【記得寫 wiki 啦】。
項目使用的環境和技術選型如下:
- 服務器環境:centos, java 7
- 開發環境:window 10,java 7,IDEA
- 框架:spring-boot 1.5.21.RELEASE
項目需求
- 如果被點名人下午5點還沒更新wiki,發送一條企業微信消息,提醒他寫wiki
- 如果被點名人第二天早上9點還沒寫,發送一條企業微信消息,提醒他補充,並且要點名。
- 如果被點名人第三天早上9點還沒寫,發送一條企業微信消息給管理員
設計實現
分析需求,要實現上面的功能,需要:
- 爬取網頁信息,分析每個人寫 wiki 的時間
- 判斷是否完成 wiki
- 設置定時任務,發送消息給對應的人
- 需要人員姓名和企業微信賬號的映射表
針對以上功能,spring boot 官方有對應的實現,scheduling-tasks,consuming-rest
基本的功能點已經明確,然而在實現的過程中還有一些小坑。在文章最后會有補充,這里暫且不表。
異常與日志
使用 spring boot 自帶的日志 logback,簡單的配置如下:
server.port=8916
logging.level.root=warn
logging.level.org.springframework.web=ERROR
logging.level.com.hbgj=warn
logging.file=logs/happy-wiki.log
關於異常,很多地方用 try...catch 進行捕獲,感覺有點 low,看后面有沒有想法優化一下。
簡單的部署上線
打包
在項目的根目錄下執行:
$ mvn clean package
會在 target/ 文件夾下生成 jar 包,假設我們生成的包名為:happy-dog-0.0.1.jar。
發布到線上
在項目根目錄下打開 shell,輸入:
$ scp target/happy-dog-0.0.1.jar root@192.0.0.1:/home/web/happy-dog-0.0.1.jar
然后輸入密碼,等待上傳結束。
note:root 是服務器用戶名,@192.0.0.1是服務器地址,/home/web/happy-dog-0.0.1.jar 表示 jar 包在服務器上的位置。
運行項目
使用 ssh 登錄服務器,進入對應的文件夾內,在本項目中,依次執行:
$ ssh root@192.0.0.1
$ cd /home/web
運行項目有兩種方法,一種臨時,一種后台。
方法一:
$ java -jar happy-dog-0.0.1.jar
這種方式特點是ssh窗口關閉時,程序中止運行。或者是運行時沒法切出去執行其他任務。但一般我們想要程序一直在后台運行,所以有方法二:
$ nohup java -jar happy-dog-0.0.1.jar >/dev/null 2>&1 &
查看和停止
輸入下面的命令,查看 java 運行的進程。
$ ps -ef | grep java
可以看到我們項目運行的進程 id。
殺死進程:
$ kill -9 29382
查看日志
$ cat logs/happy-wiki.log
一些小坑
上面提到,我們使用的 java 版本為 java7,在爬取網頁時,會出現 Connetion reset 錯誤,導致無法獲取網頁信息。
這是由於 C/S 兩端TLS版本不適配導致,具體原因可參考這篇文章CS兩端TLS版本不適配導致Connection reset問題。
需要開啟 java7 的 TLSv1.2,
private static RestTemplate restTemplate = new RestTemplate();
static {
try {
// java 7 use TLSv1.2
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(null, null, null);
CloseableHttpClient httpClient = HttpClientBuilder.create().setSSLContext(context)
.build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
restTemplate = new RestTemplate(factory);
} catch (Exception e) {
e.printStackTrace();
}
}
第二,需要判斷某天是否是工作日,簡單起見,寫了個配置文件來記錄一年中的節假日。