作者: 永恒の_☆ 地址: http://blog.youkuaiyun.com/chenghui0317/article/details/9409457
一、自定义route执行规则
在一个route中,通过在大括号中放一个占位符来定义( { and } )。当解析URL的时候,符号"/"和"."被作为一个定义符来解析,而定义符之间的值则匹配到占位符中。route定义中不在大括号中的信息则作为常量值。
下面是一些示例URL:
Valid route definitions | Examples of matching URL | |
{controller}/{action}/{id} | /Products/show/beverages | |
{table}/Details.aspx | /Products/Details.aspx | |
blog/{action}/{entry} | /blog/show/123 | |
{reporttype}/{year}/{month}/{day} | /sales/2008/1/5 |
通常,我们在Global.asax文件中的Application_Start事件中添加routes,这确保routes在程序启动的时候就可用,现在我们根据之前默认的配置,在它的基础上自定义一个route执行规则。
那就按照javaee的struts2的常用匹配路径来,比如http://localhost:8080/web/namespace/actionClass!actionName.action
上面不是说 定义的规则不在大括号内的信息将作为常量值,那么我们需要改变的紧紧是控制器和action动作方法 这两个值,其他的都不变。
配置如下:
public static void RegisterRoutes(RouteCollection routes)
{
//忽略对.axd文件的Route,也就是和WebForm一样直接去访问.axd文件
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//自定义一个route规则,这个必须放在默认配置的上面,为什么,因为上面的配置入口比较窄,放在下面它去默认配置里面找了,会报404
routes.MapRoute(
"MyRoute",
//这里是以java的struts2风格定义的route规则,system相当于命名空间(本来想用system/{controller}但是 报错说不支持多个controller出现在url中),{controller}相当于action类,{action}相当于action方法,.action相当于调用的后缀
//可以在浏览器中输入http://localhost:1950/system/User/Index.action看看效果
"system/{controller}/{action}.action",
new { controller = "Home", action = "Index" }
);
routes.MapRoute(
"Default", // Route name 顾名思义,可以定义多个route规则,用name区分
//这里的url会根据参数跳转到对应的controller,访问对应的action方法,然后访问的页面,按照约定应该是在Views下面的{controller}下的{action}文件显示。
//最开始感觉这个id没什么用 并且后面随便输入任意字符后可以访问action,后来发现这里可以根据具体的参数返回不同的视图
//这里就和javaee的mvc不一样了,如果要做成一样也不是不可以,只不过核心控制器那里的逻辑判断要发生改变了
//特别的,因为下面配置的路径是单斜杠 分开的,那么浏览器中指定的时候也只能是单斜杠分割才行
"{controller}/{action}/{id}", // URL with parameters
//如果没有指定具体的url,将进入home的控制器,处理index的请求
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
二、做一个简单的注册登录的例子,方便理解MVC
首先做一个注册功能,先看看注册页面Register.cshtml 如下:
@*@model 是Razor的一个指令,实现视图对强类型的引用。*@
@model mvc.Models.RegisterModel
@{
ViewBag.Title = "Register";
}
<h2>Register</h2>
<h2>@ViewBag.message</h2>
@using (Html.BeginForm("Register","User"))
{
<div>
用户名:@Html.TextBoxFor(model => model.UserName)
</div>
<div>
密码:@Html.PasswordFor(model => model.Password)
</div>
<div>
确认密码:@Html.PasswordFor(model => model.ConfirmPassword)
</div>
<div><input type="submit" value="Register" /></div>
}
顶部的@model mvc.Models.RegisterModel 其实就可以看作是创建了命名空间为mvc.Models.RegisterModel的model对象,然后下面的 @Html.TextBoxFor(model => model.UserName)
TextBox 是普通的TextBox 控件,TextBoxFor 是普通的TextBox给别人,给谁呢? 给后面的参数model,model接收到参数指向它的属性 UserName
同理 下面的密码也一样。
然后创建UserController 控制器,定义如下方法:
[HttpPost] //mvc不支持方法的重载,但是当方法名相当的时候 ,可以用httpPost和httpGet来区分。
public ActionResult Register(Models.RegisterModel registerModel)
{
ViewBag.Message = "Login result";
if (registerModel != null)
{
if (registerModel.Password == registerModel.ConfirmPassword)
{
Models.UserModel userModel = new Models.UserModel();
userModel.UserName = registerModel.UserName;
userModel.Password = registerModel.Password;
Session["loginUser"] = userModel;
ViewBag.Result = "Register Success";
}
else
{
ViewBag.Result = "Register Fail.. password and confirmPassword is not equals";
}
}
else {
ViewBag.Result = "Register Fail.. ";
}
return View("result");
}
这样子 ,注册成功后 注册的用户信息就保存到session内置作用域 中了。
然后再做一个登录操作:
LoadLogin.cshtml 页面如下:
@model mvc.Models.UserModel
@{
ViewBag.Title = "LoadLogin";
}
<h2>@ViewBag.message</h2>
@using (Html.BeginForm("Login","User",FormMethod.Post))
{
<div>
用户名:@Html.TextBoxFor(model => model.UserName)
</div>
<div>
密码:@Html.PasswordFor(model => model.Password)
</div>
<div><input type="submit" value="Login" /></div>
}
@using{} 可以看作是导入操作,导入一个form表单,用Html.BeginForm()中指定调用的controller, action等等参数,使用 ctrl + shift + 空格在方法名括号后使用可以清楚看到各个参数的含义,另外 FormMethod.Post 指定的提交方式也可以在 controller控制器中对应方法的顶部加上[httpPost] ,效果一样的。
接下来,处理登录,代码如下:
[HttpPost]
public ActionResult Login(Models.UserModel userModel)
{
ViewBag.Message = "Login result";
if (userModel != null)
{
Models.UserModel loginUser = (Models.UserModel)Session["loginUser"];
if (loginUser!=null && userModel.UserName == loginUser.UserName && userModel.Password == loginUser.Password)
{
ViewBag.Result = "Login Success";
return View("result");
}
}
ViewBag.Result = "Login Fail";
return View("result");
}
加一个Model, UserModel:
public class UserModel
{
public int UserID { get; set; } //用户编号
public string UserName { get; set; } //用户名
public string Password { get; set; } //密码
public int Sex { get; set; } //性别,0男,1女
public int Age { get; set; } //年龄
public int Political { get; set; } //政治面貌
public int Height { get; set; } //身高
public int Weight { get; set; } //体重
public string Graduated { get; set; } //毕业院校
public string Professional { get; set; } //专业
public DateTime GraduatedDate { get; set; } //毕业日期
public string Address { get; set; } //现住地址
public string Phone { get; set; } //联系电话
public string ImagePath { get; set; } //头相地址
public string Other { get; set; } //其他描述
}
就是这么简单。
接下来 说个有意思的功能:加载页面详情。
前面在route定义规则的时候,路径匹配是:"{controller}/{action}/{id}",
之前 一直是 使用前面两个参数,后面的没管,其实它有用的,就是作为参数传递给action方法完成后续操作的。之前有一个现在 localhost:1950/Home/About/sdfdsfds About这个action名字后面的字符串取任意字符都没问题 就是因为这个id替代的作用,如果去掉配置的id就要出错了。
UserController中的Detail(id)代码如下:
//用这种方式定义方法的话,参数只能是在Global中定义才行, 每次都必须传递参数,否则报错
//http://localhost:1950/User/Detail/0
public ActionResult Detail(int id)
{
Models.UserModel userModel = new Models.UserModel();
if (id == 0)
{
userModel.UserName = "UserName";
userModel.Password = "Password";
userModel.Sex = 0;
userModel.Age = 30;
userModel.Height = 170;
userModel.Weight = 70;
userModel.Graduated = "Graduated";
}
else
{
userModel.UserName = "Underfined";
userModel.Password = "Underfined";
userModel.Sex = 0;
userModel.Age = 0;
userModel.Height = 0;
userModel.Weight = 0;
userModel.Graduated = "Underfined";
}
return View("Detail",userModel);
}
//所以 只能通过传统方法接收参数然后处理掉
//http://localhost:1950/User/show?id=1
public ActionResult Show()
{
//request接收参数
if (Request["id"] != null)
{
int idValue = int.Parse(Request["id"]);
return Detail(idValue);
}
return null;
}
注意,return View的时候 我传递了userMode对象,所以View还有这个功能。
Detail.cshtml代码如下:
//顶部可以不用导入UserModel 模板也可以显示。
@{
ViewBag.Title = "Detail";
}
<h2>Detail</h2>
<div>用户名:@Model.UserName</div>
<div>密码:@Model.Password</div>
<div>性别:
@if (Model.Sex == 0)
{
@:男
}
else
{
@:女
}
</div>
<div>年龄:@Model.Age 岁</div>
<div>身高:@Model.Height CM</div>
<div>体重:@Model.Weight KG</div>
<div>毕业院校:@Model.Graduated</div>
<a href="../LoadUpdate/1">Update</a>
最后看看修改的代码:
控制器里面没有什么可看的,主要看看LoadUpdate.cshtml页面。
@model mvc.Models.UserModel
@{
ViewBag.Title = "Update";
}
<h2>Update</h2>
@using (@Html.BeginForm())
{
<div>
用户名:@Html.TextBoxFor(model => model.UserName, new { @style = "width: 200px" })
</div>
<div>
密码:@Html.PasswordFor(user => user.Password)
</div>
<div>
性别: 男 @Html.RadioButtonFor(user => user.Sex, 0, new { @name = "sex", @checked = "true" })
女 @Html.RadioButtonFor(user => user.Sex, 1, new { @name = "sex" })
</div>
<div>
年龄:@Html.TextBoxFor(user => user.Age) 岁
</div>
<div>
身高:@Html.TextBoxFor(user => user.Height) CM
</div>
<div>
体重:@Html.TextBoxFor(user => user.Weight) KG
</div>
<div>
毕业院校:@Html.TextBoxFor(user => user.Graduated)
</div>
<div>
<input type="submit" value="提交" /></div>
}
这样,一个简单的注册登录功能算是大功告成了。