本文可以转载,但请保留版权信息。

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>

所有须要配置的都在这里了。
这里做个简要解释

jsp网页的框架是什么一个易学易用高效便捷的MVC和ORM框架 Vue.js

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,一个支持

首先我们调用了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)