第三步:AutoController--通用自动增删查改

我的春秋痴梦第三步:

让所有的增删查改自动化,

                不用每次都实例化一个controller然后郁闷的写增删查改的方法。

效果:

根据url 得到要操作的对象,自动对model属性过滤换转,完成CURD生成对应的回传给view。

我的思路:

  @1 根据 提交的 url    /admin/article/create
  @2 实例化 article 对象   
  @3 根据 admin 和 用户找到  article 的限制
  @4 根据限制 过滤article 
  @5 再交给autoaction 即 直接 增改  
  @6 保存和上传(图片 文章 的话)
  @7 根据url对象返回页面

  @1 分析提交的 url    /admin/article/create   得到对象

  @2 实例化 (article) 对象     

  @3 根据 (article)对象 权限 找到  (article) 的限制(使用xml)  

  @4 根据限制 过滤(article)对象 

  @5 转换和上传(有图片之类的话)  

  @6 再交给auto controller即直接 增改   

  @7 根据url对象返回页面

 

 

整个想法比较简单。和之前那篇一样让程序更通用更自动化。

其实一开始接触MVC的时候就又这个想法了,当时没想好该怎么做增改这两块。

前段时间看了老D分析Suteki.Shop 介绍了 里面一个自动脚手架

两个周前我把他定下计划之中 I will make it!

废话不多说。

@1 可以想我一样自己分析url  也可以取得 route 里面的 controller的值

 

按指定 格式 切割 字符串
   
   
/// <summary>
/// 按指定 格式 切割 字符串
/// </summary>
/// <param name="content"></param>
/// <param name="sp"></param>
/// <returns></returns>
public static List < string > splitString( this string content, char sp)
{
if ( string .IsNullOrEmpty(content))
{
return null ;
}
List
< string > zhan2 = new List < string > ();
string temp = "" ;
foreach (var s in content) // content 的 格式是 /area/Article/show/1
{
if (s == sp)
{
zhan2.Add(temp);
temp
= "" ;
}
else
{
temp
+= s;
}
}
zhan2.Add(temp);
return zhan2;
}

 

当然 在这里 我并不推荐这样.直接取值更方便。

 @2 实例化(article) 对象并装配进去表单的值

 

代码
   
   
#region @2 实例化 article 对象 ===============================@2
modelvalueDictionary
= modelvalueDictionary.Init(req); // // 装载字典
if (modelvalueDictionary.Count == 0 )
{ _errmsg
= " 没有发现任何值 " ; return modelname; }
#endregion
#region ========================================自动装配 所有
foreach (var propertyInfo in modeltype.GetProperties()) // 赋值 遍历Article 属性
{
string val = null ;
Type convertType
= propertyInfo.PropertyType; // 目标类型
try
{ val
= modelvalueDictionary[propertyInfo.Name.ToLower()]; } // 目标值
catch (Exception) { }
if ( ! string .IsNullOrEmpty(val))
{
if (propertyInfo.PropertyType.IsNullable()) // 如果是 可空则 转换
convertType = propertyInfo.PropertyType.ToNonNullable();
var changedval
= Convert.ChangeType(val, convertType);
propertyInfo.SetValue(model, changedval,
new object [ 0 ]);
}
}
#endregion

 

在上一篇中我提到了不知道如何转换可空类型后来发现了这篇文章 感谢乐于分享的牛人们。(感谢cnblogs)

其中一个自己写的Init的扩展类似前一篇,就不瞎贴代码了。获得一个对象类似前一篇的根据string类型,

得到类型都是静态工厂直接new一个出来。

 

 @3 根据(article)对象用户的权限 找到  (article) 的限制和转换(使用xml)  

    @3.1 我这里选择了xml没有使用加attribute的方式,为的是更改后不用重新编译。

 

