基于.net mvc的校友录(六、codefirst的使用以及班级模块的关键部分实现)
通过EF将新用户存入数据库
这里,探讨一下如何使用EF的code first将数据存入数据库,以及如何对用户的密码进行md5加密与验证。下面是用户登陆的前台代码。
@using (Html.BeginForm("ToLogin", "Log"))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<div>
<div>
<section id="loginForm">
<span style="font-size:14px;color:red">
@ViewBag.error</span>
@Html.TextBoxFor(m => m.UserName, new { @class = "logoText" })
</div>
详细代码见附录
</div>
}
此代码是前台登陆页面中的form部分,Html.BeginForm是定义一个Form,可以直接用<form>标签代替。@ViewBag.error是后台传过来的数据,目标是在用户登陆错误的时候,再次显示此页面时,ViewBag.error将带有用户名与密码组合不错误等类似提示信息,呈现给用户。@html.textboxfor其实就是一个生成<input>标签的方法,这个之前有讲过,此处不再多说。看一下后面的new{},这是一个匿名类,其实就是一个临时对象,因为要控制input的样式,不然自动生成的input会破坏登陆页面风格,这里给它传去了一个对象,当它发现对象有一个属性与它的属性名一样的时候,它会把那个属性的值给自己的属性赋上,然后就是UserName的input标签有了logoText这个类,在css中可以通过.logoText来控制这个input。@Html.ActionLink是用来生成超链接的,一般没必要用,直接用a标签就可以了,这地方测试性的使用了一下。当用户提交了这个表单之后,数据会封装在request中,以post方式传送到后台。后台的接受方法代码如下:
public ActionResult ToLogin(LoginModel lm)
{
using (AlumniBookModel db = new AlumniBookModel())
{
lm.Password = Sleep.GetMD5(lm.Password);
var query = from m in db.User
where m.UserName == lm.UserName && m.Password== lm.Password
select m;
if (query.ToList<User>().Count() > 0)
{
详细代码见附录
}
}
ViewBag.error="您的用户名与密码组合有误,请重试";
return View("Login");
}
ToLogin方法是控制器LogController的方法,当前台用户提交登陆表单的时候,会以post方式传到这个方法上。方法执行的时候,会先实例化一个数据库上下文,就是AlumniBookModel的实例db。这个db可以理解成是系统的数据库。ToLogin的方法参数是LoginModel类型的,而登陆页面代码最上面的有一句代码是@model AlumniBook.Models.LoginModel,也就是说登陆页面是强类型页面,而具体的类型就是LoginModel,这个LoginModel并不是数据实体模型类,它不存在于数据中,只用来作为前后台传输数据的载体。ToLogin方法会从LoginModel的实例lm中取得password,然后调用封装在SLeep类中的静态方法GetMD5来将密码转成32位md5密文。然后,下面那一句就是经典的linq了,以var来定义一个动态类型变量query,这个query其实是一个查询类型,查询类型可以理解成是一个sql语句类似的东西,它在被使用时会自动执行查询。也就是下面在它调用ToList()方法的时候,它从数据库中查询用户名与密码同lm相同的实体,如果结果的count不大于0,那么说明这个用户不存在,或者说用户名密码组合不正确。此时就可以判定用户登陆失败了,然后在ViewBag.error中赋值"您的用户名与密码组合有误,请重试";再return View("Login")。这样,用户会再次返回到登陆页面,不同的是,这次ViewBag.error中有数据,会显示在页面中,用户会看见登陆失败的提示。
若是用户密码组合正确,那么将检测lm的RememberMe属性是否为true,这个属性由用户登陆时是否选择记住我而决定。若是用户选择了,那么会在cookies里面存入用户名。保存cookies方面.net不如thinkphp做得好用,.net需要先实例化一个cookie,然后将数据存入,再设定它的过期时间,然后加入到response的cookies中,返回给用户之后,用户的浏览器会将此cookies保存。若是用户没有选择记住我,那么,不管cookies中有没有用户,都会将这个值删除,这也是选择了记住我的用户取消自动登陆的一种方式。在其它需要验证的地方,也都是在方法上面加上IsLoged特性。下面来看一下工具类内容,因为上面已经用到了。
public static bool IsMyUser(string name)
{
using (AlumniBookModel db = new AlumniBookModel())
{
var query = from m in db.User
where m.UserName == name
select m;
if (query.ToList<User>().Count > 0)
{
return true;
}
}
return false;
}
这个方法从AlumniBookModel中取user里面username与name相同的User实体,然后判定个数,若个数大于0,则说明用户存在,用户名与密码正确。
public static string GetMD5(string myString)
{
MD5 md5 = new MD5CryptoServiceProvider();
byte[] fromData = System.Text.Encoding.Unicode.GetBytes(myString);
byte[] targetData = md5.ComputeHash(fromData);
string byte2String = null;
详细代码见附录
return byte2String;
}
这里使用了 MD5CryptoServiceProvider()实例化了一个MD5对象,然后将字符串转化成byte数组,也就是字节流,然后使用computeHash计算出md5值,最后md5码每一个数字转化成字符,拼接成字符串,返回最终结果。
班级的创建与加入
班级的操作非常多,包括查找,加入,创建,删除,退出等。这里不再一个个说明,只说明如何创建与加入。当用户在前台点击创建新班级的时候,会跳转到一个创建班级的页面。这个页面中要求输入的信息如图5-7所示:
创建班级表单
输入班级名称,选择要上传的班级封面图片,然后选择学校点击提交就可以新建班级了。在下拉列表中没有学校的时候,可以点击创建新学校,然后输入学校名称,进行学校创造,然后再在下拉列表中选择刚刚新建的学校名称。创建学校使用的是ajax,后面会进行说明。当此表单提交之后,将会把此页面的强类型实体传到后台,此实体为@model AlumniBook.Models.CreateClass,CreateClass也就是一个视图模型,只作数据传输用。在此说明书的开头,可以找到此类图。
public class CreateClass
{
public Class cl { get; set; }
public string ChoseSchoolName { get; set; }
public List<School> sc { get; set; }
}
它包含了一个Class,存放学校名称的字符串类型,要注意的是,本系统功能不会再加,为了尽量减少数据冗余,能不使用id的都没有使用,比如用户实体,直接用的是不可能重复的用户名作为key,然后学校是以学校的名字作为key。所以,此处第二个字段,几乎就可以认为是一个学校了,因为它可以确定唯一的一个学校。第三个字段是一个School列表,List一个集合。它用来传送多个班级。
public ActionResult ToCreate(CreateClass cc)
{
using (AlumniBookModel db = new AlumniBookModel())
{
……
{
HttpPostedFileBase fc = Request.Files[0];
if (fc != null)
{
newClass.ClassCoverPath =FileHelper.SaveFile(fc);
}
……
db.Class.Add(newClass);
db.SaveChanges();
return RedirectToAction("Index", new { className = newClass.ClassName });详细代码见附录。
ToCreate是后台接受表单的方法,参数为CreateClass类型的cc。在实例化AlumniBookModel类型的db之后,实例化一个新的Class类newClass,这个类在修改之后,把它存放到db中。首先,先验证这个班级是否已经存在,若是存在,则跳转到Error页面,并将title、msg信息放到ViewBag中传过去显示给用户。若是班级不存在,那么将执行创建班级的操作,先判定是否有图片文件,有的话,就会用工具类将文件保存,然后重新以时间命名,返回新的名称给newClass,放到ClassCoverPath中。将cc中的Class带来的数据全部传给newClass,最后将newClass添加到实体Class中,然后执行db.SaveChanges()。此时,刚刚的newClass已经保存到数据库里面了。
return RedirectToAction("Index", new { className = newClass.ClassName })与之前用的return View()不一样,它是跳转到一个控制器的方法,并且带着参数,参数不是直接传递的,而是封装在一个对象中,这里用匿名类将数据封装了进去,带去的是班级名称,因为跳转到Index的时候,需要一个班级名,以进入指定的班级,而当前进入的正是刚刚新建的班级。
下面说一下,刚刚用到创建新学校的ajax代码。此处的弹出窗口使用了JQUERY UI控件,js也使用了JQUERY库。当用户点击创建新学校的时候,会触发js事件$(" #createNewSchool"). button().click(function () { $ (" #newSchoolBox " ) .dialog(" open " ) ; } ) ;,然后会打开这个dialog,它的定义代码为:
$("#newSchoolBox").dialog({
autoOpen: false,
width: 400,
height: 180,
buttons: [ { text: "Ok", click: function() {
这是这个声明的前部,autoOpen表示是否默认打开,然后是高宽,最后是一个按钮,这个按钮直接定义了事件方法。
创建新学校对话框
弹出窗口中有一个ok按钮,当用户点击之后,会触发如下代码:
$.ajax({
type: 'POST',
url: "/Class/ToCreateNewSchool",
data: { 'newSchoolName': $("#newSchoolName").val() },
success: function (data) {
if (data.result == true) {
alert("学校添加完成");
location.reload();
} else if (data.result == false) {
alert("学校已存在,请直接选择");
$("#createNewSchoolBox").dialog("close");
} else {
alert(data.result);
}
},
dataType: 'json',
});
这是一段jquery的ajax代码,也就是传说中的异步刷新,在说明书开始部分也有讲过ajax这个技术,它给bs带来了前所未有的变化,这是一场革命,webQQ,谷歌地图等,无不是它的杰作。在这里,data是要发送的数据,这个数据的类型要是json格式,$("#newSchoolName").val() 是将学校名称的input标签值取出,放在这里面,然后当执行到此代码的时候,浏览器会向服务器发送一个包含了这个对象的请求,请求到了服务器端之后,服务端会验证学校是否已经存,若存在则返回result=false的数据对象,然后此代码中的判定语句会执行到alert,即弹出提示信息告诉用户,学校已经存在,可以直接选择。否则,控制器会创建一个学校,然后将result=true的对象发到前台来,此代码接受到了之后,执行alert("学校添加完成"); location.reload();然后此页面刷新,在下拉列表中就可以看见刚刚添加的学校了,选择即可。
转载请标注原地址:http://www.cnblogs.com/ensleep/tag/%E5%9F%BA%E4%BA%8E.net%20mvc%E7%9A%84%E6%A0%A1%E5%8F%8B%E5%BD%95/