一次沒有最後期限的編程之旅

今年上半年,是我工做以來最繁忙的六個月,總之遇到了最艱難的教程、最冗長的文檔、最繁瑣的代碼以及最窘迫的合做,最終的極度疲勞成了壓垮了個人最後一根稻草。前端

那年杭州,接連40攝氏度以上的連續高溫,突然一天39度,居然以爲整個世界都清涼了。人,就是這麼犯賤,稍有舒緩,便全然忘記曾經的抓狂。jquery

「寫一個Apple Watch APP玩玩」,突然閃過這麼一個念頭。這對執着於《證實論》和《集合論》的苦行者而言,浮現的不過是一次短暫的旅行。git

旅行,不是遷移,抑或流浪,終究是要回歸的。程序員

記得仍是在2003年的時候,萬老師曾不經意間對我說過一句話,「編程這東西,若是不是每次都催得很急的話,其實仍是蠻有樂趣的。」github

96年初次接觸Pascal開始到如今,整整19年了。我不知道編程這東西在知足一切詭異的條件下,是否依舊還有當年的樂趣。譬如,重返19歲。web

 

1 Turbo Pascalajax

沒有什麼須要整理的行囊,也沒有什麼設定的歸期,說走就走,不知什麼時候歸來的編程之旅。我並不是堅決的要找尋一些所謂編程的樂趣,只是一路風景,一路散心。算法

寫點什麼呢?我沒有作過移動端開發,可生活卻早已離不開移動端的APP,使用頻率極高的不外是「微信」、「網易新聞」、「QQ」、「支付寶」、「淘寶」、「百度地圖」、「嗶哩嗶哩動畫」、「大衆點評」以及「Uber」。我想一款優秀的移動端APP,除了移動便攜的基本特徵以外,還應能充分利用碎片時間以及豐富多源的感知設備。數據庫

事實上,遊離了很久,沒有什麼驚豔想法。隨意翻閱早已在案頭,卻無暇顧及的兩冊圖書《Objective-C基礎教程》和《精通iOS開發》,大體都是一些移動客戶端面向對象的可視化設計。我想擁有一個優秀的IDE,一整套API以及豐富文檔的支持,iOS開發的學習曲線應該不會太陡峭。編程

因而,關注點就天然轉移到了Web服務端的開發。Web服務端的開發是熟悉的,也是陌生的。最先接觸Web開發是在2000年春,用的是ASP2.0VB5.0編寫的ActiveX做爲控件,瀏覽器經過數字簽名下載到客戶端,實現服務器端文件的下載以及數據庫的鏈接。第二次系統性的開發Web應用程序是2005年,用的是WebLogic 8.1提供的一整套解決方案,包括IDE、頁面標籤、web服務器、中間件、工做流等,這是一次真正意義上的J2EE開發,但因其優秀的封裝,卻讓我無心間失去了一次自主搭建和配置Java web開發環境的絕好機會。2010年經歷了第三次Web工程項目的開發,用的是ASP.NET 4.0,整個解決方案除了web工程以外,其他都是C#編寫的類庫工程,Web Service、自定義網站模板、自定義頁面控件以及各類支付接口,在微軟從開發環境到部署的一系列支持下,ASP.NET異常強大,超乎個人想象。

我搜了一些iOS服務端的開發,也不乏使用ASP.NETWeb Service的案例。既然是一次漫無目的的旅行,不妨選擇一些對我而言極爲陌生的技術。然而,僅僅纔是初步的調研,就發現我面對的不是一種或幾種陌生的技術,而是一個陌生的世界。

你好,世界。

Java仍是PHP,形而上的選擇Java。形而上,也不全是信仰。杭州兩家大型互聯網公司,阿里巴巴和網易(網易杭州研發中心)的應用服務端也是用Java開發的。每次選擇JDK的版本,一般只是偷懶的作法,我不是什麼資深的Java程序員,也沒有成熟老舊的代碼須要兼容,直接在Oracle主頁上下載最新的1.8版本,雖然1.61.7依舊是主流。

