基于 WPF + Modern UI 的 公司OA小助手 开发总结
?
前言:
距離上一篇博客,整整一個月的時間了。人不能懶下來,必須有個階段性的總結(jié),算是對我這個階段的一個反思。人只有在總結(jié)的過程中才會發(fā)現(xiàn)自己的不足。
公司每天都要在OA系統(tǒng)上上班點擊簽到,下班點擊簽退,每天都要寫工作日志。有的時候頭腦不清醒或者忙過頭了(別說你們沒有過),就會忘記簽到或者簽退,有時候甚至忘記寫工作日志。這會直接導致扣人工啊有木有,所以我才有了這個想法。首先聲明,開發(fā)這個東西并不是博主對工作不認真不負責任,也并不是偷懶。相反,第一,可以避免因工作過忙忘記簽到扣工資;第二,在開發(fā)的過程中你學到的東西是快速的,有趣的,讓自己受益的。對于每個公司來說,OA系統(tǒng)都是他們的公司機密,所以博主并不會貼源碼,只在這里闡述一個開發(fā)流程與思想,讓你感覺到做一個自己覺得有趣的產(chǎn)品,思想的火花是多么不可思議。
?
一. 用到的模板與技術(shù)
1. WPF
相比傳統(tǒng)的WinForm,WPF真是太強大了,無論在UI還是在多線程的處理上,以及一些其它的改進,都預示著WinForm將被WPF取代(這只是理論上,事實上,因為很多產(chǎn)品都是多年前開發(fā)的,用的是WinForm,如果要整個框架移植到WPF將是一件痛苦的事,反正產(chǎn)品沒功能上的問題,這個移植就顯得沒必要了。所以目前,很多公司依然使用著WinForm的技術(shù),開發(fā)者都在這個基礎(chǔ)上對產(chǎn)品縫縫補補,更沒有機會接觸WPF了,就算是會這門技術(shù)的人,也找不到這個職位。比如我的公司就是)。本軟件全面采用WPF技術(shù),使用XAML布局以及做一些增強用戶體驗的動畫。
2. Modern UI
Modern UI 是基于WPF的一個開源項目,托管在 code plex 上。你可以參考以下方法把 Modern UI 的模板添加到你的 Visual Studio 上:
- 在Visual Studio 2012中,打開擴展管理器(工具?>?擴展和更新)
- 選擇在線?>?Visual Studio庫和搜索“?現(xiàn)代UI?“
- 選擇現(xiàn)代為WPF的UI模板,然后單擊“?下載“,下載并安裝。
關(guān)于 Modern UI 的介紹和使用,請參考http://mui.codeplex.com/,博主不再累贅。
3. 多線程
任何一個涉及到下載數(shù)據(jù)的程序都應(yīng)該使用多線程編程,我們另開一個線程去下載數(shù)據(jù)的話,界面就不會有“假死”現(xiàn)象,用戶體驗顯著提升。在WPF中,如果要在子線程中獲取或者設(shè)置界面UI的值也是很簡單的事情,這個WPF都為我們處理好了,很方便使用。
4. Lambda表達式
Lambda表達式是一個匿名方法,你不必再為只使用一次的方法獨立寫成一個函數(shù)(比如委托)。在WPF中在子線程里獲取界面控件的值的時候就使用了Lambda表達式。Lambda表達式是委托的實現(xiàn)方法。
5. MVVM設(shè)計模式
MVVM 是 Model-View-ViewModel 的縮寫,看字面你就能想到是什么意思吧。使用它的好處是,如果綁定的數(shù)據(jù)上下文改變了,會自動通知UI做出相應(yīng)的更改。這也是比WinForm進步的地方。對于開發(fā)人員來說相當方便。當然MVVM不只這些內(nèi)容。
6. XML配置文件的操作
因為要保存用戶名密碼、是否開啟自動簽到動能、自動簽到的時間等等數(shù)據(jù),就用到了App.config,實際上這是一個XML文件。
7. 系統(tǒng)托盤的處理
很多程序都有這個功能,主要是為了讓程序在后臺繼續(xù)運行,以便時間到了就自動簽到或者簽退。
8. 開機自啟
早上一來開機就自動啟動,然后自動簽到,會很爽吧,都完全不用自己動手。主要是寫入注冊表操作。
9. 模擬瀏覽器請求(重點)
使用HttpWatch來抓包,使用HttpWebRequest和HttpWebResponse來模擬瀏覽器的行為,要理解HTTP請求協(xié)議,當然在asp.net下還要理解asp.net網(wǎng)站與普通網(wǎng)站的差異(asp.net的原理)。asp.net的網(wǎng)站,使用服務(wù)器控件開發(fā)的話,頁面上會有一大堆“垃圾代碼”,用來保存頁面狀態(tài),控件狀態(tài)等等信息,這些信息在發(fā)送post報文的時候也需要發(fā)送過去,而且它的值的長度很長。
10. 正則表達式
軟件里面大量使用了正則表達式從服務(wù)器返回的html頁面來獲取我們需要的數(shù)據(jù),比如我的工作日志列表,簽到記錄等等。關(guān)于正則表達式無非兩個類,Match/MatchCollection、Regex。有興趣的自己去了解一下正則表達式的使用,即便是做前端開發(fā)的,也需要掌握js下的正則表達式來做客戶端的表單驗證。
?
?
二. 核心代碼HtmlHelper
?
public static class HtmlHelper{private static string cookieHeader = string.Empty;/// <summary>/// 添加日志/// </summary>/// <param name="strUrl">請求的url</param>/// <param name="param">參數(shù)</param>/// <returns></returns>public static string PostData(string strUrl, string param){string strResult = "";HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(strUrl);myHttpWebRequest.AllowAutoRedirect = true;myHttpWebRequest.KeepAlive = true;myHttpWebRequest.Accept = "image/gif, image/x-xbitmap, image/jpeg, imagepeg, applicationnd.ms-excel, application/msword, application/x-shockwave-flash, */*";myHttpWebRequest.Timeout = 10000;myHttpWebRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 2.0.50727)";myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";myHttpWebRequest.Method = "POST";myHttpWebRequest.Headers.Add("cookie:" + cookieHeader);Stream MyRequestStrearm = myHttpWebRequest.GetRequestStream();StreamWriter MyStreamWriter = new StreamWriter(MyRequestStrearm, Encoding.ASCII);//把數(shù)據(jù)寫入HttpWebRequest的Request流 MyStreamWriter.Write(param);//關(guān)閉打開對象 MyStreamWriter.Close();MyRequestStrearm.Close();HttpWebResponse response = null;System.IO.StreamReader sr = null;response = (HttpWebResponse)myHttpWebRequest.GetResponse();sr = new System.IO.StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")); // //utf-8strResult = sr.ReadToEnd();return strResult;}/// <summary>/// 功能描述:模擬登錄頁面,提交登錄數(shù)據(jù)進行登錄,并記錄Header中的cookie/// </summary>/// <param name="strURL">登錄數(shù)據(jù)提交的頁面地址</param>/// <param name="strArgs">用戶登錄數(shù)據(jù)</param>/// <returns></returns>public static string PostLogin(string strURL, string strArgs){string strResult = "";HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(strURL);myHttpWebRequest.AllowAutoRedirect = true;myHttpWebRequest.KeepAlive = true;myHttpWebRequest.Accept = "image/gif, image/x-xbitmap, image/jpeg, imagepeg, applicationnd.ms-excel, application/msword, application/x-shockwave-flash, */*";myHttpWebRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 2.0.50727)";myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";myHttpWebRequest.Method = "POST";myHttpWebRequest.Headers.Add("cookie:" + cookieHeader);CookieContainer myCookieContainer = new CookieContainer();myHttpWebRequest.CookieContainer = myCookieContainer;Stream MyRequestStrearm = myHttpWebRequest.GetRequestStream();StreamWriter MyStreamWriter = new StreamWriter(MyRequestStrearm, Encoding.ASCII);//把數(shù)據(jù)寫入HttpWebRequest的Request流 MyStreamWriter.Write(strArgs);//關(guān)閉打開對象 MyStreamWriter.Close();MyRequestStrearm.Close();HttpWebResponse response = null;System.IO.StreamReader sr = null;response = (HttpWebResponse)myHttpWebRequest.GetResponse();cookieHeader = myHttpWebRequest.CookieContainer.GetCookieHeader(new Uri(strURL));sr = new System.IO.StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")); // //utf-8strResult = sr.ReadToEnd();return strResult;}/**//// <summary>/// 功能描述:在PostLogin成功登錄后記錄下Headers中的cookie,然后獲取此網(wǎng)站上其他頁面的內(nèi)容/// </summary>/// <param name="strURL">獲取網(wǎng)站的某頁面的地址</param>/// <param name="strReferer">引用的地址</param>/// <returns>返回頁面內(nèi)容</returns>public static string GetPage(string strURL){string strResult = "";HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(strURL);myHttpWebRequest.ContentType = "textml";myHttpWebRequest.Method = "GET";myHttpWebRequest.Headers.Add("cookie:" + cookieHeader);HttpWebResponse response = null;System.IO.StreamReader sr = null;response = (HttpWebResponse)myHttpWebRequest.GetResponse();sr = new System.IO.StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")); // //utf-8strResult = sr.ReadToEnd();return strResult;}/// <summary>/// 獲取隱藏控件的value/// </summary>/// <param name="loginHtml">HTML頁面代碼字符串</param>/// <param name="regex">要獲取的值的正則表達式</param>/// <param name="replaceLeft">左邊要刪除的字符串</param>/// <param name="replaceRight">右邊要刪除的字符串</param>/// <returns></returns>public static string GetHiddenValue(string loginHtml, string regex, string replaceLeft, string replaceRight){string viewState = string.Empty;Match match = new Regex(regex).Match(loginHtml);if (match.Success){viewState = match.Value.Replace(replaceLeft, "");viewState = viewState.Replace(replaceRight, "");}return viewState;}HtmlHelper
?
吐槽一下自己,這個類其實可以優(yōu)化,比如PostLogin和PostData其實可以合并,GetHiddenValue也可以寫得更好,只是工作這邊還比較忙,剛剛接手了一個任務(wù),是把項目的結(jié)構(gòu)全面改版,使得每一個功能就是一個小項目,這樣管理起來方便很多,所以沒有時間進行優(yōu)化,做好了自己能用就用著先,還是工作比較重要。
很明顯,里面有4個方法,每個方法的作用以及調(diào)用方式都有很詳細的注釋,我就不重復了。至于更多的代碼我就不貼了,畢竟涉及到商業(yè)機密的問題。講講原理吧。
?
三. 原理
首先,我們知道http是無狀態(tài)連接,每次瀏覽器向服務(wù)器端發(fā)送請求,服務(wù)器返回數(shù)據(jù)之后就斷開了,你下一次請求的時候服務(wù)器并不知道你是否已經(jīng)登錄,那么asp.net下服務(wù)器怎么知道你的登陸狀態(tài)呢?當你登陸之后,服務(wù)器會給瀏覽器發(fā)送一個cookie,用來標識你的登錄狀態(tài),下一次請求的時候瀏覽器會把這個cookie一同發(fā)給服務(wù)器,服務(wù)器接收到之后驗證你發(fā)過來的cookie數(shù)據(jù),然后就知道你是否已經(jīng)登陸過。如果沒登陸,就不讓你請求別的頁面數(shù)據(jù)。我們可以使用HttpWebRequest和HttpWebResponse類來模擬瀏覽器的請求。
登陸之后,我們要寫工作日志,就要把日志內(nèi)容拼成要提交的報文,然后post到服務(wù)器,這就是一個post請求過程。還有一種請求叫做get請求,這種請求是不提交報文的,直接發(fā)請求,然后服務(wù)器就會返回一個html頁面,然后我們就可以利用正則表達式來獲取我們需要的數(shù)據(jù)了。
這里有一個值得注意的地方,因為我們的程序要一個掛在電腦上,以便它可以到時間后自動簽退或者簽到,但是服務(wù)器為你保存的登錄狀態(tài)是有時間段的,如果過了一段時間你沒有請求操作,服務(wù)器認為你已經(jīng)斷開連接,不再為你保持登錄狀態(tài)(我們公司的OA系統(tǒng)似乎是半個小時),所以我們進行一個請求之前要判斷一下登錄狀態(tài)是否還保持著,如果斷開了就重新登錄一下再進行請求。怎么判斷登錄狀態(tài)呢?我們公司的OA系統(tǒng)會彈出一個提示框提示身份驗證過期,而這個提示框當然是在html頁面上的,我們只需要請求一下主頁,看它返回的html頁面中是否包含身份驗證過期這個信息就行了(別說你不知道html頁面其實就是一個字符串)。
?
四. 曬圖
1.登陸(其實只是保存了用戶名密碼,并沒有真正登陸,到需要進行登陸操作的時候才登陸,比如提交日志、簽到、簽退、獲取日志列表、登錄信息等等,當然并不是每次這些操作都登陸,只要登錄狀態(tài)還保持著,就不需要重新登陸了)
?
2.主頁
?
3.添加工作日志
?
4.個性化(模板自帶)
?
5.用戶信息(用于登陸)
?
6.系統(tǒng)托盤
?
7.簽到成功提示
?
五. 后話
在這個浮躁的世界里,我們不可以浮躁。人要有夢想,不然跟條咸魚有什么分別。雖然我在追求自己喜歡的生活方式上有著各種阻礙,但是我還是認為,以自己喜歡的方式生活才是最開心的。人就一輩子,只要能承擔責任,還有什么必要跟自己過不去呢?昨天我朋友從鳳凰古城給我寄來一張明信片,我感慨萬千,于是回復了一句:祝前程似錦,山明水秀,兄弟情誼,萬古長青。切記,莫屈服,要以自己喜歡的方式生活。
也獻給你們,親愛的園友。
轉(zhuǎn)載于:https://www.cnblogs.com/rainlam163/p/3365181.html
總結(jié)
以上是生活随笔為你收集整理的基于 WPF + Modern UI 的 公司OA小助手 开发总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 看电影玩游戏门窗隔音要用什么
- 下一篇: 如何创建一个基础jQuery插件