modelfilter
   
   
<? xml version="1.0" encoding="utf-8" ?>
<!--
1 action up => type jpg
2 function => par
-->
< models >
<!-- model name -->
< model name ="Article" >
<!-- 版本模型属性 1来自哪个 id (id由url转换) ,权限,版本什么的 -->
< modelattr id ="xxxx" role ="everyone" >
<!-- validata="int,>,5,过短,不能为空"验证信息: 1表达式 2出错信息可以 堆叠 -->
< FullTitle validata ="int,>,5,过短" validata2 ="!=null,不能为空" class ="myval1" />
< ShortTitle function ="setvalue,1,不能赋值" class ="myval1" />
<!-- 上传: 1上传后的路径 2格式 all ,type1 具体定制在 另一块 3出错信息 -->
<!-- <IsAudit fileup="url1,jpg,上传失败" /> -->
<!-- 方法执行:方法全在filter下定义 1方法名2参数 :self 是指调用者自身3出错信息 -->
<!-- <ArticleType function="md5,self,无法加密" validata="notNull,不能为空"/> -->
</ modelattr >
</ model >
< model name ="Flash" >
< modelattr id ="xxxx" role ="everyone" >
< picUrl fileup ="/UpFile/,*,上传失败" />
</ modelattr >
</ model >
< coustum >
< modelattr id ="sss" >
< item class ="myval1" validata ="int,>,5,过短" validata2 ="!=null,不能为空" />
</ modelattr >
</ coustum >
</ models >

 

 这里我的想法比较多,但是很多都还没有实现。

 比如根据url生成验证的id版本,根据权限选择不同的url,类似html的css 可以自定义 验证和转换。

   @3.2 再来看看 Linq 2 XML 进行读取和解析 xml  