繼續Eclipse麼?此次終於能夠選擇了,由於此次選擇權掌握在本身手裏。2007年使用Eclipse Plug-in參與開發一個無線傳感網絡(WSN)自定義語言的集成開發環境,尤爲是開發Debug功能,簡直是噩夢,到如今都還有恐懼的後遺症。論文的最終版本終於廢棄了調試功能,但在presentation的時候仍是被人問到。我用蹩腳的口語搪塞道,「It’s very difficult to implement, and need further research.」其實,這還算不得research,只是真的無法implement。雖然還不至於到達算法邊界,但早已在個人編程能力以外了。據我瞭解,如今不少Java程序員在使用Intellij IDEA開發。有一個毛估估的統計數據,網易杭州研發中心的開發人員中使用EclipseIntellij IDEA的比例已經達到了1:1。相比免費的Eclipse2000多元的Personal License多是貴了點,不過對於如此一款優秀的IDE,這個價格真不算高。我下載了試用版,這就算開始了。可選的經典Darcula主題確實至關美觀。至於和Maven完美結合之類優勢,我天然體會不到的,由於這將是我第一次使用Maven開發。

 

2 Darcula主題的Intellij IDEA

此前,對於Maven,我是極度陌生的。好在如今互聯網上學習教程太多了,首先從Apache官網上下載最新的Maven應用程序,接着配置 Maven的環境變量,而後Intellij IDEA設置下Mavenhome directory,固然也可直接使用Intellij IDEA內嵌的Bundled (Maven 3)插件。如今可使用Intellij IDEA開發Maven Project了。創建maven-archetype-webapp工程,在pom.xml中配置好Maven插件,以及各類須要引用的庫。使用Maven管理庫,確實很是方便,真是一種全新的開發體驗。

直到要運行了,纔想起web服務器都沒有安裝。無論三七二十一,下了Tomcat8.0.23,照着網上的教程,在Intellij IDEA配置好了運行環境。瀏覽器中出現了「hello, world」,「全小寫,有逗號,逗號後空一格,且無感嘆號。」至此,JDK 1.8, Maven3.3.3, Intellij IDEA14.1.4, Tomcat8.0.23以及一個「Hello,World」程序,一個很美好的開端。

Hello, World」寫完了,沒有下一步的計劃和目標。Spring是主流麼?反正阿里巴巴和網易都用Spring。因而,買本書《Spring MVC學習指南》看看,翻了三兩個小時,對Web服務端開發依舊沒有什麼清晰的概念。看來個人此次沒有計劃的旅行彷佛有了下一個目標,把Java web開發的架構搞搞清楚。畢竟搞清楚了架構,剩下的無非是算法了。

尋找並學習Jave web架構的最佳實踐,比我預想的困難的多。瘋狂搜索的結果是各類技術及其框架浩如煙海,徹底沒有概念,直到發如今GitHub上有一個叫quick4j的開源項目(https://github.com/starzou/quick4j),讓我對Jave web開發的架構有了初步認識。

我很快在IntellijIDEA中導入了quick4j這個項目,並根據README.md的說明在MySQL中運行了數據庫腳本,創建了數據庫及表。關於MySQL,我不得很少數幾句。MySQL20159DB-Engines排名第二的數據庫,我卻歷來沒有使用過,主要由於2010年之後再無開發數據庫相關係統,而2010年之前幾回開發數據庫的工程主要使用OracleSQL Server。如今大型互聯網公司大都使用根據自身業務優化的特定分佈式實時數據庫。固然,對於中小企業的開發,MySQL依舊是上佳選擇。此外,在一個應用中同時創建與MySQLMongoDB的鏈接,合理利用每一種數據庫的優勢也是一種趨勢。

 

3 SQL Server存儲過程

quick4j採用Druid做爲數據庫鏈接池。我查了下才知道,Druid是阿里巴巴的開源項目,是JDBC的一個擴展,項目負責人的年紀應該和我差很少。既然是開源,用的人彷佛也很多,那就學習下。在pom.xml中配置好依賴(dependency),而後在applicationContext.xml中配置bean的一些系列參數,除了修改urlusername以及password外,其他參數留着之後有興趣提高性能的時候再去研究罷。

Druid之上,quick4j採用的是Mybatis,也是徹底沒用過,查了下和Hibernate是一個層次的東西,屬於對象關係模型(ORM)範疇。Hibernate好久之前彷佛還用過,當年的學習曲線如何,已沒了印象。不過,Mybatis的入門彷佛很是簡單,在applicationContext.xml中將MybatisDruid關聯好,就能夠在xml中編寫SQL了。quick4j對於MybatisXML文件寫得仍是很不錯的,是一個很是好的範例,尤爲對我這樣一個初學者,比網上一些介紹Mybatis概念的示例強得多。幾乎就是一張表對應一個XML配置文件和一個DAO接口,這些DAO接口很容易被上層調用。

quick4j中,最初使用Mybatis的是一個叫Shiro的安全框架,用於用戶的權限管理。固然quick4jDAOMapper)層和Shiro調用之間還封裝了一層Service。權限管理是一件使人頭疼的事情,好在權限管理再複雜,其關係不過張二維表。根據quick4j5張表(useruser_rolerolerole_permissionpermission),我創建了一個權限的示意關係表,三個字段名分別是「Username」、「Role」、「Permission」,Username表示用戶名稱,如adminlaceRole表示用戶角色,如Admin(管理員)、Guest(訪客);Permission表示許可,如user: createuser: readuser: updateuser: delete等。在概要設計時,一般先創建這張權限的示意關係表,而後再轉化爲實際的數據表。至於Shiro基本功能使用,如SecurityRealmdoGetAuthorizationInfodoGetAuthenticationInfo的編寫並不太複雜,並且quick4j也給出了很好的樣例。

