關於博客訪問量的問題,影響因素有不少,例如你的權重,你的博客數量,包括你的標題是否吸引人都是一個衡量的標準。
這些東西須要的是日積月累,今天咱們從其中的一個維度入手:發帖時間。相信你們都明白,不管是csdn,博客園這種技術博客
仍是今日頭條百度貼吧或者抖音快手這種娛樂論壇,都有本身的在線高峯期。例如百度貼吧,用戶年齡段廣泛偏小,「夜貓子」佔據主力。
21-23點是在線高峯期,這個時間的閱讀量以及評論量也是最多的,自媒體人確定會選擇在這個時間發帖已獲得更多的閱讀及評論。
那咱們的博客園呢?目前咱們還不知道,既然園子裏面都是程序猿,數據統計咱就要拿出點技術人員該有的樣子,接下來咱們
寫一個爬蟲統計全部的發帖時間以及閱讀數量。
所需語言:
python
c#
sql server
- 爬取數據
咱們打開博客園首頁,首頁的文章列表有發帖時間,閱讀數,博客園最多隻有200頁,咱們只要將這200頁的全部文章閱讀數,發帖時間爬取到就ok。
下面咱們用python+scrapy 來編寫爬蟲代碼。
環境配置:
pip install scrapy 安裝爬蟲框架,scrapy安裝容易遇到坑,scrapy教程與常見坑,不懂scrapy看連接。
scrapy startproject csblog 建立項目
scrapy gensider scblogSpider 「csblogs.com」 建立爬蟲文件
修改csblog下面的items.py
title:文章標題
read:閱讀數
date:發帖時間
# -*- coding: utf-8 -*- # Define here the models for your scraped items # # See documentation in: # https://doc.scrapy.org/en/latest/topics/items.html import scrapy class CnblogsItem(scrapy.Item): title = scrapy.Field() read = scrapy.Field() date = scrapy.Field()
而後咱們編寫爬蟲代碼,首先審查下首頁的html結構。
首先吐槽下翻頁遇到的坑,https://www.cnblogs.com/#p4,表面看上去#p4是頁碼,可是屢次嘗試變化頁碼爬取,都無效果,始終爲第一頁。
通過調試工具查看請求才發現,這個url是被重寫過得,想要翻頁得這麼發請求。
接下來就容易多了,向這個地址發請求,在返回的html中取得相應的數據就行了,貼代碼。
# -*- coding: utf-8 -*- import scrapy from cnblogs.items import CnblogsItem class CsblogSpider(scrapy.Spider): name = 'csblog' allowed_domains = ['cnblogs.com'] start_urls= ['https://www.cnblogs.com/mvc/AggSite/PostList.aspx'] PageIndex = 1 def start_requests(self): url = self.start_urls[0] #由於博客園只容許200頁 for each in range(1,200): print("抓取頁碼") print(each) post_data ={ 'CategoryId':'808', 'CategoryType':"SiteHome", 'ItemListActionName':"PostList", 'PageIndex':str(each), 'ParentCategoryId':'0', 'TotalPostCount':'400' } yield scrapy.FormRequest(url=url, formdata=post_data) def parse(self, response): items = [] #全部文章都在<div class="post_item">中 for each in response.xpath("/html/body/div[@class='post_item']"): #提取標題 title = each.xpath('div[@class="post_item_body"]/h3/a/text()').extract() #提取發佈日期 date = each.xpath('div[@class="post_item_body"]/div/text()').extract() #提取閱讀數 read = each.xpath('div[@class="post_item_body"]/div/span[@class="article_view"]/a/text()').extract() title = title[0] #去除無用的字符 date = str(date).replace("[' \\r\\n ', ' \\r\\n",'').replace(" \\r\\n ']","").replace("發佈於 ","").lstrip() read = read[0].replace("閱讀(","").replace(")","") item = CnblogsItem() item['title'] = title item['read'] = read item['date'] = date items.append(item) return items
爬蟲的代碼很簡單,這也是python的強大之處。
運行 scrapy crawl csblog -o data.xml 將爬取到的數據保存爲xml。
咱們已經將抓取到的數據保存到本地xml了,接下來要作的事情就是數據統計了。所謂「術業有專攻」,作統計沒有比sql 更強大的語言了,python的任務到此結束。
- 數據存儲
爲了方便的對數據進項統計查詢,咱們把xml保存到MS Sql Server中,作個這個事情沒有比Sql server的老夥計C#更合適的了,沒啥好說的簡簡單單的幾個方法。
static void Main(string[] args) { data d = (data)Deserialize(typeof(data), File.OpenRead(@"D:/MyCode/cnblogs/cnblogs/data.xml")); DataTable dt = ToDataTable<data.item>(d.items); dt.TableName = "t_article"; dt.Columns.Remove("date"); SqlHelper.ExecuteNonQuery(dt); } /// <summary> /// Convert a List{T} to a DataTable. /// </summary> private static DataTable ToDataTable<T>(List<T> items) { var tb = new DataTable(typeof(T).Name); PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (PropertyInfo prop in props) { Type t = GetCoreType(prop.PropertyType); tb.Columns.Add(prop.Name, t); } foreach (T item in items) { var values = new object[props.Length]; for (int i = 0; i < props.Length; i++) { values[i] = props[i].GetValue(item, null); } tb.Rows.Add(values); } return tb; } /// <summary> /// Determine of specified type is nullable /// </summary> public static bool IsNullable(Type t) { return !t.IsValueType || (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)); } /// <summary> /// Return underlying type if type is Nullable otherwise return the type /// </summary> public static Type GetCoreType(Type t) { if (t != null && IsNullable(t)) { if (!t.IsValueType) { return t; } else { return Nullable.GetUnderlyingType(t); } } else { return t; } } /// 反序列化 /// </summary> /// <param name="type"></param> /// <param name="xml"></param> /// <returns></returns> public static object Deserialize(Type type, Stream stream) { XmlSerializer xmldes = new XmlSerializer(type); return xmldes.Deserialize(stream); }
數據已經成功的存儲到sql server,接下來的數據統計是重頭戲了。
- 數據統計
--200頁碼帖子總數量 select COUNT(*) from t_article
--查詢的哪一個時間段閱讀量最多 --查詢結果顯示早9點閱讀量是最多的,並不意外 --而早6點(5180)與7點(55144)相差了近10倍 --7點與8點相比差了也有三倍,這說明程序猿們陸續 --開始上班了,上班敲代碼必定是查資料的高峯期, --果不其然,8,9,10,11,15,16是閱讀量最高峯的幾個時間段 --都分佈在上班時間,而出乎意料的事22點的閱讀量也不低 --看來程序猿們回家後也很努力的嘛(應該是在加班) select CONVERT(INT, CONVERT(varchar(2),time, 108)) as count, SUM([read]) as [read] from t_article group by CONVERT(INT, CONVERT(varchar(2),time, 108)) order by [read] desc
--查詢閱讀量在一個星期內的分佈狀況 --結果一點都不意外,星期三比另六天 --高得多,星期一到星期五是工做日 --天天的閱讀量都很高,週末閱讀量下滑 --的厲害,由於休息了嘛(竟然沒在加班) select datename(weekday, time) as weekday, SUM([read]) as [read] from t_article group by datename(weekday, time) order by [read] desc
--按照閱讀數量排行 --閱讀數量與發帖時間基本成正比 --這意味着,你辛辛苦苦寫的文章 --沒人看,沒有關係。時間不會辜負你 select CONVERT(varchar(100), time, 111), sum([read]) from t_article group by CONVERT(varchar(100), time, 111) order by sum([read])
- 總結
閱讀的最高峯時段是早9點,因此這也是發帖的最優時間,8,9,10都是不錯的時間,若是你想要更多的閱讀,不要錯過呦。
閱讀數量最少的是星期六跟星期日,這兩天能夠不用發帖了,能夠給本身放個假。
閱讀數量會隨着時間慢慢變多,也就是說一開始沒有閱讀也不要緊,只要帖子裏有乾貨,隨着時間推移依然還會有許多閱讀從搜索引擎跳轉過來,閱讀量會慢慢上去的。
看完python這段爬蟲代碼,java流淚了c#沉默了
哈哈,其實很簡單,寥寥幾行代碼網頁爬一部小說,不賣關子,馬上開始。
首先安裝所需的包,requests,BeautifulSoup4
控制檯執行
pip install requests
pip install BeautifulSoup4
若是不能正確安裝,請檢查你的環境變量,至於環境變量配置,在這裏再也不贅述,相關文章有不少。
兩個包的安裝命令都結束後,輸入pip list
能夠看到,兩個包都成功安裝了。
好的,咱們馬上開始編寫代碼。
咱們的目標是抓取這個連接下全部小說的章節 https://book.qidian.com/info/1013646681#Catalog
咱們訪問頁面,用chrome調試工具查看元素,查看各章節的html屬性。咱們發現全部章節父元素是<ul class="cf">這個元素,章節的連接以及標題,在子<li>下的<a>標籤內。
那咱們第一步要作的事,就是要提取全部章節的連接。
'用於進行網絡請求' import requests chapter = requests.get("https://book.qidian.com/info/1013646681#Catalog") print(chapter.text)
頁面順利的請求到了,接下來咱們從頁面中抓取相應的元素
'用於進行網絡請求' import requests '用於解析html' from bs4 import BeautifulSoup chapter = requests.get("https://book.qidian.com/info/1013646681#Catalog") ul_bs = BeautifulSoup(chapter.text) '提取class爲cf的ul標籤' ul = ul_bs.find_all("ul",class_="cf") print(ul)
ul也順利抓取到了,接下來咱們遍歷<ul>下的<a>標籤取得全部章節的章節名與連接
'用於進行網絡請求' import requests '用於解析html' from bs4 import BeautifulSoup chapter = requests.get("https://book.qidian.com/info/1013646681#Catalog") ul_bs = BeautifulSoup(chapter.text) '提取class爲cf的ul標籤' ul = ul_bs.find_all("ul",class_="cf") ul_bs = BeautifulSoup(str(ul[0])) '找到<ul>下的<a>標籤' a_bs = ul_bs.find_all("a") '遍歷<a>的href屬性跟text' for a in a_bs: href = a.get("href") text = a.get_text() print(href) print(text)
ok,全部的章節連接搞定,咱們去看想一想章節詳情頁面長什麼樣,而後咱們具體制定詳情頁面的爬取計劃。
打開一個章節,用chrome調試工具審查一下。文章標題保存在<h3 class="j_chapterName">中,正文保存在<div class="read-content j_readContent">中。
咱們須要從這兩個標籤中提取內容。
'用於進行網絡請求' import requests '用於解析html' from bs4 import BeautifulSoup chapter = requests.get("https://book.qidian.com/info/1013646681#Catalog") ul_bs = BeautifulSoup(chapter.text) '提取class爲cf的ul標籤' ul = ul_bs.find_all("ul",class_="cf") ul_bs = BeautifulSoup(str(ul[0])) '找到<ul>下的<a>標籤' a_bs = ul_bs.find_all("a") detail = requests.get("https:"+a_bs[0].get("href")) text_bs = BeautifulSoup(detail.text) text = text_bs.find_all("div",class_ = "read-content j_readContent") print(text)
正文頁很順利就爬取到了,以上代碼僅是用第一篇文章作示範,經過調試文章已經能夠爬取成功,全部下一步咱們只要把全部連接遍歷逐個提取就行了
'用於進行網絡請求' import requests '用於解析html' from bs4 import BeautifulSoup chapter = requests.get("https://book.qidian.com/info/1013646681#Catalog") ul_bs = BeautifulSoup(chapter.text) '提取class爲cf的ul標籤' ul = ul_bs.find_all("ul",class_="cf") ul_bs = BeautifulSoup(str(ul[0])) '找到<ul>下的<a>標籤' a_bs = ul_bs.find_all("a") '遍歷全部<href>進行提取' for a in a_bs: detail = requests.get("https:"+a.get("href")) d_bs = BeautifulSoup(detail.text) '正文' content = d_bs.find_all("div",class_ = "read-content j_readContent") '標題' name = d_bs.find_all("h3",class_="j_chapterName")[0].get_text()
在上圖中咱們看到正文中的每個<p>標籤爲一個段落,提取的文章包含不少<p>標籤這也是咱們不但願的,接下來去除p標籤。
可是去除<p>標籤後文章就沒有段落格式了呀,這樣的閱讀體驗很不爽的,咱們只要在每一個段落的結尾加一個換行符就行了
'用於進行網絡請求' import requests '用於解析html' from bs4 import BeautifulSoup chapter = requests.get("https://book.qidian.com/info/1013646681#Catalog") ul_bs = BeautifulSoup(chapter.text) '提取class爲cf的ul標籤' ul = ul_bs.find_all("ul",class_="cf") ul_bs = BeautifulSoup(str(ul[0])) '找到<ul>下的<a>標籤' a_bs = ul_bs.find_all("a") '遍歷全部<href>進行提取' for a in a_bs: detail = requests.get("https:"+a.get("href")) d_bs = BeautifulSoup(detail.text) '正文' content = d_bs.find_all("div",class_ = "read-content j_readContent") '標題' name = d_bs.find_all("h3",class_="j_chapterName")[0].get_text() txt = "" p_bs = BeautifulSoup(str(content)) '提取每一個<p>標籤的內容' for p in p_bs.find_all("p"): txt = txt + p.get_text()+"\r\n"
去掉<p>標籤了,全部的工做都作完了,咱們只要把文章保存成一個txt就能夠了,txt的文件名以章節來命名。
'用於進行網絡請求' import requests '用於解析html' from bs4 import BeautifulSoup def create_txt(path,txt): fd = None try: fd = open(path,'w+',encoding='utf-8') fd.write(txt) except: print("error") finally: if (fd !=None): fd.close() chapter = requests.get("https://book.qidian.com/info/1013646681#Catalog") ul_bs = BeautifulSoup(chapter.text) '提取class爲cf的ul標籤' ul = ul_bs.find_all("ul",class_="cf") ul_bs = BeautifulSoup(str(ul[0])) '找到<ul>下的<a>標籤' a_bs = ul_bs.find_all("a") '遍歷全部<href>進行提取' for a in a_bs: detail = requests.get("https:"+a.get("href")) d_bs = BeautifulSoup(detail.text) '正文' content = d_bs.find_all("div",class_ = "read-content j_readContent") '標題' name = d_bs.find_all("h3",class_="j_chapterName")[0].get_text() path = 'F:\\test\\' path = path + name+".txt" txt = "" p_bs = BeautifulSoup(str(content)) '提取每一個<p>標籤的內容' for p in p_bs.find_all("p"): txt = txt + p.get_text()+"\r\n" create_txt(path,txt) print(path+"保存成功")
圖片二進制轉換與存入數據庫相關
關於轉換問題,剛開始我須要從數據庫讀出一個二進制數據流,並將其轉換成一個Image格式。
在不涉及數據庫的狀況下,我先將一個圖片轉換成一個二進制數組顯示出來,再寫一個方法將其轉換成圖片image格式。
1、 先不涉及數據庫,將圖片轉換成二進制,在將二進制轉換成圖片。
1.protected void Button1_Click(object sender, EventArgs e) { string str = null; PictureToBinary ptb = new PictureToBinary(); // str = Convert.ToBase64String( ptb.Data("E:/workspace/asp/TEST/PictureTurnToBinary/PictureTurnToBinary/img/Tulips.jpg")); Image newImage = Image.FromFile(Server.MapPath("Tulips.jpg")); str =Convert.ToBase64String( ptb.PhotoImageInsert(newImage)); Label1.Text = str;
//label能夠用response代替(response.write(str);)
}
第一步,我將圖片轉換成二進制數組,並轉換成string格式,用一個Label展示(也能夠用Response直接輸出到頁面顯示)。產生的數組並非二進制構成的數據流而是一串字節,以下:
因此建議先將圖片壓縮一下,否則會很大。
第二步,將獲得的二進制字節碼轉換爲圖片格式。
2. protected void Button2_Click(object sender, EventArgs e) { PictureToBinary ptb = new PictureToBinary(); Image newImage = Image.FromFile(Server.MapPath("Tulips.jpg")); WritePhoto(ptb.PhotoImageInsert(newImage)); } //圖片輸出到頁面 public void WritePhoto(byte[] streamByte) { Response.ContentType = "image/JPEG"; Response.BinaryWrite(streamByte); }
public class PictureToBinary { public PictureToBinary() { // // TODO: 在此處添加構造函數邏輯 // } public byte[] PhotoImageInsert(System.Drawing.Image imgPhoto) { //將Image轉換成二進制流數據 MemoryStream mstream = new MemoryStream(); imgPhoto.Save(mstream, System.Drawing.Imaging.ImageFormat.Bmp); byte[] myData = new Byte[mstream.Length]; mstream.Position = 0; mstream.Read(myData, 0, myData.Length); mstream.Close(); return myData; } }
結果以下:
2、將獲得的二進制數據保存到數據庫,再將其讀出。
須要用到這麼幾個控件:一個fileLoad控件,兩個按鈕,分別是存入和讀取。
存入圖片到數據庫:
protected void Saveintodatabase_Click(object sender, EventArgs e) { //將圖片保存到數據庫 //加載文件,並以字節數組格式存入數據庫 HttpPostedFile loadPhoto = FileUpload1.PostedFile; //獲取記載圖片內容長度 int photoLength = loadPhoto.ContentLength; //存爲字節數組 byte[] photoArray = new byte[photoLength]; Stream photoStream = loadPhoto.InputStream; photoStream.Read(photoArray, 0, photoLength); //鏈接數據庫讀取文件 SqlConnection conn = new SqlConnection(); conn.ConnectionString = "Data Source=localhost;Database=Test;User Id=sa;Pwd=123456789"; string sql = "insert into Test_Picture values(@image,3)"; SqlCommand cmd = new SqlCommand(sql,conn); cmd.CommandType = System.Data.CommandType.Text; cmd.Parameters.Add("@image",SqlDbType.Image); cmd.Parameters["@image"].Value = photoArray; conn.Open(); //執行sql,成功執行返回1,不然返回0(insert,update,delete),其餘命令返回-1 int row = cmd.ExecuteNonQuery(); Response.Write(row); conn.Close(); }
讀取文件:
protected void PhotoShowInWebSite_Click(object sender, EventArgs e) { //讀取數據庫圖片文件,並保存到本地。 SqlConnection conn = new SqlConnection(); conn.ConnectionString = "Data Source=localhost;Database=Test;User Id=sa;Pwd=123456789"; //選擇你須要的字段值,這邊就直接賦值了 string sql = "select Picture from Test_Picture where Number = 3"; SqlCommand cmd = new SqlCommand(sql, conn); byte[] MyData = new byte[0]; try { conn.Open(); SqlDataReader mySqlDataReader; mySqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection); if (mySqlDataReader.Read()) { Response.Clear(); Response.ContentType = "image/JPEG"; Response.BinaryWrite((byte[])mySqlDataReader["Picture"]); /*將圖片寫入到本地d盤 //圖片字節流 MyData = (byte[])mySqlDataReader["Picture"]; int ArraySize = MyData.GetUpperBound(0); FileStream fs = new FileStream(@"d:\02.jpg", FileMode.OpenOrCreate, FileAccess.Write); fs.Write(MyData, 0, ArraySize); fs.Close(); */ } } catch (SqlException SQLexc) { Response.Write(SQLexc.ToString()); } conn.Close(); }
以上爲整理的爲圖片二進制轉換與存取數據庫相關的內容。
C#7.0--引用返回值和引用局部變量
1、在C#7.0以上版本中,方法的返回值能夠經過關鍵字ref指定爲返回變量的引用(而不是值)給調用方,這稱爲引用返回值(Reference Return Value,或ref returns);
1.與引用參數同樣,使用關鍵字ref聲明引用返回值:
public ref int MyFunc(int[] nums) { //do… return ref nums[0]; }
2.使用引用返回值避免了值類型在方法返回時的淺拷貝操做,提升了效率;
3.使用引用返回值一般是爲了讓調用方有權訪問(和修改)此變量,所以引用返回值不支持無返回值方法(即返回值類型爲void);
引用返回值所返回變量指向對象的生命週期必須大於方法,即不能返回指向值類型局部變量的變量(值類型局部變量會在方法執行完返回時進行回收),能夠返回指向引用類型局部變量的變量、傳遞給方法的引用參數、靜態字段和實例字段;
※引用返回值不能夠返回字面量、常量、枚舉或按值返回的方法、屬性,但能夠返回當前值爲null的符合上述條件的變量;
※異步方法不能使用引用返回值,由於異步方法可能會在執行還沒有完成且返回值未知時就返回;
4.查看聲明引用返回值方法的IL代碼:
5.在調用引用返回值的方法時,調用方能夠選擇將方法返回的變量看成按值返回或是按引用返回處理,若是是按值返回處理,則與調用普通方法同樣:
int[] myNums = new int[] { 1, 2, 3, 4, 5 }; int myNum = MyFunc(myNums);
6.若是是按引用返回處理,則調用方須要使用引用局部變量(Reference Local Variable,或ref locals)接收,保留對方法返回變量的引用:
ref int myNum = ref MyFunc(myNums);
2、可使用關鍵字ref聲明引用局部變量、初始化引用局部變量及調用引用返回值的方法:
ref int myNum = ref myNums[0]; //此時引用局部變量myNum保存的是數組myNums中索引0的內存地址
1.使用引用局部變值避免了值類型在賦值時的淺拷貝操做,提升了效率;
2.引用局部變量必須在聲明時進行初始化,初始化時會確認該引用局部變量的做用範圍,這個做用範圍決定該引用局部變量可否做爲引用返回值返回;
對引用局部變量的賦值操做,將直接改變該變量所指向內存地址中對象的值:
myNum = 10; Console.WriteLine(myNums[0]); //10
3.對引用局部變量的讀取操做與普通局部變量同樣,將訪問該變量所指向內存地址中對象的值:
int num = myNum + 10; //20
4.引用局部變量能夠做爲引用參數的實參傳遞,一樣須要使用修飾符ref修飾,對於給定的方法:
public void MyFunc(ref int num) { } //使用時: MyFunc(ref myNum);
5.在C#7.3以上版本中,能夠對引用局部變量從新分配其它引用:
myNum = ref MyFunc(myNums);
※給引用局部變量從新分配不能改變該引用局部變量在聲明時確認的做用範圍,所以不能給一個做用範圍較大的局部引用變量賦值一個做用範圍較小的變量;
1、操做系統用進程(Processe)分隔正在執行的程序,用線程(Thread)做爲操做系統分配處理器時間的基本單元,進程上下文中能夠運行多個線程,進程的全部線程共享其虛擬地址空間,全部線程都可執行程序代碼中的任意部分,包括其餘線程正在執行的代碼;
1.默認狀況下,.NET程序只啓動單個線程,被稱爲主線程(Primary Thread),也能夠在運行時開啓其它線程,與主線程並行同時執行代碼,這些線程被稱爲工做線程(Worker Thread);由.Net開啓和管理的線程一般稱爲託管線程(Managed Thread);
2.託管線程又分爲前臺線程和後臺線程,二者相似,但前臺線程會阻止進程中止,然後臺線程不會,即當進程的Main方法結束後,只有在全部前臺線程都中止時,CLR纔會結束該進程,此時會對仍處於活動狀態的後臺線程調用Abort方法來結束全部後臺進程;
※關閉程序如遇到沒法關閉全部線程時,能夠在Main方法結束前經過如下代碼強制關閉全部線程,詳見:
System.Environment.Exit(0);
2、在使用多線程時,不一樣線程不只能夠同時執行同一段代碼,還能夠同時訪問同一內存中的數據,因此會存在必定的數據衝突問題,稱爲爭用條件(Race Condition):
static int MyNum; static int RaceConditionCount; static void MyFunc() { while (true) { if (MyNum == 0) { MyNum++; if (MyNum == 0) { RaceConditionCount++; //只有在出現爭用條件時纔會執行此語句 } } MyNum = 0; } } static void Main(string[] args) { for (int i = 0; i < 2; i++) { Thread thread = new Thread(MyFunc); thread.Start(); } Thread.Sleep(1000); Console.WriteLine(RaceConditionCount); //輸出1秒內產生爭用條件的次數 Console.Read(); }
1.對於爭用條件的發生頻率,發佈版本比調試版本的出現次數多(發佈版本編譯出的代碼被優化過並且開啓了JIT優化),多核CPU比單核CPU的出現次數多(多核CPU中多個線程能夠同時運行,單核CPU的線程調度是搶佔式的,也會出現此問題,只是次數較少);
3、爲了不產生爭用條件,須要注意數據的同步問題,能夠經過給對象加鎖,使同一時間內只有一個線程能夠執行加鎖對象所鎖定的代碼;
JS直接調用C#後臺方法(ajax調用)
1. 先手動引用DLL或者經過NuGet查找引用,這裏提供一個AjaxPro.2.dll的下載;
2. 以後的的過程不想寫了,網上都大同小異的,直接參考之前大佬寫的:
AjaxPro2完整入門教程
Linq To Json
using Newtonsoft.Json.Linq;
/// <summary> /// 遞歸生成部門樹 /// </summary> /// <param name="depList">部門列表</param> /// <param name="parentId">用戶部門的父級部門Id</param> /// <returns></returns> private JArray ConvertDepartTree(IList<AspSysDepartmentDto> depList, int parentId) { var jArray = new JArray(from a in depList where a.ParentId == parentId select new JObject( new JProperty("id", a.Id), new JProperty("text", a.Name), new JProperty("children", ConvertDepartTree(depList, a.Id) ))); return jArray; }
JSON.net Linq To Json文檔地址:https://www.newtonsoft.com/json/help/html/CreatingLINQtoJSON.htm
SqlServer 遞歸查詢
--查詢部門及下屬部門列表 WITH TEMP --遞歸 AS (SELECT Id, Code, Name, ParentId FROM [dbo].[AspSysDepartments] WHERE Id = 38 --查詢當前部門 UNION ALL SELECT B.Id, --查詢子部門 B.Code, B.Name, B.ParentId FROM TEMP A INNER JOIN [dbo].[AspSysDepartments] B ON B.ParentId = A.Id) SELECT Id, Code, Name, ParentId FROM TEMP --獲取遞歸後的集合
結果: