在園友的強烈呼喚下,我還是負責任的分享給大家,因為對代碼比較熟悉一下,還是有些問題要說明,不然別人看起來會比較費勁。說實話除了這個bootstrap的界面風格和這件事情本身對大家有吸引力之外,內部的邏輯,結構,可能有些捉襟見肘,會讓大家見笑,大牛們完全可以略過.現在源碼已經讓我推到GitHub上面去了。我先從頭到尾的介紹一下,然后說一些存在的問題。也希望大家給出更好的建議。
一、結構說明
1.MVC 我先說模型,共有20幾張表,支持數據遷移。BaseInfos(基本資料),DetailInfos(詳細資料),LoveViews(戀愛觀) 應該是做到一張User表中的,腦抽的我把他們分成了三張表,因為他們是分別存儲的。下載之后,改成你自己的數據庫,運行就能創建新表了。
using System; using System.Collections.Generic; using System.Data.Entity; using Findlover.Migrations; namespace Findlover.Models { public class LoveDb:DbContext { private const string DbNameOrDbConnectionstring = "Data Source=your-pc;Initial Catalog=LoveDB;User ID=sa;Password=code;Persist Security Info=True"; //Persist Security Info=True public DbSet<BaseInfo> BaseInfos { get; set; }// 基本資料 public DbSet<User> Users { get; set; }// 用戶 public DbSet<Requirement> Requirements { get; set; }//擇偶需求 public DbSet<DetailInfo> DetailInfos { get; set; }//詳細資料 public DbSet<LoveView> LoveViews { get; set; }//戀愛觀 public DbSet<InfoStatistic> InfoStatistics { get; set; }// 信息統計,統計用戶資料的完整度。避免每次都要去三張表數一遍。 public DbSet<UserHot> UserHots { get; set; }//用戶的人熱度 public DbSet<Praise> Praises { get; set; }//贊 也就是喜歡 public DbSet<State> States { get; set; }// 狀態 public DbSet<Iamgbox> Iamgboxes { get; set; }// 相冊 public DbSet<Message> Messages { get; set; }//私信 public DbSet<LoginLog> LoginLogs { get; set; }// 登錄日志記錄 public DbSet<Role> Roles { get; set; }//角色 public DbSet<Hello> Hellos { get; set; }//打招呼 public DbSet<RoleLog> RoleLogs { get; set; }// 角色的日志 public DbSet<Authority> Authoritys { get; set; }// 權限 public DbSet<AdminStatistic> AdminStatistics { get; set; }//管理員操作統計 這個功能沒有多大意義 你可拿掉 public DbSet<VisitLog> VisitLogs { get; set; }// 訪問記錄 public DbSet<Report> Reports { get; set; }//舉報 public DbSet<ReportLog> ReportLogs { get; set; }//舉報日志 public DbSet<MyLove> MyLoves { get; set; }// 我喜歡的人 public DbSet<DisLove> DisLoves { get; set; }//我不喜歡的人 相當於黑名單 public DbSet<Topic> Topics { get; set; }// 話題 public DbSet<Comment> Comments { get; set; }//評論 public DbSet<EnjoyTopic> EnjoyTopics { get; set; }//感興趣的話題 public LoveDb() : base(DbNameOrDbConnectionstring) { Database.SetInitializer(new MigrateDatabaseToLatestVersion<LoveDb, Configuration<LoveDb>>()); } } }
2. 控制器: 共有8個控制器,其中BaseController 里面集合一些常用的方法和屬性,其他都繼承這個控制器,其他看名字你也知道是干啥的,Interactive是對應的Topic,本來是打算一個專門用來做交互的控制器。現在只有話題。但可能讓大家惱火的就是,這分的還不細致,不准確。之前自己偷懶,什么方法寫在什么控制器沒有明確的定義清楚,這對以后維護和擴展造成不方便。
3.視圖:主要是基於Bootstrap2,Jquery1.7.2.,form.js 注冊的日期控件和Topic的編輯器用的是KendoUi, 小伙伴們可以去換成Ckeditor,而Bootstrap用的地方主要是在
Layout的導航,后台導航,舉報、私信、圖片上傳的模態對話框,在主頁面使用它的柵格比較少,因為老是和導航對不齊,就放棄了。或許是我用的不對。Jquery用來交互,獲取數據。form.js 用的比較多,很多地方是form提交,沒有用MVC自帶的Create。原因就是不好看,而且不好控制,ie下面會走樣。
二、前端特別說明
這里特別要說明的就是一些函數和窗口的觸發
1.圖片上傳和舉報框。
在用戶主頁的視圖和PersonalInfo視圖中會有這兩個相似的html代碼,是用來觸發圖片上傳框的。
<div class="infopercentright">上傳4張照片,資料完整度+8% <a class="infotag" id="imgup" href="#imgupload" data-toggle="modal" title="上傳照片"><i class="icon-camera"></i></a> </div>
<a class="infotag" id="imgupload" href="#imgupload" data-toggle="modal" title="上傳照片"><i class="icon-camera"></i></a>
圖片上傳的模態對話框:

<div id="imgupload" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <h4>上傳圖片</h4> </div> <div class="modal-body"> <div class="uploadbox" data-count="0" style="display: inline;"> <span class="closespan" title="刪除照片">×</span> <div class="imgcontainer"> <div class="add">+</div> <div class="stt">點擊上傳</div> </div> <span class="infospan"> <img src='../../Content/Photos/loading.gif' />正在上傳...</span> </div> <div class="uploadbox" data-count="0" > <span class="closespan" title="刪除照片">×</span> <div class="imgcontainer"> <div class="add">+</div> <div class="stt">點擊上傳</div> </div> <span class="infospan"> <img src='../../Content/Photos/loading.gif' />正在上傳...</span> </div> <div class="uploadbox"data-count="0" > <span class="closespan" title="刪除照片">×</span> <div class="imgcontainer"> <div class="add">+</div> <div class="stt">點擊上傳</div> </div> <span class="infospan"> <img src='../../Content/Photos/loading.gif' />正在上傳...</span> </div> <div class="uploadbox"data-count="0" > <span class="closespan" title="刪除照片">×</span> <div class="imgcontainer"> <div class="add">+</div> <div class="stt">點擊上傳</div> </div> <span class="infospan"> <img src='../../Content/Photos/loading.gif' />正在上傳...</span> </div> <div class="inputdiv"><input type="text" disabled="disabled" id="Remark" name="Remark" placeholder="補充說明下~"/></div> </div> <div class="modal-footer"> 上傳大小在8k-10M之間 <span class="imguploadmessage"></span> <button class="btn btn-success " disabled="disabled" id="imgsubmit">發布</button> <form action="/User/UpLoadPhoto" method="POST" enctype="multipart/form-data" name="ImgForm" id="ImgForm"> <input type="file" name="file" id="imgFlie" required="required" /> <input type="submit" name="subt" value="上傳圖片" /> </form> </div> </div>
生成的圖像如下:
舉報也同樣的做法: 但舉報需要提供更多的信息,所以加了很多data屬性。用腳本觸發對話框
<span class="report" data-reportType="personal" data-relateId="@Model.UserId" data-content="@Model.UserName" data-userId="@Model.UserId" data-userName="@Model.UserName" data-sextag="@ViewBag.Sex">拉黑/舉報</span>
//舉報框----------------------report-------------------------------------------- $(".report").each(function () { $(this).click(function () { var id = $(this).attr("data-userId"); var name = $(this).attr("data-userName"); var sextag = $(this).attr("data-sextag");//對方性別 var type = $(this).attr("data-reportType"); var relateId = $(this).attr("data-relateId"); var content = $(this).attr("data-content"); $("#reportedname").html(name).attr("data-id", id);//被舉報人id $(".reportinfo span").html(sextag); $("#reportName").html(name); $("#reporttype").val(type);//舉報類型 $("#reporttype").attr("data-relateId", relateId); $("#reporttype").attr("data-content", content); //值是舉報或者拉黑這個人 初始化 $(".divrow:eq(1)").show(); $("#reportcontent").hide(); $(".reportmessage").html(); $("#reportcontent").html(content); //不同類型,不同對話 switch (type) { case "personal": $(".divrow:eq(1)").hide(); break; case "message": $("#reportType").html("發給我的私信"); $("#IsReport").attr("checked", "checked"); $("#reportcontent").show(); break; default: } $("#IsReport").click(function () { var ss = $(this).is(':checked'); if (ss) { $(".divrow:eq(1),#reportcontent").slideDown(); } else { $(".divrow:eq(1),#reportcontent").slideUp(); } }); $('#report_box').modal('show'); }); });
舉報框:
我想大家也明白了,就是這樣的一回事,腳本沒有壓縮,大家可以去看。其他像 喜歡,私信,都是一個道理,定義好一個樣式,主要是樣式名稱,在layout里面寫腳本,這樣就很方便了。
2.form提交:
用form.js,能很好的控制整個提交過程,BeginForm,隱藏的form,圖片上傳的form。
編輯基本資料:

<div class="infoedit hide" > @using (Html.BeginForm("UpdateBaseInfo", "User", FormMethod.Post, new { name = "Form1", id = "Form1" })) { <table class=""> <tr> <td>身高:</td> <td> <select name="Height" id="Height"></select></td> <td>學歷:</td> <td> <select name="Education" id="Education"></select></td> </tr> <tr> <td>月收入:</td> <td> <select name="MonthlyIncome" id="MonthlyIncome"></select></td> <td>畢業院校:</td> <td> <input type="text" name="School" id="School" value="@Model.BaseInfo.School"/></td> </tr> <tr> <td>工作單位:</td> <td> <select name="Company" id="Company"></select></td> <td>居住地:</td> <td> <select name="ResidenceProvince" id="ResidenceProvince" style="width: 90px"></select> <select name="ResidenceCity" id="ResidenceCity" style="width: 90px"></select></td> </tr> <tr> <td>目前職位:</td> <td> <select name="Position" id="Position"></select></td> <td>行業:</td> <td> <input type="text" id="Profession" readonly="readonly" name="Profession" value="生產/工藝/制造"></td> </tr> <tr> <td>當前狀態:</td> <td> <select name="State" id="State"></select></td> </tr> </table> <button type="submit" class="btn btn-info"> 保存</button> <span class="cancel-eidt">取消編輯</span> } </div>
這樣的方式用了很多,腳本基本上是下面這樣,還可以加上beforeSend,complete. 其他項獲取json數據這些,就是家常便飯了,沒什么說的。
$('#Form1').submit(function () { $(this).ajaxSubmit(options); return false; }); var options = { dataType: 'json', success: processJson, }; function processJson(data) { // 還是返回json的好,再去更新。 $(".infowrap").show(); //...... $("#sProfession").html(data.Profession); $("#sPosition").html(data.Position); $("#sSchool").html(data.School); $("#sState").html(data.State); }
二、后台邏輯
其實這個部分是最沒有含金量的,只要大家清楚業務流程了,邏輯再怎么也能寫出來。我也沒有用AOP來記錄日志或者處理異常,用IOC/DI來解耦。這也是我的弱點。所以我就簡單說明下。
1.符合基本條件的用戶: 因為是相親交友,所以要篩選用戶。在BaseController中有個GetBaseUsers
/// <summary> /// 獲取基本的異性集合 不可以允許未審核圖片的人進來! /// </summary> /// <param name="id"></param> /// <returns></returns> protected IEnumerable<User> GetBaseUsers(int id) { var lz = LoveDb.One((User n) => n.UserId == id); var dislikelist = GetDislikeList();//過濾的名單。 過掉我不喜歡的人。 //還要過掉不喜歡我的人? if (lz != null) { //選出所有異性中圖片審核過的,資料審核過的人,且資料開放,沒有被禁止的人 return LoveDb.UserAll() .Where(n => n.Sex != lz.Sex && n.IsVerified && n.IsVerifiedImg && n.IsOpen && n.Enable == 1&&!dislikelist.Contains(n.UserId)) .ToList(); } return null; }
2.推薦的用戶:推薦,動態,搜索的基本用戶都是來自這里。 你可以稍微改下代碼讓他可以選擇同性。而推薦和動態的用戶 還需要滿足一個用戶的基本擇偶要求。 就是比如我擇偶的要求是
158以上,江蘇,22歲以上。那出現在這兩個頁面的用戶就必須滿足這三個條件是硬性指標,但學歷,薪水是可以不匹配的。所以在推薦頁面是這樣的:
public ActionResult RecommendPage() { var id = CheckValid(); if (id == -1 || Session["uid"] == null) { return RedirectToAction("Logon", "User");//不知道有沒有效果 } var require = LoveDb.One((Requirement r) => r.UserId == id); var baseusers = GetBaseUsers(id).Where(n => PartMathUser(require, LoveDb.GetUninUser(n.UserId)));//找出所有正規的異性符合需求的。 ViewBag.Sex = GetMyself().User.Sex == "man" ? "她" : "他"; var userlist = baseusers.Select(baseuser => GetRecommendUser(baseuser.UserId)).ToList(); return PartialView(userlist.OrderByDescending(n => n.Rate.TotalRate)); }
partMathUser 就是一個專門用來比對的函數。原理就是撈出來一個一個比對,三個條件全部對了就是true。搜索也是一個道理,前台把條件傳過來,后台來處理。我想這個地方應該是很有優化的空間。
3.推薦度和熱度
計算推薦度,就是看兩者資料的匹配度,而熱度大家可以去看模型就知道了,就是統計數據再綜合排名。換成百分率。
/// <summary> /// 用戶熱度,相互符合度,生活觀契合度 /// </summary> /// <param name="selfid">本人</param> /// <param name="otherid">比較者</param> /// <returns></returns> public RecommendRate GetRecommendRate(int selfid, int otherid) { var usersum = LoveDb.UserAll().Count; //得到兩個人的需求表 來計算相互符合度 var myre = LoveDb.One((Requirement r) => r.UserId == selfid); var youre = LoveDb.One((Requirement r) => r.UserId == otherid); var yourUnin = LoveDb.GetUninUser(otherid); var me = GetMyself(); var rr = new RecommendRate { //用戶熱度排名UserHotRate UserHotRate = (double)(usersum - LoveDb.UserHotAllDes().FindIndex(n => n.UserId == otherid)) / usersum, ForMeRate = TomeRate(yourUnin, myre), ForOtherRate = TomeRate(me, youre), LoveViwRate = GetLoveViewRate(yourUnin, me) }; rr.TotalRate = (rr.UserHotRate + rr.LoveViwRate + rr.ForMeRate + rr.ForOtherRate) / 4; return rr; }
其他就沒啥好說的,各種return json,return partview() 我想這個是容易看明白的。
三、數據層
1.LoveDb倉庫,像單例模式,獲取實例,用反射封裝了Add,Delete,One,All等常用方法。
public class LoveDbRepository { private static LoveDbRepository _loveDb; private LoveDbRepository() { } public static LoveDbRepository GetIntance() { return _loveDb ?? (_loveDb = new LoveDbRepository()); } #region 常規方法 Add Delete All One Ones LastOne #region Add public void Add<T>(T t) { using (var loveDb = new LoveDb()) { switch (t.GetType().Name) { case "User": loveDb.Users.Add(t as User); break; case "BaseInfo": loveDb.BaseInfos.Add(t as BaseInfo); break; case "Requirement": loveDb.Requirements.Add(t as Requirement); break; case "DetailInfo": loveDb.DetailInfos.Add(t as DetailInfo); break; case "LoveView": loveDb.LoveViews.Add(t as LoveView); break; case "InfoStatistic": loveDb.InfoStatistics.Add(t as InfoStatistic); break; case "UserHot": loveDb.UserHots.Add(t as UserHot); break; //..................break; } loveDb.SaveChanges(); } }
........................
2.數據遷移。修改model,自動更新數據庫。這個也是老生常談了,也可以看博客 http://www.cnblogs.com/stoneniqiu/archive/2013/06/04/3117499.html
namespace Findlover.Migrations { using System.Data.Entity; using System.Data.Entity.Migrations; internal sealed class Configuration<TContext> : DbMigrationsConfiguration<TContext> where TContext : DbContext { public Configuration() { AutomaticMigrationsEnabled = true; AutomaticMigrationDataLossAllowed = true; } protected override void Seed(TContext context) { } } }
再就是Lambda ,linq。到處都是,沒有寫一句sql語句。這個沒什么說的。
四、問題和擴展
大大小小的問題還是蠻多的,兼容性的,腳本的,邏輯的,性能的,結構的。這些都還要慢慢的改。所以有問題不要驚奇,是很正常的。像上傳和文本編輯應該換uploadfy和ckeditor控件。這個版本還么有加入分頁,或者換成流行的滾動加載。增加一些好玩的功能,這些就要看你們的了,盡情的去折騰吧。小丘比特謝謝你!
祝你幸福~
五、說下開源
CodePlex和gitHub合作了,CodePlex可以用git上傳,而git也變成了這個windows風格: 方便大方好用。
在github的工程名稱叫FindLover(說DreamLover更合適些吧),因為FindLover是先取的,名字想了很久才叫意中人。
總結下:現在MVC5已經出來了,我還在看MVC4,EntityFrameWork6也來了,還有VS2013,.NetFrameWork4.5。Bootstrap也到3了。Html5動畫研究的還不咋地,還有各種前端的,后端的框架,目不暇接,人艱不拆啊。
新的技術提供了一些更好的方式,但是你更需要的是一個方向,一個ideal,幾個一條路上的小伙伴。
需要源碼的同學請 猛擊這里!!!! https://github.com/stoneniqiu/FindLover (幫助文檔還有其他說明)
( 下載后可能又的問題。
1.缺少引用:請在package1中找缺少的引用。 建議安裝Nuget ,會自動給你還原。
2.不能生產表格。是因為沒有EntityFramework. 沒有啟用codefirst 功能。可以參考博客:http://www.cnblogs.com/stoneniqiu/archive/2013/06/04/3117499.html
我晚上再補上創建表的SQL命令。 數據庫我不傳了。
3.缺少kendo.MVC.dll 這個dll沒有包含在package1中,我也奇怪。漏掉了。可以在http://download.csdn.net/my/uploads 下載。 晚上我也會更新到github上去。
4.缺少引用的dll中,只有Nlog,kendo.MVC,Web.Provider是有用的,其他的缺少的dll可以移除。是因為之前做過其他的測試留下的。
還有問題可以給我留言
)
最新版本:http://pan.baidu.com/s/1pJoiM1P
DB:http://pan.baidu.com/s/1gdkvvu7