終於到了Spring MVC這一層,由於這東西剛看過書,總體的概念要比什麼DruidMybatisShiro強的多。除了配置pom.xml, web.xml, dispatcher-servlet.xml外,主要就是這個Controller類。其實也就是requestresponse了,根據@RequestMapping註解指定訪問的URL,關聯的方法處理提交的數據,處理完了return一個網頁回去,就這麼簡明。只是封裝的過於完美,讓我感受都不像在編程。

旅行,不是定居,亦很是年生活,淺嘗即止。

所謂服務端開發彷佛瀏覽完了,順便也瞭解下quick4j的前端開發。quick4j採用了一套被稱爲「響應式後臺管理模板」Metronic來實現(這裏指的「後臺」是業務的後臺),版本是1.5.5,不過即便是1.5.5,其效果也足以讓我驚訝了。我上網查了下,最新版本已是4.1.0了。Metronic是收費的,Regular License價格爲28美圓,而Extended License價格達到了1400美圓。國內也有演示的版本,的確很是精美,萬能的淘寶也必然是有的賣的,最新的版本僅僅9塊錢人民幣。Metronic1.5.5是基於Bootstrap v3.0.3,而Bootstrap則大名鼎鼎,不過我也是剛纔知道的。Bootstrap基於HTML5CSS3以及Javascript,是一套極爲優秀的前端開發框架。不過我粗粗看了下,彷佛把Metronic以及相關的JQuery用下,前端的UI開發基本也算了解了,Bootstrap暫時是不用學習了。

既然Metronic已經4.1.0了,不如替換quick4j1.5.5Metronic4.1.0很是大,竟然有644MMetronic4.1.0其實已經支持AngularJS,不過我仍是選用了JQuery。緣由很簡單,聽說AngularJS2.01.3有很是大的變化,雖然2.0是革命性的,但1.3巨大的用戶還處於搖擺不定的狀態,能夠預見2.0出現須要一大波小白鼠。顯然,做爲遊客,是沒有太多精力的。我選擇了「v4.1.0\theme\templates\admin4」模板,並無仔細甄別「\v4.1.0\theme\assets」文件夾,由於引用的目錄過於複雜,所有拷貝到webapp目錄下,雖然這個assets達到了125M,但模板中引用文件的路徑中只要刪除「../../」,修改成相對目錄便可,由於quick4j在前端頁面經過JSP獲取了根目錄。偷懶是偷懶了點,但增長新的模板文件其實真的很方便。

至此,整個開發架構彷佛清晰了。數據庫採用MySQL;後端包括Druid, Mybatis,Shiro, Spring MVC;前端採用Metronic (HTML5, CSS3, JQuery, Bootstrap)JSPIDE、庫管理以及Web服務器分別採用IntellijIDEMaven以及Tomcat

架子終於搭好了,不寫個啥的,真是太惋惜了。畢竟動手寫點什麼才叫編程之旅麼。先從完善用戶登陸開始吧。第一個小功能,「記住我」。「記住我」功能僅用前端技術是沒法實現的,由於只有在用戶名和密碼在後臺驗證正確後,記錄這個選項纔有意義,記錄的方式經過Cookie是最爲方便的。後端在驗證經過後,將記住我狀態,用戶名和密碼都保存到Cookie中,這樣前端頁面每次刷新時就可經過js讀取Cookie中記住個人狀態,並在須要的時候填充到文本框中。此外,還要考慮的一個小問題是用戶輸入密碼不是加密的,而提交的密碼是經過sha256加密的,就在每次提交表單時加密。但前端js經過Cookie讀取的已是加密的密碼,提交時應防止再次加密。我一會兒也沒有想到好的辦法,只是利用了sha256加密後的長度均爲64,而用戶密碼均小於64這個假設條件來判斷。