Linq2XML
   
   
var mp = HttpContext.Server.MapPath( " ~/modelFilter/modelFilter.xml " );
XMLHelper xmlHelper
= new XMLHelper(mp);
var xe5
= xmlHelper.GetByModel(modelname, modeltype, rolegp);
var fileups
= xe5.Where(a => a.Attribute( " fileup " ) != null );
// <FullTitle validata="Length&gt;,5,过短" validata2="!=null,不能为空" />b
foreach (var element in fileups) // <DownUrl fileup="/UpFile/,*,上传失败" />
{

我的xmlHelper

XMLHelper
   
   
public class XMLHelper
{
public XElement xElement;
public XMLHelper( string path)
{
if ( string .IsNullOrEmpty(path))
throw new Exception( " path is null " );
xElement
= XElement.Load(path);
}

public IEnumerable < XElement > GetByModel( string modelname, Type modeltype, string role)
{
var xe3
= xElement.Elements().Where(a => a.Name == " model " && (a.Attribute( " name " ) != null && a.Attribute( " name " ).Value == modelname));
// <modelattr id="xxxx" role="everyone" validata="notNull"> 根据 权限 和 版本 url 得到对应的 验证 信息
var xe4 = xe3.Elements().Single(a => a.Name == " modelattr " && (a.Attribute( " role " ) != null && a.Attribute( " role " ).Value == role));
var xe5
= xe4.Elements().Where(a => modeltype.GetProperty(a.Name.LocalName) != null );
return xe5;
}
}

比较简陋 。。我是实用主义。

这样我们就可以在

  
  
foreach (var element in fileups){}// <DownUrl fileup="/UpFile/,*,上传失败" />  

中间专心写自己的处理了。

 @3.3延迟执行 

    在这里的时候我,我突然发现如果在这里以检查上传没问题就即时上传的话,可能他并没有通过后面的检查

而导致白白的消耗性能和硬盘。这里我先把要执行的方法先保存起来。(感谢重典兄的指点)

 

  
  
private List < Func < bool >> functions = new List < Func < bool >> ();

 

@4 根据限制 过滤(article)对象  

使用非常简单 依次添加,遍历执行即可。整个东西有3个需要做的,

第一个是文件上传 

第二个指定转换

第三个验证,验证你也可以用其他的,比如分离自带的那个验证为自己用。

 

文件上传
   
   
#region 文件上传
List
< string > list = element.Attribute( " fileup " ).Value.splitString( ' , ' );
var httppostfile
= req.Files.Get(element.Name.LocalName); //
functions.Add(() =>
{
try
{
FileUp fileUp
= new FileUp(httppostfile, this .Server.MapPath( " ~/UpFile/ " ));
if (fileUp.errormessage != "" )
{
_errmsg
+= fileUp.errormessage;
return false ;
}
fileUp.Up();
// 把属性装配上去
var changedtype = modeltype.GetProperty(
element.Name.LocalName).PropertyType;
// 1 得到属性 的值
string re1 = fileUp.downpath;
// 2 转换为 nullable // 3 赋值
modeltype.GetProperty(
element.Name.LocalName).SetValue(model, re1.toType(changedtype),
new object [ 0 ]);
return true ;
}
catch (Exception)
{

_errmsg
+= list.LastOrDefault();

}
return false ;

});
#endregion

 

指定方法
   
   
#region function
var pif_filter
= element.Attribute( " function " ); // 得到 属性
List < string > list = pif_filter.Value.splitString( ' , ' ); // 切割 参数
// 延迟加载 方法
functions.Add(() =>
{
try
{
// 构造方法和参数
Type type = typeof (Filter);
Filter filter
= new Filter();
MethodInfo methodInfo
= type.GetMethod(list[ 0 ]);
var parameters
= new object [ 1 ];
parameters[
0 ] = list[ 1 ];
var re1
= methodInfo.Invoke(filter, parameters).ToString();
if ( ! string .IsNullOrEmpty(re1))
{
// 赋值
var changedtype = modeltype.GetProperty(
element.Name.LocalName).PropertyType;
modeltype.GetProperty(
element.Name.LocalName).SetValue(model, re1.toType(changedtype),
new object [ 0 ]);

}
return re1 != null ;
}
catch (Exception e)
{
_errmsg
+= list.LastOrDefault();
}
return false ;
}
);
#endregion

验证我这里就没有贴了比上面两者都简单 。

指定方法的执行我采用的是调用我指定的一个对象下面的方法,本来 是想调用任意的,在xml那里写全对象的

namespace那些就可以调用,后来还是放弃了,感觉不实用。方法也只是一个单参数的方法。比如

md5加密和指定转换 普通用户发的文章为 未审核等。 

@5 保存和上传(有图片之类的话) 

 

  
  
var result = functions.All(a => a.Invoke()); // 都满足 返回 true

 

 @6 再交给auto controller即直接 增改  

 

  
  
var ir = IRR.GetRepository(urlHelper.modelName.str2type());
ir.InsertOnSubmit(model);
ir.SubmitChanges();

 

@7 根据url对象返回页面。这里给出我在controller中的实现:

 

代码
   
   
[HttpPost]
[ValidateInput(
false )]
public ActionResult Create( object t)
{
var model
= Created();
#region // @5 再交给autoaction 即 直接 增改
try
{
if (ModelState.IsValid)
{
if (_errmsg != "" ) return View(t); // 验证
Ir.InsertOnSubmit(model);
Ir.SubmitChanges();
return RedirectToAction( " list " ); // can't use strongly typed redirect here or the wrong controller name will be picked up
}
return View(model);
}
catch (Exception e)
{
Response.Write(e.ToString());
return View(model);
}
#endregion
}

 

提醒一下

1暂时那个    ModelState.IsValid 验证没有任何意义,因为传进来的model是object。

2如果不知道我那个 public IRepository Ir;怎么出来的可以参见我的上一篇。

在这里可以写成

 

  
  
public class AutoController < T > : Controller where T : class , new ()

 

就可以使用验证了。我不这样做是因为 我不想每次都要实例化一个。来模板继承。

但是目前我采用的做法仍然是 依靠一个 具体类 继承 我那个自动类。然后让原本访问具体类的增删查改方法的

去访问自动类了。而这时我们只需要在xml里面写明规则那么一切OK。

至此 问题依然 没有解决 那就是 由于 依托于具体类继承自动类。每次还是得实例化类。

(我是后台:可不可以不要那么多XXXcontroller文件啊!)

 

我们其实可以在 Global.asax 那里 拦截请求。

不给controller执行 而是 构造自己的 RouteHandler 解析路由 和HttpHandler 转到view

 此处参考重典兄的 route 

 实现的思路

1在 global 处 截断 指定格式的请求

2构造自己的RouteHandler 进行解析

3 分发给对应的 httphandler

 

  
  
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add(
new Route( " {page}.np " , new MyRouteHandler())); // 解析.aspx
}

 

我指定以.np后缀访问的都是我自动类处理的天下。

我的想法是这样  /area(Default)/model/action/id.np 

同时对应view页面的位置统一。其实现非常简单。参看重典兄的就可以做出来。

这时我们会遇到几个问题

1如何传值到页面 viewdata 肯定不行了,因为controller与我们渐行渐远。

