强烈推荐YangMVC:一个易学易用高效便捷的MVC和ORM框架
ccwgpt 2024-09-13 16:17 86 浏览 0 评论
开发目的
@copyright 杨同峰 保留所有权利
本文可以转载,但请保留版权信息。
SSH框架配置复杂、难用。个人认为这不是一个框架应该有的样子。框架应该使用简单、配置简单、代码简洁。于是参照Django的一些特性,编写了这个MVC+ORM框架。
特性
- 大量的默认约定,避免了大量的配置
- 配置方便、使用便捷、易于上手
- 支持延迟加载技术的List
- 和JSTL无缝兼容
配置
- 新建一个Web Project(MyEclipse为例)
- 将以下jar放到WebRoot/Web-INF下面
- yangmvc-1.6-all-in-one.jar
- 下载地址
- http://git.oschina.net/yangtf/YangMVC/attach_files
- 在web.xml中(web-app标签内)加入
<filter> <filter-name>yangmvc</filter-name> <filter-class>org.docshare.mvc.MVCFilter</filter-class> <init-param> <param-name>controller</param-name> <param-value>org.demo</param-value> </init-param> <init-param> <param-name>template</param-name> <param-value>/view</param-value> </init-param> </filter> <filter-mapping> <filter-name>yangmvc</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <context-param> <param-name>dbhost</param-name> <param-value>localhost</param-value> </context-param> <context-param> <param-name>dbusr</param-name> <param-value>root</param-value> </context-param> <context-param> <param-name>dbpwd</param-name> <param-value>123456</param-value> </context-param> <context-param> <param-name>dbname</param-name> <param-value>mvc_demo</param-value> </context-param> <context-param> <param-name>dbport</param-name> <param-value>3306</param-value> </context-param>
所有需要配置的都在这里了。这里做个简要说明
MVCFilter是我们MVC框架的入口。(不管是啥MVC框架都免不了这个)
它有controller和template两个参数。
controller 是你控制器存放位置的包名。 比如这里是org.demo 你建立的控制器都必须写在这个包中
template是你存放模板(视图)的地方。这个路径是相对于WebRoot即网站根目录的。
比如这里的配置(/view)是WebRoot下的view目录。
dbhost dbname dbusr dbpwd 是数据库的 地址、数据库名、用户名和密码。目前这个MVC框架只支持MySQL,后续会添加其他数据库的支持。
注意,模板目录(template参数所配置的值)以/开头,如/view。
YangMVC的第零个例子-HelloWorld程序
public class IndexController extends Controller { public void index(){ output("Hello YangMVC"); } }
他的作用就是显示一句话。如图
第零个例子的显示
IndexController来处理应用的根目录下的请求。 index方法来处理这个目录下的默认请求。
YangMVC第一个Demo
在org.demo包下建立此类:
public class BookController extends Controller { public void index(){ DBTool tool = Model.tool("book"); LasyList list = tool.all().limit(0, 30); put("books", list); render(); } }
在WebRoot/view/book/下建立一个index.jsp
其中核心的代码为
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> (此处省略一堆无关的HTML代码) <table class="table table-bordered"> <c:forEach var="b" items="${books }"> <tr> <td>${b.id }</td> <td>${b.name }</td> <td>${b.author }</td> <td>${b.chaodai }</td> <td>${b.tm_year }</td> <td> <a href='book/edit?id=${b.id}'>编辑</a> <a href='book/del?id=${b.id}'>删除</a> </td> </tr> </c:forEach> </table>
一个显示列表的网页就此搞定。访问应用目录下的book/目录即可显示出结果
这里写图片描述
你作出的结果可能没那么好看,这完全取决于css。
在YangMVCDemo / WebRoot / view / book / mvc.css 中有一个漂亮的表格定义。
你可以通过类似下面的语句来加入到网页中
<link href="view/book/mvc.css" rel="stylesheet">
注意路径要对。
说明:
这个BookController是一个控制器,它的每一个公共方法都对应一个网页(如果不想对应,你需要将其设为私有的)
Model和DBTool是整个ORM框架的核心。Model表示模型,它用来与数据库表相对应。在创建一个Model时,会指定对应的表名。
这里和Hibernate不同,Hibernate需要预先生成所有数据库表的对应类, 而这个Model可以与任何表格关联,而不需要预先生成任何一个类。 这正是YangMVC中的ORM的优势所在。
DBTool tool = Model.tool("book");
程序中使用Model的静态方法tool获取一个DBTool对象,tool传入的参数book是数据库的表名。
这样DBTool就和book表建立了关联。
LasyList list = tool.all().limit(0, 30);
伙计们快看,这是个LasyList,一个支持懒惰加载机制的列表。它是List类的子类,这也就是它为什么能在JSTL中使用foreach变量的原因。
首先我们调用了tool的all()方法,天哪,难道要加载book表的所有数据,兄弟不用害怕,在这个时候,它并没有进行任何数据的读写,指示记录了现在要访问book表的所有数据这一信息。 all()方法会返回一个LasyList对象。这么设计的原因是我们后面可以跟一连串的过滤方法。方便我们编程。我们可以写出这样的东西:
list = tool.all().gt("id", 12).lt("id", 33).eq("name","haha").like("author","王");
这个例子相当于执行了如下SQL语句:
select * from book where id>12 and id<33 and name='haha' and author like '%王%'
在上面的例子中, all()返回的LasyList又调用了它的limit方法,这一步仍然没有真正访问数据库。
那么访问数据库从哪里开始呢? 从你获取这个列表的一项时。
一个List,可以使用枚举的方法来访问
for(Model m : list){ }
也可以使用get方法来访问。如
Model m = list.get(12)
在你访问具体它的一个元素(Model)时,数据库查询才会启动。而且也不是将所有数据放到内存中。比如你通过上面for的方法枚举时,其实它是通过ResultSet的next游标在移动,所以它很高效!也避免了无用的数据库操作。
put("book",list)
该方法将查询得到的book塞入request中,在jsp网页中就可以使用JSTL来使用它。因为它是一个List,所以用forEach去访问他。
Model 的一个对象对应于数据库表的一行(一条记录),Model是一个Map的子类!!!,所以在JSTL中,你可以使用
${ b.name } 的方式来访问名为b的Model 的name项。 它相当于
Model m = .... m.get("name")
是不是很方便??? 真的是非常方便的。。
第二个Demo
添加书籍页面
public void add(){ DBTool tool = Model.tool("book"); //处理提交数据 if(isPost()){ //isPost Model m = tool.create(); //创建新的 Log.d(m); paramToModel(m); tool.save(m); put("msg","添加成功"); } //显示数据 renderForm(tool.create()); }
对应的/view/book/add.jsp (这是默认对应的模板地址)的核心内容
<div style="margin-left:100px"> <h1>添加书籍 ${msg }</h1> ${book_form } </div>
这里写图片描述
上面的例子控制器其实是对应两个页面。 在收到Get请求的时候显示表单,在用户提交数据时,做插入操作,并显示表单。(我们当然可以把这两个页面写到两个不同的方法中)
我们还是使用Model.tool获取一个DBTool。
先来看显示表单,就一句话
renderForm(tool.create());
tool的create方法会返回一个Model对象,这个对象和book表相关联(因为tool和book表关联)。
并将这个Model传递给renderForm方法。这个方法会根据book表格的元数据自动创建一个表格。
哇偶!
那么这个Form插入到网页的什么位置呢? 将 ${book_form } 放入网页中 即可。
如果来的是POST请求(使用isPost()方法来判断)
使用tool的create方法创建一个新的Model, 尽快还有其他创建Model对象的方式,但如果你希望插入,请尽量使用这种方式。
paramToModel(m) ,这个方法会自动查找表单中,名字与数据库字段名匹配的项,并自动赋值给Model的相应项。是不是很方便。。。
想起了Struts那悲催的功能定义。 泪奔。。。。
随后直接调用tool的save方法将其保存到数据库中!OK了!万事大吉!
细心的小朋友会问: 数据库中的字段名都是英文的如name,为什么在网页上显示的是中文???
看看我的数据库表格定义
CREATE TABLE `book` ( `id` int(11) NOT NULL auto_increment COMMENT '编号', `file_name` varchar(50) default NULL, `name` varchar(50) default NULL COMMENT '名称', `author` varchar(50) default NULL COMMENT '作者', `chaodai` varchar(50) default NULL COMMENT '朝代', `tm_year` varchar(50) default NULL COMMENT '年代', `about` longtext COMMENT '简介', `type` varchar(50) default NULL COMMENT '类型', `catalog_id` int(11) default NULL COMMENT '分类', PRIMARY KEY (`id`), KEY `catalog` USING BTREE (`catalog_id`) ) ENGINE=InnoDB AUTO_INCREMENT=912 DEFAULT CHARSET=utf8;
真相大白与天下,我是通过给字段加注释实现的这一点。只要你将数据库表格加上注释,它就会自动获取注释并显示,对于没有注释的字段,则会显示字段名。如那个扎眼的file_name
好了,这几行代码就搞定了输入表单和表单的处理。
第三个demo-编辑(自动创建的修改表单)
细心的朋友发现,我们是按照CRUD的逻辑来将的。下面是编辑网页。
public void edit() throws NullParamException{ DBTool tool = Model.tool("book"); //处理提交数据 if(isPost()){ //isPost Model m = tool.get(paramInt("id")); Log.d(m); paramToModel(m); tool.save(m); put("msg","修改成功"); } //显示数据 Integer id = paramInt("id"); checkNull("id", id); renderForm(tool.get(id)); }
HTML页面放在/view/book/edit.jsp中,核心代码只是将add.jsp中的添加二字改为了"编辑“二字。
<div style="margin-left:100px"> <h1>编辑书籍 ${msg }</h1> ${book_form } </div>
这个代码长了一点, 有17行。对于用YangMVC的,已经算够长的了。它仍然是两个网页!!!
你可以吧显示表单的代码和处理表单的分到两个方法中写。
先看显示数据。 首先使用paramInt方法获取URL参数id,我们就是要编辑id指定的书籍。
调用checkNull来检查一下。 在我的开发生涯中,遇到各种参数检查,所以这个功能是必须有的,如果checkNull不过,就会抛出一个异常。 这样做的目的是不要让这种参数检查干扰我们正常的逻辑。这不就是异常之所以存在的意义么?
如果缺少这个参数,页面会提示说缺少这个参数。
下面使用tool.get(id)方法来获取一个Model(一条记录)。这个方法是根据表格的主键进行查询,返回的不是列表而是一个具体的Model对象。在这里我建议主键应当是整数、且是数据库自增的。
renderForm传入一个model,这个model中有数据,就会被显示出来。
就这样。编辑功能写好了。
有的朋友问,如果不想用默认的表单怎么办? 那你自己写一个表单在你的模板里就是了。只不过,你可以先用这个方法吧表单生成出来,然后按你的意图修改就成了。这也节省大量时间啊。做过Form的请举手。
第四个DEMO-删除
public void del(){ Integer id = paramInt("id"); Model.tool("book").del(id); jump("index"); }
瞧瞧就这点代码了, 获取参数id,并调用tool的del方法删除。最后一句我们第一次见,就是跳转。跳转到同目录下的index这个默认页(显示的是书籍列表)
控制器创建
控制器是一个Java类,类有若干方法。在YangMVC的设计中,控制器的每一个公共的方法都映射对应一个网页。这样一个Java类可以写很多的网页。 方便管理。(当然,你也可以在一个控制器中只写一个方法来支持网页,这没问题(⊙﹏⊙)b)
所有的控制器都要继承 org.docshare.mvc.Controller 这个类。充当控制器方法的方法应当是没有参数没有返回值的。如上面demo所示。
public class IndexController extends Controller { public void index(){ output("Hello YangMVC"); } }
这些控制器都要写在配置所制定的package中,或者子package中。如在上面的配置中
<init-param> <param-name>controller</param-name> <param-value>org.demo</param-value> </init-param>
这个包为org.demo所有的控制器都要卸载这个包内。(你可以写到外面,但它不会管用O(∩_∩)O~)
路径映射
所谓路径映射就是要将 一个控制器(一个Java类)和一个网址建立关联。 用户访问某网址时,框架自动调用控制器的某个函数。
因为本框架设计思想希望配置尽可能少,所以这里的路径映射是通过命名关系的。
假设应用的根目录为
http://localhost:8080/YangMVC/
如在org.demo下(这个目录可以在web.xml中配置,可见上一节)有一个BookController。
那么这个类的路径是 http://localhost:8080/YangMVC/book/
用户访问这个路径时,框架会调用BookController 的index方法。如果没有这个方法则会报错。
index方法用以处理某个路径下的默认网页(网站以斜杠结尾的都会调用某个类的index方法来处理)。
book这个地址,将第一个字母大写,后面追加Controller。于是
book (路径名)-> Book -> BookController(类名)
这就是路径和类名的默认关联。
在这个网站后加入方法名可以访问BookController的 任何一个公共方法。
如 http://localhost:8080/YangMVC/book/edit 与BookController的edit方法关联。
需要注意的是,如果你写的是 http://localhost:8080/YangMVC/book/edit/ (比上一个网站多了一个斜杠), 则它对应的是 book.EditController下的index方法 而不是BookController下的edit方法。
控制器方法
获取request中的参数
String s = param("name"); Integer id = paramInt("id");
输出方法
output方法
output("Hello YangMVC");
这个方法输出一个文本到网页上(输出流中),并关闭输出流。因为它会关闭流,所以你不要调用它两次。你如果需要输出多次,以将内容放到StringBuffer中,然后统一输出。
render方法
public void paramDemo(){ put("a", "sss"); render("/testrd.jsp"); }
这里的testrd.jsp是模板目录(/view)目录下的。 /view/testrd.jsp
这里的参数应该是相对于模板目录的相对路径。
render方法使用参数制定的网页(一个包含JSTL的jsp文件),将其输出。可以通过put来制定参数。下面会详细讲。
render()方法
这个render方法是没有参数的,它会使用默认模板,如果这个模板不存在,就会提示错误。 public void renderDemo(){ request.setAttribute("a", "sss"); render(); }
在配置 controller 为org.demo , template为/view 这种情况下。
org.demo.IndexController的renderDemo方法会对应/view/renderDemo.jsp
之所以模板存在于模板根目录下,是因为这个IndexController是处理应用根目录的。他们有对应关系。
如果是org.demo.BookController,它对应 app根目录下的 /book/ 目录。
它的add方法对应路径 /book/add
如果应用名为hello,那么完成路径应该是 /hello/book/add
outputJSON 方法
该方法将参数转化为JSON,并向网页输出。
public void jsonDemo(){ Map<String, Object> map = new HashMap<String, Object>(); map.put("id", 12); map.put("name", "Yang MVC"); map.put("addtm",new Date()); outputJSON(map); } 这个代码稍长,其实上面的所有都是生成一个Map,最后一句输出。outputJSON可以输出List,Map和任何Java对象。内部转换是使用fastjson实现的。
自动生成并输出一个表单
public void renderForm(Model m,String template,String postTo)
该函数会根据模型对应的表结构,自动生成一个表单,并将其内容放入 表格名_form 中,如book表会输出到 book_form 中。
在网页中,直接写 ${book_form}就可以将表单放下去。
template制定对应的模板文件,可以省略,省略后按照默认规则查找模板文件。
postTo设定 表单提交的网页,可以省略,默认是"",即当前网页(Controller)。
获取参数的方法
- param(String p) 获取参数p的值,以String类型返回
- paramInt(String p) 获取参数p的值,以Int类型返回,如果不是整数,则会出现异常
- public Model paramToModel(Model m)
- 根据名称匹配的原则,将与模型中参数名相同的参数的值放入模型中。并返回该模型。
- 是收集表单数据到模型中的神器,手机后就可以直接进行数据库操作了。
- paramWithDefault 获取参数,但同时带上默认值,如果没这个参数则返回默认值。
检查方法
public void checkNull(String name,Object obj)
检查obj是否为null,如果是抛出NullParamException异常。
ORM框架
Model与DBTool
Model 对象对应数据库的表格,它会与一个表格进行绑定。DBTool相当于是它的DAO类。
YangMVC的ORM组件可以单独使用。使用前需要先配置数据库:
Config.dbhost = "localhost"; Config.dbname = "dc2"; Config.dbpwd = "123456"; Config.dbusr ="root"; Config.dbport="3306";
也可以和MVC框架一起使用。配置时在web.xml中配置
创建一个DBTool对象
DBTool tool = Model.tool("book");
其中book是数据库表的名字。
创建一个空的Model
DBTool tool = Model.tool("book");
Model m = tool.create(); //创建新的
根据主键读取一个Model
Model m = tool.get(12);
查询表中所有的行
LasyList list = tool.all(); all返回一个LasyList对象。这个对象在此事并没有真正进行数据库查询,只有在页面真正读取时才会读取数据库。这是它叫做Lasy的原因。此处借鉴了Django的实现机制。
查询的limit语句
LasyList list = tool.all().limit(30); list = tool.all().limit(10,30);
查询的等式约束
tool.all().eq("name","本草纲目")
查询的不等式约束
tool.all().gt("id",12) //id < 12 tool.all().lt("id",33) //id <33 tool.all().gte("id",12) //id>=12 tool.all().lte("id",33) //id<=33 tool.all().ne("id",33) //不相等
模糊查询
tool.all().like("name","本草") 查找所有名字中包含本草的书。返回一个LasyList
排序
tool.all().orderby("id",true); 按照id的增序排列。 如果是false,则是降序。
级联查询
因为这些上面的过滤器函数全部都会返回一个LasyList对象, 所以可以采用级联的方式进行复杂查询。如:
list = tool.all().gt("id", 12).lt("id", 33).eq("name","haha").like("author","王");
这个例子相当于执行了如下SQL语句:
select * from book where id>12 and id<33 and name='haha' and author like '%王%'
根据原始sql获取(version >=1.5.4)
LasyList list = LasyList.fromRawSql("select name from book");
使用原始的sql获取的List中的模型将和数据库表没有关联。
Model的相关功能
model 是一个继承自Map<String,Object> 的类,所以对于
Model m;
你可以在网页中使用${m.name}的方式来访问它的name键对应的值。相当于m.get("name")
这种写法在JSTL中非常有用。让Model继承Map的初衷就在于此:方便在JSTL中使用。
大家也许注意到了LasyList是一个继承自List<Model> 的类.
这就使得不管是LasyList还是Model在JSTL中访问都极为的便利。
访问所有的键值(即DAO对象的所有属性)
model.keySet();
访问某一个属性的值
model.get(key)
设置某一个属性的值
model.put(key,value)
相关推荐
- css布局方案汇总(28个实例图文并茂)
-
简介布局在我们前端日常开发来说是非常重要的,一个好的布局能简化代码的同时还能提高网页的性能。常见的布局方法有浮动(float)布局、绝对定位(position)布局、表格布局(table)、弹性(fl...
- 十款免费的CSS框架加速Web开发
-
Pure这是Yahoo最新推出的一款CSS框架,它只有HTML和CSS,没有使用任何JavaScript语言。总大小只有4.4kb,但功能却非常丰富,支持响应式样式和各种导航、表格、表单、按钮、网格和...
- Tailwind CSS 是不是目前世上最好的CSS框架?
-
转载说明:原创不易,未经授权,谢绝任何形式的转载今天看了一篇国外大佬对TailwindCSS的看法,在这里分享给大家,看看大家是否赞同,以下是其相关内容的整理,由于翻译水平有限,欢迎大家讨论和指...
- 下一代 CSS 框架:Mojo CSS,为何如此受欢迎?
-
TailwindCSS推出即受到广大开发者的欢迎,当前Githubstar数已达77.8k。它是一个功能类优先(utility-first)的CSS框架,它提供了一系列功能类,让开发者...
- 常见的几种摄影构图方式
-
摄影构图,是一种在摄影画面中表现结构美、形式美的方式。构图能让摄影主体更加突出,画面更加有序。所以说,构图在摄影中是非常重要的一个环节。无论是前期构图还是后期构图,摄影者都要对构图有一个比较深的了解。...
- 风光摄影10大构图技巧,会用构图,照片更容易好看
-
风光摄影10大构图技巧,会用构图,照片更容易好看先解释一下,为什么会使用构图之后,照片更容易好看?因为,构图是根据很多好看的照片,总结出来的技巧,使用这些构图技巧,就相当于站在了巨人的肩膀上,也就是用...
- 掌握框式构图的摄影技巧,会让摄影爱好者的作品更有魅力!
-
很多摄影爱好者都知道摄影构图中有个框式构图,但大多数人对框式构图的摄影技巧,却一知半解。所以摄影爱好者们有必要更全面、深入的了解,并掌握框式构图,会对你摄影水平的提高更有帮助。【欢迎点击上方关注:金立...
- 这个构图很简洁,但为什么不耐看?
-
摄影爱好者最常犯的错就是过于复杂、主体不明确,但当遇到简单的场景往往又会出现单调、不耐看的状况。为什么会这样?说白了还是观察力不够。下面是本周的摄影入围习作,我们一起来看看这些照片中主体、陪体以及背景...
- 初学者需要记牢的八种常用构图法
-
作者:冯海军摄影中,构图很关键,决定照片是否成功,所以在构图上要加以重视和推敲,虽然说构图无定法,但是也有很多的规律可循,以下列举几种常用构图,会对初学者有很大的帮助。多彩刘卫洲摄苏州姑苏俱乐部(...
- 构图这件事不难!掌握14种构图模式就稳了
-
如果说视觉元素是视觉信息的载体,那么构图就是视觉元素的载体。没有适当形式的构图对视觉元素有机、有序地承载,平面设计将无法传达预定的设计意图和视觉信息。因此,对于平面设计而言,构图是平面设计不可或缺的重...
- 框架构图如何使用?
-
1分钟教你用手机拍大片。今天我们利用框架构图,在不同的运镜方法下拍摄。·首先将手机贴近地面,拍摄人物走过的画面。·然后利用3D效果的背景衬托,将手机贴近地面,以低角度仰拍人物。·最后我们用高清画质来呈...
- 面构图的5种超实用的构图形式 前景构图,框架构图,填充构图
-
面构图的5种超实用的构图形式。为什么有的人拍摄的照片好看又舒适?仔细观察会发现他们善用构图。大家好,今天带大家了解摄影中5种超实用的面构图形式。·一、前景构图。前景是构图中的神奇要素,可以提升照片的表...
- 一看就懂!跟着马格南的大师学构图
-
马格南图片社是迄今为止全球最重要的摄影图片社,其网站包涵了太多经典的名字和照片。细细品味这些经典图片,能够学到很多有用的构图手法。跟着大师走,总不会错吧?前后景的运用这似乎是非常常见的一种手法,仔细看...
- 这才是框架构图,有想法!能给你启发么?
-
框架构图大家并不陌生,但并不是有一个框就行了。框架构图用得不好,就很死板生硬,给人感觉很假。如果你理解透了,拍出的作品不会单调。今天就给大家分享一下框架构图,你看看有哪些妙用?1.广角与长焦的应用长焦...
- 7B小模型写好学术论文,新框架告别AI引用幻觉
-
ScholarCopilot团队投稿量子位|公众号QbitAI学术写作通常需要花费大量精力查询文献引用,而以ChatGPT、GPT-4等为代表的通用大语言模型(LLM)虽然能够生成流畅文本,但...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 若依框架 (41)
- MVC框架 (46)
- spring框架 (46)
- 框架图 (58)
- bootstrap框架 (43)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- jpa框架 (47)
- scrapy框架 (52)
- beego框架 (42)
- java框架spring (43)
- grpc框架 (55)
- 前端框架bootstrap (42)
- orm框架有哪些 (43)
- ppt框架 (48)
- 内联框架 (52)
- winform框架 (46)
- gui框架 (44)
- cad怎么画框架 (58)
- ps怎么画框架 (47)
- ssm框架实现登录注册 (49)
- oracle v (42)
- oracle字符串长度 (48)
- oracle提交事务 (47)