下一個小功能是用戶註冊,用戶註冊顯然須要用到驗證,前端驗證天然用到了基於JQueryjquery.validate驗證框架。jquery.validate雖然是前端驗證,但也提供經過ajax提交後臺驗證,正是這個後臺驗證讓我遇到了很多小問題。通常對於格式的驗證,好比用戶名長度,郵件格式什麼的,jquery.validate的前端驗證徹底勝任。但對於用戶名已經被註冊這樣的功能,則須要經過後臺驗證。jquery.validate畢竟是一個經常使用功能,網上的樣例很是多,但適用於目前這個架構的卻很少。將幾種樣例反覆嘗試,始終進入不了Controller中的設置的斷點。直到查閱了官方最新樣例,竟沒有「contentType : "json"」這行數據的,我刪除以後果真成功了。顯然,網上衆多的樣例是基於不一樣版本的寫法。各類框架集成的首要問題必然是明確各類框架所用的版本,也應多從官方文檔中尋找樣例。驗證經過後,用戶信息的提交和後臺的處理則沒有遇到什麼問題,後臺Controller直接經過request獲取前端的數據,直接調用DAO接口,並插入了新的記錄。

既然註冊都實現了,接下來不妨寫一個用戶管理功能吧,CRUD麼。Create功能彷佛和註冊功能疑似,惟一的不一樣是想作一個導航的功能,也就是說左側是導航菜單,右側是目標頁面。網頁框架的設計本來是很熟悉的,核心不過是用邊框爲0的表格打框架,iframe用做容器,在超連接的target設置iframe的名字,當年幾十個核心頁面就是這樣搭建起來的。世界畢竟變了,MetronicBootstrap這些框架都是用DIV來搭建的。那麼如何實現導航功能呢?如今JQuery主流的作法是DIV上經過load來實現。一條核心語句就是$('#main-content').load(url);其中main-content爲目標DIVid。明白了這個作法,底氣足了不少,很快經過導航左側點擊,右側出現添加用戶頁面就作好了。但提交頁面數據的方式,我卻改用了Ajax,畢竟這是局部刷新。首先,將form中的數據轉化爲json格式,經過JQuery$.ajax方式提交,固然後臺Controller對應的方法也@ResponseBody的方式,直接接受json數據,這樣的寫法彷佛更有Spring MVC的樣式,最後返回個帶有success信息的Map給前端意思下。

用戶管理功能應該有個表,表的每行均可以刪除,編輯啥的,表天然是要分頁的。接下來,就被這個DataTables搞死了。爲了實現數據列表,我想用JQuery的一個插件庫DataTables來實現。最初,我使用原生態的DataTables,樣式是難看點,先搞清楚數據渲染麼。可前端使用DataTables,後端使用Spring MVC響應的幾乎沒有正確的樣例。將網上最爲接近的一個樣例反覆調試和修改,這才關聯了後臺數據。接下來是前端分頁,仍是後端分頁這個棘手問題了。quick4j其實已經提供後端分頁取數據的方法了,由於DataTables前端能夠傳入當前即將顯示記錄頁面的「記錄的起始索引」和「每頁顯示的行數」,只要將起始索引轉換爲頁碼的索引,便可直接調用後端分頁方法,從而獲取「記錄的起始索引」開始,而且長度爲「每頁顯示的行數」的記錄列表了,這是一種典型的後端分頁方法,實現過程比我想象的要順利些。數據渲染正確後,使用Metronic中的DataTables替換原生態的DataTables,發現表格數據並無顯示。調試後發現,Metronic4.1修改了原生態DataTables提交的參數名,好比將「iDisplayStart」改成「start」,「iDisplayLength」改成「length」,不明白Metronic 4.1爲什麼如此修改,由於Metronic 1.5.5和標準的DataTables參數仍是一致的。最後,經過查看DataTables提交json的參數,修改了Controller的解析方式,使用Metronic樣式的DataTables終於能夠顯示錶格數據了。