2此时view上的XXhelper ,HTML 的方法都没了,以前构造html的方法都没了。

对于第一点 我们可以使用session 只需要加上IRequiresSessionState

 

  
  
public class MyPage : IHttpHandler, IRequiresSessionState

 

这里有个有趣的问题,但是我又不知道怎么回事。在构造函数执行的时候,session null不可用。

而构造完后才开始有session。这是怎么回事呢。

对于第二点我就有点无奈了。我参考源码,暂时还没把他整个方法移植过来。郁闷的是,由于那个是模板的,而我们

已经没有了页面MODEL了。所以比较麻烦。很多方法里也内嵌了MODEL。即时勉强移植过来还是会存在一些不能用的

语法但是又存在。感觉不爽。

 

 

走到这里的时候我感觉到很吃力。 丢掉了controller之后,我还有一大堆view丢不掉,还有怎么和以前的路由兼容?

不然的话整个view上路由的重写也有点小麻烦。

感觉使用框架的便利,自己也被绑架到框架上了。自己的代码原始积累应该是与框架无关的啊!这样才能形成自己的

代码库。

最后由于无法丢弃以前的view暂时使用前一种方法,来优化自己的CMS。走到第三步。这次的感觉有点沉重。

越发觉得自己的渺小和对知识认识的浅薄,当时以为委托 很简单,自己遇到了问题需要解决才发现,好多其实都

没有理解好。另一点沉重也许是对未来的一种迷茫吧。基于框架的代码还是我们的代码吗?昨天有个牛人说他为了

不让自己的代码有隐患,尽量不用第三方的框架SSH那些都不用。而是做自己的基于基础类库的原始积累。

也许JAVA和.NET不一样吧。我始终坚持,一步一步优化,一步一步积累。把时间精力花在最需要解决问题的地方,

慢慢的用自己的代码替换别人的框架,像我这次这样替换掉controller,也许有一天就用自己的东西替换了

mvc了呢。虽然没有mvc的通用,但最合适自己。不是嘛?


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本火锅店点餐系统采用Java语言和Vue技术,框架采用SSM,搭配Mysql数据库,运行在Idea里,采用小程序模式。本火锅店点餐系统提供管理员、用户两种角色的服务。总的功能包括菜品的查询、菜品的购买、餐桌预定和订单管理。本系统可以帮助管理员更新菜品信息和管理订单信息,帮助用户实现在线的点餐方式,并可以实现餐桌预定。本系统采用成熟技术开发可以完成点餐管理的相关工作。 本系统的功能围绕用户、管理员两种权限设计。根据不同权限的不同需求设计出更符合用户要求的功能。本系统中管理员主要负责审核管理用户,发布分享新的菜品,审核用户的订餐信息和餐桌预定信息等,用户可以对需要的菜品进行购买、预定餐桌等。用户可以管理个人资料、查询菜品、在线点餐和预定餐桌、管理订单等,用户的个人资料是由管理员添加用户资料时产生,用户的订单内容由用户在购买菜品时产生,用户预定信息由用户在预定餐桌操作时产生。 本系统的功能设计为管理员、用户两部分。管理员为菜品管理、菜品分类管理、用户管理、订单管理等,用户的功能为查询菜品,在线点餐、预定餐桌、管理个人信息等。 管理员负责用户信息的删除和管理,用户的姓名和手机号都可以由管理员在此功能里看到。管理员可以对菜品的信息进行管理、审核。本功能可以实现菜品的定时更新和审核管理。本功能包括查询餐桌,也可以发布新的餐桌信息。管理员可以查询已预定的餐桌,并进行审核。管理员可以管理公告和系统的轮播图,可以安排活动。管理员可以对个人的资料进行修改和管理,管理员还可以在本功能里修改密码。管理员可以查询用户的订单,并完成菜品的安排。 当用户登录进系统后可以修改自己的资料,可以使自己信息的保持正确性。还可以修改密码。用户可以浏览所有的菜品,可以查看详细的菜品内容,也可以进行菜品的点餐。在本功能里用户可以进行点餐。用户可以浏览没有预定出去的餐桌,选择合适的餐桌可以进行预定。用户可以管理购物车里的菜品。用户可以管理自己的订单,在订单管理界面里也可以进行查询操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值