在每行最後添加「編輯」和「刪除」連接以後,真正麻煩的問題出現了,在每次點擊「上一頁」、「下一頁」以及「搜索」等操做都會觸發向後臺取數據的操做,然而返回後「編輯」和「刪除」對應的操做徹底丟失,反覆出現,不得其解。最後仍是在強哥的提醒下,這多是DOM重建的緣由,我恍然大悟。將「編輯」和「刪除」對應的功能都寫在DataTablesfnDrawCallback回調函數,由於fnDrawCallback回調函數會在「初始化、上一頁、下一頁以及搜索」等狀況下會觸發。至於編寫「編輯」連接相應的功能則較爲簡單,特別要注意的是,在DIV load的時候要傳遞當前須要編輯的記錄信息,傳遞的格式爲json,畢竟在編輯功能是在原有數據上進行修改,而jsp頁面則可經過request.getParameter來獲取數據。

只剩下刪除操做了,不一樣於編輯功能,點擊編輯時會在列表的上方DIV中顯示編輯界面,點擊刪除連接時,應彈出用於提示用戶確認的模式對話框。我看了下Metronic的模板頁,正好利用原有頁面中的id="portlet-config"的一個div,能夠用做模式對話框。接下來的問題是如何經過js向這個div傳遞當前記錄的編號。我在portlet-config這個div中添加了一個隱藏輸入框,而後在js中將該隱藏輸入框的值設置爲當前記錄編號。這樣,在提交模式對話框時,當前記錄編號便被傳遞至模式對話框所對應的js中,以後再將該記錄編號組建成一個json數據,經過Ajax向後臺發送一個異步請求,後臺的響應和「編輯」相似。固然爲了獲取模式對話框「肯定」仍是「取消」,還須要一個頁面級的開關變量來控制。

至此,這個想到哪寫到哪的程序,已經具有了用戶登陸,註冊以及關於用戶的添加、編輯、刪除以及經過列表方式查看等基本功能。不過,從業務上來說,超級用戶可經過管理員頁面登陸,具有管理用戶的基本功能,而通常的用戶則經過前臺頁面登陸。突然想到,是否能借助Shiro來實現這些功能。首先要作的是分別創建管理員和通常用戶登陸頁面,以及登陸後的主頁面。管理員登陸後,能夠添加、列表查看、刪除、編輯以及退出功能。而通常用戶可登陸、註冊以及退出操做。創建好兩張登陸一頁面以及對應的js文件後,分別編寫對應的Controller,這樣寫得目的主要區分不一樣的url,同時也更加清晰。在處理登陸url提交時,首先經過Shiro進行身份驗證,而後經過subject記錄的用戶權限判斷是否可跳轉到相應的主頁。此外,爲了防止只有超級用戶訪問的主頁被通常用戶訪問,可在相應的Controller方法上方添加@RequiresRoles(value = RoleSign.ADMIN)。因而,經過Shiro不只管理了用戶登陸、退出,並且能根據權限訪問指定頁面,實現前臺、後臺的權限管理。

 

4 MyCRUDDataTables

給這個程序取了個名MyCRUD,此次編碼過程當中從GitHub學到了很多,深切的感覺了開源的力量。所以,也將此代碼上傳至GitHubhttps://github.com/lacelove/MyCRUD同時也好好學習了下GitHub的基本用法。首先,在本地安裝msysgit以及一個客戶端TortoiseGit,利用客戶端工具中的puttygen生成一個公鑰和私鑰。而後註冊一個GitHub的帳號,在建立repository以後,設置SSH key,也就是客戶端生成的公鑰。此後,客戶端設置好GitHub帳號後,就能夠CloneCommitPush了。其餘用戶若是獲取上述私鑰後,也能夠直接CommitPush。固然,其餘用戶沒有私鑰的話,則可經過pull request方式貢獻本身代碼。最後還順便學習了下GitHub Flavored Markdown來編寫RAEDME.md,是用標籤控制格式的語法,Latex的感受,難度不大,簡單的寫了點。

旅行,有些累了,就暫且休息下。

過去五年,埋頭實時控制系統的設計、開發與測試,突然擡頭看世界,真的變了。這是一次沒有最後期限的編程之旅,也是一次陌生世界的探索之旅。一路上,好奇、驚歎一次次沖淡了旅途的疲倦。在沒有最後期限,沒有需求的設定下,多少重拾了一些編程的樂趣。

記得有兩部影片,《楚門的世界》和《土撥鼠之日》,主人公的環境很是相似,可最後突破自個人方式卻大相徑庭。在《楚門的世界》裏,主人公冒着死亡的危險,也要衝出去看看外面的世界;而《土撥鼠之日》主人公無奈到只能在不斷死亡中尋找樂趣,最終仍是在這個城市裏改變了自我。

這個世界,無從選擇。

也許——

走出去,是旅行;

只在一處,也是旅行。

 

 

 

 

 

 
相關文章
相關標籤/搜索